什么是梯度下降法
梯度下降法已经有很多其他博主做了充分的介绍,可以自行百度,我个人觉得Evan这个帖子讲的很清楚。这里不在赘述,感兴趣的可以自行查阅。
代码实现梯度下降法
-
批量梯度下降法(batch_gradient_descent)
批量梯度下降法指的是在每次调整梯度寻找最优解的时候都将所有样本考虑在内。优点:收敛的最优解准确,数量级小时收敛也很快。
缺点:样本数量多时,收敛速度慢,更新一次梯度需要很长时间。
代码实现:
import numpy as np
import time
start = time.process_time()
# 这里相当于是随机X维度X1,rand是随机均匀分布
for i in range(0,5):
X = 2 * np.random.rand(100, 1)
# 人为的设置真实的Y一列,np.random.randn(100, 1)是设置error,randn是标准正太分布
y = 4 + 3 * X + np.random.randn(100, 1)
# 整合X0和X1
X_b = np.c_[np.ones((100, 1)), X]
learn_rate = 0.1
m = 100
t = 2000
theta = np.random.randn(2, 1)
for i in range(t):
gradient = 1 / m * X_b.T.dot(X_b.dot(theta) - y)
theta = theta - learn_rate * gradient
print(theta)
end = time.process_time()
print(end-start)
可以看出,在代码中我设置的迭代次数为2000,样本数量为100,维度为2。结果如下:
在2000次迭代的情况下,执行五次梯度下降,时间为0.046875s,平均每次0.009375s
- 随机梯度下降法:
随机梯度下降法指的是在每次调整梯度寻找最优解的时候只随机考虑一个样本。
优点:不需要考虑所有样本,比批量梯度下降法高效。
缺点:得到的可能不是全局最优解,会受到某个离群样本的干扰。
代码实现:
import numpy as np
import matplotlib.pyplot as plt
import time
start = time.process_time()
# 这里相当于是随机X维度X1,rand是随机均匀分布
for i in range(0, 5):
X = 2 * np.random.rand(100, 1)
# 人为的设置真实的Y一列,np.random.randn(100, 1)是设置error,randn是标准正太分布
y = 4 + 3 * X + np.random.randn(100, 1)
# 整合X0和X1
X_b = np.c_[np.ones((100, 1)), X]
t0 = 5
t1 = 50
m = 100
t = 20
def change_learning_rate(lr):
return t0 / (t1 + lr)
theta = np.random.randn(2, 1)
for i in range(t):
for j in range(m):
temp = np.random.randint(0, m)
xi = X_b[temp:temp + 1]
yi = y[temp:temp + 1]
gradient = 2 * xi.T.dot(xi.dot(theta) - yi)
learn_rate = change_learning_rate(i * m + j)
theta = theta - learn_rate * gradient
print(theta)
end = time.process_time()
print(end - start)
可以看出,在同等条件下,为了限制随机梯度下降的步长,动态变化了学习率。结果为:
同样的条件,与批量梯度下降相比,效率更高,但是收敛的结果距离最优解的差别也大于批量梯度下降。
-
mini-batch梯度下降
mini-batch梯度下降指的是上述两个办法的一种折中方案,既考虑了随机梯度下降准确性的问题,又考虑了批量梯度下降效率的问题,每次取一部分样本进行更新梯度。
优点:比批量梯度下降法高效,比随机梯度下降法准确性好。
缺点:处于两个方法中间,准确性和效率都并非最高。
代码实现:
import numpy as np
import matplotlib.pyplot as plt
import time
start = time.process_time()
# 这里相当于是随机X维度X1,rand是随机均匀分布
for i in range(0,5):
X = 2 * np.random.rand(100, 1)
# 人为的设置真实的Y一列,np.random.randn(100, 1)是设置error,randn是标准正太分布
y = 4 + 3 * X + np.random.randn(100, 1)
# 整合X0和X1
X_b = np.c_[np.ones((100, 1)), X]
t0 = 5
t1 = 50
m = 100
t = 20
b = 20
def change_learning_rate(lr):
return t0/(t1+lr)
#初始化theta的随机值
theta = np.random.randn(2, 1)
for i in range(t):
for j in range(m):
temp = np.random.randint(0,m-b)
xi = X_b[temp:temp+b]#取b个样本
yi = y[temp:temp+b]
gradient = 1/b*xi.T.dot(xi.dot(theta) - yi)
learn_rate = change_learning_rate(i*m+j)
theta = theta - learn_rate * gradient
print(theta)
end = time.process_time()
print(end-start)
结果:
可以看出,准确性要高于随机梯度下降法,运行时间小于批量梯度下降法。