写点什么

如何减小机器学习模型的大小

  • 2020-02-28
  • 本文字数:3511 字

    阅读完需:约 12 分钟

如何减小机器学习模型的大小

导读:众所周知,机器学习模型需要大量的计算、内存和功耗,这就给我们在实时推理或在计算资源有限的嵌入式设备上运行模型带来了瓶颈。更复杂、更庞大的模型带来的是更多的内存消耗,进而带来更多的功耗。这就是模型优化要解决的问题。模型优化的技术有剪枝、量化等,我们今天翻译并分享了 Amandeep Singh 的文章,讲述了如何让模型变得再小一些,以飨读者。


机器学习模型变得越来越大,计算成本也越来越高。嵌入式设备的内存、计算能力和电池都受到限制。但我们可以对模型进行优化,使其在这些设备上能够顺利运行。通过减小模型的大小,我们减少了需要执行的操作数量,从而减少了计算量。较小的模型也很容易转化为更少的内存使用,也就更节能。人们一定会认为,减少计算次数可以减少功耗,但相反,从内存访问获得的功耗比进行加法或乘法运算要高出 1000 倍左右。现在,既然没有免费的午餐,也就是说,所有一切都是有代价的,因此,我们就会失去模型的正确率。记住,这些加速的措施并不是为了训练模型,而是为了进行推理。

剪枝

剪枝(Pruning)就是删除对输出贡献不大的多余网络连接。剪枝网络的想法可以追溯到 20 世纪 90 年代,即“最优脑损伤”(Optimal Brain Damage)和“最优脑手术”(Optimal Brain Surgeon)。这些方法使用 Hessians 来确定连接的重要性,这也使得它们不适用于深度网络。剪枝方法使用迭代训练技术,即训练 → 剪枝 → 微调。剪枝后的微调恢复了网络经剪枝后丢失的正确率。一种方法是使用 L1/L2 范数对网络中的权重进行排序,并去掉最后的 x% 的权重。其他类型的方法也使用排序,使用神经元的平均激活,神经元在验证集上的激活次数为零,还有许多其他创造性的方法。这种方法是由 Han 等人在 2015 年的论文中首创的。



神经网络的剪枝。Han 等人


更近一些的是 2019 年,Frankle 等人在论文《彩票假说》(The Lottery Ticket Hypothesis)中发现,在每个深度神经网络中都存在一个子集,在同等数量的训练下,该子集也具有同样的正确率。这些结果适用于非结构化剪枝,即剪枝整个网络,从而得到一个稀疏网络。稀疏网络在 GPU 上效率低下,因为它们的计算没有结构。为了补修这一点,需要进行结构化剪枝,即对网络的一部分进行剪枝,例如某一层或某一通道。Liu 等人发现,前面讨论的彩票假说在这里并不适用。相反,他们发现,在剪枝之后重新训练网络比微调更好。除了性能之外,稀疏网络还有其他用途吗?是的,正如 Ahmed 等人的论文所指出的那样,稀疏网络在噪声输入的情况下更具健壮性。在 TensorFlow(tensorflow_model_optimization 包)和 PyTorch(torch.nn.utils.prune)都支持剪枝。


要在 PyTorch 中使用剪枝,你可以从 torch.nn.utils.prune 中选择一个技术类,或者实现 BasePruningMethod 的子类。


from torch.nn.utils import prunetensor = torch.rand(2, 5)pruner = prune.L1Unstructured(amount=0.7)pruned_tensor = pruner.prune(tensor)
复制代码


为了对模块进行剪枝,我们可以使用 torch.nn.utils.prune 中给出的剪枝方法(基本上就是上述的类的包装器),并指定哪个模块要进行剪枝,甚至是该模块的哪个参数。


conv_1 = nn.Conv(3, 1, 2)prune.ln_structured(module=conv_1, name='weight', amount=5, n=2, dim=1)
复制代码


这将使用剪枝后的结果替换参数权重,并添加一个参数 weight_orig 来存储输入的未剪枝版本。剪枝掩码(pruning mask)存储为 weight_mask,并作为模块缓冲区保存。这些参数可以通过 module.named_parameters()module.named_buffers() 来检查。为了实现迭代剪枝,我们可以只在下一次迭代中应用剪枝方法,这样它就可以正常工作了,这是因为 PurningContainer 在处理最终掩码的计算时,考虑到了之前使用 computer_mask 方法的剪枝。

量化

量化(Quantization)是为了限制一个权重可以取的可能值的数量,这将减少一个权重可以减少的内存,从而减小模型的大小。实现这一点的一种方法是,更改用于存储权重的浮点数的位宽。以 32 位浮点数或 FP32 到 FP16、或 8 位定点数形式存储的数字,越来越多地以 8 位整数的形式存储。减少位宽具有以下许多优点:


  • 从 32 位转换到 8 位,可以让我们立即获得 4 倍的内存优势。

  • 较低的位宽还意味着,我们可以在寄存器 / 高速缓存中压缩更多的数字,从而减少内存访问,进而减少时间和功耗。

  • 整数计算总是比浮点计算要快。


之所以可行,是因为神经网络对其权重的微小扰动是非常健壮的,我们可以很轻松地舍去它们,而不会对网络的正确率产生太大的影响。此外,由于训练中使用的正则化技术,权重并不包含在非常大的范围内,因此我们不必使用过大的范围,比如,对于 32 位浮点数,取 就可以了。例如,在下图中,MoboileNet 中的权重值都非常接近于零。



MobileNetV1 的 10 层的权重分布


一个量化方案是我们如何将实际权重转换为量化权重,该方案的一个最基本的形式是线性缩放。假设我们要讲范围 的值转换为 的整数范围,其中, 是整数表示的位宽。因此,


其中, 是权重的原始值, 是比例, 是量化值, 是映射到 0.0f 的值。这也称为仿射变换(affine mapping)。由于 为整数,因此对结果进行四舍五入。现在的问题是,我们如何选择 。实现这一点的简单方法是生成权重和激活的分布,然后用量化分布计算他们的 KL 散度(Kullback-Leibler divergence,缩写为 KLD 或 KL divergences),并使用与原始值差异最小的那个。一种更为优雅的方法是使用伪量化(Fake Quantization),即,在训练期间将量化感知层引入网络。这个想法是由 Jacob 等人 提出的。



(a)普通卷积层;(b)增加伪量化单元的卷积层;(c)量化网络的时延与正确率的比较。Jacob 等人


在训练时,伪量化节点计算权重和激活的范围,并存储它们的移动平均值。完成训练后,我们用这个范围来对网络进行量化,以获得更好的性能。


Rastegari 等人的关于异或(XOR)网络的论文、Courbariaux 等人的关于三值(Ternary)网络的论文、Zhu 等人的关于二值(Binary)网络的论文中也探讨了更大的位宽。在 PyTorch 1.3 中,引入了量化支持。为量化操作引入了三种新的数据类型:torch.quint8torch.qint8torch.qint32。它还提供了各种量化技术,包含在 torch.quantization 中。


  • 训练后动态量化:将浮点权重替换为其动态量化版本。默认情况下,只对权重交大的层(即线性和 RNN 变体)进行权重量化。


quantized_model = torch.quantization.quantize_dynamic(    model, {nn.LSTM, nn.Linear}, dtype=torch.qint8)
复制代码


  • 训练后静态量化:静态量化不仅可以将浮点数权重转换为整数,还可以记录激活的分布情况,并用于确定推理时的量化比例。为了支持这种校准类型的量化,我们在模型的开头和结尾分别添加了 QuantStubDeQuantStub。它涉及下面提到的步骤。


myModel = load_model(saved_model_dir + float_model_file).to('cpu')# Fuse Conv, bn and relumyModel.fuse_model()
# Specify quantization configuration# Start with simple min/max range estimation and per-tensor # quantization of weightsmyModel.qconfig = torch.quantization.default_qconfig
torch.quantization.prepare(myModel, inplace=True)
# Calibrate with the training setevaluate(myModel, criterion, data_loader, neval_batches=num_calibration_batches)
# Convert to quantized modeltorch.quantization.convert(myModel, inplace=True)
复制代码


  • 量化感知训练:在训练时使用伪量化模块来存储比例。为了启用量化感知训练,我们使用 qconfig 作为 get_default_qat_qconfig('fbgemm'),使用 prepare_qat 来代替 prepare。之后,就可以对模型进行训练或微调,在训练结束时,使用 与上述相同的 torch.quantization.convert 得到量化模型。


PyTorch 中的训练后量化目前仅支持 CPU 上的操作。


有关详细的代码示例,请参阅 PyTorch 文档。在 TensorFlow 方面,通过 将 optimizations 参数设置为 tf.lite.Optimize.OPTIMIZE_FOR_SIZE,可以使用 TFLite 的 tf.lite.TFLiteConverter API 进行量化。伪量化是通过 tf.contrib.quantize 包启用的。


作者介绍:


Amandeep Singh,供职于 99acres.com 的高级软件工程师。之前曾在三星诺伊达(印度)研究院 工作。广泛研究设备上的机器学习和自然语言处理的问题。


原文链接:


https://amandeepsp.github.io/ml-model-compression-part1/


2020-02-28 16:273063

评论

发布
暂无评论
发现更多内容

HDC开发者盛典 | 破解创业老板高效制果汁奥秘挑战!赢取代金券、按摩枕、收纳袋等礼品~

华为云PaaS服务小智

云计算 软件开发 华为云 华为开发者大会2023

架构课模块一作业

庚小庚

人脸识别技术的精度提高及其应用

来自四九城儿

山西等级保护测评机构有哪些?有几家?

行云管家

信息安全 等级保护 等保测评 等级测评 山西

软件测试/测试开发丨Selenium的常用元素定位方法

测试人

Python 软件测试 自动化测试 测试开发 selenium

解决ueditor表格拖拽没反应的问题

互联网工科生

数据库 Vue

ABAQUS有限元分析软件吃CPU还是GPU比较多?

思茂信息

gpu cpu 显卡 ANAQUS 有限元分析

如何用 TDengine 预测 “未来”

爱倒腾的程序员

涛思数据 tdengine 时序数据库

人脸识别技术的安全性和隐私保护

来自四九城儿

华为云CodeArts IDE Online:让你随时随地畅享云端编码乐趣

华为云PaaS服务小智

云计算 软件开发 华为云 华为开发者大会2023

prometheus描点原理

蓝胖子的编程梦

Docker 云原生 Grafana Prometheus #k8s

了解Java可见性的本质

阿里技术

Java java 编程

玩转“擎舵”,秒变AIGC时代营销创意“掌舵人”

Geek_2d6073

关于Java已死,看看国外开发者怎么说的

越长大越悲伤

Java 后端

研发质量指标大 PK:MTTR vs MTBF,谁是靠谱王?

LigaAI

高可用性 研发效能度量 MTTR 研发效能管理 企业号 7 月 PK 榜

手把手教你如何做手机PCB电磁兼容性设计

华秋PCB

电磁 PCB 电路板 电子 PCB设计

文盘Rust -- FFI 浅尝 | 京东云技术团队

京东科技开发者

rust C语言 企业号 7 月 PK 榜 FFI

推荐书单:个人成长的一些方法

老张

个人成长 书单

在 7 月 4 日,PoseiSwap 治理通证 $POSE 上线了 BNB Chain 上的头部

威廉META

在 7 月 4 日,PoseiSwap 治理通证 $POSE 上线了 BNB Chain 上的头部

鳄鱼视界

PoseiSwap 治理通证POSE登录PancakeSwap,开盘涨幅超2100%

西柚子

制造业用哪款堡垒机好一点?为什么?

行云管家

网络安全 堡垒机 双因子认证 制造业

ElasticSearch - 批量更新bulk死锁问题排查 | 京东云技术团队

京东科技开发者

elasticsearch MQ 企业号 7 月 PK 榜 BulkProcessor

2023年CCF-百度松果基金课题申报持续进行中,截至7月24日

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

MatrixOne 0.8.0 开放公测啦!

MatrixOrigin

云原生 超融合 #数据库 MatrixOne

GPU 容器虚拟化新能力发布和全场景实践

Baidu AICLOUD

GPU容器虚拟化

“多”维演进:智能编码的深度进化

阿里云CloudImagine

云计算 编码 视频编码 视频云

为什么越来越多的网站选择海外主机跨越国界?

一只扑棱蛾子

海外主机

5G与妈祖守护的那片海

白洞计划

5G

Spring Loaded代码热更新实践和原理分析 | 京东云技术团队

京东科技开发者

spring 热更新 Loader 企业号 7 月 PK 榜

【OpenAI】ChatGPT函数调用(Function Calling)实践 | 京东云技术团队

京东科技开发者

openai 数据交互 企业号 7 月 PK 榜 Function Calling

如何减小机器学习模型的大小_AI&大模型_Amandeep Singh_InfoQ精选文章