
在使用PyTorch进行模型训练时,开发者有时会遇到参数看似没有更新的问题,即使已正确调用优化器。本文将深入探讨这一常见现象,揭示其背后往往是学习率设置过低,导致参数更新幅度相对于参数自身值或梯度而言微不足道。我们将通过代码示例和详细分析,演示如何诊断并解决此类问题,强调学习率在优化过程中的关键作用。
在PyTorch中,模型的参数更新是深度学习训练的核心环节。一个典型的优化循环包括以下几个关键步骤:
当开发者遵循这些步骤,但仍然观察到参数没有明显变化时,问题可能并非出在代码逻辑错误,而在于优化过程的细节。
考虑以下PyTorch优化代码示例,它尝试优化一组“份额”(shares)以匹配目标权重:
import torch
import numpy as np
np.random.seed(10)
def optimize(final_shares: torch.Tensor, target_weight, prices, loss_func=None):
# 确保份额非负
final_shares = final_shares.clamp(0.)
# 计算市值
mv = torch.multiply(final_shares, prices)
# 计算权重
w = torch.div(mv, torch.sum(mv))
# print(w) # 调试时可以打印权重
return loss_func(w, target_weight)
def main():
position_count = 16
cash_buffer = .001
starting_shares = torch.tensor(np.random.uniform(low=1, high=50, size=position_count), dtype=torch.float64)
prices = torch.tensor(np.random.uniform(low=1, high=100, size=position_count), dtype=torch.float64)
prices[-1] = 1.
# 定义可学习参数
x_param = torch.nn.Parameter(starting_shares, requires_grad=True)
# 定义目标权重
target_weights = ((1 - cash_buffer) / (position_count - 1))
target_weights_vec = [target_weights] * (position_count - 1)
target_weights_vec.append(cash_buffer)
target_weights_vec = torch.tensor(target_weights_vec, dtype=torch.float64)
# 定义损失函数
loss_func = torch.nn.MSELoss()
# 初始化优化器,学习率 eta 设置为 0.01
eta = 0.01
optimizer = torch.optim.SGD([x_param], lr=eta)
print(f"初始参数 x_param: {x_param.data[:5]}") # 打印前5个初始参数
initial_loss = optimize(final_shares=x_param, target_weight=target_weights_vec,
prices=prices, loss_func=loss_func)
print(f"初始损失: {initial_loss.item():.6f}")
for epoch in range(10000):
optimizer.zero_grad()
loss_incurred = optimize(final_shares=x_param, target_weight=target_weights_vec,
prices=prices, loss_func=loss_func)
loss_incurred.backward()
# 可以在此处打印梯度信息进行调试
# if epoch % 1000 == 0:
# print(f"Epoch {epoch}, Loss: {loss_incurred.item():.6f}, Avg Grad: {x_param.grad.abs().mean().item():.8f}")
# print(f"x_param (before step): {x_param.data[:5]}")
optimizer.step()
# if epoch % 1000 == 0:
# print(f"x_param (after step): {x_param.data[:5]}")
final_loss = optimize(final_shares=x_param.data, target_weight=target_weights_vec,
prices=prices, loss_func=loss_func)
print(f"最终参数 x_param: {x_param.data[:5]}") # 打印前5个最终参数
print(f"最终损失: {final_loss.item():.6f}")
if __name__ == '__main__':
main()运行上述代码,你会发现x_param的值在10000个epoch后几乎没有变化,损失值也只是略微下降。这让人误以为参数没有更新。
问题的核心在于学习率(learning_rate或lr)与梯度(grad)以及参数自身尺度的不匹配。
参数更新的幅度由 learning_rate * grad 决定。如果这个乘积非常小,即使参数确实在更新,其变化也可能微乎其微,以至于在视觉上或通过打印参数值时难以察觉。
在上述示例中:
这意味着,每次迭代参数的平均变化量仅为 1e-7。要使一个平均值为 24 的参数值发生 1 单位的变化,大约需要 24 / 1e-7 = 2.4 * 10^8 次迭代。而代码中只有 10000 次迭代,因此参数的变化量是极其微小的,几乎可以忽略不计。
解决这个问题最直接有效的方法是调整学习率。如果学习率过低导致更新不明显,那么就需要适当提高学习率。
将eta从0.01调整为100,观察参数的变化:
# ... (代码省略,与上文相同的部分) ...
# 初始化优化器,学习率 eta 调整为 100
eta = 100
optimizer = torch.optim.SGD([x_param], lr=eta)
print(f"初始参数 x_param: {x_param.data[:5]}")
initial_loss = optimize(final_shares=x_param, target_weight=target_weights_vec,
prices=prices, loss_func=loss_func)
print(f"初始损失: {initial_loss.item():.6f}")
for epoch in range(10000):
optimizer.zero_grad()
loss_incurred = optimize(final_shares=x_param, target_weight=target_weights_vec,
prices=prices, loss_func=loss_func)
loss_incurred.backward()
optimizer.step()
# 打印中间结果以便观察
if epoch % 1000 == 0 or epoch == 9999:
print(f"Epoch {epoch}, Loss: {loss_incurred.item():.6f}, Avg Grad: {x_param.grad.abs().mean().item():.8f}")
print(f"x_param (after step, first 5): {x_param.data[:5]}")
final_loss = optimize(final_shares=x_param.data, target_weight=target_weights_vec,
prices=prices, loss_func=loss_func)
print(f"最终参数 x_param: {x_param.data[:5]}")
print(f"最终损失: {final_loss.item():.6f}")
# ... (main 函数和 if __name__ == '__main__': 保持不变) ...通过将学习率提高到100,每次参数更新的平均幅度将变为 100 * 1e-5 = 1e-3。这个更新幅度相对于参数的原始值 24 来说已经显著得多,因此在10000次迭代后,参数和损失值都会有明显的、可观察到的变化。
当PyTorch模型参数看似没有更新时,首先应检查优化循环的逻辑是否正确。如果逻辑无误,那么最常见的原因是学习率设置过低。通过理解参数更新的机制(param = param - learning_rate * grad),我们可以推断出,当learning_rate * grad的乘积相对于参数的原始尺度过小时,参数的变化将难以察觉。通过适当调整学习率,通常可以有效解决这一问题。在实践中,合理地选择和调整学习率是模型训练成功的关键一步。
以上就是PyTorch参数更新不明显?深度解析学习率与梯度尺度的影响的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号