深入理解:SLAM技术中的图优化方法探索
1.图优化的入门
在上节中,直接用俩俩匹配搭建一个里程计,但是如果:1.错误匹配,整个图就会看起来很奇怪,就是错了。2.误差会累积,常见的现象是:相机转过去的过程能作对,但转回来就很奇怪。3.效率低。由于地图拼接中累计误差是个很严重的问题,所以要保证每次匹配都精确无误,而这是很难实现的。所以我们把所有整的信息都考虑进来,成为一个全slam问题。
姿态图(原理部分)
姿态图,是由相机姿态构成的一个图(graph)。这里的图,从图论意义上来说,一个图有节点(位姿)和边构成(R,t)
在最简单的情况下节点代表相机的各个位姿(四元数或者矩阵): p=[x,y,z,qx,qy,qz,qw] p = [ x , y , z , q x , q y , q z , q w ]
而边则代表各个位姿的转换关系: T=[R3×30t3×11] T = [ R 3 × 3 t 3 × 1 0 1 ]
则我们对于简单的回环来说可以大概表示为: 1→21T2→32T3→43T4 1 → 1 2 T 2 → 2 3 T 3 → 3 4 T 4
用高博的图即:
像这样子的vo,我们除了对边进行优化之外,没有比较好的方法了,构造最小二乘法问题,使得整个VO的边误差最小,则有:
minR,t=minE=∑i,j||xi−Ti,jxj||22 m i n R , t = m i n E = ∑ i , j | | x i − T i , j x j | | 2 2
于是,我们的工作转移到了对代价函数: xi−Ti,jxj x i − T i , j x j 进行最小优化。
怎么把SLAM问题表示成图呢?
(参考高博的博客加上自己的一些理解)
图:顶点(需要调整的变量,即最小二乘中的决策变量)和边(观测方程z(测出来的东西)),然后我们是以 ek=zk−h(xk) e k = z k − h ( x k ) 为误差,以 minxFk(xk)=|ek| m i n x F k ( x k ) = | e k | 为目标函数。
那么优化变量(即顶点): 可以是一个机器人的pose(6*度下为4x4的变换矩阵T或者3*度下的x,y,)也可以是一个空间点(三维空间的[x,y,z]或者二维像素的[x,y])。观测方程(这里的观测方程,我之前纠结了好久,但是通俗的讲就是你传感器测出来的数据计算出的你想要求的变量)也有很多形式:
1.机器人俩个Pose之间的变换;
2.机器人在某个Pose处用激光测量到了某个空间点,得到了它离自己的距离和角度。
3.机器人在某个Pose处用相机观测到了某个空间点,得到了它的像素坐标。
在图中,以顶点为优化变量(在最小二乘中为决策变量),以边为观测方程(就是测出来的东东)。由于边可以链接一个或多个顶点,所以我们把它的形式写成更广义的 zk=h(xk1,xk2,...) z k = h ( x k 1 , x k 2 , . . . ) ,以不限制顶点数量的意思。
1.机器人俩个pose之间的变换;——一条Binary Edge(二元边),边的方程为: T1=ΔT⋅T2 T 1 = Δ T ⋅ T 2
2.机器人在某个Pose处用相机观测到了某个空间点,得到它的像素坐标;——Binary Edge,顶点为一个3D Pose:T和一个空间点 x=[x,y,z]T x = [ x , y , z ] T ,观测数据为像素坐标 z=[u,v]T z = [ u , v ] T ,观测方程为: z=C(Rx+t) z = C ( R x + t )
总而言之,顶点就是优化变量(三维空间点或者Pose),边就是观测方程(T或者二维坐标)
2.图优化的深入理解
图优化是什么?在graph-based SLAM中,机器人的位姿是一个节点或顶点(vetex),位姿之间的关系构成边(edge),比如t+1时刻和t时刻之间的odometry关系构成边,或者由视觉计算出来的位姿转换矩阵也可以构成边。一旦图构成了,就要调整机器人的位姿去尽量满足这些边构成约束。
图优化SLAM能分解成俩个任务:
1.构建图,机器人位姿当做顶点,位姿关系当做边,称为前端。
2.优化图,调整机器人位姿顶点尽量满足边的约束,称为后端。
图优化过程中:先堆积数据,机器人位姿为构建的顶点。边是位姿之间的关系,可以是编码器数据计
算的位姿,也可以是通过ICP匹配计算出来的位姿,还可以是闭环检测的位姿关系。
左图为建完图未经优化的图,而右图为调整顶点满足边的约束,最后得到的地图。
—————一个帮助理解的例子:——————–
如下图所示,假如机器人初始点在0处,然后机器人向前移动,通过编码器测得是1,再编码器又测得了它向后0.8,结果通过闭环检测却发现它又回到了起点。可以看出,编码器出现了点小问题,那么需要机器人这几个状态中的位姿到底是怎么样的才最好的满足这些条件呢?
建立关系:
上一篇:
模型的图形优化导论
推荐阅读
f1=x0=0;f2=x1−x0−1=0;f3
【摩尔线程+Colossal-AI强强联手】MusaBert登上CLUE榜单TOP10:技术细节揭秘
- 技术实力:摩尔线程凭借"软硬兼备"的技术底蕴,让MusaBert得以从底层优化到顶层。其内置多功能GPU配备AI加速和并行计算模块,提供了全面的AI与科学计算支持,为AI推理和低资源条件下的大模型训练等场景带来了高效、经济且环保的算力。
- 算法层面亮点:依托Colossal-AI AI大模型开发系统,MusaBert在训练过程中展现出了卓越的并行性能与易用性,特别在预处理阶段对DataLoader进行了优化,适应低资源环境高效处理海量数据。同时,通过精细的建模优化、领域内数据增强以及Adan优化器等手段,挖掘和展示了预训练语言模型出色的语义理解潜力。基于MusaBert,摩尔线程自主研发的MusaSim通过对比学习方法微调,结合百万对标注数据,MusaSim在多个任务如语义相似度、意图识别和情绪分析中均表现出色。
- 数据资源丰富:MusaBert除了自家高质量语义相似数据外,还融合了悟道开源200GB数据、CLUE社区80GB数据,以及浪潮公司提供的1TB高质量数据,保证模型即便在较小规模下仍具备良好性能。
当前,MusaBert已成功应用于摩尔线程的智能客服与数字人项目,并广泛服务于语义相似度、情绪识别、阅读理解与声韵识别等领域。为了降低大模型开发和应用难度,MusaBert及其相关高质量模型代码已在Colossal-AI仓库开源,可快速训练优质中文BERT模型。同时,通过摩尔线程与潞晨科技的深度合作,仅需一张多功能GPU单卡便能高效训练MusaBert或更大规模的GPT2模型,显著降低预训练成本,进一步推动双方在低资源大模型训练领域的共享目标。
MusaBert荣登CLUE榜单TOP10,象征着摩尔线程与潞晨科技联合研发团队在中文预训练研究领域的领先地位。展望未来,双方将携手探索更大规模的自然语言模型研究,充分运用上游数据资源,产出更为强大的模型并开源。持续强化在摩尔线程多功能GPU上的大模型训练能力,特别是在消费级显卡等低资源环境下,致力于降低使用大模型训练的门槛与成本,推动人工智能更加普惠。而潞晨科技作为重要合作伙伴,将继续发挥关键作用。
深入理解:SLAM技术中的图优化方法探索
激光定位与建图(LiDAR SLAM)中的图优化技术详解
理解SLAM中的关键环节:BA(束调整)与图优化方法详解
深度解析 | 比较SLAM中不同姿态估计算法的图优化技术
入门到精通:从理解图优化g2o代码到实战编程——SLAM技术的全程解析(详述)
理解工作流:自动化业务流程管理与Activiti实践"
**简述**
工作流(Workflow)是一种利用电脑技术自动化管理业务流程的方式,让不同参与者按既定路径执行任务,确保文档、信息或任务在预设规则下顺利传递,最终达成期望的业务目标。
**核心概念**
- **工作流自动化**: 计算机驱动业务流程处理与执行,如在参与者间自动传递文档和任务。
- **目标与应用**: 管理工作流程确保按时、由合适的人执行,同时允许人工介入以增强灵活性。
- **工作流框架示例**: Activiti、JBPM、OSWorkflow 和 Workflow,它们背后通常依赖数据库支持。
- **关键组件**: ProcessEngine 在 Activiti 中扮演核心角色,负责流程实例创建、数据管理和流程监控。
**相关领域**
- **业务流程管理 (BPM)**: 一种系统性方法论,聚焦于构建并优化端到端卓越业务流程以提升企业业绩,在EMBA、MBA等商业课程中得到关注。
- **业务流程建模与标记语言 (BPMN)**: 用于绘制业务流程图的工具,探讨其在不同场景下的应用精确度、标准化价值以及未来发展愿景。
**辅助术语**
- 流对象 (Flow Objects): BPMN 中用于描述流程中活动、决策、序列和其他元素的具体实现单元。
【2022新手指南】Java编程进阶之路 - 六、技术架构篇
### MySQL索引底层解析与优化实战
- 你会讲解MySQL索引的数据结构吗?性能调优技巧知多少?
- Redis深度揭秘:你知道多少?从基础到哨兵、主从复制全梳理
- Redis持久化及哨兵模式详解,还有集群搭建和Leader选举黑箱打开
- Zookeeper是个啥?特性和应用场景大公开
- ZooKeeper集群搭建攻略及 Leader选举、读写一致性、共享锁实现细节
- 探究ZooKeeper中的Leader选举机制及其在分布式环境中的作用
- Zab协议深入剖析:原理、功能与在Zookeeper中的核心地位
- RabbitMQ全方位解读:工作模式、消费限流、可靠投递与配置策略
- 设计者视角:RabbitMQ过期时间、死信队列与延时队列实践指南
- RocketMQ特性和应用场景揭示:理解其精髓与差异化优势
- Kafka详细介绍:特性及广泛应用于实时数据处理的场景解析
- ElasticSearch实力揭秘:特性概述与作为搜索引擎的广泛应用
- MongoDB认知升级:非关系型数据库的优势阐述,安装与使用实战教学
- BIO/NIO/AIO网络模型对比:掌握它们的区别与在网络编程中的实际应用
- Netty带你飞:理解其超快速度背后的秘密,包括线程模型分析
- 网络通信黑科技:Netty编解码原理与常用编解码器的应用,Protostuff实战演示
- 解密Netty粘包与拆包现象,怎样有效应对这一常见问题
- 自定义Netty心跳检测机制,轻松调整检测间隔时间的艺术
- Dubbo轻骑兵介绍:核心特性概览,服务降级实战与其实现益处
- Dubbo三大神器解读:本地存根与本地伪装的实战运用与优势呈现
-----------------------
七、结语与回顾
深度学习中的不确定性量化:2020年实用技术与应用大解析 - 61页精华解读"
这份报告深入剖析了近年来深度学习领域中不确定性量化(UQ)技术的最新发展,包括其在强化学习(RL)中的运用实例。探讨了贝叶斯近似和集成学习等主流UQ方法在各个具体场景中的广泛应用,比如自动驾驶、目标识别、图像修复、医疗影像分析(如分类和分割)、文本理解(如文本分类和风险评估)、以及生物信息学等多个领域。
报告进一步梳理了UQ方法在深度学习领域的关键应用案例,并针对当前面临的挑战及未来研究方向进行了概览和展望,为这一领域的研究人员和实践者提供了有价值的参考指南。
【Netty】「萌新入门」(七)ByteBuf 的性能优化-堆内存的分配和释放都是由 Java 虚拟机自动管理的,这意味着它们可以快速地被分配和释放,但是也会产生一些开销。
直接内存需要手动分配和释放,因为它由操作系统管理,这使得分配和释放的速度更快,但是也需要更多的系统资源。
另外,直接内存可以映射到本地文件中,这对于需要频繁读写文件的应用程序非常有用。
此外,直接内存还可以避免在使用 NIO 进行网络传输时发生数据拷贝的情况。在使用传统的 I/O 时,数据必须先从文件或网络中读取到堆内存中,然后再从堆内存中复制到直接缓冲区中,最后再通过 SocketChannel 发送到网络中。而使用直接缓冲区时,数据可以直接从文件或网络中读取到直接缓冲区中,并且可以直接从直接缓冲区中发送到网络中,避免了不必要的数据拷贝和内存分配。
通过 ByteBufAllocator.DEFAULT.directBuffer 方法来创建基于直接内存的 ByteBuf:
ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer(16);
通过 ByteBufAllocator.DEFAULT.heapBuffer 方法来创建基于堆内存的 ByteBuf:
ByteBuf heapBuf = ByteBufAllocator.DEFAULT.heapBuffer(16);
注意:
直接内存是一种特殊的内存分配方式,可以通过在堆外申请内存来避免 JVM 堆内存的限制,从而提高读写性能和降低 GC 压力。但是,直接内存的创建和销毁代价昂贵,因此需要慎重使用。
此外,由于直接内存不受 JVM 垃圾回收的管理,我们需要主动释放这部分内存,否则会造成内存泄漏。通常情况下,可以使用 ByteBuffer.clear 方法来释放直接内存中的数据,或者使用 ByteBuffer.cleaner 方法来手动释放直接内存空间。
测试代码:
public static void testCreateByteBuf {
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(16);
System.out.println(buf.getClass);
ByteBuf heapBuf = ByteBufAllocator.DEFAULT.heapBuffer(16);
System.out.println(heapBuf.getClass);
ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer(16);
System.out.println(directBuf.getClass);
}
运行结果:
class io.netty.buffer.PooledUnsafeDirectByteBuf
class io.netty.buffer.PooledUnsafeHeapByteBuf
class io.netty.buffer.PooledUnsafeDirectByteBuf
池化技术
在 Netty 中,池化技术指的是通过对象池来重用已经创建的对象,从而避免了频繁地创建和销毁对象,这种技术可以提高系统的性能和可伸缩性。
通过设置 VM options,来决定池化功能是否开启:
-Dio.netty.allocator.type={unpooled|pooled}
在 Netty 4.1 版本以后,非 Android 平台默认启用池化实现,Android 平台启用非池化实现;
这里我们使用非池化功能进行测试,依旧使用的是上面的测试代码 testCreateByteBuf,运行结果如下所示:
class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf
class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf
class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf
可以看到,ByteBuf 类由 PooledUnsafeDirectByteBuf 变成了 UnpooledUnsafeDirectByteBuf;
在没有池化的情况下,每次使用都需要创建新的 ByteBuf 实例,这个操作会涉及到内存的分配和初始化,如果是直接内存则代价更为昂贵,而且频繁的内存分配也可能导致内存碎片问题,增加 GC 压力。
使用池化技术可以避免频繁内存分配带来的开销,并且重用池中的 ByteBuf 实例,减少了内存占用和内存碎片问题。另外,池化技术还可以采用类似 jemalloc 的内存分配算法,进一步提升分配效率。
在高并发环境下,池化技术的优点更加明显,因为内存的分配和释放都是比较耗时的操作,频繁的内存分配和释放会导致系统性能下降,甚至可能出现内存溢出的风险。使用池化技术可以将内存分配和释放的操作集中到预先分配的池中,从而有效地降低系统的内存开销和风险。
内存释放
当在 Netty 中使用 ByteBuf 来处理数据时,需要特别注意内存回收问题。
Netty 提供了不同类型的 ByteBuf 实现,包括堆内存(JVM 内存)实现 UnpooledHeapByteBuf 和堆外内存(直接内存)实现 UnpooledDirectByteBuf,以及池化技术实现的 PooledByteBuf 及其子类。
UnpooledHeapByteBuf:通过 Java 的垃圾回收机制来自动回收内存;
UnpooledDirectByteBuf:由于 JVM 的垃圾回收机制无法管理这些内存,因此需要手动调用 release 方法来释放内存;
PooledByteBuf:使用了池化机制,需要更复杂的规则来回收内存;
由于池化技术的特殊性质,释放 PooledByteBuf 对象所使用的内存并不是立即被回收的,而是被放入一个内存池中,待下次分配内存时再次使用。因此,释放 PooledByteBuf 对象的内存可能会延迟到后续的某个时间点。为了避免内存泄漏和占用过多内存,我们需要根据实际情况来设置池化技术的相关参数,以便及时回收内存;
Netty 采用了引用计数法来控制 ByteBuf 对象的内存回收,在博文 「源码解析」ByteBuf 的引用计数机制 中将会通过解读源码的形式对 ByteBuf 的引用计数法进行深入理解;
每个 ByteBuf 对象被创建时,都会初始化为1,表示该对象的初始计数为1。
在使用 ByteBuf 对象过程中,如果当前 handler 已经使用完该对象,需要通过调用 release 方法将计数减1,当计数为0时,底层内存会被回收,该对象也就被销毁了。此时即使 ByteBuf 对象还在,其各个方法均无法正常使用。
但是,如果当前 handler 还需要继续使用该对象,可以通过调用 retain 方法将计数加1,这样即使其他 handler 已经调用了 release 方法,该对象的内存仍然不会被回收。这种机制可以有效地避免了内存泄漏和意外访问已经释放的内存的情况。
一般来说,应该尽可能地保证 retain 和 release 方法成对出现,以确保计数正确。