LiteFlow决策系统的策略模式,顺序、最坏、投票、权重

个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


image

想必大家都有听过或做过职业和性格测试吧,尤其是现在的毕业生,在投了简历之后经常会收到一个什么测评,那些测评真的是又臭又长,做的简直让人崩溃,很多时候都是边骂边做,都什么玩意!?

然而,本篇就由此出发,把整个测评作为一个策略的话,其中每一项都是一条规则,通常每一条规则(问答)需要我们输入一个类似1-9的分数,1和9分别代表两个极端,最终这个策略会结合所有的问答结果计算出我们的性格/职业。这是如何做的呢?其实就是一种分类算法,就拿二维平面直角坐标系举例吧!

如下二维平面直角坐标系下分出了4个区域,性格/职业测评的每条问答可以理解为其中一条经过原点的直线,1-9分别指示两个方向,你的答案最终会是一个由原点出发的n条直线,这n条直线可以绘成一个多边形,而这个多边形就构成了最终结果,长得有点类似雷达图。

image

image

image

当然这只是二维平面直角坐标系的例子,实际上现实往往比这个更复杂,高于三维的我也举不出例子啊🙂‍↔️

总之最后结果绝大多数情况下都会是一个不规则的东西(我实在不知道更高维的该怎么描述),这种测评会取出凸点作为我们的倾向性格/职业。

好吧,关于文章开篇就到这里了,下面就可以正式开始了。不过我还是想讲一个题外话,小时候接触的数学函数(方程)可以很轻易的表示在二维直角坐标系下,随着对于数学的深入探索,出现了越来越多的奇奇怪怪的字母和方程,有人也讲“数学的尽头是字母”🤔然而当我们换一个坐标系,这些是不是也会变个模样呢?所以说有时候换个角度看问题就会有不同收获,或者说换个角度问题就会迎刃而解。

策略

策略组件大致实现如下,编排时会使用p_cn.tag("code"),运行FOR(p_fn).DO(r_cn).BREAK(p_bn);FOR(p_fn).parallel(true).DO(r_cn);,前者适用于顺序模式,其他皆适用于后者。

@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.POLICY_COMMON_NODE, nodeType = NodeTypeEnum.COMMON, nodeName = "策略普通组件")
public void policy(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.PolicyCtx policy = PolicyConvert.INSTANCE.convert2Ctx(policyMapper.selectByCode(bindCmp.getTag()));policyContext.addPolicy(policy.getCode(), policy);log.info("当前策略(code:{}, name:{}, code:{})", policy.getCode(), policy.getName(), policy.getCode());if (PolicyMode.ORDER.equals(policy.getMode())) {bindCmp.invoke2Resp(LFUtil.P_F, policy.getCode());} else {bindCmp.invoke2Resp(LFUtil.P_FP, policy.getCode());}
}

循环次数组件p_fn如下,查询策略下的所有规则(规则还没做版本控制,后面再改),返回规则列表大小。

@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_FOR, nodeId = LFUtil.POLICY_FOR_NODE, nodeType = NodeTypeEnum.FOR, nodeName = "策略for组件")
public int policyFor(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);String policyCode = bindCmp.getSubChainReqData();List<PolicyContext.RuleCtx> ruleList = RuleConvert.INSTANCE.convert2Ctx(ruleMapper.selectByPolicyCode(policyCode));policyContext.addRuleList(policyCode, ruleList);return ruleList.size();
}

循环中断组件p_bn如下,当策略上下文中有命中风险规则时就可以停止循环了。

@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_BOOLEAN, nodeId = LFUtil.POLICY_BREAK_NODE, nodeType = NodeTypeEnum.BOOLEAN, nodeName = "策略break组件")
public boolean policyBreak(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);String policyCode = bindCmp.getSubChainReqData();return policyContext.isHitRisk(policyCode);
}

另外在使用异步循环编排时需要注意并发操作问题,尤其是对上下文的操作。

剩下的规则组件r_cn和策略上下文PolicyContext请往下看。

顺序:按部就班、循序渐进

顺序模式是最好理解,就是顺序运行策略下的所有规则,默认在第一条设定的风险规则触发后结束,其实更准确的叫法应该是首次。如下表在顺序模式下执行,到规则2就结束了,因为默认pass之外的才是风险规则。

规则是否命中处置方式
1truepass
2truereject
3falsesms
4truereview

最坏:未雨绸缪,防患未然

与顺序模式不同,需要执行所有的规则,综合最坏的作为结果。如下表在最坏模式下,最终结果是reject(因为reject>review>pass,这个是配置的)。

规则是否命中处置方式
1truepass
2truereject
3falsesms
4truereview

投票:集体智慧,共同决策

同上,需要执行完所有规则,以命中规则的结果最多的作为最终结果。如下表在投票模式下,结果是pass

规则是否命中处置方式
1truepass
2truereject
3falsereview
4truepass

可以使用这样的计数器,但是考虑到策略集下有不一样的策略集,想必还要再包一层Map<String,ConcurrentHashMap<String, AtomicInteger>>,以策略code作为键。

private final ConcurrentHashMap<String, AtomicInteger> counters = new ConcurrentHashMap<>();/*** 增加指定 key 的计数值。* 如果 key 不存在,则初始化为 1;如果存在,则将当前值加 1。*/
public void increment(String key) {// 使用 computeIfAbsent 方法来确保只在第一次遇到该 key 时创建新的 AtomicIntegercounters.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet();
}/*** 获取指定 key 的当前计数值。* 如果 key 不存在,则返回 0。*/
public int get(String key) {// 获取指定 key 的 AtomicInteger,并调用 get() 方法获取其值AtomicInteger counter = counters.get(key);return (counter != null) ? counter.get() : 0;
}

本来考虑的是在规则True组件中根据策略不同做不同的事情,但后来放弃了,还是统一放在上下文中吧,且往下看。

image

权重:量化评估,科学分配

一样,需要运行完所有规则,综合权重模式阈值配置得出最终结论。如下表在权重模式下,结果是23+21+20=64,注意!!!这里只是得到一个数字,在策略设置为权重模式后额外还需要配置一个阈值表,拿这个数字去匹配对应的阈值区间得出最终结论。当然这只是个最简单例子,下面将展开,讨论其丰富的应用场景和更灵活的使用方法。

规则是否命中得分
1true23
2true21
3false30
4true20

阈值配置表

得分结果
(-214,20]pass
(20,45]review
(45,70]sms
(70,900)reject

设计过程

阶段一:规则增加简单的分数属性,命中时累计就好,如:规则1命中时+10,规则2命中时-2,这样最为简单,也因此适用场景最少,最不灵活。

阶段二:固定公式计算,如下规则附加这些属性,在规则命中时计算一下,这种只适合简单的线性相关的规则计算。

/*** 计算公式为:base + al aOpType(加/减/乘/除) ${value}(取决于opType类型,是指标还是字段),结果范围[lowerLimit,upperLimit]** @author wnhyang* @date 2024/12/9**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Weight {private Double base; // 基础权重private Double al; // 权重调整因子private String aOpType; // 操作类型:加/减/乘/除private String opType; // 指标还是字段private String value; // 指标名称或字段名称private Double upperLimit; // 上限private Double lowerLimit; // 下限/*** 计算最终权重** @param trueValue 实际值,当 opType 为 "zb" (指标) 时使用* @return 最终计算出的权重*/public double compute(double trueValue) {if (al == null || trueValue == 0 && ("/".equals(aOpType))) {throw new IllegalArgumentException("Invalid parameters for computation.");}double adjustment = 0;switch (aOpType) {case "+":adjustment = al + trueValue;break;case "-":adjustment = al - trueValue;break;case "*":adjustment = al * trueValue;break;case "/":adjustment = al / trueValue;break;default:throw new UnsupportedOperationException("Unsupported operation type: " + aOpType);}double result = base + adjustment;return Math.min(upperLimit, Math.max(lowerLimit, result));}public static void main(String[] args) {Weight weight = new Weight(10.41, -2.154, "*", "zb", "count", 5000.545, -56.654);double compute = weight.compute(25.21);System.out.println("Computed weight: " + compute);}
}

阶段三:灵活公式,使用QLExpress实现。如下讲计算公式作为规则的一个属性,通过getOutVarNames获取需要用到的外部变量名,在运行表达式之前通过LiteFlow上下文取值塞到QLExpress的上下文中。

当然还有可以优化的地方,1、设计上下文时实现QLExpressIExpressContext接口,也就不用获取后在塞,直接拿LiteFlow上下文作为QLExpress上下文用就行;2、还有就是min(upperLimit, max({}, lowerLimit))是否要放在表达式中,其实也是没必要,可以放在表达式计算完成之后嘛。3、是否要计算平均值,现在是权重之和,是否要做加权平均呢?4、等等

@Test
public void test3() throws Exception {ExpressRunner runner = new ExpressRunner();DefaultContext<String, Object> context = new DefaultContext<>();String fun = "base + al * value";String express = StrUtil.format("min(upperLimit, max({}, lowerLimit))", fun);log.info(express);String[] outVarNames = runner.getOutVarNames(express);log.info(Arrays.toString(outVarNames));context.put("base", 45.434);context.put("al", 3.352);context.put("value", 24.3264);context.put("lowerLimit", -35.342);context.put("upperLimit", 3463.57);Object r = runner.execute(express, context, null, true, false);log.info("{}", r);
}

注意点

对于像这种可输入的、脚本类的、在系统中运行的,一定要做好安全性校验,避免直接操作系统资源,稍微不注意控制就会有安全漏洞。在保证安全的前提下,再考虑如何优化用户使用体验,如用户需要使用一些系统字段时,在编辑器文本域输入特殊字符(像“@”或“#”),监听到输入后显示候选列表,可以关键词匹配并选择需要的字段,一旦选中,这个将作为一个整体,只能整体操作,就像我们在发邮件,或者聊天时输入“@”一样,另外再做一个内置运算符的提示符,这样编辑公式就更加便捷,且能降低出错率。再进一步就是做一个常用公式库,提示列表中有直接选中就行,剩下的就是填充需要的字段就行。

image

应用场景

比如在做密码登录时,设置了两条规则,一条正向规则y1=f(x1)x1表示最近人脸登录成功次数,其与结果负相关,人脸登录成功次数越多得到的负数越大;一条反向规则y2=f(x2)x2表示最近密码登录失败次数,其与结果正相关,密码登录失败次数越多得到的分数越大,而且保证其“增长率”大于f(x1)

可以大致表示为下面的曲线,最近人脸登录成功次数少时,风险高一些,多时也会存在上限,因为再多也没有意义了;最新密码登录错误次数少时风险低,但密码登录次数越多风险急剧增加,这样的话在整合y=y1+y2=f(x1)+f(x2)后,风险受密码登录错误次数的影响更大。

image

当然将两个公式整合到一块做为一个规则也是可以的,差别就是是否需要独立的规则条件。

条件公式
不合并condition1f(x1)
condition2f(x2)
合并condition1f(x1)+f(x2)

还有就是在信贷计算信用时,需要计算收入稳定性+信用历史+就业情况+债务水平+资产情况的场景时,当然这依赖多方数据,而且一般的信用评估不是简单的规则配置能解决的。

模型:智能学习,进化升级

最终都将到这一步的,虽然现在做的项目中还没有集成模型,但是我之后一定会做。先立flag嘛,实现不是实现另说吧🧐可别连立flag的勇气都没有了!

关于模型我也不是专业的,也是仅有一点点了解。我一直认为学习能力、看待、解决问题的思想是最重要的,特别是我看了几个关于机器学习的视频后,虽然其中很多的公式我都不懂,但是能理解到其看待、解决问题的思路方法,很受益,很有启发。

规则

以下分别是规则组件(包含isAccess实现)、命中规则、未命中规则组件。在规则命中时额外计算规则配置的权重表达式。

@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS, nodeId = LFUtil.RULE_COMMON_NODE, nodeType = NodeTypeEnum.COMMON)
public boolean ruleAccess(NodeComponent bindCmp) {String policyCode = bindCmp.getSubChainReqData();int index = bindCmp.getLoopIndex();PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.RuleCtx rule = policyContext.getRule(policyCode, index);return !RuleStatus.OFF.equals(rule.getStatus());
}@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.RULE_COMMON_NODE, nodeType = NodeTypeEnum.COMMON, nodeName = "规则普通组件")
public void rulProcess(NodeComponent bindCmp) {String policyCode = bindCmp.getSubChainReqData();int index = bindCmp.getLoopIndex();PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.RuleCtx rule = policyContext.getRule(policyCode, index);bindCmp.invoke2Resp(StrUtil.format(LFUtil.RULE_CHAIN, rule.getCode()), rule);
}@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.RULE_TRUE, nodeType = NodeTypeEnum.COMMON, nodeName = "规则true组件")
public void ruleTrue(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.RuleCtx rule = bindCmp.getSubChainReqData();log.info("命中规则(name:{}, code:{})", rule.getName(), rule.getCode());if (RuleStatus.MOCK.equals(rule.getStatus())) {policyContext.addHitMockRuleVO(rule.getPolicyCode(), rule);} else {// 权重if (PolicyMode.WEIGHT.equals(policyContext.getPolicy(rule.getPolicyCode()).getMode())) {try {Double value = (Double) QLExpressUtil.execute(rule.getExpress(), bindCmp.getContextBean(FieldContext.class));rule.setExpressValue(value);} catch (Exception e) {log.error("规则表达式执行异常", e);}}policyContext.addHitRuleVO(rule.getPolicyCode(), rule);}
}@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.RULE_FALSE, nodeType = NodeTypeEnum.COMMON, nodeName = "规则false组件")
public void ruleFalse(NodeComponent bindCmp) {log.info("规则未命中");
}

策略上下文

直接上代码了。

/*** @author wnhyang* @date 2024/4/3**/
public class PolicyContext {/*** 处置方式集合*/private final Map<String, DisposalCtx> disposalMap = new ConcurrentHashMap<>();/*** 策略集*/private PolicySetCtx policySet;/*** 初始化** @param disposalCtxList 处置方式集合* @param policySet       策略集*/public void init(List<DisposalCtx> disposalCtxList, PolicySetCtx policySet) {for (DisposalCtx disposalCtx : disposalCtxList) {disposalMap.put(disposalCtx.getCode(), disposalCtx);}this.policySet = policySet;}/*** 策略集合*/private final Map<String, PolicyCtx> policyMap = new ConcurrentHashMap<>();/*** 添加策略** @param policyCode 策略code* @param policy     策略*/public void addPolicy(String policyCode, PolicyCtx policy) {policyMap.put(policyCode, policy);}/*** 获取策略** @param policyCode 策略code* @return 策略*/public PolicyCtx getPolicy(String policyCode) {return policyMap.get(policyCode);}/*** 规则集合*/private final Map<String, List<RuleCtx>> ruleListMap = new ConcurrentHashMap<>();/*** 添加规则集合** @param policyCode 策略code* @param ruleList   规则列表*/public void addRuleList(String policyCode, List<RuleCtx> ruleList) {ruleListMap.put(policyCode, ruleList);}/*** 获取规则** @param policyCode 策略code* @param index      规则索引* @return 规则*/public RuleCtx getRule(String policyCode, int index) {return ruleListMap.get(policyCode).get(index);}/*** 命中规则集合*/private final Map<String, List<RuleCtx>> hitRuleListMap = new ConcurrentHashMap<>();/*** 添加命中规则** @param policyCode 策略code* @param rule       规则*/public void addHitRuleVO(String policyCode, RuleCtx rule) {if (!hitRuleListMap.containsKey(policyCode)) {hitRuleListMap.put(policyCode, CollUtil.newArrayList());}hitRuleListMap.get(policyCode).add(rule);}/*** 是否命中风险规则** @param policyCode 策略code* @return true/false*/public boolean isHitRisk(String policyCode) {if (CollUtil.isNotEmpty(hitRuleListMap.get(policyCode))) {for (RuleCtx ruleCtx : hitRuleListMap.get(policyCode)) {if (!DisposalConstant.PASS_CODE.equals(ruleCtx.getDisposalCode())) {return true;}}}return false;}/*** 命中模拟规则集合*/private final Map<String, List<RuleCtx>> hitMockRuleListMap = new ConcurrentHashMap<>();/*** 添加命中模拟规则** @param policyCode 策略code* @param rule       规则*/public void addHitMockRuleVO(String policyCode, RuleCtx rule) {if (!hitMockRuleListMap.containsKey(policyCode)) {hitMockRuleListMap.put(policyCode, CollUtil.newArrayList());}hitMockRuleListMap.get(policyCode).add(rule);}/*** 转策略集结果** @return 策略集结果*/public PolicySetResult convert() {PolicySetResult policySetResult = new PolicySetResult(policySet.getName(), policySet.getCode(), policySet.getChain(), policySet.getVersion());for (Map.Entry<String, PolicyCtx> entry : policyMap.entrySet()) {PolicyCtx policy = entry.getValue();PolicyResult policyResult = new PolicyResult(policy.getName(), policy.getCode(), policy.getMode());// 最坏String maxDisposalCode = DisposalConstant.PASS_CODE;int maxGrade = Integer.MIN_VALUE;// 投票Map<String, Integer> votes = new HashMap<>();// 权重double weight = 0.0;List<RuleCtx> ruleList = hitRuleListMap.get(policy.getCode());if (CollUtil.isNotEmpty(ruleList)) {for (RuleCtx rule : ruleList) {if (PolicyMode.VOTE.equals(policy.getMode())) {// 投票votes.put(rule.getDisposalCode(), votes.getOrDefault(rule.getDisposalCode(), 0) + 1);} else if (PolicyMode.WEIGHT.equals(policy.getMode())) {// 权重weight += rule.getExpressValue();}RuleResult ruleResult = new RuleResult(rule.getName(), rule.getCode(), rule.getExpress());// 最坏和顺序DisposalCtx disposal = disposalMap.get(rule.getDisposalCode());if (null != disposal) {ruleResult.setDisposalName(disposal.getName());ruleResult.setDisposalCode(disposal.getCode());if (disposal.getGrade() > maxGrade) {maxGrade = disposal.getGrade();maxDisposalCode = disposal.getCode();}}// 模拟/正式规则区分开if (RuleStatus.MOCK.equals(rule.getStatus())) {policyResult.addMockRuleResult(ruleResult);} else {policyResult.addRuleResult(ruleResult);}}}if (PolicyMode.VOTE.equals(policy.getMode())) {String maxVoteDisposalCode = DisposalConstant.PASS_CODE;int maxVoteCount = Integer.MIN_VALUE;for (Map.Entry<String, Integer> entry1 : votes.entrySet()) {if (entry1.getValue() > maxVoteCount) {maxVoteCount = entry1.getValue();maxVoteDisposalCode = entry1.getKey();}}policyResult.setDisposalName(disposalMap.get(maxVoteDisposalCode).getName());policyResult.setDisposalCode(maxVoteDisposalCode);} else if (PolicyMode.WEIGHT.equals(policy.getMode())) {List<Th> thList = policy.getThList();// 排序thList.sort(Comparator.comparing(Th::getScore));for (Th th : thList) {if (weight <= th.getScore()) {policyResult.setDisposalName(disposalMap.get(th.getCode()).getName());policyResult.setDisposalCode(th.getCode());break;}}} else {policyResult.setDisposalName(disposalMap.get(maxDisposalCode).getName());policyResult.setDisposalCode(maxDisposalCode);}policySetResult.addPolicyResult(policyResult);}// TODO 入度大于1?考虑投票、加权平均等方法:不考虑policySetResult.setDisposalName(DisposalConstant.PASS_NAME);policySetResult.setDisposalCode(DisposalConstant.PASS_CODE);return policySetResult;}
}

策略集

策略集是用来编排策略的,即前面的策略组件p_cn.tag("code"),从前面已知策略会有结果的,那么编排他们的策略集如何取这个结果呢?

这就要考虑如何设计策略集的编排了,两种情况,入度为1,入度大于1。

如下,图1并行运行策略1、2,并最终都返回到结束节点,这时就要考虑如何处理策略1、2的结果了,投票?加权平均?随机选一个?还是其他什么方法?图2通过分流结束节点只会接收到一个策略,那么此时就不会有冲突,分流到哪个就返回哪个。

当然这块还没想好怎么做,只是一些想法。

image

小结

本来还想分享一下项目进展的,但转眼一看好像写的已经有点多了,那就下次吧!

写在最后

拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。


个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63761.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机视觉基础CV-图像分类】02-入门详解图像分类、经典数据集、比赛与冠军图像模型演进史

前言 图像分类&#xff08;Image Classification&#xff09;是计算机视觉&#xff08;Computer Vision&#xff09;中一项基础且核心的任务。简单来说&#xff0c;就是让计算机从给定的类别集合中&#xff0c;为一张输入图片分配一个正确的类别标签。这个过程听起来直观&…

嵌入式驱动开发详解20(IIO驱动架构)

文章目录 前言IIO子系统简介主要结构体主要API函数 IIO子系统实现SPI框架IIO框架IIO通道详解通道结构体分析通道命名分析icm20608设备通道实现 读取函数写入函数 测试测试效果命令行读取应用程序读取 后续参考文献 前言 IIO 全称是 Industrial I/O&#xff0c;翻译过来就是工业…

Linux 网络维护相关命令简介

目录 零. 概要一. ping二. ip命令2.1 ip address2.2 ip route2.3 ip neighbour 三. traceroute四. DNS查询4.1 nslookup4.2 dig 五. ss 查看网络连接状态 零. 概要 ⏹在Linux系统中有2套用于网络管理的工具集 net-tools 早期网络管理的主要工具集&#xff0c;缺乏对 IPv6、网…

Jenkins持续集成部署——jenkins安装

前言 Jenkins 是一个开源的自动化服务器&#xff0c;主要用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;。它为软件开发团队提供了一个易于使用的平台来自动化构建、测试和部署应用程序的过程。 Jenkins 主要功能 1. 持续集成 (CI) 自动构建…

PYG - Cora数据集加载 (自动加载+手动实现)

本文从Cora的例子来展示PYG如何加载图数据集。 Cora 是一个小型的有标注的图数据集&#xff0c;包含以下内容&#xff1a; data.x&#xff1a;2708 个节点&#xff08;即 2708 篇论文&#xff09;&#xff0c;每个节点有 1433 个特征&#xff0c;形状为 (2708, 1433)。data.ed…

机器学习基础算法 (二)-逻辑回归

python 环境的配置参考 从零开始&#xff1a;Python 环境搭建与工具配置 逻辑回归是一种用于解决二分类问题的机器学习算法&#xff0c;它可以预测输入数据属于某个类别的概率。本文将详细介绍逻辑回归的原理、Python 实现、模型评估和调优&#xff0c;并结合垃圾邮件分类案例进…

BiTCN-BiGRU基于双向时间卷积网络结合双向门控循环单元的数据多特征分类预测(多输入单输出)

Matlab实现BiTCN-BiGRU基于双向时间卷积网络结合双向门控循环单元的数据多特征分类预测&#xff08;多输入单输出&#xff09; 目录 Matlab实现BiTCN-BiGRU基于双向时间卷积网络结合双向门控循环单元的数据多特征分类预测&#xff08;多输入单输出&#xff09;分类效果基本描述…

51c大模型~合集94

我自己的原文哦~ https://blog.51cto.com/whaosoft/12897659 #D(R,O) Grasp 重塑跨智能体灵巧手抓取&#xff0c;NUS邵林团队提出全新交互式表征&#xff0c;斩获CoRL Workshop最佳机器人论文奖 本文的作者均来自新加坡国立大学 LinS Lab。本文的共同第一作者为上海交通大…

【大学英语】英语范文十八篇,书信,议论文,材料分析

关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…

一起学Git【第一节:Git的安装】

Git是什么&#xff1f; Git是什么&#xff1f;相信大家点击进来已经有了初步的认识&#xff0c;这里就简单的进行介绍。 Git是一个开源的分布式版本控制系统&#xff0c;由Linus Torvalds创建&#xff0c;用于有效、高速地处理从小到大的项目版本管理。Git是目前世界上最流行…

【day11】面向对象编程进阶(继承)

概述 本文深入探讨面向对象编程的核心概念&#xff0c;包括继承、方法重写、this和super关键字的使用&#xff0c;以及抽象类和方法的定义与实现。通过本文的学习&#xff0c;你将能够&#xff1a; 理解继承的优势。掌握继承的使用方法。了解继承后成员变量和成员方法的访问特…

随手记:小程序兼容后台的wangEditor富文本配置链接

场景&#xff1a; 在后台配置wangEditor富文本&#xff0c;可以文字配置链接&#xff0c;图片配置链接&#xff0c;产生的json格式为&#xff1a; 例子&#xff1a; <h1><a href"https://uniapp.dcloud.net.cn/" target"_blank"><span sty…

6.8 Newman自动化运行Postman测试集

欢迎大家订阅【软件测试】 专栏&#xff0c;开启你的软件测试学习之旅&#xff01; 文章目录 1 安装Node.js2 安装Newman3 使用Newman运行Postman测试集3.1 导出Postman集合3.2 使用Newman运行集合3.3 Newman常用参数3.4 Newman报告格式 4 使用定时任务自动化执行脚本4.1 编写B…

计算机网络之王道考研读书笔记-2

第 2 章 物理层 2.1 通信基础 2.1.1 基本概念 1.数据、信号与码元 通信的目的是传输信息。数据是指传送信息的实体。信号则是数据的电气或电磁表现&#xff0c;是数据在传输过程中的存在形式。码元是数字通信中数字信号的计量单位&#xff0c;这个时长内的信号称为 k 进制码…

法规标准-C-NCAP评测标准解析(2024版)

文章目录 什么是C-NCAP&#xff1f;C-NCAP 评测标准C-NCAP评测维度三大维度的评测场景及对应分数评星标准 自动驾驶相关评测场景评测方法及评测标准AEB VRU——评测内容(测什么&#xff1f;)AEB VRU——评测方法(怎么测&#xff1f;)车辆直行与前方纵向行走的行人测试场景&…

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书正式赛题

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项任务书-A 目录 一、竞赛阶段 二、竞赛任务书内容 &#xff08;一&#xff09;拓扑图 &#xff08;二&#xff09;模块A 基础设施设置与安全加固(200分) &#xff08;三&#xff09;B模块安全事件响应/网络安全数据取证/…

Halcon例程代码解读:安全环检测(附源码|图像下载链接)

安全环检测核心思路与代码详解 项目目标 本项目的目标是检测图像中的安全环位置和方向。通过形状匹配技术&#xff0c;从一张模型图像中提取安全环的特征&#xff0c;并在后续图像中识别多个实例&#xff0c;完成检测和方向标定。 实现思路 安全环检测分为以下核心步骤&…

Java——多线程进阶知识

目录 一、常见的锁策略 乐观锁VS悲观锁 读写锁 重量级锁VS轻量级锁 总结&#xff1a; 自旋锁&#xff08;Spin Lock&#xff09; 公平锁VS非公平锁 可重入锁VS不可重入锁 二、CAS 何为CAS CAS有哪些应用 1&#xff09;实现原子类 2&#xff09;实现自旋锁 CAS的ABA…

达梦 本地编码:PG_GBK, 导入文件编码:PG_UTF8错误

问题 达梦 本地编码&#xff1a;PG_GBK, 导入文件编码&#xff1a;PG_UTF8错误 解决 右键管理服务器 查看配置 新建一个数据库实例&#xff0c;配置跟之前的保持一致 新建一个用户&#xff0c;跟以前的用户名一样 在用户上&#xff0c;右键导入&#xff0c;选择dmp的位置 导…

深度学习卷积神经网络CNN之MobileNet模型网络模型详解说明(超详细理论篇)

1.MobileNet背景 2.MobileNet V1论文 3. MobileNett改进史 4. MobileNet模型结构 5. 特点&#xff08;超详细创新、优缺点及新知识点&#xff09; 一、MobileNet背景 随着移动设备的普及&#xff0c;深度学习模型的应用场景逐渐扩展至移动端和嵌入式设备。然而&#xff0c;传统…