1.3d稀疏卷积——spconv源码剖析(一)
2.PostgreSQL-源码学习笔记(5)-索引
3.MediaCodec源码浅析
4.3d稀疏卷积——spconv源码剖析(五)
5.3d稀疏卷积——spconv源码剖析(三)
3d稀疏卷积——spconv源码剖析(一)
本文主要阐述卷积的网站网站基本理论,并以spconv源码为例进行解析。源码p源首先,视频介绍2D与3D卷积的网站网站基础知识及其分类。随后,源码p源深入探讨3D稀疏卷积的视频android 小部件 电量 源码工作原理。
2D卷积涉及卷积核在二维图像空间上的网站网站滑动操作。它分为单通道卷积与多通道卷积。源码p源单通道卷积在输入图像的视频单一通道上进行,得到特征图。网站网站多通道卷积在同一图像中不同通道上进行,源码p源每个通道得到一个对应的视频新通道,最终通过相加生成特征图。网站网站
3D卷积在此基础上扩展到三维空间,源码p源涉及单通道与多通道情况。视频三维单通道卷积在立方体上进行,而三维多通道卷积则处理拥有多个通道的三维图像。
2D与3D卷积计算涉及输入层、输出层与参数关系的数学公式。考虑偏置参数与计算量,FLOPS(浮点运算量)也在此阶段被计算。
稀疏卷积分为SC(Sparse Convolution)与VSC(Valid Sparse Convolution)两种类型。SC卷积计算激活站点并丢弃非激活站点,溯源码查真伪而VSC卷积在SC的基础上进行了简化。
卷积神经网络对三维点云数据处理时,面临计算量增加的问题,而SC与VSC卷积利用稀疏性实现高效处理。构建输入与输出哈希表,对点云数据进行快速访问。GetOffset()函数用于定位卷积操作的位置,Rulebook用于存储原子操作规则,指导稀疏卷积过程。
稀疏卷积的关键在于构建输入、输出哈希表以及建立两者之间的联系,实现对稀疏数据的有效处理。spconv库中的get_indice_pairs函数通过调用getIndicePairs实现这一过程。
PostgreSQL-源码学习笔记(5)-索引
索引是数据库中的关键结构,它加速了查询速度,尽管会增加内存和维护成本,但效益通常显著。在PG中,索引类型丰富多样,包括B-Tree、Hash、GIST、虚拟sim卡源码SP-GIST、GIN和BGIN。所有索引本质上都是独立的数据结构,与数据表并存。
查询时,没有索引会导致全表扫描,效率低下。创建索引可以快速定位满足条件的元组,显著提升查询性能。PG中的索引操作函数,如pg_am中的注册,为上层模块提供了一致的接口,这些函数封装在IndexAmRoutine和IndexScanDesc中。
B-Tree索引采用Lehman和Yao的算法,每个非根节点有兄弟指针,页面包含"high key",用于快速扫描。PG的B-Tree构建和维护流程涉及BTBuildState、spool、元页信息等结构,包括创建、插入、Android mmkv 源码分析扫描等操作。
哈希索引在硬盘上实现,支持故障恢复。它的页面结构复杂,包括元页、桶页、溢出页和位图页。插入和扫描索引元组时,需要动态管理元页缓存以提高效率。
GiST和GIN索引提供了更大的灵活性,支持用户自定义索引方法。GiST适用于通用搜索,而GIN专为复合值索引设计,支持全文搜索。它们在创建时需要实现特定的访问方法和函数。
尽管索引维护有成本,但总体上,它们对提高查询速度的价值不可忽视。了解并有效利用索引是数据库优化的重要环节。
MediaCodec源码浅析
本文从MediaCodec源码的主要结构出发,深入分析了其核心函数dequeueOutputBuffer的实现机制。MediaCodec主要结构包括API、linux源码安装readmeJNI、Native三个部分,这些部分共同构成了客户进程中运行的代码基础。在这些结构中,应用代码通过Java层MediaCodec接口与JNI代码交互,进而调用Native代码,实现解码器的主要逻辑。
结构上,MediaCodec源码主要分为以下几个关键组件:JMediaCodec、MediaCodec、ACodec和OMXClient。JMediaCodec作为与Java层交互的桥梁,包含智能指针sp和MediaCodec实例mCodec,以及用于事件循环的mLooper。MediaCodec则负责将ACodec与OMX服务端连接起来,实现解码功能。ACodec内部实现为状态机,并继承CodecBase功能,其构造函数初始化内部状态类,并设置初始状态为UninitializedState。OMXClient则负责维护与binder的连接,访问binder方法,实现与服务端的交互。
在分析过程中,重点关注了dequeueOutputBuffer函数的调用流程。该函数从MediaCodec.java调用native_dequeueOutputBuffer,在android_media_MediaCodec.cpp中映射到android_media_MediaCodec_dequeueOutputBuffer函数。最终,此函数通过JMediaCodec.dequeueOutputBuffer调用MediaCodec::dequeueOutputBuffer。在这一过程中,JMediaCodec.dequeueOutputBuffer构建kWhatDequeueOutputBuffer消息,通过ALooper传递给自己处理。消息处理后,将结果返回给调用者,完成输出缓冲区的获取。
在处理过程中,使用了消息队列来管理输入输出缓冲区。消息队列中包含两个关键组件:mPortBuffers和mAvailPortBuffers。mPortBuffers用于存储解码器的所有缓冲区,而mAvailPortBuffers则作为缓冲区队列,用于管理当前可用的缓冲区。dequeuePortBuffer函数用于从mAvailPortBuffers中获取可用缓冲区的索引。生产过程则通过updateBuffers更新缓冲区状态,清理过程则在returnBuffersToCodecOnPort中进行,清空了mAvailPortBuffers。
综上所述,MediaCodec源码的核心在于其结构设计和dequeueOutputBuffer函数的实现,通过消息队列管理和缓冲区操作,实现了高效的解码流程。
3d稀疏卷积——spconv源码剖析(五)
介绍在构建的Rulebook指导下执行特定的稀疏卷积计算,关注于类SparseConvolution,其代码位于spconv/conv.py。
Fsp.indice_subm_conv和Fsp.indice_conv经过spconv/functional.py中的SubMConvFunction和SparseConvFunction对象转换,最终会调用spconv/ops.py模块中的indice_conv等函数。
专注于子流线卷积接口:indice_subm_conv,其代码位于spconv/functional.py。
通过Python接口调用底层C++函数可能不够直观,因此使用torch.autograd.Function封装算子底层调用,该类表示PyTorch中的可导函数,具备前向推理和反向传播实现时,即可作为普通PyTorch函数使用。
值得注意的是,Function类在模型部署中具有优势,若定义了symbolic静态方法,此Function在执行torch.onnx.export()时,可依据symbolic定义规则转换为ONNX算子。
apply方法是torch.autograd.Function的一部分,此方法负责在前向推理或反向传播时的调度工作。通过将indice_subm_conv = SubMConvFunction.apply简化为indice_subm_conv接口,简化了算子使用,屏蔽了SubMConvFunction的具体实现。
SubMConvFunction的前向传播方法forward调用spconv/ops.py的indice_conv函数。在src/spconv/all.cc文件中,通过PyTorch提供的OP Register对底层C++API进行注册。
通过torch.ops.load_library加载.so文件,使用torch.ops.spconv.indice_conv调用src/spconv/spconv_ops.cc文件中的indiceConv函数。
深入探索src/spconv/spconv_ops.cc文件中的indiceConv函数。
代写部分代码内容...
3d稀疏卷积——spconv源码剖析(三)
构建Rulebook
下面看ops.get_indice_pairs,位于:spconv/ops.py
构建Rulebook由ops.get_indice_pairs接口完成
get_indice_pairs函数具体实现:
主要就是完成了一些参数的校验和预处理。首先,对于3d普通稀疏卷积,根据输入shape大小,kernel size,stride等参数计算出输出输出shape,子流行稀疏卷积就不必计算了,输出shape和输入shape一样大小
准备好参数之后就进入最核心的get_indice_pairs函数。因为spconv通过torch.ops.load_library加载.so文件注册,所以这里通torch.ops.spconv.get_indice_pairs这种方式来调用该函数。
算子注册:在src/spconv/all.cc文件中通过Pytorch提供的OP Register(算子注册的方式)对底层c++ api进行了注册,可以python接口形式调用c++算子
同C++ extension方式一样,OP Register也是Pytorch提供的一种底层扩展算子注册的方式。注册的算子可以通过 torch.xxx或者 tensor.xxx的方式进行调用,该方式同样与pytorch源码解耦,增加和修改算子不需要重新编译pytorch源码。用该方式注册一个新的算子,流程非常简单:先编写C++相关的算子实现,然后通过pytorch底层的注册接口(torch::RegisterOperators),将该算子注册即可。
构建Rulebook实际通过python接口get_indice_pairs调用src/spconv/spconv_ops.cc文件种的getIndicePairs函数
代码位于:src/spconv/spconv_ops.cc
分析getIndicePairs直接将重心锁定在GPU逻辑部分,并且子流行3d稀疏卷积和正常3d稀疏卷积分开讨论,优先子流行3d稀疏卷积。
代码中最重要的3个变量分别为:indicePairs,indiceNum和gridOut,其建立过程如下:
indicePairs代表了稀疏卷积输入输出的映射规则,即Input Hash Table 和 Output Hash Table。这里分配理论最大的内存,它的shape为{ 2,kernelVolume,numAct},2表示输入和输出两个方向,kernelVolume为卷积核的volume size。例如一个3x3x3的卷积核,其volume size就是(3*3*3)。numAct表示输入有效(active)特征的数量。indiceNum用于保存卷积核每一个位置上的总的计算的次数,indiceNum对应中的count
代码中关于gpu建立rulebook调用create_submconv_indice_pair_cuda函数来完成,下面具体分析下create_submconv_indice_pair_cuda函数
子流线稀疏卷积
子流线稀疏卷积是调用create_submconv_indice_pair_cuda函数来构建rulebook
在create_submconv_indice_pair_cuda大可不必深究以下动态分发机制的运行原理。
直接将重心锁定在核函数:
prepareSubMGridKernel核函数中grid_size和block_size实则都是用的整形变量。其中block_size为tv::cuda::CUDA_NUM_THREADS,在include/tensorview/cuda_utils.h文件中定义,大小为。而grid_size大小通过tv::cuda::getBlocks(numActIn)计算得到,其中numActIn表示有效(active)输入数据的数量。
prepareSubMGridKernel作用:建立输出张量坐标(通过index表示)到输出序号之间的一张哈希表
见:include/spconv/indice.cu.h
这里计算index换了一种模板加递归的写法,看起来比较复杂而已。令:new_indicesIn = indicesIn.data(),可以推导得出index为:
ArrayIndexRowMajor位于include/tensorview/tensorview.h,其递归调用写法如下:
接着看核函数getSubMIndicePairsKernel3:
位于:include/spconv/indice.cu.h
看:
上述写法类似我们函数中常见的循环的写法,具体可以查看include/tensorview/kernel_utils.h
NumILP按默认值等于1的话,其stride也是gridDim.x*blockDim.x。索引最大值要小于该线程块的线程上限索引blockDim.x * gridDim.x,功能与下面代码类似:
参考: blog.csdn.net/ChuiGeDaQ...
2024-11-27 05:23
2024-11-27 05:12
2024-11-27 05:04
2024-11-27 03:38
2024-11-27 03:37
2024-11-27 03:05