Category: Programming Languages/Modern C++/Python
-
机器学习系列算法新版本分享计划
大家好,最近正在准备机器学习原理与实践系列课程,欢迎感兴趣或有意从事相关工作的朋友们一起将机器学习相关算法原理探索和代码实现进行更加具体详细的分析和理解,也希望在知识求学和实践的过程中给大家提供一点帮助,期待大家的反馈意见,以便向大家提供更好的知识内容材料,谢谢。 References
-
新时期的数字化工程应用技术教育教学新需求
今天有幸受邀参加华为和合作伙伴举行的产教融合教育方面的研讨活动,记录一下相关的产业和教育相关的信息以备后需。 随着harmony os及相关的一系列的自主信息化技术的发展及逐渐普及,相关工程技术的教育教学也需要同步的跟进,这里据我了解的情况和背景做一点说明,如有需要补充的地方,请大家联系我补充更新。 一、鸿蒙生态开发,鸿蒙os的应用范围逐渐增多,从手机,平板到各种物联设备(如美的等智能家电),还有一些To B的专业设备如高铁,机场等的嵌入式物联网设备,都部署了鸿蒙系统,鸿蒙系统通过soft bus实现了跨设备的数据共享(不同设备感觉可以成为相互的外围设备一样),众多的android上的应用要移植到鸿蒙系统上来,就需要大量的相关app开发人才,这起码在近几年都是一个显性的应用开发人才需求,应用本科和高职的技术技能人才是比较适合这个方向的; 二、人工智能,人工智能的技术发展也很快,但是除了门槛比较高的人工智能新算法设计发明外,还有一类就是人工智能应用工程师,这类开发主要在利用人工智能的技术去搭建具体的场景应用,包括怎么去做prompt enginerring。怎么利用人工智能已有的sdk和开发套件搭建机械狗,小车,机械臂等具体的场景应用,怎么利用大模型商城代码等等这类也是应用技术型人才所适合的工作方向; 三、云原生技术,很多公司的数据平台和业务都会部署在云平台,这些公司只需关注自己的业务,而不用太专注计算设备平台的物理环境和基础软件的部署和配置。包括IaaS基础设施,PaaS如各种实验平台,大数据平台等; 四、低代码开发,低代码开发以后也会成为应用开发的主要形式,据了解大约在2025年会有70%的应用以低代码的形式开发出来,低代码开发到时候可能也是人人都可以学习的开发技术,通过拖拽和一些简单的操作就可以人人开发出自己的应用来,这方面了解的不多,以后有机会再多关注一下; 还有更多的自主技术,如操作系统,数据库,软硬件协同开发(物联网IOT,AIOT等),以及AI等方方面面需要进一步的推广和普及,关于工程应用开发的大量需求,培养这方面的工程师也是当前较为紧迫的,怎么和企业合作高效培养和对接工作需求,怎么培养同学的实践能力并且达到举一反三,自主学习新技术的能力和方法,也是职业和应用技术教育需要去讨论,总结并将好的思路,实践加以推广从而达到更好的应用工程师工程素养培养的目标。
-
einsum is all you need-einsum函数在数值计算中的应用示例说明
在深度学习框架和numpy等数值计算库中,记住不同的矩阵计算,如内积(dot products)、外积(outer products)、矩阵转置(transposes ),矩阵和向量相乘,以及矩阵和矩阵的乘法这些运算的函数名称和参数是容易混淆的一件事情,而爱因斯坦和(einsum)是通过一种领域语言(domain-specific language),用一种优雅的方式去解决这个问题,同时更进一步还可以描述更复杂的tensor的操作。 einsum函数采用如下的格式,einsum(equation,operands),下面为一个模板:result=einsum(“□□,□□□,□□->□□”,arg1,arg2,arg3)。其中□为占位符,表示张量的一个维度,如前面的equation的形式为“□□,□□□,□□->□□”,表示的含义为由三个输入参数,第一个和第三个为矩阵,第二是阶数为3的张量。计算的结果为矩阵。 下面将解释一些使用示例: 其中张量的缩并(tensor contraction)操作是两个多维张量中的分别两个大小相同的维度的内积,具体可以参考链接1中的示例。其中广播操作(broadcast)的实现方式可以参考引文7中的示例说明。 关于示例和相关说明,后面再根据实践会进一步补充更新或进行相关的修正,欢迎读者提出问题意见和建议。 References
-
Apollo 粗粒度结构及系统启动流程简介
Apollo系统是智能驾驶领域很有影响力的开源系统,本篇文章从粗粒度上介绍Apollo系统的结构,并分析其其启动流程。后续有机会再介绍细节,不正确的地方欢迎批评指正。 Apollo系统是个比较复杂的系统应用,首先其实现了通信及任务调度的中间件CyberRT(在代码仓的apollo\cyber目录下),也称为Apollo系统的运行时环境(RT即为Runtime),Apollo系统的各个业务逻辑模块,包括感知perception,规划planning,控制control等等各上层的模块,都是基于CyberRT的基础上进行构建的。CyberRT提供了两个核心的运行时功能,1为任务调度,基于协程,多线程实现的不同任务可以按照智能驾驶的业务逻辑编排成高效的执行模式运行,2为通信模式,借鉴了ROS里边的node发布订阅模式,实现了进程内(intra),shm(共享内存单机多进程间通信),rtsp(实时发布订阅协议,多个host之间的网络通信协议),以及hybrid(混合模式,基于component之间通信的物理状态动态选择上述三种模式以达高效通信)。在CyberRT的实现里,一个任务以component为载体,里边的业务处理逻辑通过协程来实现,同时其有对应node,实现了reader和writer,也就是可以接收和发送消息(不同的消息以channel来区分,类似于ros里的topic)。关于通信的实现可以参考apollo\cyber\transport目录下面的代码,引文2中也有相关的介绍。 CyberRT可以理解为在底层操作系统之上构建的一个RTOS,在Apollo的源码仓里,系统的各个模块的逻辑实现依赖于CyberRT提供的接口,这些模块的代码在目录apollo\modules里。具体阅读相关代码实现。 这里以一个模块的启动为例进行说明,一般来说,每一个模块都有一个启动的文件(dag有向无环图文件),如下面的路径为摄像头bev感知模块的dag文件:apollo\modules\perception\camera_detection_bev\dag\camera_detection_bev.dag。一般通过mainboard程序启动一个module。mainboard即为cyberrt运行时编译后生成的可执行文件,会加载CyberRT运行时环境,load相应模块的so文件(一个module可以由多个component组成)。而整个新系统将会是很多个module组成的大系统,因此会有很多个mainboard程序启动,整个智能驾驶系统将是一个多进程程序(不同进程有可能会跨不同的主机host)。具体的启动方式的介绍在引文3中有详细介绍,在此不做赘述。 References
-
Apollo CyberRT的两种任务调度策略实现代码简要说明
Apollo CyberRT为智能驾驶的中间件(middle ware),提供了类似于ROS概念(并优于ROS平台)的机器人运行时环境。CyberRT在任务的调度上进行了优化的设计,提供了经典调度模式和编排调度模式,使得系统的诸多任务可以按照任务之间的逻辑拓扑结构来进行编排,从而在执行性能上得到很好的保证。同时CyberRT在通信上也做了很好的支持,在单机内部,多机之间的不同component都能够进行高效的通信。这里主要就任务调度方式来做一下说明,也是加以记录以备后面查阅,不正确的地方欢迎批评指正。 首先,在CyberRT实现里,Processor类对应着线程的封装,CRoutine类是对协程的封装,Component类对应着组件(任务)的封装,在Component类里,会创建协程来处理任务。 经典调度模式(ClassicContext):在经典调度模式下,可以将任务进行分组,分组的目的主要是在基于NUMA架构的计算环境上,实现资源的隔离,在同一个组的任务会安排在同一个NUMA节点下运行,这样保证了同一组的任务之间的通信不会由于跨NUMA节点而带来更多的资源消耗和计算时长。而且每一个组下面维护一个多优先级的协程(CRoutine)队列,每一个优先级下面维护一个协程的数组。ClassicContext类对经典调度模式的上下文进行了建模,而且在CyberRT实现里,每一个Processor对应着一个ClassicContext,并且任务(component,以协程的方式实现)的优先级队列作为ClassicContext类成员的静态变量,在不同的线程里边实现共享。ClassicContext调度任务时,会从高优先级的任务里优先调度。在这里补充说明一下,CRoutine的同一个实例可以在不同的线程里调度,CRoutine类里有thread_local类型的相关变量,保证了同一个协程在不同的线程里有对应的相关变量的副本。 编排调度模式(ChoreographyContext):在编排调度模式下,一个Processor对应着一个ChoreographyContext,并且封装了一个multimap类型的变量,key为协程的优先级,value为协程,保证了可以支持同等的优先级下的多个协程。而且这个变量不是静态变量,在多个线程(Processor)之间不共享,保证了执行的协程任务的CPU亲和性(不会在多个cpu之间调度同一个协程),可以基于此通过配置文件来实现任务的编排(如定义某些任务在某些cpu上执行)。 更多的代码细节建议阅读官方开源的代码仓的关键部分,如apollo\cyber\scheduler,apollo\cyber\croutine,apollo\cyber\component等,上述的文字说明都可以在这几个目录的代码里找到实现。 References
-
C++11中atomic类型和内存模型
本篇文章介绍C++11中的原子变量的内存模型,内存模型比较复杂,与多线程、CPU缓存以及指令优化都有关系,这里记录一下现在的理解,如有不正确的地方欢迎批评指正。后续也会进一步更新更深入的理解。 C++11是在C/C++99之后出现的变动较大的C++版本,一般Mordern C++是指C++11以后的C++。Modern C++有很多新的特性,其中automic变量(原子变量)就是一种支持的新的特殊类型。所谓原子变量,顾名思义,针对这些变量的操作都是原子操作(完整不可分),这为多线程程序中的共享变量的实现提供了一个便捷的方法。C++11 对常见的原子操作进行了抽象,定义出统一的接口,并根据编译选项/环境产生平台相关的实现。新标准将原子操作定义为atomic模板类的成员函数,囊括了绝大多数典型的操作——读(load)、写(store)、CAS(Compare and Swap, 比较并替换,如compare_exchange_weak)等。 现代的处理器并不是逐条处理机器指令的。内存模型是一个硬件上的概念,表示的是机器指令(或者将其视为汇编指令也可以)是以什么样的顺序被处理器执行的。指令1、2、3(a赋值)和指令4、5(b赋值)毫不相干。一些处理器可能将指令乱序执行,比如按照1->4->2->5->3这样的顺序(超标量流水线,即一个时钟周期里发射多条指令)。如果指令是“乱序”执行的,我们称这样的内存模型为弱顺序的(weak ordered)。弱顺序的内存模型的好处在可以进一步挖掘指令中的并行性,提高指令执行的性能。 顺序一致内存顺序/memory_order_seq_cst,memory_order_seq_cst 表示该原子操作必须顺序一致的,这是C++11中所有atomic原子操作的默认值。这样来理解“顺序一致”:即代码在线程中运行的顺序与程序员看到的代码顺序一致。也就是说,用此值提示编译器“不要给我重排序指令,不要整什么指令乱序执行,就按照我代码的先后顺序执行机器指令”。在示例代码中,a的赋值语句先于b的赋值语句执行,这种称之为”先于发生(happens-before)“关系。用memory_order_seq_cst 可以确保这种happens_before关系。 松散内存顺序memory_order_relaxed,表示该原子操作指令可以任由编译器重排或者由处理器乱序执行。和普通变量的对编译器的表现没有什么差异。 上面讲的顺序一致和松散方式对应着两个极端——一个是严格禁止”指令乱序加速优化“,一个是允许随便”指令乱序加速优化“。但是现实的逻辑问题是:严格禁止”指令乱序优化“,指令执行不够快;允许随便”指令乱序优化“,在多线程程序场景下很可能又违反了计算的正确逻辑得不到正确结果。 Release-acquire内存顺序,memory_order__acquire规则定义:本线程中,所有后续的读写操作,必须在本条原子操作完成后执行。(本线程中,读写操作在本代码后面的要保证我先读),memory_order_release规则定义:本线程中,所有之前的内存读写操作完成后,才能执行本原子写操作。(在本线程中,写操作在本代码前面的要保证你们先写,我最后写……)下面有一段示例代码说明。memory_order_release,Perform release operation. Informally speaking, prevents all preceding memory operations to be reordered past this point.;memory_order_acquire,Perform acquire operation. Informally speaking, prevents succeeding memory operations to be reordered before this point.memory_order_acq_rel,Perform both release and acquire operation. memory_order_acquire & memory_order_release成对作用在一个原子对象上,能保证在多个线程中对这个原子对象的修改和读取是一致的。 memory_order_acquire & memory_order_release 相比 relaxed序具有更大的同步开销。 上述的直观的理解这么解释:关于原子变量的load读操作如果设为memory_order_acquire,在本线程内后面的内存读写必须等待读操作完成后才能进行,同理原子变量的store写操作如果设为memory_order_release,则在本线程内前面的内存读写必须在store写操作之前完成。两个不同的线程共享的原子变量a,如果在线程1中成功load到线程2store后的状态,则线程2中store之前的共享的内存数据状态对于线程1是可见的。如上面的代码所示,只有Thread1中的b.store写入2后,Thread2读取的b的状态才是2,这时才会退出while循环,这时Thread2的后面的代码中a的状态就是Thread1中保存的值1(因为Thread1中保证a.store会在b.store之前完成。 C++标准库中的memory order其实与具体的machine无关的,在实现上会通过memory barrier(FENCE)来进行order,memory barrier在不同CPU类型上表现不一定一致。 CAS的操作以compare_exchange_weak函数为例进行说明, The memory…