八. 实战:CUDA-BEVFusion部署分析-学习CUDA-BEVFusion推理框架设计模式

news2024/9/24 7:53:28

目录

    • 前言
    • 0. 简述
    • 1. 回顾一下RAII是什么
    • 2. 实现类,接口类与命名空间
    • 3. CUDA-BEVFusion设计框架(namespace)
    • 4. CUDA-BEVFusion设计框架(接口类)
    • 5. CUDA-BEVFusion设计框架(实现类)
    • 6. CUDA-BEVFusion设计框架(各个类负责的内容)
    • 7. CUDA-BEVFusion中的接口函数和实现类(RAII模式初始化)
    • 8. CUDA-BEVFusion中的接口函数和实现类(forward)
    • 总结
    • 下载链接
    • 参考

前言

自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考

本次课程我们来学习下课程第八章——实战:CUDA-BEVFusion部署分析,一起来学习 CUDA-BEVFusion 推理框架设计模式

Note:接口模式和 RAII 杜老师之前也讲到过,感兴趣的可以看看 7.4.tensorRT高级(2)-使用RAII接口模式对代码进行有效封装

课程大纲可以看下面的思维导图

在这里插入图片描述

0. 简述

本小节目标:理解大项目 C++ 推理框架阅读的技巧,以及 CUDA-BEVFusion 中的设计模式,命名空间/接口类/实现类的设计用意

今天给大家讲第八章的第 8 小节,学习 CUDA-BEVFusion 的推理框架设计模式,这个可以说是整个第八章节中比较精彩的一部分,我们学习一下大项目,其实不光是 CUDA-BEVFusion,我们以后如果要自己用 C++ 写一个推理框架的时候,要学会推理框架的设计模式。比如哪些模块可以共享同一个设计方案,类与类之间的对应关系是什么,namespace 命名空间是怎么设计的,那这些都是我们在设计初期就需要考虑的

我们在第六章的时候给大家讲过一个好的推理框架需要注意以下 5 点:

  • 代码可复用性
  • 可扩展性
  • 安全性
  • 可读性
  • 可调试性

第一个要注意的是代码的可复用性,可复用性就是说代码哪些地方是可以重复使用的,哪些地方我们尽量给它做个封装,尽量给它做个模块化,那这样大家在以后写代码的时候,只需要调用每一个模块就好了,这是一个比较好的代码设计方案。

那第二个要注意的是代码的可扩展性,可扩展性就是说一个代码写好后它需要能够做一个类似于像 Plugin 那种,每个部分能够像搭积木一样,每次有新的功能时能够实现最小限度的修改,只关注和它有关的东西,那些偏底层无关的东西不用关注,最小限度的去加入一些模块搭积木上去,这是一个可扩展性比较强的方案

第三个要注意的是代码的安全性,安全性讲的就是我们尽量在代码设计初期的时候不要暴露很多没有必要的接口,比如我们从 main 调用一个函数的时候实现某个复杂功能时能够越简单越好,一些跟底层实现相关的接口我们没有必要暴露给 main,在类的使用中我们也可以通过接口类去把不必要的接口给隐藏起来,全部放到实现类中,那这就是代码的安全性

同时还要注意 RAII 资源获取即初始化,我们在创建一个对象时就把一系列的初始化给做了,那这样的话就避免我们在设计的时候还得做一个构造函数,在结束的时候再做个析构函数,还要做各种 free、destroy、release 这些东西,那这个我们尽量能避免就避免

最后要注意的是代码的可调试性,代码可调试性就是说能够在代码中随处看到它的各种日志信息,设置不同的级别会打印出来

那这就是设计推理框架时要注意的几个点,CUDA-BEVFusion 框架其实是一个写得非常好的代码,我们在阅读代码之前需要先把它的框架理解好,要不然我们在看代码时会一头雾水,不知道从哪开始看,那所以整个第 8 小节我们主要是围绕它的命名空间、接口类和实现类这样一个设计关系

1. 回顾一下RAII是什么

我们先来回顾下 RAII 是什么,RAII 全称是 Resource Acquisition Is Initialization 资源换取即初始化

在这里插入图片描述

拿上图为例,比如说我们要去操作系统里面调用一个 API 获取资源时,它是直接调用 RAII Constructor,调用了它之后就开始去做各种初始化,比如说分配空间、分配内等等。以 CUDA-BEVFusion 来看的话就是分配 CPU 上的空间,分配 GPU 上的空间或者是创建推理引擎,创建 network,反序列化,还有设置各种参数,这一切它跟设计实现没有任何关系,它其实就是初始化

那么对于初始化的话,当我们系统在拿到这个资源的时候,它就是自动做了这些初始化的,那做完初始化之后,当我们这个系统不用它这个资源了,需要 release resource 怎么办,我们的系统也没有必要自己去 destroy 这个资源,那这个资源它自己有个 RAII Destrcutor,让资源自己直接释放就好了,那这个主要体现在哪呢,体现的就是 shared_ptr 智能指针这方面,我们可以把一个类里面的成员变量都设置成智能指针,那它们的生命周期如果到了,它们里面的各种信息就自动销毁了,这是一个比较好的设计模式

RAII 参考资料:RAII in C++, RAII is one of the patterns in C++ to manage resources.

2. 实现类,接口类与命名空间

那我们再看实现类、接口类和命名空间,我们直接看代码里面它们的设计关系我们可能看不懂,我们先看几个例子

在这里插入图片描述

我们现在有个 main 函数,右边还有一个类 classA,那 class A 它开放的接口的函数有 N 个,那现在在 main 函数中我想调用 class A 中的接口函数该怎么做呢?一个能想到的的方法就是我们可以先创建一个 classA 的一个 instance 实例,之后我们就可以根据它的实例对象调用 func1()、func2()…,

那这其实就代表我们 main 里面的函数会特别多,那只有一个 class 还好,那如果有多个 class,那每一个 class 之间它还有很多个函数,那 class 后面又有 class,那样的话调用起来特别麻烦,那其实这样子就是意味着我们把所有接口全暴露出来了,暴露给 main 看,那写的程序可读性特别差,并且写的程序比较危险,因为有的时候我们不知道哪些函数它是可以调用的,哪些函数是不可以调用的,有可能某些函数以错误的调用方式或者调用的一个顺序造成访问越界问题

在这里插入图片描述

那怎么做才是一种比较好的方式呢?一般来说我们可以给它设计一个接口类,我们设计一个 classA,那 classA 它暴露的函数就只有两个,一个 func1() 一个 func2(),那 main 函数它主要跟接口类 classA 打交道,main 可以调用的只有一个 func1() 或 func2(),那后续的 func3() 到 funcn() 都放到实现类 class AImplement 中去了

那这样我们就可以通过 class A 里面的 func1() 去调用 func3()、func4()…,func2 里面去调用 func()5、func6()…,通过这样的一个方式,我们让 main 函数只关注它需要的接口,而具体的实现细节它无需关注。那我们如果在看 CUDA-BEVFusion 代码的实现,可以发现接口类和实现类之间是一个继承关系,class A 是父类,class AImplement 是子类,那这个子类它是继承 classA 里面的很多函数。

那比如我们在 main 中在调用 class A 的一个函数的时候,如果这个函数在 class A 是个虚函数,而这个函数在 class AImplement 有一个自己的实现,那整个调用过程就是 main 调用接口类的 func1(),实际上是调用了实现类中的 func1(),从而完成某个功能的实现,就是这么一个调用关系

在这里插入图片描述

拿上面的案例来说,我们 main 调用 initialization() 初始化函数,我们通过接口类 class A 的 initialization 最终调用的是实现类 class AImplement 中的 init_step1()、init_step2()…,同理 forward 也一样,都是这么一套调用关系

在这里插入图片描述

多个类的情况也一样,class A、class B、class C、class D 每一个 class 它都有一个自己的接口类和自己的实现类,每一个类都调用自己的一个子类即实现类,那这样子的话其实也会有一个问题,那问题就是 main 这边它还是调用的是每一个 class 的 initialization 和 forward,其实还是会有一点不好操作,每次都需要调用不同类的 initialization 和 forward,我们能不能只调用一次初始化函数和前向传播函数呢

在这里插入图片描述

那这边有一个方案,在 main 和 class A、B、C、D 之间再设计一个类,这个类的名字叫 class Core,那 Core 它也是有一个接口类和一个实现,我们希望暴露给 main 的接口越简单越好,不要让它去访问其它没有用的东西,那上图中 main 访问 Core initialization 就意味着 Core 会调用 CoreImplement 实现类里面的 init_A()、init_B()、init_C()、init_D(),之后调用每个类相应的 initialization(),之后再调用子类实现类的 initialization,本质上就是一个套娃,那最终我们这么做的目的就是为了让 main 调用的接口越简单越好,实现起来比较方便也比较好管理。

在这里插入图片描述

OK,为了设计起来比较方便,我们可以把同一种类型的类放在同一个命名空间,比如说 class A 和 class B 是同一个类型的 task,比如都是跟 Camera 有关的 task,那我们可以放到一个命名空间中,class C 和 class D 也是同一个类型的 task,比如都是跟 LiDAR 有关的,那我们也可以放到一个命名空间中。接口 Core 中的两个 class 属于同一个类型也放在同一个命名空间,那这个就是 CUDA-BEVFusion 中实现类、接口类与命名空间一个参考的部分

3. CUDA-BEVFusion设计框架(namespace)

OK,我们理解了实现类、接口类与命名空间之间的关系后,我们来看看 CUDA-BEVFusion 是如何做的,我们先看 namespace 命名空间,如下图所示:

在这里插入图片描述

CUDA-BEVFusion 中最上层的命名空间是 bevfusion,在 bevfusion 下面又有 camera、lidar、fuser、head 四个命名空间,这其实对应的是 BEVFusion 网络架构中的四个 ONNX,不是说 namespace 和 onnx 是相对应的,只是说命名空间里面会调用相应的 onnx

我们可以看到 head 下面还有一个 transbbox 的命名空间,它这个设计可能是考虑 BEVFusion 是一个 multi-task 的网络,它有两个 task,一个是 3D Detection,一个是 Segmentation,只是这里没有设计 Segmentation 只有一个 transbbox 命名空间,大家感兴趣的话可以在 head 下面扩展一个 segmentation 的命名空间

这个就是 CUDA-BEVFusion 中 namespace 之间的层级关系,同时下面还有一个独立的 TensorRT 的 namespace,这个也是 NVIDIA 自己设计的,里面包含网络的反序列化、读取 onnx 等等,与 TensorRT 相关的接口都在这个命名空间里面

值得注意的是虽然 bevfusion 和 TensorRT 两个命名空间是相互独立的,但是二者是可以相互调用的,

4. CUDA-BEVFusion设计框架(接口类)

我们看完命名空间之后再来看接口类,如下图所示:

在这里插入图片描述

首先 bevfusion 命名空间有一个自己的接口类叫做 Core,之后它下面的每一个命名空间都有属于自己的接口类,camera 命名空间下有 Backbone、Geometry、BEVPool、Normalization、Depth、VTransform 接口类;lidar 命名空间下有 SCN、Voxelization 接口类;fuser 命名空间下有 Transfusion 接口类;transbbox 命名空间下有 TransBBox 接口类,每个接口类所负责的功能我们之后会提到

同时 TensorRT 命名空间也有一个接口类叫做 Engine,可以做反序列化等操作

5. CUDA-BEVFusion设计框架(实现类)

OK,我们再看实现类,如下图所示:

在这里插入图片描述

那实现类的话和接口类其实是一一对应的,我们可以看到每一个接口类都有属于它自己的实现类,比如 Backbone 有属于自己的 Backbone Implement,SCN 有属于自己的 SCN Implement,接口类暴露最简单最少的一些接口,实现类的一些具体实现函数是不会暴露出来的

大家看代码可以对照着上图来看

6. CUDA-BEVFusion设计框架(各个类负责的内容)

OK,我们来看看各个类负责的内容:

在这里插入图片描述

首先 core 有一个 Core 类,它是作为 main 的接口部分,通过 core 来调用其它的接口类

camera 一共有六个类,Backbone 是用于 camera backbone 的 DNN 推理,这部分是 TensorRT 来做加速的;BEVPool 是用于 camera 到 BEV grid 的投影,这部分是 CUDA 来做加速的;Depth 是用于将 LiDAR 点云投影到 camera 上,这部分是 CUDA 加速的;Geometry 是计算 camera 到 ego 到 bev 过程的投影,这部分是 CUDA 来做加速的,BEVPool 中优化方式有一个是 Precomputation,提取计算 BEV Grid 上的每个点对应的是哪个 camera 上的哪个点,那这个就是 Geometry 要做的事情;Normalization 是用于做图像预处理的,这部分是 CUDA 来做加速的;VTransform 用于对 BEV Feature map 特征提取,做一个 downsample,这部分是 TensorRT 来做加速的。

lidar 有两个类,SCN 用于调用 voxelization,LiDAR SCN 网络推理,这部分使用自定义的 CUDA 加速,它内部可能实现了 spconv 的加速方案;Voxelization 用于点云预处理,使用 CUDA 进行体素化加速。

fuser 有 一个 Transfusion 类,它用于 Fuser DNN 网络的推理,这部分是 TensorRT 来做加速的,它主要是融合模块将 Camera BEV Feature 和 LiDAR BEV Feature 进行融合

head 有一个 TransBBox 类,它用于 head DNN 网络的推理,这部分是 TensorRT 来做加速的,它主要是检测头模块利用融合后的 BEV Feature 得到检测结果,值得注意的是这里还包括检测结果的 decode 与绘图等相关内容,那这部分则是 CUDA 来做加速的

以上都是 bevfusion 命名空间下的类,最后我们来看下 TensorRT namespace,TensorRT 有一个 Engine 类,它用于反序列化 TensorRT 推理引擎,创建 context、runtime 这些东西,那它这里没有做序列化,因为这里 engine 的生成方式不是通过 TensorRT C++ API 创建的,直接是通过 trtexec 工具来创建的,所以这里只需要拿一个 engine 反序列化就 OK 了。

7. CUDA-BEVFusion中的接口函数和实现类(RAII模式初始化)

我们通过 CUDA-BEVFusion 中命名空间、接口类与实现类的关系来看它们之间的函数调用关系,我们主要看两个函数,一个是初始化一个是 forward,我们先来看初始化函数的调用关系,如下图所示:

在这里插入图片描述

初始化这边是用的 RAII 模式的初始化,main 函数先调用 bevfusion 命名空间中的 create_core 函数,它会创建 Core Impl 类的 instance 之后初始化 Impl 类,接着同理调用下面各个命名空间(camera、lidar、fuser、head)中的 create 函数,然后分别创建对应的实现类的实例对象之后初始化实现类,值得注意的是 create 函数中创建的是实现类的实例对象,返回的是接口类

代码实现部分如下:

在这里插入图片描述

src/bevfusion/bevfusion.cpp

8. CUDA-BEVFusion中的接口函数和实现类(forward)

那下面我们在来看看 forward 函数的调用关系,如下图所示:

在这里插入图片描述

main 函数调用 forward 的时是调用的 Core class 的 forward,又由于这个 forward 是纯虚函数,它在 Core Implement class 中有实现,而且 Core Implement 继承自 Core,因此我们调用的是 Core Implement class 中的 forward 函数,同理接下来就是调用每个模块各自接口类的 forward 函数,而实际上最终调用的是各个接口类对应实现类中的 forward

代码实现部分如下所示:

在这里插入图片描述

src/bevfusion/bevfusion.cpp

这里面实现了以下几个 forward:

  • lidar_scn_:cuda 预处理 + TensorRT DNN 推理,先将点云转为 voxel feature,输入的点云 shape 是(242180, 5), 输出的 shape 是 (1200, 1200, 40), 并且是 fp16
  • normalizer_:cuda 预处理,将图像进行预处理 (bilinear + normalization + NHWC2NCHW), 并将多个 camera 的数据汇总在一起, output 是 fp32, shape 是 (1x6x3x256x704)
  • camera_depth_:cuda 预处理,将 LiDAR 点云的信息投影到各个 camera 的坐标系上,camera 上每一个点的坐标表示的是 distence,output 是 fp16
  • camera_backbone_:TensorRT DNN 推理,直接调用 engine 的一个 context 里的 enqueueV2
  • camera_bevpool_:cuda 预处理,将 6 个 camera 坐标系下的 camera feature 和 depth feature 融合到 BEV grid 空间中, 得到 camera-bev-feature, output 是 fp16
  • camera_vtransform_:TensorRT DNN 推理,将 BEVPool 结束后的 BEV feature map 通过几个卷积进行特征提取。直接调用 engine 的一个 context 里的 enqueueV2, output 是 fp16
  • transfusion_:TensorRT DNN 推理,直接调用 engine 的一个 context 里的 enqueueV2 (注意这里输入是 camera_bev 和 lidar_bev), output 是 fp16
  • transbbox_:TensorRT DNN 推理 + cuda 后处理,直接调用 engine 的一个 context 里的 enqueueV2 (注意这的输出是 6 个), 以及从输出中 decode 出想要的 3D bbox

值得注意的是这里调用的是接口类的 forward,而接口类的 forward 并没有任何实现,它是个纯虚函数,它最终调用的其实是实现类中的 forward,每个 task 都有自己具体的实现,大家看代码的时候看相关实现就行了,这里是个引导给大家作为参考

OK,CUDA—BEVFusion 整个代码的设计框架就介绍到这里,接下来我们要去看代码了,建议大家对照着这小节的内容自己先去阅读下相关代码,看看自己是怎么理解的,之后再去看韩君老师的讲解会比较好

总结

这节课程我们主要学习了 CUDA-BEVFusion 推理框架设计模式,我们首先了解了 RAII、接口类、实现类和命名空间,然后深入到 CUDA-BEVFusion 中详细讲解了其中的各个关系,CUDA-BEVFusion 中的命名空间和 BEVFusion 网络结构的各个模块相对应,每个命名空间下都有实现其功能的接口类和实现类,此外初始化函数采用了 RAII + 接口模式的方式,总的来说 CUDA-BEVFusion 整个推理框架的设计是非常不错的,值得大家借鉴学习

OK,以上就是第 8 小节有关 CUDA-BEVFusion 推理框架设计模式的全部内容了,下节是本章的最后一小节,跟随韩君老师一起去阅读下 CUDA-BEVFusion 的相关代码,敬请期待😄

下载链接

  • 论文下载链接【提取码:6463】
  • 数据集下载链接【提取码:data】
  • 代码和安装包下载链接【提取码:cuda】

参考

  • RAII in C++, RAII is one of the patterns in C++ to manage resources.
  • 7.4.tensorRT高级(2)-使用RAII接口模式对代码进行有效封装

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

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

相关文章

failed to connect to ‘127.0.0.1:58526‘: Connection refused

WSA使用体验 链接: 知乎-穿越时间一步到位,教你完美安装Windows 11 Android 安卓子系统 CPU不满足要求 明明是12700H,满足要求,但是应用商店说不满足,在设置(注意不是控制面板的区域)把地区改…

ChatGPT 4.0使用之论文阅读

文章目录 阅读环境准备打开AskYourPDF进入主站 粗读论文直接通过右侧边框进行提问选中文章内容翻译或概括插图的理解 总结 拥有了GPT4.0之后,最重要的就是学会如何充分发挥它的强大功能,不然一个月20美元的费用花费的可太心疼了(家境贫寒&…

HTML~

HTML HTML是一门语言,所有的网页都是用HTML这门语言编写出来的HTML(HyperText Markup Language):超文本标记语言 超文本:超越了文本的限制,比普通文本更强大。除了文字信息,还可以定义图片、音频、视频等内容 标记语言:由标签构成的语言 …

谨用ArrayList中的subList方法

谨用ArrayList中的subList方法 规范一&#xff1a; ArrayList 的 subList 结果不可强转成 ArrayList&#xff0c;否则会抛出 ClassCastException 异常&#xff1a; public static void test7() {List<Integer> list new ArrayList<>();list.add(1);list.add(2);…

云服务器无法Ping通解决

问题: 使用公网IP地址PING云服务器,无法PING通 但是可SSH到服务器,表示通信链路是正常的,可能是端口或路径规则未开放导致 登陆云服务器后台,进行安全组规则查看,发现ICMP没有放行 添加允许ICMP连接规则 成功PING通云服务器

Linux文本处理三剑客:awk(结构化命令)

在Linux操作系统中&#xff0c;grep、sed、awk被称为文本操作“三剑客”&#xff0c;上几期中&#xff0c;我们详细介绍grep、sed、awk的基本使用方法&#xff0c;希望能够帮助到有需要的朋友。 目录 1、前言 2、条件控制语句 语法结构&#xff1a;IF 语法结构&#xff1a…

蓝桥杯练习题——前缀和

1.壁画 思路 1.求最坏情况下&#xff0c;画的墙总和是多少 2.画的墙在中间连续一段&#xff0c;画了的墙长度是 n / 2 向上取整 3.取最大的 n / 2 向上取整区间和 #include<iostream> using namespace std; const int N 5e6 10; char s[N]; int a[N]; int t, n;int m…

【RHEL】三分钟启动完整版vim——vim9 huge编译安装

详细安装步骤 一键安装传送门 Vim提供了许多快捷键和命令来加快文本编辑的速度和效率。它具有强大的搜索和替换功能&#xff0c;支持多种文件格式&#xff0c;可以通过插件扩展功能&#xff0c;并提供了强大的自动补全功能。   然而在大多数Linux操作系统中利用系统软件源安装…

【深度学习笔记】计算机视觉——锚框

锚框 目标检测算法通常会在输入图像中采样大量的区域&#xff0c;然后判断这些区域中是否包含我们感兴趣的目标&#xff0c;并调整区域边界从而更准确地预测目标的真实边界框&#xff08;ground-truth bounding box&#xff09;。 不同的模型使用的区域采样方法可能不同。 这里…

事故预测 | Matlab基于FuzzySVR模糊支持向量机多特征变量事故预测

事故预测 | Matlab基于FuzzySVR模糊支持向量机多特征变量事故预测 目录 事故预测 | Matlab基于FuzzySVR模糊支持向量机多特征变量事故预测预测效果基本描述程序设计参考资料 预测效果 基本描述 Matlab基于FuzzySVR模糊支持向量机多特征变量事故预测 运行环境: Matlab2023及以 上…

Nature 研究亮点(Volume 626 Issue 8001, 29 February 2024)

文章目录 激光雕刻肥皂膜卵细胞的回收系统巴斯克语的起源产后抑郁症的治疗 激光雕刻肥皂膜 研究者&#xff1a;Haitao Xu 和 Yu Zhao&#xff0c;清华大学&#xff0c;北京。 发现&#xff1a;在特定条件下&#xff0c;可以使用激光在肥皂膜上进行雕刻。肥皂膜由洗涤剂分子&am…

ElasticSearch DSL语法

一、文档批量操作 1.批量获取文档数据 批量获取文档数据是通过_mget的API来实现的 (1)在URL中不指定index和type 请求方式&#xff1a;GET 请求地址&#xff1a;_mget 功能说明 &#xff1a; 可以通过ID批量获取不同index和type的数据 请求参数&#xff1a; docs : 文档数…

Tomcat介绍在IDEA中创建JavaWeb工程

文章目录 一、WEB服务器服务器概述使用Java代码手写web服务器 二、服务器软件Web服务器服务器软件的使用步骤 三、TomcatTomcat的下载Tomcat的安装与卸载Tomcat的启动与关闭常见问题 四、新建Java Web项目并将项目部署到tomcat中新建Java Web项目将项目部署到Tomcat中出现的问题…

在你的 Vue + Electron 项目里,引入 ESLint

因为我的项目是基于 Electron 平台的 Web 应用&#xff0c;使用 Vue 3 实现&#xff0c;而且用了 TypeScript&#xff0c;所以&#xff0c;在引入 ESLint 的时候&#xff0c;要考虑好几种规范的问题。 文章目录 零、简介1. 规则2. 配置文件3. 共享配置4. 插件5. 解析器6. 自定义…

Unity 切换场景

场景切换前必须要将场景拖动到Build中 同步加载场景 using System.Collections; using System.Collections.Generic; //using UnityEditor.SearchService; using UnityEngine; // 场景管理 需要导入该类 using UnityEngine.SceneManagement;public class c3 : MonoBehaviour {…

你是否知道Python的列表翻转、排序和多维列表

1.reverse() 表示翻转列表中的元素&#xff0c;不会生成新列表 list1 [2343, 55, 4, 345, 676, 768] list1.reverse() print(list1) # [768, 676, 345, 4, 55, 2343] 2.sort() 对原列表元素进行排序&#xff0c;默认是升序 list1 [2343, 55, 4, 345, 676, 768] list1…

在Python中使用多线程(通俗版本)

一、多线程的介绍&#xff1a; 1.进程 通常一个进程包含一个或者多个线程&#xff0c;每个进程有自己独立的一块内存空间&#xff0c;所有的线程共享这一块空间&#xff0c;例如&#xff1a;在Windows操作系统中&#xff0c;一个运行的xx.exe就是一个进程。 2.线程 一个进程…

lua调用C++函数

第一步搭建lua的环境. win10 lua环境搭建-CSDN博客 我使用的环境是win10vs2015lua54 先来个最简单的lua调用C函数, 无参数无返回值的 第一步:定义C函数. int CTest(lua_State* L) // 返回值是固定的int类型,返回0表示没有返回参数,返回1表示有一个返回参数 {std::cout &l…

什么是支持向量机(Support vector machine)和其原理

作为机器学习的基础算法&#xff0c;SVM被反复提及&#xff0c;西瓜书、wiki都能查到详细介绍&#xff0c;但是总是觉得还差那么点&#xff0c;于是决定自己总结一下。 一、什么是SVM&#xff1f; 1、解决什么问题&#xff1f; SVM&#xff0c;最原始的版本是用于最简单的线…

【C++从0到王者】第五十站:B树

文章目录 一、内查找与外查找1.内查找2.外查找 二、B树概念三、B树的插入1.B树的插入分析2.B树插入总结3.插入代码实现4.B树满树和最空时候的对比5.B树的删除6.遍历B树7.B树的性能分析 一、内查找与外查找 1.内查找 像我们之前所用的在内存中的查找就是内查找 种类数据格式时…