2. 卷积核权重分布可视化与冗余分析

任务目标

分析一个已训练CNN模型中各卷积层的权重分布,通过直方图可视化识别分布集中(方差小)的层——这类层通常冗余度较高,是后续剪枝的候选对象。本案例使用PyTorch加载预训练的ResNet18,提取全部卷积层权重并绘制直方图。

环境依赖

  • Python 3.8+,PyTorch 1.9+,torchvision,matplotlib,numpy
  • 无需GPU,CPU即可完成

核心实现

import torch
import torchvision.models as models
import matplotlib.pyplot as plt
import numpy as np

# 1. 加载预训练模型并提取卷积层
model = models.resnet18(pretrained=True)
model.eval()

conv_layers = []
for name, module in model.named_modules():
    if isinstance(module, torch.nn.Conv2d):
        conv_layers.append((name, module.weight.data.numpy()))

print(f"共找到 {len(conv_layers)} 个卷积层")

# 2. 计算每层权重统计量(均值、标准差、稀疏度)
stats = []
for name, w in conv_layers:
    flat = w.flatten()
    std = float(np.std(flat))
    mean = float(np.mean(flat))
    # 稀疏度:|w| < 0.01 的权重占比
    sparse_ratio = float(np.mean(np.abs(flat) < 0.01))
    stats.append((name, mean, std, sparse_ratio))

# 3. 绘制直方图(每层一个子图)
n = len(conv_layers)
cols = 4
rows = (n + cols - 1) // cols
fig, axes = plt.subplots(rows, cols, figsize=(16, 3 * rows))
axes = axes.flatten()

for i, (name, w) in enumerate(conv_layers):
    ax = axes[i]
    flat = w.flatten()
    ax.hist(flat, bins=60, color='steelblue', alpha=0.7)
    ax.set_title(f"{name}\nstd={stats[i][2]:.4f}", fontsize=8)
    ax.set_xlim([-0.5, 0.5])
    ax.tick_params(labelsize=6)

# 隐藏多余的子图
for j in range(n, len(axes)):
    axes[j].axis('off')

plt.tight_layout()
plt.savefig("conv_weight_hist.png", dpi=150)
print("直方图已保存为 conv_weight_hist.png")

# 4. 输出冗余度排序(按标准差升序,即分布最集中的层)
print("\n=== 冗余度排序(标准差最小 = 分布最集中)===")
sorted_stats = sorted(stats, key=lambda x: x[2])
for name, mean, std, sparse in sorted_stats[:5]:
    print(f"{name:30s} mean={mean:+.4f} std={std:.4f} 稀疏度={sparse:.2%}")

运行方式

pip install torch torchvision matplotlib numpy
python weight_hist.py

验证方法与判定标准

  • 运行成功标志:终端输出卷积层数量(ResNet18为20层),并生成conv_weight_hist.png文件。
  • 可视化判读:观察直方图——若某层直方图呈尖峰状且集中在0附近(标准差小),说明该层大量权重接近0,冗余度高;若分布平坦(标准差大),则信息量相对丰富。
  • 量化判据:程序输出的排序列表中,前几层(如conv1或深层残差块中的3×3卷积)通常std最小,这些层即为剪枝优先考虑的对象。
  • 预期输出示例(基于ResNet18预训练权重的确定性统计):conv1层std约为0.05~0.07,而layer4.1.conv2等深层std约为0.01~0.03,后者冗余度更高。

常见问题

  • 首次运行需下载权重:约45MB,需联网;若网络受限,可设置model = models.resnet18(weights=None)仅观察随机初始化分布(此时各层std接近,无法体现训练后的冗余差异)。
  • 直方图横轴范围:代码固定为[-0.5, 0.5],若个别层权重超出此范围,可调整ax.set_xlim参数。