MIT-BEVFusion系列七--量化2_Camera、Fuser、Decoder网络的量化

目录

        • Camera 量化
          • Camera Backbone (Resnet50) 量化
            • 替换量化层,增加residual_quantizer,修改bottleneck的前向
            • 对 Add 操作进行量化
          • Camera Neck (GeneralizedLSSFPN) 量化
            • 将 Conv2d 模块替换为 QuantConv2d 模块
            • Camera Neck 中添加对拼接操作的量化
            • 替换 Camera Neck 中的 Forward
          • Camera VTransform 量化
            • 将 Conv2d 模块替换为 QuantConv2d 模块
          • 模型中所有的拼接使用相同的 scale
            • 处理 Camera Backbone 的 layer3 中的 concat
            • 处理 Camera Backbone 的 layer3 中的 concat
        • Fuser 量化
          • 将 Conv2d 模块替换为 QuantConv2d 模块
        • Decoder 量化

Camera 量化

从终端输出、onnx、csdn上博主网络结构图、代码四个角度熟悉camera的backbone即Resnet50网络的结构。
在这里插入图片描述
在这里插入图片描述

  • 观察 model.encoders.cameraneckvtransform
    • 组成部分 backbone

ModuleDict(
(backbone): ResNet(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): ResLayer(
(0): Bottleneck(
(conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(downsample): Sequential(
(0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): Bottleneck(
(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(2): Bottleneck(
(conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
)
(layer2): ResLayer(
(0): Bottleneck(
(conv1): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(downsample): Sequential(
(0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): Bottleneck(
(conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(2): Bottleneck(
(conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(3): Bottleneck(
(conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
)
(layer3): ResLayer(
(0): Bottleneck(
(conv1): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(downsample): Sequential(
(0): Conv2d(512, 1024, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): Bottleneck(
(conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(2): Bottleneck(
(conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(3): Bottleneck(
(conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(4): Bottleneck(
(conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(5): Bottleneck(
(conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
)
(layer4): ResLayer(
(0): Bottleneck(
(conv1): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(downsample): Sequential(
(0): Conv2d(1024, 2048, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(1): Bottleneck(
(conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
(2): Bottleneck(
(conv1): Conv2d(2048, 512, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(conv3): Conv2d(512, 2048, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn3): BatchNorm2d(2048, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
)
)
)
init_cfg={'type': 'Pretrained', 'checkpoint': '[https://download.pytorch.org/models/resnet50-0676ba61.pth'}](https://download.pytorch.org/models/resnet50-0676ba61.pth'%7D)
(neck): GeneralizedLSSFPN(
(lateral_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(768, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(activate): ReLU(inplace=True)
)
(1): ConvModule(
(conv): Conv2d(3072, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(activate): ReLU(inplace=True)
)
)
(fpn_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(activate): ReLU(inplace=True)
)
(1): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(activate): ReLU(inplace=True)
)
)
)
(vtransform): DepthLSSTransform(
(dtransform): Sequential(
(0): Conv2d(1, 8, kernel_size=(1, 1), stride=(1, 1))
(1): BatchNorm2d(8, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(8, 32, kernel_size=(5, 5), stride=(4, 4), padding=(2, 2))
(4): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): Conv2d(32, 64, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2))
(7): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(8): ReLU(inplace=True)
)
(depthnet): Sequential(
(0): Conv2d(320, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): Conv2d(256, 198, kernel_size=(1, 1), stride=(1, 1))
)
(downsample): Sequential(
(0): Conv2d(80, 80, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(1): BatchNorm2d(80, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(80, 80, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(4): BatchNorm2d(80, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): Conv2d(80, 80, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(7): BatchNorm2d(80, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(8): ReLU(inplace=True)
)
)
)
Camera Backbone (Resnet50) 量化

在这里插入图片描述
对 camera backbone 进行量化

替换量化层,增加residual_quantizer,修改bottleneck的前向

389行,pytorch_quantization中支持的层替换为量化层。
下图剩余部分遍历model_camera_backbone的所有模块,找到bottleneck.__class__.__name__Bottleneck的模块,即有加法(残差)的模块,手动增加residual_quantizer层,residual_quantizer层的量化起使用Bottleneck的模块中名字为conv1的卷积层的量化器(bottleneck.conv1._input.quantizer)这是为了为量化加法即QuantAdd做准备。

通常,量化能考虑到加法、concat等方法, 防止reformate节点,已经算比较精细的量化了。
在这里插入图片描述

  • bottleneck.__class__.__name__举例
'TensorQuantizer'
'BatchNorm2d'
'Bottleneck'
'QuantConv2d'
'Sequential'

在这里插入图片描述

遍历` _DEFAULT_QUANT_MAP 中的所有量化映射条目,将每个条目中的 orig_mod (原始模块) 中的 mod_name (模块属性名称) 对应的属性提取出来,然后将提取的属性的 id 作为 key,属性本身作为 value 储存在 module_dict 中。

在这里插入图片描述

在这里插入图片描述

之后会对 model (resnet50) 中的所有子模块进行遍历,知道当前的模块中没有子模块为止,查看当前的模块的 id 是否在之前的 module_dict 中,如果存在,这个模块就会被替换为量化后的模块。

在这里插入图片描述

上图188行,使用__new__创建一个空的量化模块对象,遍历需要量化的模块nninstance中的所有属性和属性的值,并将获得属性和值添加到量化模块quant_instance对象中,这样就可以保证量化模块对象与需要量化的模块具有相同的属性。

在这里插入图片描述
添加属性的过程

在这里插入图片描述

上图289行,调用__init__函数进行初始化,这里的 self 就是 quant_instance。主要是初始化 QuantInputMixin中的输入的量化描述器或者 QuantMixin 中的输入和权重的量化描述器。

以量化卷积为例,pytorch_quantization中的量化卷积继承两个类,看下图,分别是nn的_ConvNd以及pytorch_quantization中的QuantMixin
在这里插入图片描述
继承QuantMixin类的通常是activation(input)与weight都要量化的,比如卷积
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

上上图193行,这里会将 kwargs 中的键为 quant_desc_input的值 pop 出来,如果不存在,就是用默认的输入量化描述器。

上图162行的 input_only 就表示是 QuantInputMixin 还是 QuantMixin,影响后续返回的量化描述器的个数。

在这里插入图片描述

  • 上图self.init_quantizer就是调用QuantInputMixin 或者 QuantMixin的类方法,来创建self._input_quantizer以及self._weight_quantizer

在这里插入图片描述

self._input_quantizerself._weight_quantizer 会根据上面默认的量化描述器进行初始化,因为最开始我们对每个 DEAFULT_QUANT_MAP 都设置了 _calib_method 为 'histogram’,所以上图创建 TensorQuantizer 对象时,就会将 self._input_quantizer._calibrator 设置为一个 HistogramCalibrator 对象。

在这里插入图片描述
根据 self.init_quantizer 中的配置,上图对于卷积的input来说,self._input_quantizer._calibrator 就是 calib.HistorgramsCalirator 的对象。

上图200行打开_torch_hist开关,来开启高性能的标定。否则标定将会非常慢

总的来说,init 函数的作用就是为输入 (和权重) 初始化量化器和量化方法。

replace_to_quantization_module 函数中,先判断 camer backbone 中的不可再分的子模块是否有匹配的可量化模块,如果存在,就将这个子模块替换为量化模块,并未量化模块进行初始化。在下面用于替换其他 BEVFusion 网络中的子模块时,也是相同的作用。

对 Add 操作进行量化

在这里插入图片描述

之后需要对 resnet50 模型中的所有 Bottleneck 模块进行修改。Resnet50 中有四个残差块,残差块中的 Bottleneck 的数量设置为 [3, 4, 6, 3],每个残差块的第一个 Bottleneck 中才具有 Downsample 模块。

在这里插入图片描述

将 Bottleneck 的 Downsample 中的卷积层的输入量化器设置为与该残差块中的第一个卷积层的输入量化器,主要是为了避免在残差连接时进行精度的转换。

在这里插入图片描述

然后对 bottleneck 添加一个 residule_quantizer 属性用于对残差计算进行量化。

  • 举例if中增加的residual_quantizer
    • 下图右下角WAATCH中显示name=layer2.0对应resnet的第2个ResLayer,有4个Bottleneck,第一个bottleneckdownsample。就会触发if选项。
    • 第315行执行完毕。就会发现在downsample下多出了residual_quantizerper-tensor量化,直方图校准。见下方文本框

在这里插入图片描述
在这里插入图片描述

Bottleneck((conv1): QuantConv2d(256, 128, kernel_size=(1, 1), stride=(1, 1), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): QuantConv2d(128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): QuantConv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(downsample): Sequential((0): QuantConv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(residual_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)
)
  • 举例else中增加的residual_quantizer
    • 直接在Bottleneck最后增加(residual_quantizer)
      在这里插入图片描述
Bottleneck((conv1): QuantConv2d(512, 128, kernel_size=(1, 1), stride=(1, 1), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): QuantConv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): QuantConv2d(128, 512, kernel_size=(1, 1), stride=(1, 1), bias=False(_input_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)(_weight_quantizer): TensorQuantizer(8bit fake axis=0 amax=dynamic calibrator=MaxCalibrator scale=1.0 quant))(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace=True)(residual_quantizer): TensorQuantizer(8bit fake per-tensor amax=dynamic calibrator=HistogramCalibrator scale=1.0 quant)
)

在这里插入图片描述
在这里插入图片描述
对原始输入通过residual_quantizer再去和out相加
在这里插入图片描述
原始的bottleneck.forward

最后将 bottleneck.forward 替换为自定义的函数 (hook_bottleneck_forward) 进行前向。通过对比可以发现,区别在于进行量化时,会将 identity,即对输入进行与卷积操作相同的量化精度,这样在后续进行残差操作时,可以保证不会发生 reformat

在这里插入图片描述
找到Bottleneck后,打印的模块信息,也可以确认它在每层的数量为[3, 4, 6, 3]

总结一下 camera backbone 的量化流程

  • 先遍历 resnet50 中所有的子模块,将 Conv2d 替换为量化模块并初始化一些量化的参数,

    在这里插入图片描述
    未量化前

在这里插入图片描述
量化后

在这里插入图片描述
量化后与量化前onnx可视化对比

  • 之后将 resnet50 中的 bottleneck 中的残差计算替换为包含了量化的计算方法。
Camera Neck (GeneralizedLSSFPN) 量化

在这里插入图片描述

将 Conv2d 模块替换为 QuantConv2d 模块

在这里插入图片描述

这里与量化 camera backbone 时的操作相同,会将模型中的子模块替换为量化模块并初始化量化模块。在 neck 中,torch.nn.Conv2d 模块会被替换为 quant_nn.QuantConv2d 模块。

在这里插入图片描述
替换量化模块前的neck网络结构

在这里插入图片描述
替换量化模块后的neck网络结构

Camera Neck 中添加对拼接操作的量化

在这里插入图片描述

在这里插入图片描述

上图50行,创建 _input_quantizer,使用一个精度为 8,校准方法为 histogramQuantDescriptor 创建的 TensorQuantizer 赋值,将输入量化器的 _calibrator_torch_hist 设置为 True,并将 _fake_quant 也设置为 True

在前向中,如果需要量化,就会使用输入量化器对输入进行伪量化 (QDQ),之后再进行拼接或相加的操作,这里可以看到对多个输入也使用了相同的输入量化器,保证进行相同精度的量化。

在这里插入图片描述

替换 Camera Neck 中的 Forward

在这里插入图片描述
在这里插入图片描述
执行了新添加的两个quant_concat的前向

在这里插入图片描述
原来 GeneralizedLSSFPN 的 forward

对比之后,可以看到区别在于拼接方法的使用。在自定义的 forward 中,会将原来的 torch.concat 替换为自定义的 QuantConcat 对象,如果需要进行量化,就会对两个输入张量进行相同量化精度操作,再将这两个量化的结果通过 torch.concat 操作进行拼接。

Camera VTransform 量化

在这里插入图片描述

对 camera vtransform 中的 dtransform 和 depthnet 进行量化。
在这里插入图片描述

将 Conv2d 模块替换为 QuantConv2d 模块

在这里插入图片描述

将模型中这两个模块中的子模块替换为量化模块并初始化量化模块,主要就是将 torch.nn.Conv2d 替换为 quant_nn.QuantConv2d

在这里插入图片描述
替换量化模块前的dtransform网络结构

在这里插入图片描述
替换量化模块后的dtransform网络结构

在这里插入图片描述
替换量化模块前的depthnet网络结构

在这里插入图片描述
替换量化模块后的depthnet网络结构

模型中所有的拼接使用相同的 scale

这种做法在最开始提到过,主要是为了使用 TensorRT 前向时提高性能。

处理 Camera Backbone 的 layer3 中的 concat

在这里插入图片描述

处理 Camera Backbone 的 layer3 中的 concat

在这里插入图片描述

Fuser 量化

在这里插入图片描述

将 Conv2d 模块替换为 QuantConv2d 模块

将模型中的子模块替换为量化模块并初始化量化模块,主要就是将 torch.nn.Conv2d 替换为 quant_nn.QuantConv2d。

在这里插入图片描述
替换量化模块前的ConvFuser网络结构

在这里插入图片描述
替换量化模块后的ConvFuser网络结构

Decoder 量化
  • 也是主要替换卷积,后decoder中是transformer结构,在导出onnx时会有所不同

在这里插入图片描述

  • 结构
_ModuleDict(_
_  (backbone): SECOND(_
_    (blocks): ModuleList(_
_      (0): Sequential(_
_        (0): Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (1): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (2): ReLU(inplace=True)_
_        (3): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (4): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (5): ReLU(inplace=True)_
_        (6): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (7): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (8): ReLU(inplace=True)_
_        (9): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (10): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (11): ReLU(inplace=True)_
_        (12): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (13): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (14): ReLU(inplace=True)_
_        (15): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (16): BatchNorm2d(128, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (17): ReLU(inplace=True)_
_      )_
_      (1): Sequential(_
_        (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)_
_        (1): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (2): ReLU(inplace=True)_
_        (3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (4): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (5): ReLU(inplace=True)_
_        (6): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (7): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (8): ReLU(inplace=True)_
_        (9): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (10): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (11): ReLU(inplace=True)_
_        (12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (13): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (14): ReLU(inplace=True)_
_        (15): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)_
_        (16): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (17): ReLU(inplace=True)_
_      )_
_    )_
_  )_
_  init_cfg={'type': 'Kaiming', 'layer': 'Conv2d'}_
_  (neck): SECONDFPN(_
_    (deblocks): ModuleList(_
_      (0): Sequential(_
_        (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)_
_        (1): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (2): ReLU(inplace=True)_
_      )_
_      (1): Sequential(_
_        (0): ConvTranspose2d(256, 256, kernel_size=(2, 2), stride=(2, 2), bias=False)_
_        (1): BatchNorm2d(256, eps=0.001, momentum=0.01, affine=True, track_running_stats=True)_
_        (2): ReLU(inplace=True)_
_      )_
_    )_
_  )_
_  init_cfg=[{'type': 'Kaiming', 'layer': 'ConvTranspose2d'}, {'type': 'Constant', 'layer': 'NaiveSyncBatchNorm2d', 'val': 1.0}]_
_)_

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

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

相关文章

STM32自学☞对射式红外传感器计数

infrared_count.c文件 /* 编写步骤 一、初始化函数 1.开启GPIO、AFIO时钟 (NVIC和EXIT不需要开启,因为EXIT时钟一直处于开启状态,而NVIC是内核里的外设和CPU处在一起且RCC管理的是内核外的外设,综上所述,所以不用开启) 2.配…

【机器学习】卷积和反向传播

一、说明 自从 AlexNet 在 2012 年赢得 ImageNet 竞赛以来,卷积神经网络 (CNN) 就变得无处不在。从不起眼的 LeNet 到 ResNets 再到 DenseNets,CNN 无处不在。 您是否想知道 CNN 的反向传播中会发生什么,特别是反向传播在 CNN 中的工作原理。…

Stream流学习笔记

Stream流 创建流中间操作1、filter2、map3、distinct4、sorted5、limit6、skip7、flatMap 终结操作1、forEach2、count3、max&min4、collect5、查找与匹配 创建流 单例集合&#xff1a;集合对象.stream() List<Integer> list new ArrayList<>(); Stream<…

C语言:详解操作符(下)

上一篇链接&#xff1a;C语言&#xff1a;详解操作符&#xff08;上&#xff09;摘要&#xff1a; 在上篇文章中&#xff0c;我们已经讲过位操作符等涉及二进制的操作符&#xff0c;这些有助于帮助我们后期理解数据如何在计算机中运算并存储&#xff0c;接下来本篇将更多的讲述…

mac docker 宿主机和容器间网络打通

动因 是这样&#xff0c;笔者最近满怀欣喜入手Docker&#xff0c;看着各种文章命令都是不断点头称道&#xff1a;“嗯嗯&#xff0c;不错不错”,在接下来终于准备大干一场的时候碰壁了&#xff0c;主要情况是说在Mac中跑了第一把的时候发现碰到&#xff0c;虚拟机和宿主机居然…

CentOS7下如何安装Nginx

一、Ngxin是什么 Nginx是一个开源的 Web 服务器&#xff0c;具有反向代理、负载均衡、缓存等功能。它可以作为 HTTP 服务器&#xff0c;将服务器上的静态文件&#xff08;如 HTML、图片&#xff09;通过 HTTP 协议展现给客户端&#xff0c;也可以实现动静分离&#xff0c;把动态…

【后端高频面试题--Nginx篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;后端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 后端高频面试题--Nginx篇 什么是Nginx&#xff1f;为什么要用Nginx&#xff1f;为什么Nginx性能…

FAST角点检测算法

FAST&#xff08;Features from Accelerated Segment Test&#xff09;角点检测算法是一种快速且高效的角点检测方法。它通过检测每个像素周围的连续像素集合&#xff0c;确定是否为角点。以下是 FAST 角点检测算法的基本流程&#xff1a; FAST 角点检测算法的基本过程主要包括…

精读《Web Components 的困境》

本期精读的文章是&#xff1a;The broken promise of Web Components 以及对这篇文章的回应: Regarding the broken promise of Web Components 1 引言 我为什么要选这篇文章呢&#xff1f; 就在前几天的 Google I/O 2017 上, Polymer 正式发布了 Polymer 2.0 版本. 来看…

HTTP基本概念-HTTP 是什么?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) HTTP 是什么? HTTP 是超文本传输协议&#xff0c;也就是HyperText Transfer Protocol。 能否详细解释「超文本传输协议」? HTTP 的名字「超文本协议传输」&#xff0c;它可以拆成三个部分: 超文本传输…

pycharm控制STM32F103ZET6拍照并上位机接收显示(OV7670、照相机、STM32、TFTLCD)

基于STM32的照相机 准备工作最终效果一、下位机1、主函数2、OV7670初始化 二、上位机1、控制拍照2、接收图片数据 三、资源获取 准备工作 一、硬件及片上资源: 1,串口1(波特率:921600,PA9/PA10通过usb转ttl连接电脑&#xff0c;或者其他方法)上传图片数据至上位机 2,串口2(波特…

Java语法学习反射

Java语法学习反射 大纲 基本介绍class的介绍 具体案例 1. 基本介绍 流程图&#xff08;程序在计算机的阶段&#xff09; 反射的主要的类 这个提高效率不大 2. class的介绍 对于第三点&#xff1a;首先类只会加载一次&#xff0c;得到的class的对象&#xff0c;也只有一…

Linux第52步_移植ST公司的linux内核第4步_关闭内核模块验证和log信息时间戳_编译_并通过tftp下载测试

1、采用程序配置关闭“内核模块验证” 默认配置文件“stm32mp1_atk_defconfig”路径为“arch/arm/configs”; 使用VSCode打开默认配置文件“stm32mp1_atk_defconfg”&#xff0c;然后将下面的4条语句屏蔽掉&#xff0c;如下&#xff1a; CONFIG_MODULE_SIGy CONFIG_MODULE_…

【C语言】实现双向链表

目录 &#xff08;一&#xff09;头文件 &#xff08;二&#xff09; 功能实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;打印链表 &#xff08;3&#xff09; 头插与头删 &#xff08;4&#xff09;尾插与尾删 &#xff08;5&#xff09;指定位置之后…

STM32 + ESP8266,连接阿里云 上报/订阅数据

&#xff08;文章正在编辑中&#xff0c;一点点地截图操作过程&#xff0c;估计要拖拉两三天&#xff09; 一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是AT固件。连接阿里云&#xff0c;需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板&#xff0c;板载…

‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序

遇到 vue-cli-service 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 的错误时&#xff0c;通常意味着Vue CLI没有被正确安装或配置在项目中。这可能是因为node_modules目录缺失了必要的包&#xff0c;或者局部安装的Vue CLI没有被正确设置到系统的PATH环境…

洛谷: P1308 [NOIP2011 普及组] 统计单词数

前言: 这道题没理解清题目表达意思&#xff0c;我开始想的是用map来记录个数&#xff0c;然后一个变量记录一开始出现的单词位置&#xff0c;不挺简单的吗&#xff0c;然后....就AC了2个..从错误提示能看到个数没啥问题&#xff0c;但是第一个单词位置不对&#xff0c;看了新样…

【51单片机】AT24C02(江科大、爱上半导体)

一、AT24C02 1.AT24C02介绍 AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 存储介质:E2PROM 通讯接口:12C总线 容量:256字节 2.引脚即应用电路 本开发板AT24C02原理图 12C地址全接地,即全为0 WE接地,没有写使能 SCL接P21 S…

Microsoft Excel 加载数据分析工具

Microsoft Excel 加载数据分析工具 1. 打开 Excel&#xff0c;文件 -> 选项2. 加载项 -> 转到…3. 分析工具库、分析工具库 - VBA4. 打开 Excel&#xff0c;数据 -> 数据分析References 1. 打开 Excel&#xff0c;文件 -> 选项 2. 加载项 -> 转到… ​​​ 3…

不安全的 HTTP请求 漏洞原理以及修复方法

漏洞名称&#xff1a;不安全的HTTP方法、危险的HTTP方法 漏洞描述&#xff1a;不安全的HTTP方法一般包括&#xff1a;TRACE、PUT、DELETE、COPY 等。其中最常见的为TRACE方法可以回显服务器收到的请求&#xff0c;主要用于测试或诊断&#xff0c;恶意攻击者可以利用该方法进行…