PyTorch上我的网络参数未更新

PyTorch上我的网络参数未更新,pytorch,Pytorch,我想用Pytork做一个自动校准系统 我尝试将齐次变换矩阵作为神经网络的权值 我编写了一个参考PyTorch教程的代码,但在调用backward方法后,我的自定义参数不会更新 当我打印每个参数的“grad”属性时,它是一个None 我的代码如下。有什么问题吗 请给我任何建议。多谢各位 导入火炬 导入torch.nn作为nn 导入torch.nn.功能为F 将torch.optim导入为optim 将numpy作为np导入 类别网络(nn.模块): 定义初始化(自): 超级(网络,自我)。\uuu

我想用Pytork做一个自动校准系统

我尝试将齐次变换矩阵作为神经网络的权值

我编写了一个参考PyTorch教程的代码,但在调用backward方法后,我的自定义参数不会更新

当我打印每个参数的“grad”属性时,它是一个None

我的代码如下。有什么问题吗

请给我任何建议。多谢各位

导入火炬
导入torch.nn作为nn
导入torch.nn.功能为F
将torch.optim导入为optim
将numpy作为np导入
类别网络(nn.模块):
定义初始化(自):
超级(网络,自我)。\uuuu初始化
self.params=nn.参数(火炬号(6))
self.rx,self.ry,self.rz=self.params[0],self.params[1],self.params[2]
self.tx,self.ty,self.tz=self.params[3],self.params[4],self.params[5]
def前进(自身,x):
tr_mat=火炬张量([[1,0,0,自参数[3]],
[0,1,0,self.params[4]],
[0,0,1,self.params[5]],
[0,0,0,1]],需要_grad=True)
rz_mat=torch.tensor([[torch.cos(self.params[2]),-torch.sin(self.params[2]),0,0],
[torch.sin(self.params[2]),torch.cos(self.params[2]),0,0],
[0, 0, 1, 0],
[0,0,0,1]],需要_grad=True)
ry_mat=torch.tensor([[torch.cos(self.params[1]),0,torch.sin(self.params[1]),0],
[0, 1, 0, 0],
[-torch.sin(self.params[1]),0,torch.cos(self.params[1]),0],
[0,0,0,1]],需要_grad=True)
rx_mat=火炬张量([[1,0,0,0],
[0,torch.cos(self.params[0]),-torch.sin(self.params[0]),0],
[0,torch.sin(自参数[0]),torch.cos(自参数[0]),0],
[0,0,0,1]],需要_grad=True)
tf1=火炬材料(tr_材料、rz_材料)
tf2=torch.matmul(tf1,ry_-mat)
tf3=torch.matmul(tf2,rx_mat)
tr_local=torch.tensor([[1,0,0,x[0]],
[0,1,0,x[1]],
[0、0、1、x[2],
[0, 0, 0, 1]])
tf_输出=torch.matmul(tf3,tr_本地)
输出=tf_输出[:3,3]
返回输出
def get_损失(自身、输出):
通过
model=Net()
input_ex=np.array([-0.01,0.05,0.92],
[-0.06, 0.03, 0.94]])
输出=np.数组([-0.3,0.4,0.09],
[-0.5, 0.2, 0.07]])
打印(列表(model.parameters())
optimizer=optim.Adam(model.parameters(),0.001)
标准=nn.MSELoss()
对于输入\u np,在zip中标记\u np(输入\u ex,输出\u ex):
input_tensor=torch.from_numpy(input_np).float()
label\u tensor=torch.from\u numpy(label\u np).float()
输出=模型(输入张量)
optimizer.zero_grad()
损耗=标准(输出、标签张量)
loss.backward()
optimizer.step()
打印(列表(model.parameters())
发生了什么 您的问题与PyTorch将
torch.tensor
隐式转换为
float
有关。假设你有:

tr_mat = torch.tensor(
    [
        [1, 0, 0, self.params[3]],
        [0, 1, 0, self.params[4]],
        [0, 0, 1, self.params[5]],
        [0, 0, 0, 1],
    ],
    requires_grad=True,
)
torch.tensor
只能从具有类似Python的值的列表中构造,不能在其中包含
torch.tensor
。比如说,引擎盖下发生的是
self.params
的每个元素,它们可以转换为
float
is(在这种情况下,它们都可以,例如
self.params[3]
self.params[4]
self.params[5]

tensor
的值被转换为
float
时,它的值被复制到Python对应的对象中,因此它不再是计算图的一部分,它是一个新的纯Python变量(不能明显地反向传播)

解决方案 你所能做的就是选择你的
self.params
元素,并将它们插入眼睛矩阵中,这样梯度就会流动。您可以看到对
forward
方法的重写,并将此考虑在内:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.params = nn.Parameter(torch.randn(6))

    def forward(self, x):
        sinus = torch.cos(self.params)
        cosinus = torch.cos(self.params)

        tr_mat = torch.eye(4)
        tr_mat[:-1, -1] = self.params[3:]

        rz_mat = torch.eye(4)
        rz_mat[0, 0] = cosinus[2]
        rz_mat[0, 1] = -sinus[2]
        rz_mat[1, 0] = sinus[2]
        rz_mat[1, 1] = cosinus[2]

        ry_mat = torch.eye(4)
        ry_mat[0, 0] = cosinus[1]
        ry_mat[0, 2] = sinus[1]
        ry_mat[2, 0] = -sinus[1]
        ry_mat[2, 2] = cosinus[1]

        rx_mat = torch.eye(4)
        rx_mat[1, 1] = cosinus[0]
        rx_mat[1, 2] = -sinus[0]
        rx_mat[2, 1] = sinus[0]
        rx_mat[2, 2] = cosinus[0]

        tf1 = torch.matmul(tr_mat, rz_mat)
        tf2 = torch.matmul(tf1, ry_mat)
        tf3 = torch.matmul(tf2, rx_mat)

        tr_local = torch.tensor(
            [[1, 0, 0, x[0]], [0, 1, 0, x[1]], [0, 0, 1, x[2]], [0, 0, 0, 1]],
        )
        tf_output = torch.matmul(tf3, tr_local)
        output = tf_output[:3, 3]
        return output
(您可能想再次检查此重写,但想法成立)。 另外请注意,
tru local
可以按“您的方式”完成,因为我们不需要任何值来保持梯度

需要_grad
您可以看到
requires\u grad
未在代码中的任何位置使用。这是因为需要梯度的不是整个眼睛矩阵(我们不会优化
0
1
),而是插入其中的参数。通常在神经网络代码中根本不需要
requires_grad
,因为:

  • 输入张量没有得到优化(通常,当您进行对抗性攻击或类似攻击时,这些张量可能会得到优化)
  • nn.参数
    默认情况下需要渐变(除非冻结)
  • 层和其他特定于神经网络的东西默认情况下需要梯度(除非冻结)
  • 不需要梯度(输入张量)的值通过需要梯度的层(或参数或w/e)可以反向传播

非常感谢您的善意和出色的解释。我按照您的指示编辑我的代码,所以现在我的代码运行时没有任何问题。多亏了你,我能很快解决这个问题@gus8cjf如果问题得到解决,请接受答案,谢谢。