【剪枝】torch-pruning的基本使用

news2024/9/23 11:15:44

论文:DepGraph: Towards Any Structural Pruning
工程:https://github.com/VainF/Torch-Pruning
算法和库的使用介绍:CVPR 2023 | DepGraph 通用结构化剪枝

1 TP的简介

该算法介绍了DepGraph 如何建模结构化剪枝中的层依赖,实现任意结构的剪枝。对应实现的库为 torch-pruning。
本篇博客对作者的介绍做一个自己的梳理和记录。

  • Torch-Pruning的简单介绍
    Torch-Pruning(TP)是一个结构化剪枝库,与现有框架(例如torch.nn.utils.prune)最大的区别在于,TP会物理地移除参数,同时自动裁剪其他依赖层。TP是一个纯 PyTorch 项目,实现了内置的计算图的追踪(Tracing)、依赖图(DepenednecyGraph, 见论文)、剪枝器等功能,同时支持 PyTorch 1.x 和 2.0 版本。
  • 用 Torch-Pruning 剪枝的好处
    假设正在对一个卷积结构化剪枝,需要减去哪些内容,具体第几个卷积核、对应的偏置、BN中对应的维度、与其直接或间接相连的层的核的channel。我们要实现剪枝,需要对不同模型定制不同的代码实现。Torch-Pruning可让实现者跳脱出对层剪枝时最具体的操作,而关注于整体剪枝的设置。

2 TP的初尝试


2.1 初步尝试

以 ResNet-18 结构化剪枝为例,对【conv1】进行剪枝,同时处理对应的bn、紧临的卷积。

from torchvision.models import resnet18
import torch_pruning as tp
import torch

model = resnet18(pretrained=True).eval()
tp.prune_conv_out_channels(model.conv1, idxs=[0,1]) # 剪枝前两个通道
tp.prune_batchnorm_out_channels(model.bn1, idxs=[0,1]) # 尝试修复bn
tp.prune_conv_in_channels(model.layer1[0].conv1, idxs=[0,1]) # 尝试修复紧邻的conv
output = model(torch.randn(1,3,224,224)) # 尝试运行剪枝后的网络

会报错如下:问题出在残差结构上。残差的相加操作要求传入的两个tensor具有相同的空间尺寸,也就意味着剪枝后的Tensor通道数62和另一个tensor的通道数64不再匹配。
在这里插入图片描述在这里插入图片描述


2.2 使用TP对 conv1进行剪枝

手动设置DependencyGraph是Torch-Pruning框架的底层算法,设计目标就是"自动寻找耦合层",并自动化处理。
使用TP对ResNet-18的conv1进行剪枝,代码如下:

import torch
from torchvision.models import resnet18
import torch_pruning as tp

model = resnet18(pretrained=True).eval()

# 1. 构建依赖图
DG = tp.DependencyGraph()
DG.build_dependency(model, example_inputs=torch.randn(1,3,224,224))

# 2. 获取与model.conv1存在依赖的所有层,并指定需要剪枝的通道索引(此处我们剪枝第[2,6,9]个通道)
group = DG.get_pruning_group( model.conv1, tp.prune_conv_out_channels, idxs=[2, 6, 9] )
print(model, group)

# 3. 执行剪枝操作
if DG.check_pruning_group(group): # 避免将通道剪枝到0
    group.prune()
print(model, group)
output = model(torch.randn(1,3,224,224)) # 尝试运行剪枝后的网络

上述过程一共三步:

  • 1 对网络进行依赖图构建;
  • 2 选取需要剪枝的层,指定剪枝通道,获得分组group;这里的group,是所有与conv1相依赖的层。
  • 3 执行剪枝操作,按组移除通道。那剪枝过程具体操作了哪些层呢?

左图为剪枝前的conv1 的group,右图为剪枝后的conv1 的group。
怎么去看这个group呢,在下图右侧进行了简单的标注,可以发现conv1的group都会进行剪枝,从而适应conv1的卷积核的维度发生的变化
在这里插入图片描述
左图为剪枝前的resnet结构部分,右图为剪枝后的resnet结构部分。
在这里插入图片描述


2.3 使用TP对网络中每个层进行剪枝

在实际实现时,我们希望是对整个网络结构进行剪枝,而非特定的某几层,这就涉及到如何不重复地遍历网络中所有分组的问题。
DepGraph提供了接口DG.get_all_groups来实现这以目标。该接口仅实现层的分组,并不会分辨通道的重要性。该接口包含两个参数

  • ignored_layers:指定忽略 某些希望被剪枝的层。通常包括最后的分类层、以及报错的层(也可以使用其它正确的层进行替换)
  • root_module_types:指定了每个组的起始层的类型。比如想剪枝所有的卷基层,而不想剪枝全连接层,只需要只传入对应的卷积类即可。
    值得注意的是,不同层可能出现在同一分组中,Depgraph会自动去除重复分组。

下面先提前设定好需要剪枝的通道,来展示DG.get_all_groups的使用:

import torch
import torch.nn as nn
import torch_pruning as tp
from torchvision.models import resnet18

model = resnet18(pretrained=True).eval()

# 1. 构建依赖图
DG = tp.DependencyGraph()
DG.build_dependency(model, example_inputs=torch.randn(1,3,224,224))

# 2. 获取与model.conv1存在依赖的所有层,并指定需要剪枝的通道索引(此处我们剪枝第[2,6,9]个通道)
Groups = DG.get_all_groups(ignored_layers=[model.conv1], root_module_types=[nn.Conv2d, nn.Linear])

# 3. 执行剪枝操作
for group in Groups:
    idxs = [2,4,6] # your pruning indices
    group.prune(idxs=idxs)
    print(group)

output = model(torch.randn(1,3,224,224)) # 尝试运行剪枝后的网络

但该段代码剪枝,在TP实际剪枝也是较少使用,这里是展示一个剪枝底层的基本操作。

3 TP对完整网络的剪枝


3.1 常用的结构化剪枝原理

结构化和非结构化剪枝方向,已发表的有较多的论文。但在工业上较常用的为结构化剪枝。实际中最常用的结构化剪枝方法:

  • 利用权值进行filter剪枝:Pruning Filters for Efficient ConvNets
    在这张图中,我们可以找到两个卷积参数矩阵(Kernel Matrix):第一个卷积层以 x i x_i xi 作为输入,输出特征图 x i + 1 x_{i+1} xi+1;第二个卷积层以 x i + 1 x_{i+1} xi+1作为输入,生成特征图 x i + 2 x_{i+2} xi+2
    在结构化剪枝中,这两个卷基层之间存在非常直观的依赖关系,即当我们调整第一层的输出通道时,第二个卷积层的输入通道也需要相应的进行调整,这使得蓝色高亮的参数需要同时被剪枝。
    在这里插入图片描述
    此外,作者指出网络中可能存在更复杂的依赖,例如残差结构依赖:
    在这里插入图片描述
  • 利用bn进行剪枝:Learning Efficient Convolutional Networks through Network Slimming。
    在这里插入图片描述
    BN会按通道对输入特征进行归一化,使得不同的特征处于比较接近的范围内。我们将缩放因子(从批量归一化层重用)与卷积层中的每个通道相关联。稀疏正则化在训练期间被施加在这些缩放因子上,以自动识别不重要的通道。缩放因子值较小(橙色)的通道将被修剪(左侧)。修剪后,我们获得紧凑模型(右侧),然后对其进行微调,以实现与正常训练的全网络相当(甚至更高)的精度。
    在任何一个网络中,BN的scale参数都具备一定的绝对值大小(也就是不会过小),这意味着各个通道都具有不可忽略的重要性。解决这类问题的一种有效方法是使用稀疏训练,通过对scale参数施加正则化项来稀疏化一部分通道。在slimming论文中,作者对scale参数施加了一个额外的L1正则化项,从而实现了这一过程。整个流程如下所示:稀疏训练–>剪枝–>微调
    在这里插入图片描述

3.2 TP剪枝示例

网络中存在大量复杂依赖的情况下,如何进行剪枝呢?
【1】计算网络每个group中每层的重要性

  • Torch-Puning 库内置了处理依赖的功能,并提供了可扩展的接口用于自定义剪枝器。
    tp.importance.Importance 要求我们实现一个非常简单的接口 __call__
    • 入参为一个 group,包含了多个相互耦合的层。
    • 输出为一个一维的重要性的得分向量,其含义是每个通道的重要性,因此他的维度和通道数量是相同的。
      由于输入的group通常会包含多个可剪枝层,因此我们首先对这些层进行独立的重要性计算,然后通过求平均值得到最终结果。
  • Torch-Puning也提供了常用重要性评估策略:
    tp.importance.MagnitudeImportance(p=2)p=2表示使用L2正则,对每个group中的每个层的权值,独立的计算重要性 。
    tp.importance.BNScaleImportance():利用BN计算每个group中的每个层的权值的重要性
    tp.importance.GroupNormImportance():与继承于MagnitudeImportance,且没做任何的添加和修改。

【2】对网络进行剪枝

  • Torch-Pruning库定义了一个元剪枝器 tp.pruner.MetaPruner,能够完成除了重要性评估之外的所有工作。一般常在自定义的重要性评估后,执行剪枝时使用
  • Torch-Puning也提供了常用的剪枝策略
    tp.pruner.MagnitudePruner()
    tp.pruner.BNScalePruner()
    tp.pruner.GroupNormPruner() Depgraph 提出的基于全局重要性的剪枝

【3】例子
为了增加难度,这里我们对一个DenseNet模型进行剪枝。
这里只展示了稀疏训练和微调使用的位置,仅剪枝部分能够有效跑通。

import torch
import torch.nn as nn
import torch_pruning as tp
from torchvision.models import densenet121

model = densenet121(pretrained=True)
example_inputs = torch.randn(1, 3, 224, 224)

# 1. 使用我们上述定义的重要性评估
# imp = tp.importance.MagnitudeImportance(p=2)
# imp = tp.importance.BNScaleImportance()
imp = tp.importance.GroupNormImportance()

# 2. 忽略无需剪枝的层,例如最后的分类层
ignored_layers = []
for m in model.modules():
    if isinstance(m, torch.nn.Linear) and m.out_features == 1000:
        ignored_layers.append(m) # DO NOT prune the final classifier!

# 3. 初始化剪枝器
iterative_steps = 5 # 迭代式剪枝,重复5次Pruning-Finetuning的循环完成剪枝。  
# pruner = tp.pruner.MagnitudePruner(
# pruner = tp.pruner.BNScalePruner(
pruner = tp.pruner.GroupNormPruner(
    model,
    example_inputs, # 用于分析依赖的伪输入
    importance=imp, # 重要性评估指标
    iterative_steps=iterative_steps, # 迭代剪枝,设为1则一次性完成剪枝
    ch_sparsity=0.5, # 目标稀疏性,这里我们移除50%的通道 ResNet18 = {64, 128, 256, 512} => ResNet18_Half = {32, 64, 128, 256}
    ignored_layers=ignored_layers, # 忽略掉最后的分类层
)

# 4. 稀疏训练(为了节省时间我们假装在训练,实际应用时只需要在optimizer.step前插入regularize即可)
for _ in range(100):
    pass
    # optimizer.zero_grad() 
    # ...
    # loss.backward()
    # pruner.regularize(model, reg=1e-5) # <== 插入该行进行稀疏化
    # optimizer.step()
    
# 4. Pruning-Finetuning的循环
base_macs, base_nparams = tp.utils.count_ops_and_params(model, example_inputs)
for i in range(iterative_steps):
    pruner.step() # 执行裁剪,本例子中我们每次会裁剪10%,共执行5次,最终稀疏度为50%
    macs, nparams = tp.utils.count_ops_and_params(model, example_inputs)
    print("  Iter %d/%d, Params: %.2f M => %.2f M" % (i+1, iterative_steps, base_nparams / 1e6, nparams / 1e6))
    print("  Iter %d/%d, MACs: %.2f G => %.2f G"% (i+1, iterative_steps, base_macs / 1e9, macs / 1e9))
    # finetune your model here
    # finetune(model)
    # ...
print(model)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1237445.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Fiddler模拟弱网环境

1.设置弱网&#xff1a;Rules-》Customize Rules 上传速度&#xff1a;1KB/300ms1KB/0.3s3.33KB/s 下载速度&#xff1a;1KB/150ms1KB/0.15s6.67KB/s 2.启动弱网&#xff1a;Rules-》Performance-》Simulate Modem Speeds 开启后&#xff0c;此项为勾选状态 3.验证弱网生效…

Activiti7工作流引擎:生成实时的流程图片

实时获取当前流程对应的流程图片&#xff0c;并对当前正在审批的节点进行高亮显示。 public class ActivitiController {Autowiredprivate ProcessEngine processEngine;Autowiredprivate RepositoryService repositoryService;Autowiredprivate RuntimeService runtimeService…

Vellum —— 简介

目录 一&#xff0c;介绍 二&#xff0c;原理 三&#xff0c;PBD算法 一&#xff0c;介绍 Vellum是一个解算模拟框架&#xff0c;使用更高级的PBD&#xff08;XPBD&#xff0c;extended position based dynamics&#xff09;&#xff0c;是2nd Order Integration&#xff08…

振南技术干货集:制冷设备大型IoT监测项目研发纪实(4)

注解目录 1.制冷设备的监测迫在眉睫 1.1 冷食的利润贡献 1.2 冷设监测系统的困难 &#xff08;制冷设备对于便利店为何如何重要&#xff1f;了解一下你所不知道的便利店和新零售行业。关于电力线载波通信的论战。&#xff09; 2、电路设计 2.1 防护电路 2.1.1 强电防护 …

深兰科技多款大模型技术产品登上新闻联播!

11月20日晚&#xff0c;新闻联播报道了2023中国5G工业互联网大会&#xff0c;深兰科技metamind、汉境大型城市智能体空间等大模型技术和产品在众多参展产品中脱颖而出&#xff0c;被重点播报。 2023中国5G工业互联网大会 本届大会由工信部和湖北省人民政府联合主办&#xff0c;…

D-Wave推出新开源及解决无线信道解码新方案!

​&#xff08;图片来源&#xff1a;网络&#xff09; 加拿大量子计算机公司D-Wave&#xff08;纽约证券交易所股票代码&#xff1a;QBTS&#xff09;是量子计算系统、软件和服务领域的佼佼者&#xff0c;也是全球首家商业量子计算机供应商。 近期&#xff0c;该公司发布了一…

如何打造适用的MES管理系统解决方案

在当前的制造业领域&#xff0c;项目型生产企业面临着独特的挑战。尽管国外的大型软件公司提供了某些解决方案&#xff0c;但由于地域、文化和制度的差异&#xff0c;这些方案并不完全满足企业的实际需求。为了解决这一难题&#xff0c;我们必须以客户为中心&#xff0c;围绕他…

小程序Tab栏与页面滚动联动

小程序tab栏切换与页面滚动联动 tab栏与页面滚动联动点击tab栏页面跳到指定位置滚动页面时切换tab栏 tab栏与页面滚动联动 在进行小程序开发时&#xff0c;需要实现点击tab栏页面滚动到某一指定位置&#xff0c;并且滚动页面时&#xff0c;小程序的tab栏进行切换。 在一开始&a…

H1净利润同比增长超30%,这家泛家居领先品牌与纷享销客双向奔赴

增长&#xff0c;是我们永远绕不开的话题。 一方面&#xff0c;如何推动企业精细化运营与协作是行业面临的共同挑战。 另一方面&#xff0c;如何从技术、产品、营销等各个方面出发&#xff0c;以更高的效率、更优的体验为客户提供的价值也逐渐成为决定企业盈利空间的关键点。 …

redis的性能管理和雪崩

redis的性能管理 redis的数据是缓存在内存当中的 系统巡检&#xff1a; 硬件巡检、数据库、nginx、redis、docker、k8s 运维人员必须要关注的redis指标 在日常巡检中需要经常查看这些指标使用情况 info memory #查看redis使用内存的指标 used_memory:11285512 #数据占用的…

2023年中国离心制冷机产量及产业链分析[图]

离心制冷机是一种常用的空调制冷设备&#xff0c;目前主要应用于酒店、写字楼、商场、学校等众多大型场所的集中制冷场景。离心制冷机由离心式制冷压缩机、蒸发器、冷凝器、主电动机、抽气回收装置、润滑系统、控制柜和起动柜等零部件组成。这些零部件的组成有的采用分散型组装…

使用 API 管理平台的 5 大理由

组织需要治理和控制API生态系统&#xff0c;这种治理就是API管理的作用。 Uber 使用 API​​&#xff08;应用程序编程接口&#xff09;与 Google Maps 和 Twilio 等第三方服务连接&#xff0c;这有助于改善用户体验&#xff1b; Salesforce 提供 API&#xff0c;允许开发人员…

英国国家量子计算中心与IBM签署重要协议!英国进入实用量子时代

​&#xff08;图片来源&#xff1a;网络&#xff09; 近日&#xff0c;英国国家量子计算中心&#xff08;NQCC&#xff09;与IBM达成了一项重要协议。根据该协议&#xff0c;NQCC将为英国研究人员提供IBM量子高级计划的云访问权限&#xff0c;其中包括IBM的量子计算系统舰队。…

RFID电网资产全寿命周期管理解决方案

一、方案背景 随着电网公司对电网资产全寿命周期管理的要求日益明确&#xff0c;许多电网公司已经开始积极推进存量资产PMS、PM与AM数据的联动对应&#xff0c;并将联动成果纳入资产全寿命周期管理一体化平台进行指标考核。然而&#xff0c;由于资产变动导致数据质量下降的问题…

数据资产入表在即,企业可做好四项准备

2023年8月&#xff0c;财政部正式对外发布《企业数据资源相关会计处理暂行规定》&#xff0c;标志着数据资产即将入表&#xff0c;同时宣布2024年1月1日施行&#xff0c;如今已是11月下旬了&#xff0c;很多的企业纷纷感慨来不及了&#xff1a; 1.会计相关的制度、流程都没来得…

Python中使用requests库遇到的问题及解决方案

目录 一、引言 二、问题1&#xff1a;无法导入requests库 三、问题2&#xff1a;请求超时 四、问题3&#xff1a;无法处理重定向 五、问题4&#xff1a;无法处理Cookies 六、问题5&#xff1a;无法上传文件 七、问题6&#xff1a;无法处理HTTPS请求 八、问题7&#xff…

Moonbeam Network已上线原生USDC稳定币

原生USDC已经通过XCM从波卡来到了Moonbeam&#xff0c;该如何利用&#xff1f;此次集成通过把热门的Circle稳定币带来波卡生态&#xff0c;连接了区块链世界与传统金融。现在&#xff0c;用户和开发者可以在Moonbeam网络中踏寻USDC的强大之处。 Moonbeam生态中的Moonwell、FiD…

8-cgi fastcgi wsgi uwsgi uWSGI 分别是什么?如何自定制上下文管理器、Python是值传递还是引用传递

1 cgi fastcgi wsgi uwsgi uWSGI 分别是什么&#xff1f; 2 如何自定制上下文管理器 3 Python是值传递还是引用传递 1 cgi fastcgi wsgi uwsgi uWSGI 分别是什么&#xff1f; # CGI:通用网关接口&#xff08;Common Gateway Interface/CGI&#xff09;,CGI描述了服务器&#xf…

光量子计算再创融资高峰!法国 Quandela获投5000万欧元

​&#xff08;图片来源&#xff1a;网络&#xff09; 法国光量子计算公司Quandela致力于开发首台光量子计算机&#xff0c;目前已获得超过5,000万欧元的巨额融资。投资者包括通过“法国2030计划”获得的法国政府支持以及银行合作伙伴、个人。新的投资者包括法国投资公司Seren…

redis的性能管理

redis的性能管理: redis的数据缓存在内存当中 [root10 ~]# redis-cli -h 192.168.233.10 -p 6379 192.168.233.10:6379> info memory &#xff08;几个比较重要的指标&#xff09; used_memory:853592 redis中数据占用的内存 used_memory_rss:17342464 redis向操作系统…