PyTorch基于张量点积生成层权重的反向传播定向优化问题
现有实现的核心Bug根源
你在__init__阶段通过nn.Parameter(torch.tensordot(...))给卷积层赋值权重的操作,本质是把张量计算结果的数值硬拷贝成了完全独立的新叶子参数,直接切断了V参数到卷积层权重的反向传播链路:
- 新生成的卷积层weight/bias是独立的可训练张量,梯度只会回传到张量本身
- 当初参与点积运算的
self.conv1_W_V、self.conv1_B_V因为后续没有任何计算图关联,永远不会接收到来自网络输出的梯度 - 即使V参数被加入优化器参数列表,因为没有连接到最终的损失计算路径,梯度始终为None,完全不会被更新。
可行修正方案
核心逻辑:所有需要根据V动态生成的层权重,全部在前向传播过程中实时计算,全程保留从V到网络输出的完整计算图,不要在初始化阶段把计算好的权重存成静态独立参数
具体实现要点:
- 保留V参数的
requires_grad=True设置,让Wstacked参数始终保持requires_grad=False,这部分原有逻辑不需要改动 - 给原有卷积/全连接层的静态内置权重、偏置设置
requires_grad=False,避免被优化器误更新 - 利用PyTorch层提供的“自定义权重/偏置”计算接口,把前向过程中动态计算得到的tensordot结果直接传入层的计算逻辑,不修改层本身的静态参数。
修正后的单层代码实现参考:
import torch import torch.nn as nn class NOWANet(nn.Module): def __init__(self, V, Wstacked): super(NOWANet, self).__init__() # 初始化卷积层,仅匹配输出形状,不使用其内置的静态权重 self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5) # 关闭卷积层内置权重和偏置的可训练性 self.conv1.weight.requires_grad = False self.conv1.bias.requires_grad = False # 保留可训练V参数 self.conv1_W_V = nn.Parameter(V[0], requires_grad=True) self.conv1_B_V = nn.Parameter(V[1], requires_grad=True) # 保留固定的Wstacked参数,全程不更新 self.conv1_W_stack = nn.Parameter(Wstacked[0], requires_grad=False) self.conv1_B_stack = nn.Parameter(Wstacked[1], requires_grad=False) def forward(self, x): # 前向传播时实时计算当前步的权重与偏置,打通完整计算图 current_weight = torch.tensordot(self.conv1_W_V, self.conv1_W_stack, dims=1) current_bias = torch.tensordot(self.conv1_B_V, self.conv1_B_stack, dims=1) # 直接传入动态计算的权重完成卷积计算,不改动层的静态参数 x = self.conv1._conv_forward(x, weight=current_weight, bias=current_bias) # 后续网络层逻辑按同样规则复用即可 return x
配套优化器配置注意事项
因为网络中同时存在可训练参数(V)和固定参数(Wstacked、层内置静态权重),配置优化器时直接筛选所有requires_grad=True的参数传入即可:
optimizer = torch.optim.Adam( params=[p for p in model.parameters() if p.requires_grad], lr=1e-3 )
效果验证:第一次反向传播完成后,打印
model.conv1_W_V.grad,如果能得到非None的张量值,就说明计算图已经打通,V参数可以正常参与优化,Wstacked参数因为设置了requires_grad=False,全程不会被更新。
内容的提问来源于stack exchange,提问作者Orozco
相关产品推荐
相关产品推荐

