参数量级差异显著场景下,初始猜测偏离过远导致回归失败的解决方案咨询
参数量级差异显著场景下,初始猜测偏离过远导致回归失败的解决方案咨询
我最近碰到了一个回归任务的棘手问题——模型里的参数量级差得特别大,就像下面这个例子:
import numpy as np def func(x, p): p1, p2, p3 = p return np.sin(p1*x) * np.exp(p2*x) * p3 # 真实参数:量级差了好几百倍 p1, p2, p3 = np.pi/0.01, -1.25, 1.2356 # 对应数值:314.1592, -1.25, 1.2356
这个模型对初始猜测的要求特别苛刻,只有当初始值离真实解比较近的时候,回归才能顺利收敛。比如下面这个初始猜测就可以正常工作:
p0 = [np.pi/0.01-80, -1.25-1, 1.2356-1]
但如果初始猜得太偏,尤其是量级最大的那个参数(比如上面的p1)偏离太多,回归直接就会收敛失败。像下面这个初始值,跑起来大概率会翻车:
p0 = [np.pi/0.02-10, -1.25-1, 1.2356-1]
我把完整的可复现代码整理出来了,分为Scipy和PyTorch两个版本:
Scipy 可复现代码
import numpy as np from scipy.optimize import least_squares import matplotlib.pyplot as plt def func(x, p): p1, p2, p3 = p return np.sin(p1*x) * np.exp(p2*x) * p3 def residuals(p, y, x): return y - func(x, p) # 生成带噪声的样本数据 x = np.linspace(0, 0.05, 50) p1, p2, p3 = np.pi/0.01, -1.25, 1.2356 y0 = func(x, [p1, p2, p3]) y = y0 + np.random.randn(len(x)) * 0.05 # 这个初始猜测会导致收敛失败 p0 = [np.pi/0.02-10, -1.25-1, 1.2356-1] result = least_squares(residuals, p0, args=(y, x)) print("真实参数:", [p1, p2, p3]) print("拟合得到的参数:", result.x) # 可视化结果 x_test = np.linspace(0, 0.05, 200) y_test = func(x_test, result.x) y_real = func(x_test, [p1, p2, p3]) plt.plot(x_test, y_test, label="预测曲线") plt.plot(x, y, '.r', label="样本数据") plt.legend() plt.show()
PyTorch 版本复现代码
import numpy as np import torch from torch import nn import matplotlib.pyplot as plt class guessEq(nn.Module): def __init__(self): super(guessEq, self).__init__() # 这里的初始参数如果偏离真实值太多,训练也会失败 self.params = nn.Parameter(torch.tensor([np.pi/0.02-10, -1.25+1, 1.2356-1])) def forward(self, x): out = torch.sin(self.params[0]*x) * \ torch.exp(self.params[1]*x) * \ self.params[2] return out # 生成带噪声的样本数据 x = np.linspace(0, 0.05, 100) y = np.sin(np.pi/0.01*x) * np.exp(-1.25*x) * 1.2356 + np.random.rand(x.shape[0]) * 0.05 # 转成PyTorch张量 x = torch.tensor(x, dtype=torch.float32).reshape((-1, 1)) y = torch.tensor(y, dtype=torch.float32).reshape((-1, 1)) model = guessEq() optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 训练过程 for i in range(2000): optimizer.zero_grad() y_pred = model(x) loss = torch.mean(torch.square(y_pred - y)) loss.backward() if i % 100 == 0: print(f"第{i}轮训练损失: {loss.item()}") optimizer.step() # 可视化结果 x_test = torch.linspace(0, 0.05, 200).reshape((-1, 1)) y_test = model(x_test) print(f"真实参数: [{np.pi/0.01:.4f} {p2:.4f} {p3:.4f}]") print(f"拟合得到的参数: {model.params.detach().numpy()}") plt.plot(x_test.detach().cpu().numpy().flatten(), y_test.detach().cpu().numpy().flatten(), c="blue", linewidth=2, label="预测曲线") plt.plot(x.detach().cpu().numpy().flatten(), y.detach().cpu().numpy().flatten(), '.r', label="训练样本") plt.legend() plt.show()
现在我特别头疼的是,如果没有先验知识来给出接近真实值的初始猜测,或者不小心把初始值设得离真实解太远,回归就直接失败了。有没有什么通用的方法可以解决这种参数量级差异大导致的收敛问题呀?
备注:内容来源于stack exchange,提问作者TsurumiTei
相关产品推荐
相关产品推荐

