剪枝算法&pytorch理解

volatile

volatile=True是Variable的另一个重要的标识,它能够将所有依赖它的节点全部设为volatile=True,其优先级比requires_grad=True高。因而volatile=True的节点不会求导,即使requires_grad=True,也不会进行反向传播,对于不需要反向传播的情景(inference,测试推断),该参数可以实现一定速度的提升,并节省一半的显存,因为其不需要保存梯度,但是该方法在pytorch0.4之后被移除了,用with torch.no_grad()替代

PyTorch反向传播时默认只保存叶子结点的梯度,非叶子节点的梯度不被保存,这样设计是为了节省内存,如果你想查看中间变量的梯度的话,使用register_hook
parma.requires_grid = False是冻结参数,即使发生新的训练也不会进行参数的更新。
[https://blog.csdn.net/Sugar_girl/article/details/80050690]

理想情况下,最好的剪枝方法用暴力方法 (Brute Force) 实现的逻辑是,对所有的卷积层逐一地剪枝并观察剪枝后的结果对训练数据集上代价函数的变化。

Oracle Purning(Oracle 剪枝)

它能够取得最佳排序结果使得模型的代价函数变化最小。即通过将每一个weight单独的剔除后看模型损失函数的衰减,将衰减最少的参数认为是不重要的参数,可以剔除,这也是OBD的思路,但是OBD的方法需要求二阶导数,实现起来难度较大。

论文《Pruning Convolutional Neural Networks for Resource Efficient Inference》

  • 文中用的是代价函数损失的绝对值,而不是单纯的差值。使用代价函数损失的绝对值作为优化目标,可以保证被剪枝的模型在性能上不会损失过多。
  • 对卷积单元h的排序指标为abs(C(W, D, h = 0) - C(W, D))。将卷积单元置为0,计算与原先的损失值的绝对值

taylor泰勒级数排序

L1,L2损失函数(L1-norm loss function和L2-norm loss function)

  • L1:最小化绝对误差(Least Abosulote Error)
  • L2:最小化平方误差(Least Square Error)
    [https://blog.csdn.net/weixin_43216017/article/details/88017122]

读代码

if isinstance(module, torch.nn.modules.conv.Conv2d):
  x.register_hook(self.compute_rank)
  self.activations.append(x)
  self.activation_to_layer[activation_index] = layer
  activation_index += 1
  • 遍历模型的features层,如果该层为卷积层,则register_hook,register_hook接受的是一个函数,即类中的 compute_rank()
x = x.view(x.size(0), -1)  
  • 这句话的出现就是为了将前面多维度的tensor展平成一维
 x = module(x)
  • 输出 = module(输入),将输入计算成输出,一层一层往下传递

遇到的问题

  • ForkingPickler(file, protocol).dump(obj) BrokenPipeError: [Errno 32] Broken pipe
    • 多进程错误 这个错误当子进程过早结束时会发生。你的代码可能存在一些问题,可以将 DataLoader 的 num_worker 设置为0来进行调试
    • 将num_workers=0,设置为0,0表示不使用多进程

  • 详细讲解
    • https://www.cnblogs.com/wildkid1024/p/11129217.html
    • 对比了三篇论文,详细讲了第三篇《Pruning Convolutional Neural Networks for Resource Efficient Inference》 https://blog.csdn.net/jacke121/article/details/79450321
    • 交叉熵 Cross Entropy Loss https://blog.csdn.net/xg123321123/article/details/80781611

import numpy as np
#定义L1损失函数
def L1_loss(y_true,y_pre): 
    return np.sum(np.abs(y_true-y_pre))
#定义L2损失函数
def L2_loss(y_true,y_pre):
    return np.sum(np.square(y_true-y_pre))

#假设我们得到了真实值和预测值
y_true = np.array([1,2,3,4,5,6,7,8,9])
y_pre  = np.array([1.2,2.3,3.5,4.3,4.6,5.6,6.1,7.1,8.8])

#定义函数
print('L1 loss is {}'.format(L1_loss(y_true,y_pre)))
"""L1 loss is 4.1000000000000005"""
print('L2 loss is {}'.format(L2_loss(y_true,y_pre)))
"""L2 loss is 2.450000000000001"""
#https://blog.csdn.net/weixin_43216017/article/details/88017122