在numpy中创建简单的线性回归模型后,我发现改变步长/学习率并不能有效提高模型的准确性或收敛速度。请注意给出此标准模型:
%%time
x = np.arange(100)
y = 3 * x + 5
x = np.column_stack((np.ones(100), x))
w = np.zeros((100, 2))
step_size = 10**-4
iterations = 10**5
for i in range(iterations):
loss = 2 * (np.sum(w * x, axis=1) - y)
w -= step_size * np.average(x * loss[:, None], axis=0)
print(w[0])
模型提供以下输出:
[4.60820653 3.00590689]
CPU times: user 5.04 s, sys: 19.9 ms, total: 5.06 s
Wall time: 5.07 s
更改step_size变量可以被视为超参数优化,但是当将其更改为大于10-4的任何值时,例如10-3,模型无法收敛并爆炸:
# step_size = 10**-3
[nan nan]
CPU times: user 4.98 s, sys: 38.2 ms, total: 5.02 s
Wall time: 5 s
这种行为在数学上是符合预期的,但遇到这种情况令人沮丧,并引出了一个问题:如何更有效地优化步长?
我尝试更改与梯度相关的系数(我将梯度变量标记为“损失”),而不是更改步长,因为这也会影响每个步骤的戏剧性(据我所知)给定更大或损失更小,因此下降的梯度更陡。令人惊讶的是,将损失系数从 2 更改为 5 显着提高了性能(这正是我所做的,而不是优化步长,但我想这是一个单独的主题)。
# changing loss coefficient from 2 to 5
[4.99998468 3.00000023]
CPU times: user 5.03 s, sys: 42.7 ms, total: 5.07 s
Wall time: 5.08 s
将步长从
10**-4
增加到 10**-3
相当于 10 倍的增量。那是1000%。看似很小的数字,但差别却很大。考虑将步数加倍,例如等:
w = np.zeros(2)
step_size = 0.0001
iterations = 10**5
for i in range(iterations):
direction = (x @ w - y) @ x/y.size
w -= step_size * direction
w
array([4.60820653, 3.00590689])
不同的步长
w = np.zeros(2)
step_size = 0.0005
iterations = 10**5
for i in range(iterations):
direction = (x @ w - y) @ x/y.size
w -= step_size * direction
w
array([4.99998468, 3.00000023])
在此示例中,步长不能超过 0.0006。