Python Pytorch:“;“模型重量不变”;

Python Pytorch:“;“模型重量不变”;,python,machine-learning,pytorch,Python,Machine Learning,Pytorch,有人能帮我理解为什么权重没有更新吗 unet = Unet() optimizer = torch.optim.Adam(unet.parameters(), lr=0.001) loss_fn = torch.nn.MSELoss() input = Variable(torch.randn(32, 1, 64, 64, 64 ), requires_grad=True) target = Variable(torch.randn(32, 1, 64,

有人能帮我理解为什么权重没有更新吗

    unet = Unet()
    optimizer = torch.optim.Adam(unet.parameters(), lr=0.001)
    loss_fn = torch.nn.MSELoss()
    input =  Variable(torch.randn(32, 1, 64, 64, 64 ), requires_grad=True)
    target = Variable(torch.randn(32, 1, 64, 64, 64), requires_grad=False)

    optimizer.zero_grad()
    y_pred = unet(input)
    y = target[: , : , 20:44, 20:44, 20:44]

    loss = loss_fn(y_pred, y)
    print(unet.conv1.weight.data[0][0]) # weights of the first layer in the unet
    loss.backward()
    optimizer.step()
    print(unet.conv1.weight.data[0][0]) # weights havent changed
该模型的定义如下:

class Unet(nn.Module):

def __init__(self):
  super(Unet, self).__init__()

  # Down hill1
  self.conv1 = nn.Conv3d(1, 2, kernel_size=3,  stride=1)
  self.conv2 = nn.Conv3d(2, 2, kernel_size=3,  stride=1)

  # Down hill2
  self.conv3 = nn.Conv3d(2, 4, kernel_size=3,  stride=1)
  self.conv4 = nn.Conv3d(4, 4, kernel_size=3,  stride=1)

  #bottom
  self.convbottom1 = nn.Conv3d(4, 8, kernel_size=3,  stride=1)
  self.convbottom2 = nn.Conv3d(8, 8, kernel_size=3,  stride=1)

  #up hill1
  self.upConv0 = nn.Conv3d(8, 4, kernel_size=3,  stride=1)
  self.upConv1 = nn.Conv3d(4, 4, kernel_size=3,  stride=1)
  self.upConv2 = nn.Conv3d(4, 2, kernel_size=3,  stride=1)

  #up hill2
  self.upConv3 = nn.Conv3d(2, 2, kernel_size=3, stride=1)
  self.upConv4 = nn.Conv3d(2, 1, kernel_size=1, stride=1)

  self.mp = nn.MaxPool3d(kernel_size=3, stride=2, padding=1)
  # some more irrelevant properties...
forward函数类似于:

def forward(self, input):
    # Use U-net Theory to Update the filters.
    # Example Approach...
    input = F.relu(self.conv1(input))
    input = F.relu(self.conv2(input))

    input = self.mp(input)

    input = F.relu(self.conv3(input))
    input = F.relu(self.conv4(input))

    input = self.mp(input)

    input = F.relu(self.convbottom1(input))
    input = F.relu(self.convbottom2(input))

    input = F.interpolate(input, scale_factor=2, mode='trilinear')

    input = F.relu(self.upConv0(input))
    input = F.relu(self.upConv1(input))

    input = F.interpolate(input, scale_factor=2, mode='trilinear')


    input = F.relu(self.upConv2(input))
    input = F.relu(self.upConv3(input))

    input = F.relu(self.upConv4(input))

    return input
我遵循了我能找到的任何示例和文档的方法,我不明白为什么这样做不起作用


我可以计算出,在反向调用之后,
y_pred.grad
是不应该的。如果我们没有梯度,那么优化器当然不能在任何方向上更改权重,但为什么没有梯度?

我认为不应该使用您使用的命令打印权重。尝试打印(unet.conv1.state_dict()[“weight”])而不是打印(unet.conv1.weight.data[0][0])

我认为不应该使用您使用的命令打印重量。尝试打印(unet.conv1.state_dict()[“weight”])而不是打印(unet.conv1.weight.data[0][0])

我认为这个问题属于“濒死的雷卢问题”,因为数据是Hounsfield单位,Pytorch初始权重的均匀分布意味着许多神经元将从雷卢的零区域开始,使它们瘫痪,并依赖其他神经元产生梯度,将它们拉出零区域。随着训练的进行,这种情况不太可能发生,因为所有神经元都被推入了ReLu的零区

这个问题有几种解决办法。您可以使用Leaky_relu或其他没有零区域的激活函数

您还可以使用批处理规范化来规范化输入数据,并将权重初始化为仅为正数

第二种解决方案可能是最理想的解决方案,因为两者都可以解决问题,但leaky_relu会延长训练时间,而批处理规范化则相反,可以提高准确性。另一方面,Leaky_relu是一个简单的解决方案,而另一个解决方案需要一些额外的工作


对于Hounsfield数据,还可以向输入中添加1000的常数,从而消除数据中的负单位。这仍然需要与Pytorch的标准初始化不同的权重初始化

我认为这个问题属于“濒死的雷卢问题”,因为数据是Hounsfield单位,Pytorch初始权重的均匀分布意味着许多神经元将从雷卢的零区域开始,使它们瘫痪,并依赖其他神经元产生梯度,将它们拉出零区域。随着训练的进行,这种情况不太可能发生,因为所有神经元都被推入了ReLu的零区

这个问题有几种解决办法。您可以使用Leaky_relu或其他没有零区域的激活函数

您还可以使用批处理规范化来规范化输入数据,并将权重初始化为仅为正数

第二种解决方案可能是最理想的解决方案,因为两者都可以解决问题,但leaky_relu会延长训练时间,而批处理规范化则相反,可以提高准确性。另一方面,Leaky_relu是一个简单的解决方案,而另一个解决方案需要一些额外的工作


对于Hounsfield数据,还可以向输入中添加1000的常数,从而消除数据中的负单位。这仍然需要与Pytorch的标准初始化不同的权重初始化

这确实会产生不同的结果。你知道unet.conv1.state_dict()[“weight”]和unet.conv1.weight之间的区别是什么吗?实际上我认为它们是一样的。我只是注意到两者都会改变,只是不是每次重量都会改变。就像50/50的时间。现在我必须考虑一下这是否会发生。我还检查了两个print语句是否产生相同的结果。这确实会打印出不同的结果。你知道unet.conv1.state_dict()[“weight”]和unet.conv1.weight之间的区别是什么吗?实际上我认为它们是一样的。我只是注意到两者都会改变,只是不是每次重量都会改变。就像50/50的时间。现在我必须考虑一下这是否会发生。我还检查了两个print语句是否产生相同的结果。你能展示一些解决方案中的代码吗?你能展示一些解决方案中的代码吗?