使用 NumPy 的 LMS 批量梯度下降
LMS batch gradient descent with NumPy
我正在尝试编写一些非常简单的 LMS 批量梯度下降,但我认为我在梯度方面做错了。 theta
的数量级与初始值之间的比率对于 theta
的元素非常不同,因此 theta[2]
不会移动(例如,如果 alpha = 1e-8
)或theta[1]
发射(例如如果 alpha = .01
)。
import numpy as np
y = np.array([[400], [330], [369], [232], [540]])
x = np.array([[2104,3], [1600,3], [2400,3], [1416,2], [3000,4]])
x = np.concatenate((np.ones((5,1), dtype=np.int), x), axis=1)
theta = np.array([[0.], [.1], [50.]])
alpha = .01
for i in range(1,1000):
h = np.dot(x, theta)
gradient = np.sum((h - y) * x, axis=0, keepdims=True).transpose()
theta -= alpha * gradient
print ((h - y)**2).sum(), theta.squeeze().tolist()
所写的算法是完全正确的,但是如果没有特征缩放,收敛会非常慢,因为一个特征将控制梯度计算。
您可以通过多种方式执行缩放;现在,让我们按 L^1 范数来缩放特征,因为它很简单
import numpy as np
y = np.array([[400], [330], [369], [232], [540]])
x_orig = np.array([[2104,3], [1600,3], [2400,3], [1416,2], [3000,4]])
x_orig = np.concatenate((np.ones((5,1), dtype=np.int), x_orig), axis=1)
x_norm = np.sum(x_orig, axis=0)
x = x_orig / x_norm
也就是说,x
中每列的总和为 1。如果您想保留对正确参数的正确猜测,则必须相应地缩放这些参数。
theta = (x_norm*[0., .1, 50.]).reshape(3, 1)
有了这个,我们可能会像您在原始 post 中所做的那样继续,您将不得不再次调整学习率,直到找到最佳点。
alpha = .1
for i in range(1, 100000):
h = np.dot(x, theta)
gradient = np.sum((h - y) * x, axis=0, keepdims=True).transpose()
theta -= alpha * gradient
现在让我们看看我们得到了什么,因为我们发现了一些似乎收敛的东西。同样,您的参数必须缩放以与原始未缩放的特征相关。
print (((h - y)**2).sum(), theta.squeeze()/x_norm)
# Prints 1444.14443271 [ -7.04344646e+01 6.38435468e-02 1.03435881e+02]
至此,让我们作弊并检查我们的结果
theta, error, _, _ = np.linalg.lstsq(x_orig, y)
print(error, theta)
# Prints [ 1444.1444327] [[ -7.04346018e+01]
# [ 6.38433756e-02]
# [ 1.03436047e+02]]
关于特征缩放的一般介绍性参考是 this Stanford lecture。
我正在尝试编写一些非常简单的 LMS 批量梯度下降,但我认为我在梯度方面做错了。 theta
的数量级与初始值之间的比率对于 theta
的元素非常不同,因此 theta[2]
不会移动(例如,如果 alpha = 1e-8
)或theta[1]
发射(例如如果 alpha = .01
)。
import numpy as np
y = np.array([[400], [330], [369], [232], [540]])
x = np.array([[2104,3], [1600,3], [2400,3], [1416,2], [3000,4]])
x = np.concatenate((np.ones((5,1), dtype=np.int), x), axis=1)
theta = np.array([[0.], [.1], [50.]])
alpha = .01
for i in range(1,1000):
h = np.dot(x, theta)
gradient = np.sum((h - y) * x, axis=0, keepdims=True).transpose()
theta -= alpha * gradient
print ((h - y)**2).sum(), theta.squeeze().tolist()
所写的算法是完全正确的,但是如果没有特征缩放,收敛会非常慢,因为一个特征将控制梯度计算。
您可以通过多种方式执行缩放;现在,让我们按 L^1 范数来缩放特征,因为它很简单
import numpy as np
y = np.array([[400], [330], [369], [232], [540]])
x_orig = np.array([[2104,3], [1600,3], [2400,3], [1416,2], [3000,4]])
x_orig = np.concatenate((np.ones((5,1), dtype=np.int), x_orig), axis=1)
x_norm = np.sum(x_orig, axis=0)
x = x_orig / x_norm
也就是说,x
中每列的总和为 1。如果您想保留对正确参数的正确猜测,则必须相应地缩放这些参数。
theta = (x_norm*[0., .1, 50.]).reshape(3, 1)
有了这个,我们可能会像您在原始 post 中所做的那样继续,您将不得不再次调整学习率,直到找到最佳点。
alpha = .1
for i in range(1, 100000):
h = np.dot(x, theta)
gradient = np.sum((h - y) * x, axis=0, keepdims=True).transpose()
theta -= alpha * gradient
现在让我们看看我们得到了什么,因为我们发现了一些似乎收敛的东西。同样,您的参数必须缩放以与原始未缩放的特征相关。
print (((h - y)**2).sum(), theta.squeeze()/x_norm)
# Prints 1444.14443271 [ -7.04344646e+01 6.38435468e-02 1.03435881e+02]
至此,让我们作弊并检查我们的结果
theta, error, _, _ = np.linalg.lstsq(x_orig, y)
print(error, theta)
# Prints [ 1444.1444327] [[ -7.04346018e+01]
# [ 6.38433756e-02]
# [ 1.03436047e+02]]
关于特征缩放的一般介绍性参考是 this Stanford lecture。