上一篇理解梯度下降(二)- spark和python分别实现批量梯度下降 实现了简单的批量梯度下降。最后引出了随机梯度下降(Stochastic gradient descent)。
什么是随机梯度下降,SGD是对全批量梯度下降法计算效率的改进算法。本质上来说,我们预期随机梯度下降法得到的结果和全批量梯度下降法相接近;SGD的优势是更快地计算梯度。
我们先回顾以下全批量法是如何计算每次迭代中的梯度的:
其中N是样本数量,我们很容易看出,对于最小二乘法来说,每计算一次梯度的代价是O(N)O(N),运算次数与N成线性关系。
而随机梯度下降法能将计算一次梯度的代价降低到O(1),也就是运算次数为常数次,与N无关。所以SGD特别适合大训练样本的计算。
SGD在计算∇L时,并不使用全部样本,而是随机地挑选了一个样本,
直接修改一下上一篇文章中BSG的代码,我们在求偏导数之前,每次随机选择一个样本进行迭代。
#coding=utf-8
import random
import numpy as np
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
def data():
x = range(10)
y = [(2*s+4) for s in x]
return x, y
def SGD(x,y):
flag = True
a = 0
b = 0
m = len(x)
arf = 0.05 #学习率
n = 0
sum1 = 0
sum2 = 0
exp = 0.000001
error0 = 0
error1 = 0
while flag:
# for i in range(m):
i = np.random.randint(0, m) #每次随机选择一个样本
#计算对应的偏导数
sum1 = a*x[i]+b-y[i]
sum2 = (a*x[i]+b-y[i])*x[i]
error1 = (a*x[i]+b-y[i])**2
a = a - sum2*arf/m #对a,b进行更新
b = b - sum1*arf/m
if abs(error1-error0)<exp: #计算误差
break
error0 = error1
print('a=%f,b=%f,error=%f' % (a, b, error1))
if n > 1000:
break
n += 1
if n % 10 == 0:
print('第%d次迭代:a=%f,b=%f' % (n, a, b))
return a,b
if __name__ == '__main__':
x,y = data()
a,b = SGD(x,y)
print('梯度下降BGD: y=%fX+%f'%(a,b))
部分结果如下:
...
a=2.111940,b=3.158513,error=0.079138
a=2.119525,b=3.161042,error=0.255698
a=2.119525,b=3.165236,error=0.703851
a=2.126668,b=3.167617,error=0.226755
a=2.131644,b=3.168613,error=0.039618
第1000次迭代:a=2.131644,b=3.168613
a=2.135143,b=3.172111,error=0.489641
a=2.140719,b=3.174899,error=0.310921
梯度下降BGD: y=2.140719X+3.174899