首页 > 编程知识 正文

模型,bem模型

时间:2023-05-03 12:06:34 阅读:13262 作者:4185

本教程介绍了剪枝、蒸馏、量化三种方法,最终在pc端完成了部署。 这些方法均采用各领域经典思路实现,剪枝部分(BN剪枝、直接减路)、蒸馏部分(见Hinton论文)、量化) MNN离线量化)。 教程的目的是快速进入模型压缩领域,通过实验体验剪枝、蒸馏、量化的效果,在模型调试方面积累经验。

模型压缩核心:减小模型大小,然后补偿降低的精度

实验模型: VGG16、ResNet34

数据集: CIFAR10

剪树枝

1 .直接减少频道数量

以VGG16为例,直接减少信道的剪枝策略对应于在每一层直接将信道数目减半或减少1/4,并根据VGG16的结构重建具有较少信道数目的模型,这种模型可直接初始化训练。 该方案不应该严格纳入剪枝范畴,只是模仿较好的模型结构,减少通道数量。 通常,它适合于模型大、任务相对简单的场景。 在相对简单的场景中,大模型的应用往往会导致许多参数冗馀,因此,使用减少通道的方法保留模型结构,并快速缩小模型的子大小。

2. BN剪枝

通常,模型采用Conv BN的组合,此时BN层权重可以被视为筛选卷积层信道的重要因子。 BN层中某一信道的权重越小,对应于卷积层的信道的作用越小。 (如果将具有卷积层的信道与对应于BN层的信道的较小权重相乘,则它们的输出接近于0,并且对应于该信道的输出等于0,所以这些信道可以被认为是不重要的信道,并且可以被剪去) )。

核心:在BN层找到权重小的通道,在相应的卷积层剪切这些通道,达到保留模型结构、减小模型尺寸的目的。

问题:常规训练的模型中,BN的权重往往不太接近0或很大。 在这种情况下,通过直接截断权重相对小的通道,对模型效果的影响很大

解决方法:稀疏化训练在模型稳态损耗函数中加入BN参数正则化损耗,强迫BN参数在训练中接近0,训练完成后,截断与最接近0部分BN参数对应的通道,是截断最不重要的通道

1. VGG实验直接减通道

注意: VGG16是原始结构,VGG16-HALF将所有通道数量减半,VGG16-QUARTER将所有通道数量减少1/4

当通道数量减少到1/2时,参数量增加了4倍,快件增加了2倍左右,精度下降了2%

通道数减少1/4时,参数量提高16倍,推理速度提高4倍左右,精度降低5%

对于上述两个直接减流路径的方案,模型参数量和推理速度下的增益是明显的,对于舍弃的精度,以下通过模型蒸馏进行补偿。 BN剪枝

VGG模型结构比较简单,与shortcut连接无关,且是Conv BN的标准结构。 BN剪枝比较方便,BN层决定前一个conv层的剪枝,所有conv bn组合均可参与剪枝

稀疏训练的重要性:没有进行稀疏训练的VGG16的精度特别高,只有在裁剪率为30%的情况下,因为应用BN剪枝时,BN层的权重较大,所以这些被剪切的通道都可能是对模型推理有用的通道

稀疏化训练的核心是找到合适的scale。 scale太小,BN权重正则化效果不明显,不能将权重压缩到0附近,影响后期剪枝效果的scale过大,模型总损耗过大,增加训练难度(振动) )。

TODO :代码中有错误。 如果设置不正确的阈值,一个层次的通道可能会减少到0,从而导致错误。 解决方案是设置阈值上限(每个层的BN最大值中的最小值),以防止thresh超过此值。 否则,将出现一个错误,其中某一层的通道减少到0。

tips :可以稍微提高prune ratio。 即使精度经常下降,如果后期有蒸馏,也可以尝试提高精度,所以这里的重点是提高pruneratio来减小模型大小。 当然,如上所述,即使ratio为0.7,模型也可以保持较好的精度

2. ResNet实验

注意:由于ResNet34的结构稍有调整,CIFAR10数据集的大小只有32*32,且原始ResNet中的采样大小过多,因此此处的模型相对于ImageNet上的ResNet34来说要小得多

剪枝策略:

ResNet的剪枝策略由比较复杂的repo提供的ResNet模型基于V2结构,卷积块结构为BN - Relu - Conv,每个卷积块内部Conv通道的剪枝由其前一BN层决定,vgg

ResNet中存在shortcut结构,为了使bottleneck的最后一个Conv与支路的通道数一致,不进行剪枝(最后的合并是添加操作)

通道选择作用,内部一个索引可以通过放置0或1筛选通道,放置到第一个BN层后,第一个BN层不能真正减少通道(通道数仍为256或512 ) 通道选择由于索引的选择作用,阻断了一些通道(这些通道不起作用),通道选择是ResNet剪枝所必需的。 由于卷积块的结构式BN - Relu - Conv,第一次单独卷积前面没有BN

是剪枝的,此时后面的BottleNeck的第一个BN如果按照权重剪枝,那么这两层之间的通道数就不对了,没法串接起来了。所以BottleNeck的第一个BN只能通过Channel Selection进行伪剪枝(通道数不剪,权重太小的通道被屏蔽了)此外,BottleNeck之间可能会有一些单独的卷积相连,这些相连的卷积由于缺少关联的BN层也是无法剪枝的,因此后一个BottleNeck的第一个BN层需要Channel Selection确保和前面Conv层的维度一致BN剪枝

prune ratio为0.5时参数量变为原来的1/2,准确率几乎不变;prune ratio为0.7时,参数量变为原来的1/3,准确率下降严重。

前面也提到,剪枝阶段的核心目的是确保模型尺寸尽可能的小,对于prune ratio=0.5这种情况,既缩小模型尺寸,又保持精度固然很好,如果想进一步缩小模型尺寸,可以考虑prune ratio=0.7的方案,虽然精度掉的很严重,后续的蒸馏阶段成功的把精度补回来了。实际使用时考虑prune ratio 0.5和0.7两种方案共同操作,防止prune ratio=0.7的模型后期蒸馏精度提不回来,就采用prune ratio为0.5的方案。

蒸馏

提升剪枝模型精度的方法有两种在剪枝模型的基础上finetune,相当于继续微调参数,寻找最佳状态 => VGG16 - prune 0.7的finetune

蒸馏,用一个训练好的大模型蒸馏剪枝后的模型,相当于更高级的finetune,将大模型的dark knowledge蒸给小模型 => VGG16 - QUARTER的蒸馏,ResNet(depth=92)蒸ResNet34(prune0.5/0.7)

区别:一般来说蒸馏模型的精度不会高于teacher model的精度,finetune的话可能会超过原始未剪枝模型的精度

注:蒸馏的大模型一般用同类型的网络效果较好,如resnet34用resnet151蒸馏,不同模型的混合蒸馏可能效果不一定好。

1. VGG蒸馏Prune Finetune

VGG16 - prune 0.7 由于和原始模型的VGG16 - Sparse Train精度相差不是很大,蒸馏可能效果一般,直接尝试finetune

Finetune效果不明显,可能是本身精度就比较高(接近达到VGG16 Origin的饱和精度)蒸馏实验

VGG16 - QUARTER 用VGG16去蒸馏,两者精度相差5%,但VGG16 - QUARTER的参数更少、速度更高,因此尝试通过蒸馏提升该模型的精度。

方法:采用Hinton最经典的Knowledge Distillation模型,loss = hard loss + soft loss,其中hard loss是student model和label的交叉熵,soft loss是student model和teacher model的预测输出分布的KL散度

蒸馏后,以VGG16 - QUARTER - KD(alpha=0.9, lr=0.01, temperature=10)为例,效果提升约2%,仍然没有BN剪枝好,对比BN剪枝模型的参数量(923K vs 1.17M)可能是参数量的原因,VGG16 - QUARTER的效果达到了当前参数的瓶颈(猜测)

2. ResNet蒸馏

ResNet的蒸馏针对ratio=0.5和0.7分别做了实验,对0.5做纯粹是为了拉高精度(锦上添花),对0.7做是为了证明前面的TIPS(剪枝部分先重点把模型结构缩小,降低的精度可以通过蒸馏弥补)两者进行对比。

ResNet部分蒸馏的效果还是比较明显的,ResNet34剪枝模型在蒸馏后精度逼近ResNet90大模型,超越了原始的ResNet34模型。

蒸馏体会learning rate。蒸馏时learning rate调太小,模型效果基本不提升,一直在原精度附近徘徊,涨不上去,learning rate稍稍调大一些,模型在前期精度会下降,但是后期学习率衰减之后会补偿回来(不要太在意前期精度的下降)=> 一般倾向于learning rate调大一点,调小了可能训练整个过程不起作用。

温度temperature。影响teacher model给出的软分布信息,这个信息后续是直接指导student model训练的,因此temperature的取值会直接影响模型的蒸馏效果

TODO:Temperature=50正在测试

loss的比值alpha,该项是决定soft loss(teacher model对student的指导)占比的,一般先观察soft loss和hard loss的大小关系,选择适当比例

部署

部署基于MNN框架实现

卷积BN融合

作用:加快网络推理速度,本来模型推理时conv、bn两层,要做两次计算,在推理时把bn层融合到卷积层中,只需一次计算。

原理:推理时BN层的参数是固定的,此时该层可以看成一个卷积层,融合是指通过参数的等效变换,把bn层的参数乘加到前一conv层的参数中,后面的BN层可以去掉 => 网络整体的计算量变小了,BN层的计算全都省略了,这部分的参数移到前面的卷积层了 => 变换后的卷积层其参数相当于完成了卷积 + BN两件事。

上述所有实验(VGG + ResNet)在剪枝之后就已经完成了卷积BN融合。

MNN模型转化:MNNConvert将.onnx格式的模型转化成.mnn格式,后续部署直接在C++中完成

推理流程:读取图片 => 预处理(RGB转换 + 归一化)=> MNN调模型 => 获取模型输出

MakeFile编译推理.cpp文件得到可执行文件,完成部署

量化

量化基于MNN框架实现,直接采用MNN自带的Quantized完成

理论核心:确定合适的尺度因子,使fp32和int8之间的信息损失最小 => 如何确定?最优化问题KL散度(fp32分布和int8分布尽可能一致)

L2损失(fp32 => int8 => fp32,和原始的fp32尽可能接近)

内部实现:量化过程中,遍历所有Op,若该Op支持量化,则将该Op量化;若该Op不支持量化,如果其输入是量化Op给的,后接反量化模块,将量化的输出变回未量化的输出;如果其输出后续给到量化Op,则输出后接量化模块,将该Op未量化的输出变成量化的输出。所以整个模型经过量化之后,内部支持量化的Op其参数是量化之后的int8精度,不支持量化的Op其参数仍是原始的float32精度,如果涉及量化和未量化Op相连,则要插入相应的量化 / 反量化模块

MNN量化要点:quant_config.json配置量化预处理操作(图像归一化参数mean, std,校准图像目录,量化方法)ResNet量化

模型 ResNet34 - Sparse Train - prune0.5(alpha=0.9, lr=0.01, temperature=3)用作量化示范

量化后模型尺寸明显缩小,926KB => 315KB,但在mac上测试时发现量化后的模型反而推理耗时增加了(耗时增加查下来可能是因为mac的cpu不支持int8这类定点运算,导致量化后的int8模型实际测试时还是会转化为64位,这个转化导致耗时增加 <= 不确定是不是这个原因,但自己测试了好几个模型量化之后耗时都增加了)

量化后模型的精度下降了约2%,精度损失感觉还是挺严重的,量化配置中校准图片选择测试集图片,数量无论是100张或600张或2000张,量化后的精度基本都在89.5%~90.0%之间浮动,mean和normal都和之前一致。不知道这个精度下降的点数是否正常,若不正常,暂时未找到原因。

致谢

剪枝

蒸馏

量化

部署

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。