PyTorch线性神经网络损失与输出恒定问题技术求助
神经网络训练损失与输出恒定问题求助
我正在构建一个用于计算旋转矩阵输入角度的神经网络,采用经典线性网络结构,最终将网络输出传入自定义旋转函数以返回空间点列表。但训练过程中损失值与网络输出始终保持恒定,无法进行有效训练,现寻求技术帮助解决该问题,问题解决后将提取网络所用的旋转角度。
实现代码
import torch import torch.nn as nn import torch.nn.functional as F from torch.autograd import Variable as V import torch.optim as opt import numpy as np import matplotlib.pyplot as plt cam_pos = np.array([500, 160, 1140, 1]) # with respect to vehicle coordinates img_res = (1280, 1080) aspect_ratio = img_res[0] / img_res[1] # in px cx = 636 / aspect_ratio cy = 548 / aspect_ratio fx = 241 / aspect_ratio fy = 238 / aspect_ratio u = 872 v = 423 D = 1900 # mm img_pt = np.array([u, v, 1, 1/D]).T camera_matrix = np.array([[fx, 0, cx, 0], [0, fy, cy, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) class Network(nn.Module): def __init__(self): super(Network, self).__init__() self.lin1 = nn.Linear(3,10) self.lin2 = nn.Linear(10,10) self.lin3 = nn.Linear(10,3) self.angle_list = [] def forward(self, x): x = F.relu(self.lin1(x)) x = F.relu(self.lin2(x)) x = self.lin3(x) self.angle_list.append(list(x.detach().numpy())) return torch.tensor(self.cam_function(x), requires_grad=True) def rot_x(self, alpha): return np.array([ [1, 0, 0, 0], [0, np.cos(alpha), -np.sin(alpha), 0], [0, np.sin(alpha), np.cos(alpha), 0], [0, 0, 0, 1] ]) def rot_y(self, beta): return np.array([ [np.cos(beta), 0, np.sin(beta), 0], [0, 1, 0, 0], [-np.sin(beta), 0, np.cos(beta), 0], [0, 0, 0, 1] ]) def rot_z(self, gamma): return np.array([ [np.cos(gamma), -np.sin(gamma), 0, 0], [np.sin(gamma), np.cos(gamma), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]) def cam_function(self, net_output): net_output = net_output.detach().numpy() x = net_output[0] y = net_output[1] z = net_output[2] rot_m = np.dot(self.rot_z(z), np.dot(self.rot_y(y), self.rot_x(x))) extrinsic_matrix = np.array([ [rot_m[0][0], rot_m[0][1], rot_m[0][2], cam_pos[0]], [rot_m[1][0], rot_m[1][1], rot_m[1][2], cam_pos[1]], [rot_m[2][0], rot_m[2][1], rot_m[2][2], cam_pos[2]], [0, 0, 0, 1 ]]) cam_output = img_pt * D * np.linalg.inv(camera_matrix) * extrinsic_matrix / 1000 cam_output = [cam_output[0][0], cam_output[1][1], cam_output[2][2]] return cam_output model = Network() loss_function = nn.CrossEntropyLoss() optimizer = opt.SGD(model.parameters(), lr=1e-3) target = torch.tensor([1.636, 1.405, 0.262]).float() dummy_data = torch.tensor([0, 0, 0]).float() losses = [] for epoch in range(5000): model.train() prediction= model(dummy_data) loss = loss_function(prediction, target) losses.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step()
训练异常输出
7.3858967314779305 tensor([7.9938, 3.9272, 1.8514], dtype=torch.float64, requires_grad=True) 7.3858967314779305 tensor([7.9938, 3.9272, 1.8514], dtype=torch.float64, requires_grad=True) 7.3858967314779305 tensor([7.9938, 3.9272, 1.8514], dtype=torch.float64, requires_grad=True)
问题分析与解决方案
核心问题原因
- 梯度断裂:
cam_function中调用net_output.detach().numpy()直接切断了网络输出到后续计算的梯度传播链,导致模型参数无法通过反向传播更新;手动创建返回张量时未关联原计算图,梯度无法传递回网络层。 - 损失函数误用:
CrossEntropyLoss是分类任务专用损失,当前任务是回归(预测连续空间坐标),应使用MSE或L1损失。 - 计算图破坏:使用NumPy数组进行矩阵运算,而非PyTorch张量,既破坏计算图,还可能引发类型不匹配问题。
- 矩阵运算错误:使用逐元素乘法
*替代矩阵乘法,导致空间坐标计算逻辑错误。
修正后的代码
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as opt import numpy as np import matplotlib.pyplot as plt cam_pos = torch.tensor([500, 160, 1140, 1], dtype=torch.float32) # with respect to vehicle coordinates img_res = (1280, 1080) aspect_ratio = img_res[0] / img_res[1] # in px cx = 636 / aspect_ratio cy = 548 / aspect_ratio fx = 241 / aspect_ratio fy = 238 / aspect_ratio u = 872 v = 423 D = 1900 # mm img_pt = torch.tensor([u, v, 1, 1/D], dtype=torch.float32).unsqueeze(1) # 转为列向量 camera_matrix = torch.tensor([[fx, 0, cx, 0], [0, fy, cy, 0], [0, 0, 1, 0], [0, 0, 0, 1]], dtype=torch.float32) class Network(nn.Module): def __init__(self): super(Network, self).__init__() self.lin1 = nn.Linear(3,10) self.lin2 = nn.Linear(10,10) self.lin3 = nn.Linear(10,3) self.angle_list = [] def forward(self, x): x = F.relu(self.lin1(x)) x = F.relu(self.lin2(x)) angles = self.lin3(x) self.angle_list.append(angles.detach().cpu().numpy().tolist()) return self.cam_function(angles) def rot_x(self, alpha): return torch.tensor([ [1, 0, 0, 0], [0, torch.cos(alpha), -torch.sin(alpha), 0], [0, torch.sin(alpha), torch.cos(alpha), 0], [0, 0, 0, 1] ], dtype=torch.float32) def rot_y(self, beta): return torch.tensor([ [torch.cos(beta), 0, torch.sin(beta), 0], [0, 1, 0, 0], [-torch.sin(beta), 0, torch.cos(beta), 0], [0, 0, 0, 1] ], dtype=torch.float32) def rot_z(self, gamma): return torch.tensor([ [torch.cos(gamma), -torch.sin(gamma), 0, 0], [torch.sin(gamma), torch.cos(gamma), 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ], dtype=torch.float32) def cam_function(self, angles): alpha, beta, gamma = angles[0], angles[1], angles[2] rot_m = self.rot_z(gamma) @ self.rot_y(beta) @ self.rot_x(alpha) extrinsic_matrix = torch.zeros((4,4), dtype=torch.float32) extrinsic_matrix[:3, :3] = rot_m[:3, :3] extrinsic_matrix[:3, 3] = cam_pos[:3] extrinsic_matrix[3, 3] = 1 # 修正矩阵运算逻辑 inv_camera = torch.inverse(camera_matrix) cam_output = D * inv_camera @ extrinsic_matrix @ img_pt cam_output = cam_output[:3, 0] / 1000 # 转为米单位,取前三个坐标 return cam_output model = Network() loss_function = nn.MSELoss() # 替换为回归损失 optimizer = opt.SGD(model.parameters(), lr=1e-3) target = torch.tensor([1.636, 1.405, 0.262], dtype=torch.float32) dummy_data = torch.tensor([0, 0, 0], dtype=torch.float32) losses = [] for epoch in range(5000): model.train() optimizer.zero_grad() prediction = model(dummy_data) loss = loss_function(prediction, target) losses.append(loss.item()) loss.backward() optimizer.step() # 提取最终旋转角度 final_angles = model.angle_list[-1] print("最终旋转角度:", final_angles)
额外优化建议
- 调整学习率(如
lr=1e-2)或改用Adam优化器,提升收敛速度 - 对角度输出添加范围约束(如
tanh激活函数限制在[-π, π]),避免三角函数计算不稳定 - 增加训练样本多样性,避免单一样本训练导致的过拟合或收敛困难
内容的提问来源于stack exchange,提问作者MrThiele1708
相关产品推荐
相关产品推荐

