PyTorch训练输出值量级差异极大的神经网络优化方案求助
可行训练方案
针对输出向量尺度差异极大的训练问题,以下是几个实用的优化方案,附代码示例:
1. 自适应加权MSE损失(基于真实值尺度)
你之前的固定掩码权重方法存在阈值僵化的问题,不如直接用真实值的动态尺度调整损失权重,让小数值的损失贡献自动放大,平衡不同尺度的学习优先级。
代码示例:
import torch import numpy as np gnd_truth = torch.from_numpy(np.array([20.42, -1.56e-4, -3.11, 4.2e-2, -7e-3, 10.11]))[None] dnn_in = torch.from_numpy(np.array([0.76, 0.34]))[None] optimizer.zero_grad() dnn_out = net(dnn_in) # 计算自适应权重:用真实值绝对值的倒数,加1e-8防止除以零 weights = 1.0 / (torch.abs(gnd_truth) + 1e-8) # 可选:归一化权重,避免极端值主导损失 weights = weights / weights.mean() # 加权MSE损失 loss = torch.mean((dnn_out - gnd_truth)**2 * weights) loss.backward() optimizer.step()
如果觉得倒数权重过于极端,也可以用平方根倒数:weights = 1.0 / torch.sqrt(torch.abs(gnd_truth) + 1e-8),效果更温和。
2. 分分支多输出头训练
将输出向量按数值尺度拆分为大、小数值两组,用网络的两个独立分支分别预测,再加权合并损失。这样模型可以针对不同尺度的输出单独优化参数,避免互相干扰。
代码示例:
假设你将网络net修改为返回两个分支输出:
import torch import numpy as np gnd_truth = torch.from_numpy(np.array([20.42, -1.56e-4, -3.11, 4.2e-2, -7e-3, 10.11]))[None] # 手动划分大/小数值维度(也可根据batch真实值动态划分) large_indices = [0,2,5] small_indices = [1,3,4] gnd_large = gnd_truth[:, large_indices] gnd_small = gnd_truth[:, small_indices] dnn_in = torch.from_numpy(np.array([0.76, 0.34]))[None] optimizer.zero_grad() # 修改后的网络返回两个分支输出 out_large, out_small = net(dnn_in) # 给小数值损失加权重,提升学习优先级 loss_large = torch.nn.functional.mse_loss(out_large, gnd_large) loss_small = torch.nn.functional.mse_loss(out_small, gnd_small) loss = loss_large + 100 * loss_small # 权重可根据效果调整 loss.backward() optimizer.step()
3. 对数变换+符号保留
通过对数变换把跨数量级的数值拉到同一范围,降低模型学习难度。对真实值做「符号 × log10(绝对值 + 小常数)」的变换,模型输出变换后的值,再反向变换得到原始尺度的预测结果。
代码示例:
import torch import numpy as np gnd_truth = torch.from_numpy(np.array([20.42, -1.56e-4, -3.11, 4.2e-2, -7e-3, 10.11]))[None] dnn_in = torch.from_numpy(np.array([0.76, 0.34]))[None] # 真实值变换函数 def transform_target(target): sign = torch.sign(target) abs_log = torch.log10(torch.abs(target) + 1e-8) # 加1e-8避免log(0) return sign * abs_log # 反向变换得到原始尺度预测 def inverse_transform(pred): sign = torch.sign(pred) abs_pred = torch.pow(10, torch.abs(pred)) return sign * abs_pred optimizer.zero_grad() # 模型输出变换后的数值 dnn_out_transformed = net(dnn_in) gnd_transformed = transform_target(gnd_truth) # 用变换后的MSE计算损失 loss_transformed = torch.nn.functional.mse_loss(dnn_out_transformed, gnd_transformed) # 可选:叠加原始尺度的相对误差损失,双重约束 dnn_out = inverse_transform(dnn_out_transformed) loss_relative = torch.mean(torch.abs(dnn_out - gnd_truth)/(torch.abs(gnd_truth)+1e-8)) loss = loss_transformed + 0.1 * loss_relative # 权重可调 loss.backward() optimizer.step()
4. 相对误差损失(优先保证比例正确)
对于尺度差异大的场景,相对误差比绝对误差更有参考价值。比如真实值1e-5预测成2e-5,绝对误差极小但相对误差达100%;真实值100预测成101,绝对误差大但相对误差仅1%。用相对误差作为损失,能让模型优先保证每个维度的预测比例准确。
代码示例:
import torch import numpy as np gnd_truth = torch.from_numpy(np.array([20.42, -1.56e-4, -3.11, 4.2e-2, -7e-3, 10.11]))[None] dnn_in = torch.from_numpy(np.array([0.76, 0.34]))[None] optimizer.zero_grad() dnn_out = net(dnn_in) # 平方相对误差损失 loss = torch.mean(((dnn_out - gnd_truth) / (torch.abs(gnd_truth) + 1e-8)) ** 2) # 或者用绝对相对误差 # loss = torch.mean(torch.abs(dnn_out - gnd_truth) / (torch.abs(gnd_truth) + 1e-8)) loss.backward() optimizer.step()
内容的提问来源于stack exchange,提问作者learner
相关产品推荐
相关产品推荐

