VainF / Torch-Pruning

[CVPR 2023] Towards Any Structural Pruning; LLMs / SAM / Diffusion / Transformers / YOLOv8 / CNNs
https://arxiv.org/abs/2301.12900
MIT License
2.44k stars 309 forks source link

无法进行剪枝 #45

Open jxncyym opened 2 years ago

jxncyym commented 2 years ago

when I pruner https://github.com/chenjun2hao/DDRNet.pytorch I meet the error

` def prune_model(model): model.cpu() DG = tp.DependencyGraph().build_dependency(model, torch.randn((1,3,1024,2048))) def prune_conv(conv, amount=0.2): strategy = tp.strategy.L1Strategy() pruning_index = strategy(conv.weight, amount=amount) print(pruning_index)

weight = conv.weight.detach().cpu().numpy()

      # out_channels = weight.shape[0]
      # L1_norm = np.sum( np.abs(weight), axis=(1,2,3))
      # num_pruned = int(out_channels * amount)
      # pruning_index = np.argsort(L1_norm)[:num_pruned].tolist() # remove filters with small L1-Norm
      plan = DG.get_pruning_plan(conv, tp.prune_conv, pruning_index)
      plan.exec()

prunable_modules = [ m for m in model.modules() if isinstance(m, nn.Conv2d) ]
for layer_to_prune in prunable_modules:
    print(layer_to_prune)
    prune_conv(layer_to_prune, 0.5)

return model

`

=> loading final_layer.bn1.num_batches_tracked from pretrained model => loading final_layer.conv1.weight from pretrained model => loading final_layer.bn2.weight from pretrained model => loading final_layer.bn2.bias from pretrained model => loading final_layer.bn2.running_mean from pretrained model => loading final_layer.bn2.running_var from pretrained model => loading final_layer.bn2.num_batches_tracked from pretrained model => loading final_layer.conv2.weight from pretrained model => loading final_layer.conv2.bias from pretrained model

Number of Parameters before pruner: 5.7M torch.Size([1, 3, 128, 256]) Traceback (most recent call last): File "./tools/pruner_new.py", line 142, in main() File "./tools/pruner_new.py", line 134, in main prune_model(model) File "./tools/pruner_new.py", line 84, in prune_model prune_conv(layer_to_prune, 0.8) File "./tools/pruner_new.py", line 63, in prune_conv plan = DG.get_pruning_plan(conv, tp.prune_conv, pruning_index) File "/algdata02/yiming.yu/DDRNet.pytorch_pruner/envp_20210903/lib/python3.7/site-packages/torch_pruning/dependency.py", line 378, in get_pruning_plan root_node = self.module_to_node[module] KeyError: Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)

VainF commented 2 years ago

您好,请确认一下这个layer在forward过程中执行过计算,否则它不会被注册进DependencyGraph

jxncyym commented 2 years ago

@VainF 您好,您可以参考下这个issue: https://github.com/microsoft/nni/issues/4160 ,或者该github的issue里面搜索“assert len(set(num_channels_list)) == 1 ” 也许您需要修改下您的代码,代码修改好,麻烦通知下我,谢谢!!

jamiechoi1995 commented 2 years ago

您好,请确认一下这个layer在forward过程中执行过计算,否则它不会被注册进DependencyGraph

我测试了yolov5x6模型,只有最后一层卷积层才被注册进了DependencyGraph,感觉不对啊

Willforcv commented 2 years ago

您好,请确认一下这个layer在forward过程中执行过计算,否则它不会被注册进DependencyGraph

我测试了yolov5x6模型,只有最后一层卷积层才被注册进了DependencyGraph,感觉不对啊

您好, 请问您剪枝yolov5的模型成功了没?

jamiechoi1995 commented 2 years ago

您好,请确认一下这个layer在forward过程中执行过计算,否则它不会被注册进DependencyGraph

我测试了yolov5x6模型,只有最后一层卷积层才被注册进了DependencyGraph,感觉不对啊

您好, 请问您剪枝yolov5的模型成功了没?

不成功

haodehao commented 2 years ago

我的yolov5成功了,你们出现的问题主要原因是out的grad_fn找不到,无法构建前后联系导致的剪枝失败,具体源码里的dependency.py 的506行

haodehao commented 2 years ago
# 1、结果获取不到grad_fn
# model = attempt_load(opt.weights, map_location='cpu').float().to(device)
# 2、结构获取不到grad_fn
# model = torch.load(opt.weights, map_location='cpu')['model'].float().eval().to(device)

# 3、可以获取out的grad_fn  
ckpt = torch.load(opt.weights, map_location=device)
model = Model('./models/yolov5s.yaml', ch=3, nc=1).to(device)
state_dict = ckpt['model'].float().state_dict()
state_dict = intersect_dicts(state_dict, model.state_dict(), exclude=[])
model.load_state_dict(state_dict, strict=False)
lrh454830526 commented 2 years ago

求教下大哥有没有完整的关于yolov5 剪枝的代码 或者可以参考的内容

lrh454830526 commented 2 years ago
# 1、结果获取不到grad_fn
# model = attempt_load(opt.weights, map_location='cpu').float().to(device)
# 2、结构获取不到grad_fn
# model = torch.load(opt.weights, map_location='cpu')['model'].float().eval().to(device)

# 3、可以获取out的grad_fn  
ckpt = torch.load(opt.weights, map_location=device)
model = Model('./models/yolov5s.yaml', ch=3, nc=1).to(device)
state_dict = ckpt['model'].float().state_dict()
state_dict = intersect_dicts(state_dict, model.state_dict(), exclude=[])
model.load_state_dict(state_dict, strict=False)

我现在的事情 需要把yolov5 进行剪枝 但是这个框架给的example 都是针对分类的 求教下大佬有没有使用此框架 对yolov5剪枝的详细代码

VainF commented 1 year ago

我的yolov5成功了,你们出现的问题主要原因是out的grad_fn找不到,无法构建前后联系导致的剪枝失败,具体源码里的dependency.py 的506行

您好,我现在导入的是torchvision定义好的模型,同样遇到了KeyError的问题。能否具体说说grad_fn需要怎么设置呢?

现在有一个问题,Pytorch的各种Module Hook不会记录**kwargs形式传入的参数,也就追踪不到对应的模块了。可能就是这个原因导致一部分module没有被注册进DepGraph。不过Yolo这类模型github上很多实现没有使用字典传参,应该是可以剪枝的。

[文档](https://pytorch.org/docs/stable/generated/torch.nn.modules.module.register_module_forward_hook.html#:~:text=The%20input%20contains%20only%20the%20positional%20arguments%20given%20to%20the%20module.%20Keyword%20arguments%20won%E2%80%99t%20be%20passed%20to%20the%20hooks%20and%20only%20to%20the%20forward.%20The%20hook%20can%20modify%20the%20output.%20It%20can%20modify%20the%20input%20inplace%20but%20it%20will%20not%20have%20effect%20on%20forward%20since%20this%20is%20called%20after%20forward()%20is%20called.)

The input contains only the positional arguments given to the module. Keyword arguments won’t be passed to the hooks and only to the forward. The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called after forward() is called.

YihaoChan commented 1 year ago

我的yolov5成功了,你们出现的问题主要原因是out的grad_fn找不到,无法构建前后联系导致的剪枝失败,具体源码里的dependency.py 的506行

您好,我现在导入的是torchvision定义好的模型,同样遇到了KeyError的问题。能否具体说说grad_fn需要怎么设置呢?

现在有一个问题,Pytorch的各种Module Hook不会记录**kwargs形式传入的参数,也就追踪不到对应的模块了。可能就是这个原因导致一部分module没有被注册进DepGraph。不过Yolo这类模型github上很多实现没有使用字典传参,应该是可以剪枝的。

[文档](https://pytorch.org/docs/stable/generated/torch.nn.modules.module.register_module_forward_hook.html#:~:text=The%20input%20contains%20only%20the%20positional%20arguments%20given%20to%20the%20module.%20Keyword%20arguments%20won%E2%80%99t%20be%20passed%20to%20the%20hooks%20and%20only%20to%20the%20forward.%20The%20hook%20can%20modify%20the%20output.%20It%20can%20modify%20the%20input%20inplace%20but%20it%20will%20not%20have%20effect%20on%20forward%20since%20this%20is%20called%20after%20forward()%20is%20called.)

The input contains only the positional arguments given to the module. Keyword arguments won’t be passed to the hooks and only to the forward. The hook can modify the output. It can modify the input inplace but it will not have effect on forward since this is called after forward() is called.

您居然28分钟前回复...差点看错了哈哈哈。我在https://github.com/VainF/Torch-Pruning/issues/80 上看到了类似的情况,然后我把模型里面的module都单独设置了require_grad = True,基本上解决了。不过剪枝torchvision里的detection模型时,有时候剪枝一个block里的第一个conv层后始终会报KeyError的错,而其它层不会,这个可能还需要再研究研究。

EveningLin commented 1 year ago

@VainF @haodehao @lrh454830526 @Willforcv 大哥们求教一下你们是边训练边剪枝还是训练完进行剪枝的呢?

VainF commented 1 year ago

@VainF @haodehao @lrh454830526 @Willforcv 大哥们求教一下你们是边训练边剪枝还是训练完进行剪枝的呢?

其实都行,迭代式的比较费时间,精度更高一点。没时间细致调参的情况下建议直接训练完剪枝+Finetuning。

EveningLin commented 1 year ago

@VainF 那在这种情况下的Finetuning,有没有什么训练上的细节要注意的?

VainF commented 1 year ago

@VainF 那在这种情况下的Finetuning,有没有什么训练上的细节要注意的?

最简单的处理是降低初始学习率,一般可以用训练阶段学习率*0.1来finetune模型。另外fintuning的迭代次数可以设的比较小,比如1/2,1/4甚至1/10,不过这取决于问题的复杂度。其他配置基本和训练一致就可以了。

EveningLin commented 1 year ago

还有一个问题就是我现在在剪枝的shufflenetv2是否需要像resnet一样在concat跳过剪枝呢?因为我在网上很少看见有这种轻量化骨架,很抱歉还要再次请教你

---原始邮件--- 发件人: "Gongfan @.> 发送时间: 2023年2月1日(周三) 凌晨1:50 收件人: @.>; 抄送: @.**@.>; 主题: Re: [VainF/Torch-Pruning] 无法进行剪枝 (#45)

@VainF 那在这种情况下的Finetuning,有没有什么训练上的细节要注意的?

最简单的处理是降低初始学习率,一般可以用训练阶段学习率*0.1来finetune模型。另外fintuning的迭代次数可以设的比较小,比如1/2,1/4甚至1/10,不过这取决于问题的复杂度。其他配置基本和训练一致就可以了。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

VainF commented 1 year ago

还有一个问题就是我现在在剪枝的shufflenetv2是否需要像resnet一样在concat跳过剪枝呢?因为我在网上很少看见有这种轻量化骨架,很抱歉还要再次请教你 ---原始邮件--- 发件人: "Gongfan @.> 发送时间: 2023年2月1日(周三) 凌晨1:50 收件人: @.>; 抄送: @.**@.>; 主题: Re: [VainF/Torch-Pruning] 无法进行剪枝 (#45) @VainF 那在这种情况下的Finetuning,有没有什么训练上的细节要注意的? 最简单的处理是降低初始学习率,一般可以用训练阶段学习率*0.1来finetune模型。另外fintuning的迭代次数可以设的比较小,比如1/2,1/4甚至1/10,不过这取决于问题的复杂度。其他配置基本和训练一致就可以了。 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

不需要,Torch-pruning可以自动解决concat、skip这类操作导致的多个层同时剪枝的问题,不过Torch-pruning还不能直接用来剪ShuffleNet,因为Pytorch官方给的实现包含这样一个操作:

def channel_shuffle(x: Tensor, groups: int) -> Tensor:
    batchsize, num_channels, height, width = x.size()
    channels_per_group = num_channels // groups

    # reshape
    x = x.view(batchsize, groups, channels_per_group, height, width)

    x = torch.transpose(x, 1, 2).contiguous()

    # flatten
    x = x.view(batchsize, -1, height, width)

    return x

这个操作不是用nn.Module封装的所以没法自动追踪到里面通道数量的变化。所以这个模型应该没法像example里的resnet那样傻瓜式剪枝了。

EveningLin commented 1 year ago

还有一个问题就是我现在在剪枝的shufflenetv2是否需要像resnet一样在concat跳过剪枝呢?因为我在网上很少看见有这种轻量化骨架,很抱歉还要再次请教你 ---原始邮件--- 发件人: "Gongfan @.**> 发送时间: 2023年2月1日(周三) 凌晨1:50 收件人: @.**>; 抄送: @.**@.**>; 主题: Re: [VainF/Torch-Pruning] 无法进行剪枝 (#45) @VainF 那在这种情况下的Finetuning,有没有什么训练上的细节要注意的? 最简单的处理是降低初始学习率,一般可以用训练阶段学习率0.1来finetune模型。另外fintuning的迭代次数可以设的比较小,比如1/2,1/4甚至1/10,不过这取决于问题的复杂度。其他配置基本和训练一致就可以了。 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.**>

不需要,Torch-pruning可以自动解决concat、skip这类操作导致的多个层同时剪枝的问题,不过Torch-pruning还不能直接用来剪ShuffleNet,因为Pytorch官方给的实现包含这样一个操作:

def channel_shuffle(x: Tensor, groups: int) -> Tensor:
    batchsize, num_channels, height, width = x.size()
    channels_per_group = num_channels // groups

    # reshape
    x = x.view(batchsize, groups, channels_per_group, height, width)

    x = torch.transpose(x, 1, 2).contiguous()

    # flatten
    x = x.view(batchsize, -1, height, width)

    return x

这个操作不是用nn.Module封装的所以没法自动追踪到里面通道数量的变化。所以这个模型应该没法像example里的resnet那样傻瓜式剪枝了。

非常感谢你!那我是不是只能通过底层的函数去实现呢?这样对我来说可能算得上是一个大挑战了哈哈哈哈!

VainF commented 1 year ago

@EveningLin, 也可以试试把包含这个操作的Module传给pruner的 ignored_layers 这个参数,这样TP就不会去剪这部分了。然后手动处理这些特殊层。我还没想到什么好办法处理这种网络,比较头疼。如果可以的话甚至可以换个其他轻量模型。

EveningLin commented 1 year ago

@VainF 我现在还是想尝试手动剪枝一下ShuffleNet,想请教一下如果是通过监督bn的y来实现稀疏化训练的话,对于ShuffleNet中的pw和dw卷积怎么样才是最有效的剪枝方式呢?亦或者是有残差的部分完全不进行剪枝操作?

VainF commented 1 year ago

@VainF 我现在还是想尝试手动剪枝一下ShuffleNet,想请教一下如果是通过监督bn的y来实现稀疏化训练的话,对于ShuffleNet中的pw和dw卷积怎么样才是最有效的剪枝方式呢?亦或者是有残差的部分完全不进行剪枝操作?

抱歉前几天忙回复迟了,pw和dw卷积我没有研究过怎么样最有效,按常规卷积处理就行。残差部分还是需要剪枝一下,毕竟模型里有很多残差。

Flyingpige commented 3 months ago

@VainF 我现在还是想尝试手动剪枝一下ShuffleNet,想请教一下如果是通过监督bn的y来实现稀疏化训练的话,对于ShuffleNet中的pw和dw卷积怎么样才是最有效的剪枝方式呢?亦或者是有残差的部分完全不进行剪枝操作?

请问您针对shufflenetv2剪枝成功了吗?我也想对shufflenetv2进行剪枝,目前也是无从下手o(╥﹏╥)o

study-clever commented 3 weeks ago

@VainF 我现在还是想尝试手动剪枝一下ShuffleNet,想请教一下如果是通过监督bn的y来实现稀疏化训练的话,对于ShuffleNet中的pw和dw卷积怎么样才是最有效的剪枝方式呢?亦或者是有残差的部分完全不进行剪枝操作?

请问您针对shufflenetv2剪枝成功了吗?我也想对shufflenetv2进行剪枝,目前也是无从下手o(╥_╥)o

请问您对ShuffleNetV2剪枝成功了吗?我也是不知如何对ShuffleNetV2进行剪枝