我正在为许多优化器运行线性回归。我注意到如果先激活 SGD,其他的都有很好的准确性。否则,Adam 和 RMSprop 会带来糟糕的调整。
# Generate synthetic data
X_numpy, y_numpy = datasets.make_regression(n_samples=100, n_features=1, noise=20, random_state=15)
X = torch.from_numpy(X_numpy.astype(np.float32))
y = torch.from_numpy(y_numpy.astype(np.float32))
y = y.view(y.shape[0], 1)
# Define the model
n_samples, n_features = X.shape
input_size = n_features
output_size = 1
model = nn.Linear(input_size, output_size)
# Define learning rate
learning_rate = 0.01
# Define criteria
criterion = nn.MSELoss()
# Define different optimizers
optimizers = {
"Adam": torch.optim.Adam(model.parameters(), lr=learning_rate),
"RMSprop": torch.optim.RMSprop(model.parameters(), lr=learning_rate),
"SGD": torch.optim.SGD(model.parameters(), lr=learning_rate),
}
# Training loop for each optimizer
num_epochs = 100
predictions = {}
for optimizer_name, optimizer in optimizers.items():
print(f"Optimizer: {optimizer_name}")
predictions[optimizer_name] = []
for epoch in range(num_epochs):
y_predicted = model(X)
loss = criterion(y_predicted, y)
loss.backward()
optimizer.step() #update wights
optimizer.zero_grad() #zero the gradients
predictions[optimizer_name] = model(X).detach().numpy()
# Plotting predictions with different colors
plt.figure(figsize=(10, 6))
plt.plot(X_numpy, y_numpy, 'ro', label='Original Data')
for optimizer_name, prediction in predictions.items():
plt.plot(X_numpy, prediction, label=optimizer_name)
plt.legend()
plt.show()
上面的代码生成预测:
如果我先运行 SGD,则会发生以下情况:
optimizers = {
"Adam": torch.optim.Adam(model.parameters(), lr=learning_rate),
"RMSprop": torch.optim.RMSprop(model.parameters(), lr=learning_rate),
"SGD": torch.optim.SGD(model.parameters(), lr=learning_rate),
}
为什么会这样?
问题是您为所有回归保留相同的模型,这意味着当第一次优化结束时,您将使用经过训练的模型继续进行下一个优化。碰巧学习率只适用于 SGD(对于其他两个优化器来说似乎太大了),所以总结一下这两种情况:
如果从另外两个开始,模型将表现不佳并且模型无法拟合点。在第三次训练(SGD)时,模型将得到正确的训练并拟合点。
如果您从 SGD 开始,它将训练模型,并且随后的两次训练不会太大地改变权重,从而获得相似的性能
相反,您应该重置模型并定义优化器特定的学习率:
optimizers = dict(
RMSprop=(torch.optim.RMSprop, 0.3),
SGD=(torch.optim.SGD, 0.01),
Adam=(torch.optim.Adam, 0.5),
)
for optimizer_name, (klass,lr) in optimizers.items():
model = copy.deepcopy(model_)
optimizer = klass(model.parameters(), lr=lr)
## Proceed with your training loop
通过上述设置,您将得到以下拟合,无论执行顺序如何。
假设您确实想使用不同的优化器继续优化您的模型,那么您的问题是您的问题是凸的。
凸性意味着您有一个最小值,也是全局最小值。这也意味着当您接近最小值点时,梯度会变得越来越小。在凸设置中,逐步走向梯度是一个合理的想法。
因此,当您开始使用 SGD 时,您会接近最小值并且梯度会变小。然后,其他执行次优步骤的算法(当问题是凸的时)不会造成太多混乱,因为梯度已经很小了。
另一方面,如果你从 Adam 开始,你会从错误的步骤开始,然后用 SGD 修复这些步骤,因为对于凸问题,无论起点如何,SGD 都会收敛到最小值