- 博客(63)
- 收藏
- 关注
原创 TRT4-trt-integrate -self-driving道路分析
后来的这里是加入了softmax,所以获得的是概率值,所以最终的输出output是1*512*596*4的概率值。然后就是process了,因为我的cropx和y都是0,而且type是Stretch,所以这里是仅仅只做了一个resize,其他的都没作。这里就能看到首先输入的名字是data,输入是1*512*896*3,输出的name是identity。因为swap_color是false,所以BGR----》RGB 不会做。可以看到这是一个全卷积网络,因为输入输出的宽高都一样。这里是做了一个norm。
2023-09-13 00:10:15 225
原创 从零构建深度学习推理框架-11 Resnet
这里就是首先搜寻In_channel这个param,如果诶呦的话那就报错,如果有的话那就添加进来,其余的也是,就是将pnnx.的param添加到我们的这个op的param中。我们不讲解全部算子流程, 只挑选其中的Linear算子, 其余算子的实现在流程下大同小异, 而且最复杂的几个算子我们已经在之前的课程中讲解过了.至此,为时一个月的推理课程正式结束,我将在这个专栏的后续内容里引入我自制的layer,比如laplace之类的。:这个条件判断语句检查输出张量是否为空或者为空的情况。
2023-08-30 09:49:08 840 1
原创 从零构建深度学习推理框架-10 算子的执行流程
其中,在普通的计算中,上面的op1的output_data是拷贝到op2的input_data中的,而在我们的这个推理网络中,我们是进行了一个内存的复用的。判断,如果meet_num == 输入节点数的话,那就代表之前节点的输出已经全部结束了,现在可以将他们放入到下一节点的输入里面了。我们可以看到,在图中,Graph在执行时在逻辑上可以分为两条路径,一条是控制流,另外一条是数据流。的输入存在,其中在输入和输出中传递的数据,是以前面课程中谈到的。来寻找它的后继节点,并将当前节点的输出拷贝到后继节点的输入中。
2023-08-29 09:44:18 465
原创 从零构建深度学习推理框架-9 再探Tensor类,算子输入输出的分配
第二节中我们编写的Tensor类其实并不能满足我们的使用需要,我们将在这一节以代码阅读的方式来看看一个完全版本的Tensor应该具备怎样的要素,同时我们对Tensor类的分析来看看在C++中一个设计好的类应该是怎么样的。在这里,raw_shape记录的是另外一个方面的形状信息,主要用于review和flatten层中。举一个简单的例子,当Tensor将一个大小为(2,16,1)的Tensorreshape到(32,1,1)的大小时,raw_shapes。
2023-08-21 23:27:56 427
原创 从零构建深度学习推理框架-8 卷积算子实现
将原来的kernel放到kernel_matrix_c里面,之后如果是多个channel,也就是input_c有多个,那就按照rowlen*ic依次存放到里面。然后对于每个窗口的以kernel的列为标准复制过去。w+kw指向的是窗口的列,r指向的是窗口的行。最后两个矩阵相乘就可以得到结果。
2023-08-12 16:10:48 726 1
原创 从零构建深度学习推理框架-7 计算图的表达式
用图形来表达就是这样的。但是在PNNX的表达式(Experssion Layer)中不是这个样子,而是以一种抽象得方式,替换掉输入张量改为@1,@2等等所以上面的计算图也就变成了我们是希望把这个抽象的表达式变回到一个方便后端执行的计算过程(抽象的语法树来表达,在推理的时候转为逆波兰式)。其中add和mul表示我们上一节中说到的@0和@1表示我们上一节课中说道的这就要求我们需要一个鲁棒的表达式解析和语法树构建功能。public:private:其中expr_表示表达式字符串,nodes_
2023-08-12 13:56:49 214
原创 TRT4-trt-integrate - 4 TRT的封装
看上去很庞大,但其实中间一大块:都是在打印详细信息。真正的这一块和咱们之前的没什么太大的区别。比之前省了很多的事情。 通常我们在定义input_device的时候,还会定义一块host上的内存,而这两者的大小近乎是完全一样的,所以既然着两者是成对出现的,我们将其打包到一起会不会更方便呢?GPU内存分配和复用:这个原理其实特别简单:就是比大小,如果之前你要了100字节,这次只要了50字节,那我根本就不用重新分配,直接把上一次的给你就好了,反正也没释放。但是如果这
2023-08-09 21:33:10 240
原创 SPGEMM_example解析
对于每个位置,它通过遍历矩阵 A 的非零元素和矩阵 B 的对应元素,按照稀疏矩阵乘法规则进行相乘累加操作,并将最终结果存储在。首先,它计算出每行在结果矩阵 C 中的存储位置范围(起始位置和结束位置),然后将遍历得到的矩阵 A 的非零元素所在的列索引存储在。这个核函数的作用是计算结果矩阵 C 的每一行中非零元素的数量,并将这些数量存储在偏移量数组。这个核函数的作用是执行稀疏矩阵乘法的计算,并将结果存储在结果矩阵 C 的值数组。核函数进行了实际的稀疏矩阵乘法计算,并将结果存储在矩阵 C 的值数组中。
2023-08-08 14:49:24 224
原创 从零构建深度学习推理框架-6 构建计算图
PNNX由操作数operand(运算数)和operator(运算符号),PNNX::Graph用来管理和操作这两者。得到pnnx::graph,一个一个算子去初始化 runtimegraph得到pnnx::operators -->依次便利pnnx operator 遍历,初始化一个RuntimeOperator1. 得到pnnx operator的inputs,再根据这个inputs去初始化我们RuntimeOperator::runtime_operator->input_operands。
2023-08-07 13:23:18 525
原创 从零开始构建推理框架-5 MaxPooling层的实现
池化层在深度学习网络中的作用一般是用来缓解卷积层对位置的过度敏感性.池化层每次对输入数据的一个固定形状窗口(池化窗口的大小为pooling height, pooling width)中的元素计算输出,池化层直接计算池化窗口内元素的最大值或者平均值。该运算也分别叫做最大池化或平均池化。实现如下:其上分为三个部分:要获得stride , padding_height , padding_width2 如果需要池化,则需要在周围填充一圈负无穷:先获取batch_size的大小,在每个batch上
2023-08-07 10:11:38 163
原创 从零构建深度学习推理框架-4 框架中的算子注册机制
今天要讲的这一注册机制用到了设计模式中的工厂模式和单例模式,所以这节课也是对两大设计模式的一个合理应用和实践。KuiperInfer的注册表是一个map数据结构,维护了一组键值对,key是对应的OpType,用来查找对应的value,value是用于创建该层的对应方法(Creator)。OpType就是头文件中对应的索引:创建该层的对应方法相当于一个工厂(Creator),Creator如下的代码所示,是一个函数指针类型,
2023-08-04 16:20:14 741
原创 基础篇:多线程所需知识:RAII接口模式对生产者和消费者封装以及多batch实现
1、头文件应尽量简洁2、不需要的东西都放到cpp当中,不要让接口类看到private:public:这样就不符合尽量简洁的原则,因为这里用不到stream,应该尽可能放到cpp里。3、尽量不要在头文件写using namespace,因为写了这个就代表命名空间被打开了,这样就使得所有包含了这个头文件的人的所有命名空间都被打开。但CPP里可以写。
2023-08-02 14:42:35 368
原创 基础篇:多线程所需知识:
上图是我们之前的一个例子,可以看到如果没有t.join(),那么线程是会崩掉的,因为他的生命周期在main()函数里面,所以当main结束之后他也会析构掉,但线程里面还在执行,所以会出现错误。可以通过取地址方式,保留this参数,这样做可以避免static无法使用this->的操作。可以看到在延迟了500毫秒之后,worker down这条语句来不及打印,就会直接退出。如果一个线程一旦detach之后,线程就交给了系统作管理,当程序结束后自动退出。detach是分离线程,取消管理权,使线程变成野线程。
2023-07-28 14:35:01 139
原创 从零构建深度学习推理框架-2 从CSV文件初始化Tensor
CSV(逗号分隔值)文件是一种特殊的文件类型,可在 Excel 中创建或编辑。CSV文件采用逗号分隔的形式来存储文本和数字信息,总体来说,这种形式的文件格式具有扩展性好,移植性强的特点。在try中要先将表头传到header里,再将其余的数组读到data中,但记住data中的row要-1,因为要扣除表头的一行。,例如MySQL数据库可以从CSV文件中导入数据,GMail联系人可以导出到CSV文件,然后将其导入到Outlook中。复杂,且多变维度的输出,来对比我们的推理结果。保存为tensor -->
2023-07-26 18:38:50 562
原创 使用openvino进行onnx的模型推理过程
通过model = core.compile_model(xx.onnx)编译模型- 通过iq = model.create_infer_request()创建推理请求获取输入的tensor获取输出的tensor配置输入大小,因为是动态batch,需要先设置大小,此时会分配空间获取输入指针,必须set shape后才能获取数据指针,否则会存储空间没分配而异常- 把图像预处理并储存到 input_data_host- iq.infer() 执行推理步骤。
2023-07-26 15:42:07 2130 1
原创 TRT4-trt-integrate - 3 使用onnxruntime进行onnx的模型推理过程
其余的都是和之前一样的,这是非常好用便捷的,所以如果有模型需要作测试,是非常推荐用onnxruntime的。第二个是input的dict,这个意思就是如果有好多个输入,那应该是将名字与输入进行一一对应,比如"input1 ":input1 , "input2":input2....建立一个InferenceSession,塞进去的是onnx的路径,实际运算的后端选用的是CPU。输入第一个是output的name,决定了哪几个节点作为输出,就将这个名字传递给他。也可以选用cuda等等。
2023-07-26 14:35:16 853
原创 从零构建深度学习推理框架-1 简介和Tensor
深度学习推理框架用于对已训练完成的神经网络进行预测,也就是说,能够将深度训练框架例如Pytorch、Tensorflow中定义的算法移植到中心侧和端侧,并高效执行。与训练框架不同的是,深度学习推理框架没有梯度反向传播功能,因为算法模型文件中的权重系数已经被固化,推理框架只需要读取、加载并完成对新数据的预测即可。
2023-07-25 19:49:34 1707
原创 TRT4-trt-integrate - 2 Unet分割模型 导出、编译、推理
这次我们来学习UNET分割模型如何进行导出这里最后的image_data就变成了一个标准的tensor格式这个net后来会变成一个Dataparallel的格式,这个格式对于我们导出是不太方便的,所以要在他改变之前将其导出。
2023-07-20 17:47:57 249
原创 TRT4-trt-integrate - 1 YOLOV5导出、编译、推理
在这次过程中,warpaffine(预处理)和后处理过程都可以使用我们之前的核函数去处理,这一部分打包到GPU上的话性能会变得更高。
2023-07-19 19:12:20 1299
原创 TRT3-trt-basic - 6 Int8的量化
Int8量化类似于一个黑盒子,有一点蒸馏的感觉,用int8逼近fp32的推理结果。我们只需要按照步骤设定好参数之后set就可以,并不需要特别关注于他是怎么修改权重的量化就是将浮点数转为证书的过程比如有一个FP32的浮点型数字,然后我们需要把这个数变为整型,也就是要量化它,怎么搞。我们可以把这个数字乘上一个量化系数s,比如,那么量化后的值,然后我们对这个数字进行四舍五入(也就是round操作)最终为523。但这样就行了吗?523有点大啊。
2023-07-18 18:36:00 317
原创 TRT3-trt-basic - 5.1 封装插件
传入cu里的时候也是通过info传入,之后再通过config的读取就可以读取出来各种类型的文件,这样就不用再设置字符串类型还是float32类型。从导出的onnx文件也可以看出来,类型是plugin,name是MYSELU,剩下的都在info里。首先可以看到这次的g.op不再是MYSELU了,而是plugin,那为什么.cu还能识别出来呢?之前TRTbasic4是新增插件,这次我们看看不新增插件,仅凭封装可不可以达到一样的功能。而且在这里creator什么的用的都是默认的实现。
2023-07-18 14:16:51 332
原创 TRT3-trt-basic - 5 插件的编写
还是一模一样的genonnx.py但是不一样的是这里的激活算子改为了MYSELU其中这个MYSELUImpl就是咱们插件真正实现的一个类所有的插件都要继承于torch.autograd.Function其中MYSELUImpl.apply调用的就是forwardctx是上下文,x就是数据 , p就是parameter。但forward不会实际上生成节点,真正在onnx中生成节点的是g就是graph , x , p 就是参数了我们将这个模型导出:能看到,relu已经变成MYSELU了。
2023-07-17 19:59:30 293
原创 TRT3-trt-basic - 4 ONNX结构
1、ONNX的本质,是一种Protobuf格式文件2、Protobuf则通过onnx-ml.proto编译得到onnx-ml.pb.h和onnx-ml.pb.cc或onnx_ml_pb2.py3、然后用onnx-ml.pb.cc和代码来操作onnx模型文件,实现增删改4、onnx-ml.proto则是描述onnx文件如何组成的,具有什么结构,他是操作onnx经常参照的东西model:表示整个onnx的模型,包含图结构和解析器格式、opset版本、导出程序类型。
2023-07-17 16:49:24 152
原创 BCSR(Block Compressed Sparse Row)
上图是BCSR的示例BCSR是最流行的块稀疏矩阵格式之一。在BCSR中,所有的块都有相同的大小。为了理解这种格式,想象一个块大小为1的稀疏矩阵。在这种情况下,CSR和BCSR矩阵表示是等效的。块大小的增加不会影响列指针数组和行指针数组。相反,它只是扩展了values数组。也就是说,列和行指针数组包含块的值。块连续地存储在值数组中,极大地降低了内存空间需求。
2023-07-11 19:45:30 767
原创 CSR5(极致负载均衡的方案)
出自“CSR5:An Efficient Storage Format for Cross-Platform Sparse。
2023-07-11 14:57:28 433
原创 Sgemv
因为n>=128所以一个warp就需要处理四个或以上的元素,这里就先设为四个元素,采用向量化访存。取出之后将其加和,作为一个线程所处理的数据,之后将这个warp上的各线程加和结果归并秋和,作为一行一列相乘的结果。而同理,如果n>=32的话,那么每个线程只需要取一个元素即可,那就不需要那么复杂。
2023-07-09 13:17:43 124
原创 TRT3-trt-basic - 1 basic
/第一件事,log类,获得msg。然后可以根据级别决定要不要输出public:第一件事,log类,获得msg。然后可以根据级别决定要不要输出// ----------------------------- 1. 定义 builder, config 和network -----------------------------// 这是基本需要的组件//形象的理解是你需要一个builder去build这个网络,网络自身有结构,这个结构可以有不同的配置。
2023-07-03 00:18:24 166
原创 TRT2-CUDA_Runtime_Api-4 错误处理
1. 若cuda核函数出错,由于他是异步的,立即执行cudaPeekAtLastError只会拿到对输入参数校验是否正确的状态,而不会拿到核函数是否执行正确的状态2. 因此需要等待核函数执行完毕后,才真的知道当前核函数是否出错,一般通过设备同步或者流同步进行等待block越界访问越界。
2023-07-02 21:10:03 83
原创 YOLOv5 后处理cuda实现
在mian函数中,运用load_file读取tensor文件这里用load_file打开图片, 这里是用二进制模式打开文件(ios::binary), 使用static std::vector存储数据。YOLOV5给出来的data是n x (5 + classes)的, 这里通过计算可以获得行数列数, 然后传入指向data的指针, nrows, ncols解码, 本案例提供cpu解码和GPU解码解码结束后返回的是。
2023-07-02 15:01:15 922
原创 CUDA_GPU编程
•线程组分歧():尽量保证32个线程都进同样的分支,否则两个分支都会执行。•延迟隐藏():需要有足够的blockDim供SM在陷入内存等待时调度到其他线程组。•寄存器打翻():如果核函数用到很多局部变量(寄存器),则blockDim不宜太大。•共享内存():全局内存比较低效,如果需要多次使用,可以先读到共享内存。•跨步访问(coalescedacccess):建议先顺序读到共享内存,让高带宽的共享内存来承受跨步。•区块冲突():同一个warp。
2023-07-01 18:37:51 827
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人