当前位置: 首页 > news >正文

新泰市建设局网站网站源码44444kt

新泰市建设局网站,网站源码44444kt,济南免费网站制作,建网站服务器怎么选择一、背景#xff1a;为什么需要模型剪枝#xff1f; 随着深度学习的发展#xff0c;模型参数量和计算量呈指数级增长。以ResNet18为例#xff0c;其在ImageNet上的参数量约为1100万#xff0c;虽然在服务器端运行流畅#xff0c;但在移动端或嵌入式设备上部署时#xf…一、背景为什么需要模型剪枝 随着深度学习的发展模型参数量和计算量呈指数级增长。以ResNet18为例其在ImageNet上的参数量约为1100万虽然在服务器端运行流畅但在移动端或嵌入式设备上部署时内存和计算资源的限制使得直接使用大模型变得困难。模型剪枝Model Pruning作为模型压缩的核心技术之一通过删除冗余的神经元或通道在保持模型性能的前提下显著降低模型大小和计算量是解决这一问题的关键手段。 在前面一篇文章我们也提到了模型压缩的一些基本定义和核心原理《深度学习之模型压缩三驾马车模型剪枝、模型量化、知识蒸馏》。 本文将基于PyTorch框架以ResNet18在CIFAR-10数据集上的分类任务为例详细讲解结构化通道剪枝的完整实现流程包括模型训练、剪枝策略、剪枝后结构调整、微调及效果评估。 二、整体流程概览 本文代码的核心流程可总结为以下6步 环境初始化与数据集加载原始模型训练与评估卷积层结构化剪枝以conv1层为例剪枝后模型结构调整BN层、残差下采样层等剪枝模型微调剪枝前后模型效果对比 特地说明在这里选择conv1层作为例子不是因为选择这个就会效果更好。 三、关键步骤代码解析 3.1 环境初始化与数据集准备 首先需要配置计算设备GPU/CPU并加载CIFAR-10数据集。CIFAR-10包含10类32x32的彩色图像训练集5万张测试集1万张。 def setup_device():return torch.device(cuda if torch.cuda.is_available() else cpu)def load_dataset():transform transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,)) # 归一化到[-1,1]])train_dataset datasets.CIFAR10(root./data, trainTrue, transformtransform, downloadTrue)test_dataset datasets.CIFAR10(root./data, trainFalse, transformtransform, downloadTrue)return train_dataset, test_dataset3.2 原始模型训练 使用预训练的ResNet18模型修改全连接层输出为10类匹配CIFAR-10的类别数并进行5轮训练 def create_model(device):model models.resnet18(pretrainedTrue) # 加载ImageNet预训练权重model.fc nn.Linear(512, 10) # 修改输出层为10类return model.to(device)def train_model(model, train_loader, criterion, optimizer, device, epochs3):model.train()for epoch in range(epochs):running_loss 0.0for images, labels in tqdm(train_loader):images, labels images.to(device), labels.to(device)optimizer.zero_grad()outputs model(images)loss criterion(outputs, labels)loss.backward()optimizer.step()running_loss loss.item()print(fEpoch {epoch1}, Loss: {running_loss/len(train_loader):.4f})return model3.3 结构化通道剪枝核心实现 本文重点是对卷积层进行结构化剪枝按通道剪枝具体步骤如下 3.3.1 计算通道重要性 通过计算卷积核的L2范数评估通道重要性。假设卷积层权重维度为[out_channels, in_channels, kernel_h, kernel_w]将每个输出通道的权重展平为一维向量计算其L2范数范数越小表示该通道对模型性能贡献越低越应被剪枝。 layer dict(model.named_modules())[layer_name] # 获取目标卷积层 weight layer.weight.data channel_norm torch.norm(weight.view(weight.shape[0], -1), p2, dim1) # 计算每个输出通道的L2范数3.3.2 生成剪枝掩码 根据剪枝比例如20%选择范数最小的通道生成掩码 num_channels weight.shape[0] # 原始输出通道数如ResNet18的conv1层为64 num_prune int(num_channels * amount) # 需剪枝的通道数如64*0.212 _, indices torch.topk(channel_norm, knum_prune, largestFalse) # 找到最不重要的12个通道mask torch.ones(num_channels, dtypetorch.bool) mask[indices] False # 掩码保留的通道标记为True52个剪枝的标记为False12个3.3.3 替换卷积层 创建新的卷积层仅保留掩码为True的通道 new_conv nn.Conv2d(in_channelslayer.in_channels,out_channelsnum_channels - num_prune, # 剪枝后输出通道数52kernel_sizelayer.kernel_size,stridelayer.stride,paddinglayer.padding,biaslayer.bias is not None ).to(device) # 移动到模型所在设备new_conv.weight.data layer.weight.data[mask] # 保留掩码为True的通道权重 if layer.bias is not None:new_conv.bias.data layer.bias.data[mask] # 偏置同理3.3.4 关键剪枝后结构调整 直接剪枝会导致后续层如BN层、残差连接中的下采样层的输入/输出通道不匹配必须同步调整 (1) 调整BN层 卷积层后通常接BN层BN的num_features需与卷积输出通道数一致 if conv1 in layer_name:bn1 model.bn1new_bn1 nn.BatchNorm2d(new_conv.out_channels).to(device) # 新BN层通道数52with torch.no_grad():# 同步原始BN层的参数仅保留未被剪枝的通道new_bn1.weight.data bn1.weight.data[mask].clone()new_bn1.bias.data bn1.bias.data[mask].clone()new_bn1.running_mean.data bn1.running_mean.data[mask].clone()new_bn1.running_var.data bn1.running_var.data[mask].clone()model.bn1 new_bn1(2) 调整残差下采样层 ResNet的残差块如layer1.0中若主路径的通道数被剪枝需要通过1x1卷积的下采样层downsample匹配 shortcut 的通道数 block model.layer1[0] if not hasattr(block, downsample) or block.downsample is None:# 原始无downsample创建新的1x1卷积BNdownsample_conv nn.Conv2d(in_channelsnew_conv.out_channels, # 52剪枝后的conv1输出out_channelsblock.conv2.out_channels, # 64主路径conv2的输出kernel_size1,stride1,biasFalse).to(device)torch.nn.init.kaiming_normal_(downsample_conv.weight, modefan_out, nonlinearityrelu) # 初始化权重downsample_bn nn.BatchNorm2d(downsample_conv.out_channels).to(device)block.downsample nn.Sequential(downsample_conv, downsample_bn) # 添加downsample层 else:# 原有downsample层调整输入通道downsample_conv block.downsample[0]downsample_conv.in_channels new_conv.out_channels # 输入通道改为52downsample_conv.weight nn.Parameter(downsample_conv.weight.data[:, mask, :, :].clone()) # 输入通道用掩码筛选(3) 前向传播验证 调整后需验证模型能否正常前向传播避免通道不匹配导致的错误 with torch.no_grad():test_input torch.randn(1, 3, 32, 32).to(device) # 测试输入B, C, H, Wtry:model(test_input)print(✅ 前向传播验证通过)except Exception as e:print(f❌ 验证失败: {str(e)})raise3.3的总结直接上代码 def prune_conv_layer(model, layer_name, amount0.2):# 获取模型当前所在设备device next(model.parameters()).device # 新增获取设备layer dict(model.named_modules())[layer_name]weight layer.weight.datachannel_norm torch.norm(weight.view(weight.shape[0], -1), p2, dim1)num_channels weight.shape[0] # 原始通道数如 64num_prune int(num_channels * amount)_, indices torch.topk(channel_norm, knum_prune, largestFalse)mask torch.ones(num_channels, dtypetorch.bool)mask[indices] False # 生成剪枝掩码长度 6452 个 Truenew_conv nn.Conv2d(in_channelslayer.in_channels,out_channelsnum_channels - num_prune, # 剪枝后通道数如 52kernel_sizelayer.kernel_size,stridelayer.stride,paddinglayer.padding,biaslayer.bias is not None)new_conv new_conv.to(device) # 新增移动到模型所在设备new_conv.weight.data layer.weight.data[mask] # 保留 mask 为 True 的通道if layer.bias is not None:new_conv.bias.data layer.bias.data[mask]# 替换原始卷积层parent_name, sep, name layer_name.rpartition(.)parent model.get_submodule(parent_name)setattr(parent, name, new_conv)if conv1 in layer_name:# 1. 更新与 conv1 直接关联的 BN1 层bn1 model.bn1new_bn1 nn.BatchNorm2d(new_conv.out_channels) # 新 BN 层通道数 52new_bn1 new_bn1.to(device) # 新增移动到模型所在设备with torch.no_grad():new_bn1.weight.data bn1.weight.data[mask].clone()new_bn1.bias.data bn1.bias.data[mask].clone()new_bn1.running_mean.data bn1.running_mean.data[mask].clone()new_bn1.running_var.data bn1.running_var.data[mask].clone()model.bn1 new_bn1# 2. 处理残差连接中的 downsample关键修正添加缺失的 downsampleblock model.layer1[0]if not hasattr(block, downsample) or block.downsample is None:# 原始无 downsample需创建新的 1x1 卷积BN 来匹配通道downsample_conv nn.Conv2d(in_channelsnew_conv.out_channels, # 52out_channelsblock.conv2.out_channels, # 64主路径输出通道数kernel_size1,stride1,biasFalse)downsample_conv downsample_conv.to(device) # 新增移动到模型所在设备# 初始化 1x1 卷积权重这里简单复制原模型可能的统计量实际可根据需求调整torch.nn.init.kaiming_normal_(downsample_conv.weight, modefan_out, nonlinearityrelu)downsample_bn nn.BatchNorm2d(downsample_conv.out_channels)downsample_bn downsample_bn.to(device) # 新增移动到模型所在设备with torch.no_grad():# 初始化 BN 参数可保持默认或根据原模型统计量调整downsample_bn.weight.fill_(1.0)downsample_bn.bias.zero_()downsample_bn.running_mean.zero_()downsample_bn.running_var.fill_(1.0)block.downsample nn.Sequential(downsample_conv, downsample_bn)print(✅ 为 layer1.0 添加新的 downsample 层)else:# 原有 downsample 层调整输入通道downsample_conv block.downsample[0]downsample_conv.in_channels new_conv.out_channels # 输入通道调整为 52downsample_conv.weight nn.Parameter(downsample_conv.weight.data[:, mask, :, :].clone()) # 输入通道用 mask 筛选downsample_conv downsample_conv.to(device) # 新增移动到模型所在设备downsample_bn block.downsample[1]new_downsample_bn nn.BatchNorm2d(downsample_conv.out_channels)new_downsample_bn new_downsample_bn.to(device) # 新增移动到模型所在设备with torch.no_grad():new_downsample_bn.weight.data downsample_bn.weight.data.clone()new_downsample_bn.bias.data downsample_bn.bias.data.clone()new_downsample_bn.running_mean.data downsample_bn.running_mean.data.clone()new_downsample_bn.running_var.data downsample_bn.running_var.data.clone()block.downsample[1] new_downsample_bn# 3. 同步 layer1.0.conv1 的输入通道保持原有逻辑next_convs [layer1.0.conv1]for conv_path in next_convs:try:conv model.get_submodule(conv_path)if conv.in_channels ! new_conv.out_channels:print(f同步输入通道: {conv.in_channels} → {new_conv.out_channels})conv.in_channels new_conv.out_channelsconv.weight nn.Parameter(conv.weight.data[:, mask, :, :].clone())conv conv.to(device) # 新增移动到模型所在设备except AttributeError as e:print(f⚠️ 卷积层调整失败: {conv_path} ({str(e)}))# 验证前向传播with torch.no_grad():test_input torch.randn(1, 3, 32, 32).to(device) # 确保测试输入也在相同设备try:model(test_input)print(✅ 前向传播验证通过)except Exception as e:print(f❌ 验证失败: {str(e)})raisereturn model3.4 剪枝模型微调 剪枝后模型的部分参数被删除需要通过微调恢复性能。一开始我们只是在微调时冻结了除 fc 层外的所有参数但是效果并不好当然分析原因除了动了conv1的原因conv1 是模型的第一个卷积层负责提取最基础的图像特征如边缘、纹理、颜色等。这些底层特征对后续所有层的特征提取至关重要。最重要的是裁剪后需要对裁剪的层进行微调确保参数适应新的特征维度。 微调时冻结了除 fc 层外的所有参数的代码和结果 for name, param in pruned_model.named_parameters():if fc not in name:param.requires_grad Falseoptimizer optim.Adam(pruned_model.fc.parameters(), lr0.001)print(微调剪枝后的模型)pruned_model train_model(pruned_model, train_loader, criterion, optimizer, device,epochs5)原始模型准确率: 80.07% 剪枝后模型准确率: 37.80%可以看到这个相差很大 本文选择解冻被剪枝的层如conv1、bn1及相关层如layer1.0.conv1、downsample进行参数更新 print(开始微调剪枝后的模型) for name, param in pruned_model.named_parameters():# 仅解冻与剪枝相关的层if conv1 in name or bn1 in name or layer1.0.conv1 in name or layer1.0.downsample in name or fc in name:param.requires_grad Trueelse:param.requires_grad False optimizer optim.Adam(filter(lambda p: p.requires_grad, pruned_model.parameters()), lr0.001) pruned_model train_model(pruned_model, train_loader, criterion, optimizer, device, epochs5)原始模型准确率: 78.94% 剪枝后模型准确率: 81.30%重新微调了裁剪后的层后结果有了很大改变。 四、实验结果与分析 通过代码中的evaluate_model函数评估剪枝前后的模型准确率 def evaluate_model(model, device, test_loader):model.eval()correct 0total 0with torch.no_grad():for images, labels in test_loader:images, labels images.to(device), labels.to(device)outputs model(images)_, predicted torch.max(outputs.data, 1)total labels.size(0)correct (predicted labels).sum().item()acc 100 * correct / totalreturn acc假设原始模型准确率为88.5%剪枝20%通道后模型大小降低约20%通过微调可恢复至87.2%验证了剪枝策略的有效性。 五、总结与改进方向 本文实现了基于通道L2范数的结构化剪枝重点解决了剪枝后模型结构不一致的问题如BN层、残差下采样层的调整并通过微调恢复了模型性能。 在这个例子中仅裁剪 conv1 层的影响 仅裁剪 conv1 层对模型的影响极大原因如下 底层特征的重要性 conv1 输出的是最基础的图像特征所有后续层的特征均基于此生成。裁剪 conv1 会直接限制后续所有层的特征表达能力。结构连锁反应 conv1 的输出通道减少会触发 bn1 、 layer1.0.conv1 、 downsample 等多个模块的调整任何一个模块的调整失误如通道数不匹配、参数初始化不当都会导致整体性能下降。 实际应用中可从以下方向改进 模型裁剪通常优先选择 中间层如ResNet的 layer2 、 layer3 而非底层或顶层原因如下 底层如 conv1 负责基础特征提取裁剪后特征损失大对性能影响显著。中间层如 layer2 、 layer3 特征具有一定抽象性但冗余度高同一层的多个通道可能提取相似特征裁剪后对性能影响较小。顶层如 fc 层 负责分类决策参数密度高但冗余度低裁剪易导致分类能力下降。
http://www.zqtcl.cn/news/720861/

相关文章:

  • 广东建设信息公开网站怎样策划一个营销型网站
  • 魔兽做图下载网站如何经营一个购物网站
  • 深圳做网站哪个平台好一级消防工程师考试题型
  • 网站婚礼服务态网站建设论文网站设计有限公司是干嘛的
  • 邯郸网站建设效果好广西做网站的公司
  • 网站logo上传营销型网站制作方案
  • 小说网站静态模板站长工具seo综合查询adc
  • 北京响应式网站做logo那个网站
  • 如何申请免费网站空间刚察县wap网站建设公司
  • 哪里有网站推广软件免费推广seo策略方法
  • 阿里云备案网站 网站名称怎么写京icp备案查询
  • 网站开发岗位思维导图alexa排名
  • 自适应网站建设济南济南网站建设公司
  • 巴州网站建设库尔勒网站建设钟爱网络杭州微信网站制作
  • 52做网站南京市住房城乡建设门户网站
  • 网站开发精品课程贵阳市白云区官方网站
  • seo整站优化服务会计培训班一般收费多少
  • 批量网站访问检测怎么做好手机网站开发
  • 深圳网站建设公司哪家比较好shortcodes wordpress
  • 网站内链越多越好嘛可以做3d电影网站
  • 企业网站需求文档微商引流客源最快的方法
  • 交互式网站备案业务网站在线生成
  • 自建网站百度个人网站如何在百度上做推广
  • 如何安装wordpress模板竞价网站做seo
  • 做论坛网站如何赚钱电子商务营销推广
  • 想要自己做一个网站怎么做济宁百度网站建设
  • 海会网络建设网站wordpress刷不出图片
  • 一个人做商城网站网站推广的几个阶段
  • 做国学类网站合法吗html5教程pdf下载
  • 云南省文化馆网站建设二级域名分发平台