在线性回归中使用梯度下降法每次都要更新都需要遍历所有数据,当数据量大的时候耗时非常大。
于是提出了随机梯度下降法,通过一个随机选取的数据来获取“梯度”,进行更新。
与传统梯度下降法的不同在于,随机梯度的步长变化方向不是固定的,如下图所示,不一定沿着最小方向前进。
在这种情况中eta,即学习率,不能是一个固定值。因为当随机梯度接近最小值没到最小值时,固定的eta可能会使最小值没有更小反而更大了,所以eta要随着随机梯度下降法迭代次数的增加而 减小。
实现过程如下:
#自定义虚拟数据集
import numpy as np
import matplotlib.pyplot as plt
m=100000 #m个样本
x=np.random.normal(size=m)
X=x.reshape(-1,1)
y=4.*x+3.+np.random.normal(0,3,size=m)
def J(theta,X_b,y):
try:
return np.sum((y-X_b.dot(theta)**2)/len(X_b)
except:
return float('inf')
def dJ_sgd(theta,X_b_i,y_i):
return X_b_i.T.dot(X_b_i.dot(theta)-y_i)*2.
def sgd(X_b,y,initial_theta,n_iters):
t0=5
t1=50
def learning_rate(t):
retrun t0/(t+t1)
theta=initial_theta
for cur_iter in range(n_iters):
rand_i=np.random.randint(len(X_b))
gradient=dJ_sgd(theta,X_b[rand_i],y[rand_i])
theta=theta-learning_rate(cur_iter)*gradient
return theta
%%time
X_b=np.hstack([np.ones((len(X),1)),X])
initial_theta=np.zeros(X_b.shape[1])
theta=sgd(X_b,y,initial_theta,n_iters=len(X_b)//3)
运行结果:
可以看出随机梯度下降的准确率和梯度下降差不多,但是时间大大减少了。实际上这里的时间花费只有1/3m。
在sklearn中使用随机梯度下降法
from sklearn.linear_model import SGDRegressor
sgd_reg=SGDRegressor()
%time sgd_reg.fit(x_train_standard,y_train)
sgd_reg.score(x_test_standard,y_test)