You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PyTorch中Weight Normalization与Adam优化器搭配引发Non-Leaf张量错误问题

解决Weight Normalization下Adam优化器的Non-Leaf Tensor错误

这个问题的根源很清晰:当你用weight_norm包装Conv2d层时,PyTorch会替换原Conv2d的weight张量为一个由新参数(weight_gweight_v)计算出来的非叶子张量。原Conv2d的weight不再是模型的可训练参数(它变成了计算图中的中间节点),真正需要优化的是WeightNorm模块里的weight_gweight_v。你的get_parameters函数直接去取Conv2d的weight/bias,导致收集到了非叶子张量,所以优化器抛出了错误。

下面给你两种可行的解决方案,都能保留Weight Normalization:

方案一:修改参数收集函数,适配WeightNorm

调整get_parameters函数,让它正确识别并收集WeightNorm模块的可训练参数:

def get_parameters(model, bias=False):
    for m in model.modules():
        # 处理WeightNorm模块的核心权重参数(weight_g和weight_v)
        if isinstance(m, nn.utils.weight_norm.WeightNorm):
            if not bias:
                yield m.weight_g
                yield m.weight_v
        # 处理普通Conv2d的参数
        elif isinstance(m, nn.Conv2d):
            if bias:
                if m.bias is not None:
                    yield m.bias
            else:
                # 仅收集未被WeightNorm包装的Conv2d的weight(确保是叶子张量)
                if m.weight is not None and m.weight.is_leaf and m.weight.requires_grad:
                    yield m.weight

修改后,这个函数会优先收集WeightNorm的可训练参数,再处理普通Conv2d的参数,确保所有收集到的张量都是可优化的叶子节点。

方案二:更简洁的参数分组方式

直接遍历模型的所有可训练参数(named_parameters()会自动返回所有叶子张量),按参数名分组:

# 分离权重参数(包括weight_g、weight_v和普通conv weight)和bias参数
params_weight = []
params_bias = []

for name, param in model.named_parameters():
    if "bias" in name:
        params_bias.append(param)
    else:
        params_weight.append(param)

# 初始化优化器
optimizer = torch.optim.Adam(
    [
        {'params': params_weight},
        {'params': params_bias, 'lr': opt['base_lr'] * 2, 'weight_decay': 0},
    ],
    lr=opt['base_lr']
)

这种方式更简洁,不需要手动判断模块类型,named_parameters()已经帮你过滤出了所有可优化的叶子参数,完美匹配你想要的分组逻辑——所有bias用2倍学习率且无权重衰减,权重参数用基础学习率。

两种方案都能解决你的问题,我个人更推荐方案二,代码更简洁且不易出错。

内容的提问来源于stack exchange,提问作者Mohit Lamba

火山引擎 最新活动