如何为PyTorch实现的梯度下降添加噪声以找到所有局部极小值?
给梯度下降添加噪声以找到多个局部极小值
首先明确你的目标函数 ( f(a) = a^4 - a^3 - a^2 + a - 1 ) 存在两个局部极小值,位置大致在 a≈-0.65 和 a≈1.24(通过求导找临界点并结合二阶导数判断得出)。原代码固定初始值为-5.0,只会收敛到左侧的局部极小值;要找到两个极小值,可通过添加噪声让算法有机会跳出当前极小值区域,或结合随机初始点覆盖不同收敛范围。
方法1:参数更新时添加高斯噪声
在每次梯度更新后给参数加上小幅度高斯噪声,当算法陷入某个局部极小值时,噪声有概率推动参数跳出,进而收敛到另一个极小值。噪声标准差需合理调整:太小可能跳不出当前极小值,太大则会导致训练不稳定。
修改后的代码示例:
import torch alpha = 0.001 noise_std = 0.08 # 噪声标准差,可根据效果调整 num_runs = 5 # 多次运行提升找到不同极小值的概率 def function(a): return a**4 - a**3 - a**2 + a - 1 # 多次运行,每次用随机初始点 for run in range(num_runs): # 在[-4,2]范围内随机生成初始点 start_val = torch.randn(1) * 3 - 1 x = torch.tensor(start_val, requires_grad=True) print(f"\n=== 第 {run+1} 次运行 ===") for i in range(1500): # 增加迭代次数确保收敛 loss = function(x) loss.backward() # 梯度更新 + 添加高斯噪声 noise = torch.normal(mean=0.0, std=noise_std, size=x.shape) new_val = x - alpha * x.grad + noise # 重置梯度 x = new_val.detach().clone().requires_grad_() # 每200次迭代打印状态 if i % 200 == 0: print(f"迭代 {i}: x = {float(x):.4f}, f(x) = {float(function(x)):.4f}") final_x = float(x) final_loss = float(function(x)) print(f"最终收敛点: x = {final_x:.4f}, 函数值: {final_loss:.4f}")
方法2:随机初始点+噪声结合
梯度下降的收敛结果高度依赖初始点,直接在不同随机初始点上运行梯度下降(无需每次更新加噪声),也能覆盖不同收敛区域:初始点落在左侧区域(如<0)会收敛到左极小值,落在右侧区域(如>0.5)会收敛到右极小值。
简化版代码示例:
import torch alpha = 0.001 num_runs = 4 def function(a): return a**4 - a**3 - a**2 + a - 1 # 指定不同初始点,或随机生成 start_points = [-5.0, 2.0, -1.0, 1.5] for idx, start_val in enumerate(start_points): x = torch.tensor(start_val, requires_grad=True) print(f"\n=== 初始点 {start_val} 的运行结果 ===") for i in range(1000): loss = function(x) loss.backward() new_val = x - alpha * x.grad x = new_val.detach().clone().requires_grad_() final_x = float(x) final_loss = float(function(x)) print(f"收敛点: x = {final_x:.4f}, 函数值: {final_loss:.4f}")
关键注意事项
- 噪声强度:建议从0.05~0.1的标准差开始调试,平衡跳出能力与收敛稳定性。
- 迭代次数:添加噪声后需适当增加迭代次数,确保参数能稳定收敛到极小值。
- 结果去重:多次运行后可能得到重复收敛点,可通过判断x的相似度或函数值的接近度过滤重复结果。
内容的提问来源于stack exchange,提问作者Siddd
相关产品推荐
相关产品推荐

