模型压缩-方案(二)-剪枝【①训练一个基准模型;②、对权重值的幅度进行排序,去掉低于一个预设阈值的连接,得到剪枝后的网络;③、对剪枝后网络进行微调以恢复损失的性能;④、重复第②步】
2023-09-27 14:20:40 时间
深度学习网络模型从卷积层到全连接层存在着大量冗余的参数,大量神经元激活值趋近于0,将这些神经元去除后可以表现出同样的模型表达能力,这种情况被称为过参数化,而对应的技术则被称为模型剪枝。
一、细粒度剪枝核心技术(连接剪枝)
对权重连接和神经元进行剪枝是最简单,也是最早期的剪枝技术,下图展示的就是一个剪枝前后对比,剪枝内容包括了连接和神经元。(如下图)
剪枝步骤
- 第一步:训练一个基准模型。
- 第二步:对权重值的幅度进行排序,去掉低于一个预设阈值的连接,得到剪枝后的网络。
- 第三步:对剪枝后网络进行微调以恢复损失的性能,然后继续进行第二步,依次交替,直到满足终止条件,比如精度下降在一定范围内。
二、项目案例
本项目实现如何对MLP进行剪枝处理,同时给出卷积的剪枝思路。如下图,剪枝前后的结果展示,将靠近0的权重进行处理
1、前置知识
计算一个多维数组的任意百分比分位数,此处的百分位是从小到大排列,只需用np.percentile即可
np.percentile(a, q, axis=None, out=None, overwrite_input=False, interpolation='linear', keepdims=False)
- a : array,用来算分位数的对象,可以是多维的数组
- q : 介于0-100的float,用来计算是几分位的参数,如四分之一位就是25,如要算两个位置的数就(25,75)
- axis : 坐标轴的方向,一维的就不用考虑了,多维的就用这个调整计算的维度方向,取值范围0/1
- out : 输出数据的存放对象,参数要与预期输出有相同的形状和缓冲区长度
- overwrite_input : bool,默认False,为True时及计算直接在数组内存计算,计算后原数组无法保存
- interpolation : 取值范围{‘linear’, ‘lower’, ‘higher’, ‘midpoint’, ‘nearest’},默认liner,比如取中位数,但是中位数有两个数字6和7,选不同参数来调整输出
- keepdims : bool,默认False,为真时取中位数的那个轴将保留在结果中
# 作用:找到一组数的分位数值,如二分位数等(具体什么位置根据自己定义)
# 方便我们之后设定剪枝的阈值
import numpy as np
a = np.array([[1,2,3,4,5,6,7,8,9]])
result = np.percentile(a, 50)
print('result = ', result)
打印结果:
result = 5.0
2、核心代码实现步骤
1、通过设定的阈值找到相应的权重,大于这个权重为true,小于为false,生成bool矩阵
2、将bool矩阵转为0-1矩阵,这就是我们所需的mask
3、mask乘上初始权重得到最终剪枝后的权重
3、代码实现
3.1 导入所需包
# 导入所需包
import paddle
import paddle.nn as nn
import paddle.nn.functional as F
import paddle.utils
import numpy as np
import math
from copy import deepcopy
from matplotlib import pyplot as plt
from paddle.io import Dataset
from paddle.io import DataLoader
from paddle.vision import datasets
from paddle.vision import transforms
3.2 搭建基础线性层
# 搭建基础线性层
class MaskedLinear(nn.Linear):
def __init__(self, in_features, out_features, bias=True):
super(MaskedLinear, self).__init__(in_features, out_features, bias)
self.mask_flag = False
self.mask = None
def set_mask(self, mask):
self.mask = mask
self.weight.set_value(self.weight * self.mask)
self.mask_flag = True
def get_mask(self):
print(self.mask_flag)
return self.mask
def forward(self, x):
if self.mask_flag:
weight = self.weight * self.mask
return F.linear(x, weight, self.bias)
else:
return F.linear(x, self.weight, self.bias)
3.3 搭建MLP网络
# 搭建MLP网络
class MLP(nn.Layer):
def __init__(self):
super(MLP, self).__init__()
self.linear1 = MaskedLinear(28 * 28 * 3, 200)
self.relu1 = nn.ReLU()
self.linear2 = MaskedLinear(200, 200)
self.relu2 = nn.ReLU()
self.linear3 = MaskedLinear(200, 10)
def forward(self, x):
out = paddle.reshape(x, (x.shape[0], -1))
out = self.relu1(self.linear1(out))
out = self.relu2(self.linear2(out))
out = self.linear3(out)
return out
def set_masks(self, masks):
# Should be a less manual way to set masks
# Leave it for the future
self.linear1.set_mask(masks[0])
self.linear2.set_mask(masks[1])
self.linear3.set_mask(masks[2])
打印输出网络结构:
# 打印输出网络结构
mlp_Net = MLP()
paddle.summary(mlp_Net,(1, 3, 28, 28))
打印结果:
W0127 11:14:20.232509 135 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1
W0127 11:14:20.238121 135 device_context.cc:465] device: 0, cuDNN Version: 7.6.
---------------------------------------------------------------------------
Layer (type) Input Shape Output Shape Param #
===========================================================================
MaskedLinear-1 [[1, 2352]] [1, 200] 470,600
ReLU-1 [[1, 200]] [1, 200] 0
MaskedLinear-2 [[1, 200]] [1, 200] 40,200
ReLU-2 [[1, 200]] [1, 200] 0
MaskedLinear-3 [[1, 200]] [1, 10] 2,010
===========================================================================
Total params: 512,810
Trainable params: 512,810
Non-trainable params: 0
---------------------------------------------------------------------------
Input size (MB): 0.01
Forward/backward pass size (MB): 0.01
Params size (MB): 1.96
Estimated Total Size (MB): 1.97
---------------------------------------------------------------------------
{'total_params': 512810, 'trainable_params': 512810}
参考资料:
模型压缩之剪枝(MLP)
模型压缩(量化、剪枝)
相关文章
- 蓝桥算法训练__提高组.Day2
- 带你了解3类预训练语音模型预测方法
- [计算机视觉][神经网络与深度学习]SSD安装及其训练教程
- 【计算机视觉】【神经网络与深度学习】YOLO v2 detection训练自己的数据
- 【神经网络与深度学习】Caffe使用step by step:使用自己数据对已经训练好的模型进行finetuning
- 【神经网络与深度学习】在Windows8.1上用VS2013编译Caffe并训练和分类自己的图片
- 【神经网络与深度学习】Caffe训练执行时爆出的Check failed: registry.count(t ype) == 1 (0 vs. 1) Unknown layer type
- LLM-2022:BLOOM【参数量:1760亿(176B)】【用于训练的token数量:341B】
- GNN-图卷积模型-直推式&归纳式-2017:GAT【消息传递(前向传播):聚合函数+更新函数】【聚合函数:attention(邻域所有节点根据注意力机制进行加权)】【训练更新函数的参数】【同质图】
- 语音合成:Tacotron详解【端到端语音合成模型】【与传统语音合成相比,它没有复杂的语音学和声学特征模块,而是仅用<文本序列,语音声谱>配对数据集对神经网络进行训练,因此简化了很多流程】
- Audio-预训练模型-2020:Wav2vec 2.0
- 知识图谱-KGE-模型-归纳式(Inductive)-2022:MorsE【传统直推式的KGE方法只能对训练阶段已经见过的实体进行预测和应用】【归纳式模型可用于训练阶段未见过的实体】
- AI-多模态-2021:FILIP【一种基于交互的细粒度图文预训练模型】
- CV-CNN-2014:VGG模型【重复堆叠3x3卷积增加网络深度】【设计思想:更深的网络有助于性能的提升;更深的网络不好训练,容易过拟合,所以采用小卷积核】【11层、13层、16层、19层】
- 28 天自制你的 AlphaGo(二):训练策略网络,真正与之对弈
- 训练好的深度学习模型,多种部署方式
- 【源码】tensorboard将MNIST识别训练过程可视化
- A.4.【数据标注】基于Label studio的训练数据标注指南:文本分类任务
- IBM研究人员训练Watson识别技术 可防治青光眼疾病
- 4. 使用预训练的PyTorch网络进行图像分类
- 敏捷程序员如何训练大脑
- 第十四届蓝桥杯三月真题刷题训练——第 20 天
- Keras多GPU训练指南
- Hugging Face中的Accelerate:让训练速度飞起来