You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

nn.Parameter无法更新,求问当前用法是否正确及正确实现方式

问题与解决方案

问题

定义了两个requires_grad=True的nn.Parameter变量,在类的__init__方法中声明,通过类内其他函数调用使用,但这两个参数始终无法更新,打印模型的named_parameters()也找不到它们。

原代码示例

class LG(BaseNetwork):
    def __init__(self, opt):
        super().__init__()
        self.opt = opt
        self.lparam = nn.Parameter(torch.zeros(1), requires_grad=True).cuda(device=opt.gpu_ids[0])
        self.rparam = nn.Parameter(torch.zeros(1), requires_grad=True).cuda(device=opt.gpu_ids[0])
        
    def foo(self, a, b, k=1.0, lparam=0, rparam=0):
      t = bar(a, b, k=k, lparam=lparam, rparam=rparam)
      return t

    def forward(self, a, b):
       x = self.foo(a, b, k=self.opt.k, lparam=self.lparam, rparam=self.rparam)
       return x

BaseNetwork继承自nn.Module,仅包含基础初始化逻辑

def bar(a, b, k=1.0, lparam=0, rparam=0):
    return n(a) * (b.std() * (k * lparam)) + (b.mean() * (k * rparam))

错误原因

问题出在nn.Parameter的初始化方式:直接链式调用.cuda()会返回一个新的普通张量,而非修改原nn.Parameter对象。原本PyTorch会自动将nn.Parameter实例注册到模型的参数列表中,但替换成普通张量后,模型无法追踪到这两个变量,自然不会更新它们的梯度,也不会出现在named_parameters()的输出里。

修正方案

有三种规范的实现方式,任选其一即可:

方式1:先创建Parameter,再单独移动到设备

class LG(BaseNetwork):
    def __init__(self, opt):
        super().__init__()
        self.opt = opt
        # 先创建Parameter实例,PyTorch自动注册到模型
        self.lparam = nn.Parameter(torch.zeros(1), requires_grad=True)
        self.rparam = nn.Parameter(torch.zeros(1), requires_grad=True)
        # 再将参数移动到指定GPU
        self.lparam = self.lparam.cuda(device=opt.gpu_ids[0])
        self.rparam = self.rparam.cuda(device=opt.gpu_ids[0])
        
    def foo(self, a, b, k=1.0, lparam=0, rparam=0):
        t = bar(a, b, k=k, lparam=lparam, rparam=rparam)
        return t

    def forward(self, a, b):
        x = self.foo(a, b, k=self.opt.k, lparam=self.lparam, rparam=self.rparam)
        return x

方式2:直接在目标设备创建张量后转为Parameter

class LG(BaseNetwork):
    def __init__(self, opt):
        super().__init__()
        self.opt = opt
        # 先指定设备,再创建张量并转为Parameter
        device = torch.device(f'cuda:{opt.gpu_ids[0]}')
        self.lparam = nn.Parameter(torch.zeros(1, device=device), requires_grad=True)
        self.rparam = nn.Parameter(torch.zeros(1, device=device), requires_grad=True)
        
    def foo(self, a, b, k=1.0, lparam=0, rparam=0):
        t = bar(a, b, k=k, lparam=lparam, rparam=rparam)
        return t

    def forward(self, a, b):
        x = self.foo(a, b, k=self.opt.k, lparam=self.lparam, rparam=self.rparam)
        return x

方式3:统一调用self.to()移动所有参数(推荐)

这种方式更简洁,尤其当模型有多个参数时,无需逐个移动:

class LG(BaseNetwork):
    def __init__(self, opt):
        super().__init__()
        self.opt = opt
        # 创建Parameter实例
        self.lparam = nn.Parameter(torch.zeros(1), requires_grad=True)
        self.rparam = nn.Parameter(torch.zeros(1), requires_grad=True)
        # 统一将模型所有参数移动到目标设备
        self.to(opt.gpu_ids[0])
        
    def foo(self, a, b, k=1.0, lparam=0, rparam=0):
        t = bar(a, b, k=k, lparam=lparam, rparam=rparam)
        return t

    def forward(self, a, b):
        x = self.foo(a, b, k=self.opt.k, lparam=self.lparam, rparam=self.rparam)
        return x

验证方法

创建模型实例后,执行以下代码:

model = LG(opt)
for name, param in model.named_parameters():
    print(name, param.requires_grad)

此时会输出lparam True和rparam True,训练时这两个参数也会正常更新梯度。

内容的提问来源于stack exchange,提问作者Mahmood Hussain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 15:24:18