【深度学习|学习笔记】深度学习神经网络中的权值共享 (Weight Sharing)详解。

【深度学习|学习笔记】深度学习神经网络中的权值共享 (Weight Sharing)详解。



欢迎铁子们点赞、关注、收藏!
祝大家逢考必过!逢投必中!上岸上岸上岸!upupup

大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文。详细信息可扫描博文下方二维码 “学术会议小灵通”或参考学术信息专栏:https://blog.csdn.net/2401_89898861/article/details/148877490


1. 什么是权值共享?

在一般的 全连接层 (Fully Connected Layer) 中,每个输入神经元与每个输出神经元都有独立的权重,因此参数量非常大。
而在 卷积神经网络 (CNN) 中,我们采用 卷积核 (filter/kernel) 在输入特征图上滑动,每个位置使用 相同的一组权重 来进行特征提取,这就是权值共享。

直观理解:

  • 如果用全连接层处理一张 256×256×3 的图片,参数量可能达到上亿级;
  • 使用卷积核(例如 3×3×3 大小,64 个卷积核),参数量仅仅是 3*3*3*64=1728,极大减少计算量。

优势:

  1. 减少参数量 → 避免过拟合,提高训练效率。
  2. 提高泛化性 → 一个卷积核学到的特征(如边缘/纹理)可以在图像的不同区域复用。
  3. 适合空间结构数据 → 保留图像的局部结构特征。

2. 代码示例:对比「无权值共享 vs 有权值共享」

(1) 无权值共享:每个位置独立参数(模拟卷积但不共享权值)

import torch
import torch.nn as nn

# 一个 "不共享权值的卷积":本质上是全连接的展开
class UnsharedConv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, input_size):
        super().__init__()
        H, W = input_size
        self.weight = nn.Parameter(torch.randn(out_channels, in_channels, H, W))  # 每个位置独立权值
        self.bias   = nn.Parameter(torch.zeros(out_channels))

    def forward(self, x):  # x: [N, C, H, W]
        # 模拟逐像素乘法(效率低,仅作演示)
        return (x * self.weight).sum(dim=(1,2,3), keepdim=True) + self.bias.view(1, -1, 1, 1)

x = torch.randn(1, 3, 32, 32)  # 输入 32x32x3 图像
model = UnsharedConv(3, 10, 3, (32, 32))
print("参数量(不共享):", sum(p.numel() for p in model.parameters()))

  • (2) 有权值共享(普通卷积层)
conv = nn.Conv2d(in_channels=3, out_channels=10, kernel_size=3, padding=1)
print("参数量(共享权值):", sum(p.numel() for p in conv.parameters()))

输出对比:

  • 不共享权值:参数量 ≈ 3×32×32×10 = 30720
  • 共享权值:参数量 = 3×3×3×10 + 10 = 280

参数量差距 100 倍以上,但卷积能捕捉相同甚至更好的特征。

3. 权值共享的实际效果

  • 我们可以训练一个小模型,比较 CNN (权值共享) 与 全连接网络 (无共享) 在图像分类任务上的差异。

CNN 示例(共享权值)

class SmallCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, 3, padding=1)
        self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
        self.fc = nn.Linear(32*7*7, 10)  # 假设输入 28x28
    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = torch.relu(self.conv2(x))
        x = torch.flatten(x, 1)
        return self.fc(x)

print("CNN 参数量:", sum(p.numel() for p in SmallCNN().parameters()))

MLP 示例(无共享)

class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(28*28, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, 10)
    def forward(self, x):
        x = torch.flatten(x, 1)
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        return self.fc3(x)

print("MLP 参数量:", sum(p.numel() for p in MLP().parameters()))

  • → 你会发现,CNN 参数量远小于 MLP,但在图像任务上往往效果更好,这就是 权值共享带来的好处。

4. 总结

  • 权值共享 = 相同的一组卷积核在输入的不同区域重复使用 → 显著减少参数量,增强泛化能力。
  • 在图像/序列任务中尤其重要(CNN、RNN 等都有权值共享思想)。
  • 对比实验:CNN vs 全连接 → CNN 参数量更小,收敛更快。
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐