目标检测YOLOv5 -模型压缩flyfish
1剪枝YOLOv5附带的模型压缩是什么样的? 就是剪树枝。
在一棵树里,剪不重要的树枝是剪树枝
园丁的技术不同,不同的园丁剪的效果也不同。
剪模型的树枝和园丁的工作一模一样。 我们先来看看回归实例
拟合数据的结果有适当、不适当、过度的拟合
直线是欠拟合的,每个数据点通过的曲线是过拟合的
从他们的公式来看,多项式的最高阶不同,剪枝就像去除了上图中的3次方项和4次方项一样
剪枝的方法很多,去除不重要的东西,所以在定义什么不重要,各家都有各家的方法
如果项目剪得太多,曲线就会变成值线。 这不是我们想要的。
拟合的时候,如果剪得太多而没有剩下几根树枝的话,就会变得拟合不足; 如果已经合适的话,剪了也不合适。
希望精度和再现率都不降低,降低的只有计算量
剪枝的生物学启示
深度学习剪枝被认为是人脑中突触剪枝的一种方式,是人脑中突触的消除。 突触的修剪从出生时开始,持续到20多岁左右。
浏览神经网络
连接圈和圈的线是权重,权重是山的数量
剪切节点称为pruning node或pruning neurons剪切神经元
剪线称为pruning connections或pruning synapses可以剪突触,剪权重
剪切的结果
左图为原始权重矩阵,右图为阈值0.1的修整后的矩阵。 突出显示的权重将被删除或为零。
微信剪枝的实现如何实现
原始矩阵* weight_mask=新矩阵
现在我知道代码的weight_mask和bias_mask是什么意思了
彩票假说:寻找稀疏可训练的神经网络
彩票假设简单来说,主要是随机初始化的密集神经网络包括初始化的子网,通过随机初始化权重的子网可以达到原始网络的精度。
剪枝分为unstructured和structured,区别是什么
非结构化(左)和结构化(右)剪枝差异:结构化剪枝去除了卷积滤波器和内核行,而不仅仅是剪枝连接。
结构化剪枝与非结构化剪枝的主要区别在于剪枝权重的粒度。
非结构化剪枝主要修剪各个权重
结构化剪枝粒度大,主要去除整行列的权重,即去除一个神经元,截断通道维和过滤器维。
反过来说,由于裁剪各个权重的结果是unstructured,所以看起来有点混乱。 对channel和Filter进行裁剪的结果是structured,根据裁剪后是否保留了structe来命名
YOLOv5剪枝是如何操作的YOLOv5提供的剪枝代码?
defsparsity(model ) : # returnglobalmodelsparsitya,b=0.0.forpinmodel.parameters (: a=p.numel ) b=amount=0.3 ) : # prunemodeltorequestedglobalsparsityimporttorch.nn.utils.pruneaspruneprint (pruning model.' ), min model.named _ modules (: if isinstance ) m,nn.Conv2d ) : prune.l1_unstructured(m ) m, name='weight' 'weight ' ) # makepermanentprint (' %.3 gglobalsparsity ' % sparsi ty ) model )使用YOLOv5的剪枝代码
对于函数prune.l1_unstructured的amount参数,表示要修剪(删除)的参数数(int或float )。 对于浮动,必须在0.0到1.0之间指示要修剪的参数的百分比。 对于int类型,表示要删除的参数的绝对数量。
importtorchfromtorchimportnimporttorch.nn.utils.pruneaspruneimporttorch.nn.functionalasfdevice=torch.device ' bbbb
model sparsity a, b = 0., 0. for p in model.parameters(): a += p.numel() b += (p == 0).sum() return b / adef prune(model, amount=0.3): # Prune model to requested global sparsity import torch.nn.utils.prune as prune print('Pruning model... ', end='') for name, m in model.named_modules(): if isinstance(m, nn.Conv2d): prune.l1_unstructured(m, name='weight', amount=amount) # prune prune.remove(m, 'weight') # make permanent print(' %.3g global sparsity' % sparsity(model))class LeNet(nn.Module): def __init__(self): super(LeNet, self).__init__() # 1 input image channel, 6 output channels, 3x3 square conv kernel self.conv1 = nn.Conv2d(1, 6, 3) self.conv2 = nn.Conv2d(6, 16, 3) self.fc1 = nn.Linear(16 * 5 * 5, 120) # 5x5 image dimension self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) x = F.max_pool2d(F.relu(self.conv2(x)), 2) x = x.view(-1, int(x.nelement() / x.shape[0])) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return xmodel = LeNet().to(device=device)module = model.conv1print(list(module.named_parameters()))prune(module, amount=0.3)print(list(module.named_parameters()))剪枝前
[('weight', Parameter containing:tensor([[[[-0.2032, -0.0269, -0.0981], [-0.1920, -0.2737, 0.2451], [ 0.1116, 0.1331, 0.0147]]],... [[[ 0.3109, 0.0082, -0.0080], [-0.3009, -0.0805, -0.0308], [-0.0347, -0.2851, 0.1614]]]], device='cuda:0', requires_grad=True)), ('bias', Parameter containing:tensor([-0.0874, 0.2916, 0.2522, 0.2425, -0.2085, 0.2855], device='cuda:0', requires_grad=True))]剪枝后
Pruning model... 0.267 global sparsity[('bias', Parameter containing:tensor([-0.0874, 0.2916, 0.2522, 0.2425, -0.2085, 0.2855], device='cuda:0', requires_grad=True)), ('weight', Parameter containing:tensor([[[[-0.2032, -0.0000, -0.0981], [-0.1920, -0.2737, 0.2451], [ 0.1116, 0.1331, 0.0000]]],... [[[ 0.3109, 0.0000, -0.0000], [-0.3009, -0.0805, -0.0000], [-0.0000, -0.2851, 0.1614]]]], device='cuda:0', requires_grad=True))]我们看到不重要的权重变成了0