Pytorch 在这个简单的例子中,为什么损失是不变的?

Pytorch 在这个简单的例子中,为什么损失是不变的?,pytorch,mathematical-optimization,torch,Pytorch,Mathematical Optimization,Torch,我正在编写一个代码示例,用PyTorch做一个简单的线性投影(比如PCA)。一切似乎都很正常,只是损失不会随着训练的进行而改变。改变学习率不会影响这一点,这是一个简单的一维问题,因此损失肯定会改变。我错过了什么 将numpy导入为np 进口火炬 导入torch.nn作为nn 导入torch.nn。功能为nnF PCArot2D类(nn.模块): 2D PCA旋转,表示为梯度下降问题 定义初始化(自): 超级(PCArot2D,self)。\uuuu init self.theta=nn.参数(t

我正在编写一个代码示例,用PyTorch做一个简单的线性投影(比如PCA)。一切似乎都很正常,只是损失不会随着训练的进行而改变。改变学习率不会影响这一点,这是一个简单的一维问题,因此损失肯定会改变。我错过了什么

将numpy导入为np
进口火炬
导入torch.nn作为nn
导入torch.nn。功能为nnF
PCArot2D类(nn.模块):
2D PCA旋转,表示为梯度下降问题
定义初始化(自):
超级(PCArot2D,self)。\uuuu init
self.theta=nn.参数(torch.tensor(np.random.random()*2*np.pi))
def getrotation(自):
sintheta=torch.sin(self.theta)
costheta=torch.cos(self.theta)
返回torch.tensor([[costheta,-sintheta],[sintheta,costheta]],需要_grad=True,dtype=torch.double)
def前进(自身,x):
xmeans=torch.mean(x,dim=1,keepdim=True)
rot=self.getrotation()
返回火炬.mm(旋转,x-x平均值)
def协方差(y):
“计算其输入的协方差矩阵(作为torch变量)”
y平均值=火炬平均值(y,dim=1,keepdim=True)
ycentred=y-ymeans
返回火炬.mm(居中,居中/居中形状[1]
net=PCArot2D()
例2=火炬张量(np.random.randn(2,33))
#定义损失函数和优化程序
标准=nn.MSELoss()
optimizer=torch.optim.SGD(net.parameters(),lr=0.001,momentum=0.1)
#培训网络
num_epochs=1000
对于范围内的历元(num_历元):
optimizer.zero_grad()
#向前+向后+优化
输出=净(火炬双张量(示例2))
#输出通道之间的协方差是我们希望最小化的度量
协方差=(输出[0,:]*输出[1,:])。平均值()
损失=标准(协方差,火炬张量(0,数据类型=火炬双))
loss.backward()
optimizer.step()
运行损失=损失。项目()
如果((epoch&(epoch-1))==0)或epoch==(num_epochs-1):#不要在所有epoch上打印
#打印统计数据
打印('[%d]损失:%.8f'%
(历元、运行损耗)
打印(‘已完成培训’)
输出:

[0] loss: 0.00629047
[1] loss: 0.00629047
[2] loss: 0.00629047
[4] loss: 0.00629047
[8] loss: 0.00629047
etc

问题似乎出在
getrotation
函数中。当从其他张量创建新张量时,不再返回:

def getrotation(自):
sintheta=torch.sin(self.theta)
costheta=torch.cos(self.theta)
返回torch.tensor([[costheta,-sintheta],[sintheta,costheta]],需要_grad=True,dtype=torch.double)
所以你需要找到其他的方法来构造你的返回张量

这里有一个建议似乎在使用torch.cat时起作用:

def getrotation(自):
sintheta=torch.sin(self.theta)
costheta=torch.cos(self.theta)
#返回torch.tensor([[costheta,-sintheta],[sintheta,costheta]],需要_grad=True,dtype=torch.double)
A=火炬猫([costheta.unsqueze(0),-sintheta.unsqueze(0)],尺寸=0)
B=焊炬类别([sintheta.UNSQUEZE(0),costheta.UNSQUEZE(0)],尺寸=0)
返回火炬。cat([A.未喷射(0),B.未喷射(0)],dim=0。双()
实施此变更后,损失发生变化:

[0]损失:0.00765365
[1] 损失:0.00764726
[2] 损失:0.00764023
[4] 损失:0.00762607
[8] 损失:0.00759777
[16] 损失:0.00754148
[32]损失:0.00742997
[64]损失:0.00721117
[128]损失:0.00679025
[256]损失:0.00601233
[512]损失:0.00469085
[999]损失:0.00288501
完成训练
我希望这有帮助


编辑: 更简单、更漂亮的版本:

def getrotation(自):
sintheta=torch.sin(net.theta).double().unsqueze(0)
costheta=torch.cos(net.theta).double().unsqueze(0)
返回火炬。cat([costheta,-sintheta,sintheta,costheta])。重塑((2,2))

很有效,谢谢!我温和地重写为:
def getrotation(self):sintheta=torch.sin(net.theta.double().unqueze(0);costheta=torch.cos(net.theta).double().unsqueze(0);返回火炬。cat([costheta,-sintheta,sintheta,costheta])。重塑((2,2))