在学习了有关梯度下降算法后,自己动手实现了一遍,选用的也是最为简单的线性回归作为例子
梯度下降的的相关原理及推导网上有很多,由于个人不擅长推理总结,我就不再画蛇添足了,贴几个我看完之后觉的不错的帖子,在此感谢各位博主
深度解读最流行的优化算法:梯度下降
一文看懂常用的梯度下降算法
梯度下降的三种形式BGD、SGD、以及MBGD
梯度下降的三种形式BGD、SGD、以及MBGD
最后两个是不同的博客,但他们的标题相同
三种算法中文名分别为
批量梯度下降(Batch gradient descent)
随机梯度下降(Stochastic gradient descent)
小批量梯度下降(Mini-batch gradient descent)
不过都叫梯度下降算法,可见他们的核心是没有变的,变化的只是取训练集的方式,而梯度下降最核心的就是对函数求偏导,这个是在高等数学里有的。
首先是BGD,他是使用所有数据集进行训练。具体代码为:
import matplotlib.pyplot as plt
import random
import matplotlib
#生成数据
def data():
x = range(10)
y = [(2*s+4) for s in x]
for i in range(10):
y[i] = y[i]+random.randint(0,8)-4
return x, y
#使用梯度下降进行训练
def diedai(x,y):
flag = True
a = random.randint(0,5)
b = random.randint(0,10)
m = len(x)
arf = 0.005 #学习率
n = 0
sum1 = 0
sum2 = 0
exp = 0.000001
error0 = 0
error1 = 0
while flag:
for i in range(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) 500:
#flag = False
break
n += 1
if n % 10 == 0:
print('第%d次迭代:a=%f,b=%f' % (n, a, b))
return a,b
#使用最小二乘法计算结果
def calculation(x, y):
c1 = 0
c2 = 0
c3 = 0
c4 = 0
n = len(x)
for i in range(n):
c1 += x[i]*y[i]
c2 += x[i]*x[i]
c3 += x[i]
c4 += y[i]
a = (n*c1-c3*c4) /( n*c2-c3*c3) #利用公式计算a, b
b = (c2*c4-c3*c1) / (n*c2-c3*c3)
return a, b
if __name__ == '__main__':
x,y = data()
a1,b1 = diedai(x,y)
X1 = range(10)
Y1 = [(a1*s+b1) for s in X1]
print('梯度下降y=%fX+%f'%(a1,b1))
a2,b2 = calculation(x,y)
X2 = range(10)
Y2 = [(a2*s+b2) for s in X2]
print('最小二乘法y=%fX+%f'%(a2,b2))
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] #设置字体中文,防止乱码
plt.scatter(x, y, color = 'red',label = '数据')
plt.plot(X1, Y1, color = 'blue',label = '梯度下降')
plt.plot(X2, Y2, color = 'green',label = '最小二乘法')
plt.legend()
plt.show()
这里我使用了最小二乘法作为参考
训练的结果为
可以很明显的看出,两种方法是存在偏差的,至于原因我也很想知道,也许是梯度下降算法作为迭代算法迭代的不够彻底,不过这也只是我的猜测,希望谁知道的能和我透露一下
批量梯度下降算法由于是使用了所有的数据集,因此,当数据集很大时,他的计算会出现溢出,或者计算时间非常长的问题,而随机梯度下降算法就很好的解决了问题,他的每次迭代使用的是一组数据,也就是一个结果(y)和他对应的变量(x),下面是他的代码:
from matplotlib import pyplot as plt
import random
#生成数据
def data():
x = range(10)
y = [(2*i+4) for i in x]
for i in range(10):
y[i] = y[i]+random.randint(0,8)-4
return x,y
#使用随机梯度下降训练
def SGD(x,y):
error0 = 0
step_size = 0.001
esp = 1e-6
#a = random.randint(0,4)
#b = random.randint(0,8)
a = 1.2 #将给a,b随机赋初始值
b = 3.5
m = len(x)
n = 0
while True:
i = random.randint(0,m-1)
print(i)
sum0 = a * x[i] + b - y[i]
sum1 = (a * x[i] + b - y[i])*x[i]
error1 = (a * x[i] + b - y[i])**2 #计算模型和结果的误差
a = a - sum1*step_size/m
b = b - sum0*step_size/m
print('a=%f,b=%f,error=%f'%(a,b,error1))
if abs(error1-error0)500):
break
return a,b
if __name__ == '__main__':
x,y = data()
a,b = SGD(x,y)
X = range(10)
Y = [(a*i+b) for i in X]
plt.scatter(x,y,color='red')
plt.plot(X,Y)
plt.show()
运算结果为:
和批量梯度下降算法一样他也能很好的得到结果,不过这个算法也存在缺陷,那就是由于每次迭代只是用一组数据,因此他受噪声/离群点/异常值的影响非常大,由此有了一种折中的方法,那就只小批量梯度下降算法,他在每次迭代时使用一批数据,这批数据可以自行选择也可以随机产生,大小也可自由自定,越大越接近批量梯度下降算法,越小越接近随机梯度下降算法,下面是我的代码:
from matplotlib import pyplot as plt
import random
#生成数据
def data():
x = range(10)
y = [(3*i+2) for i in x]
for i in range(len(y)):
y[i] = y[i]+random.randint(0,5)-3
return x,y
#用小批量梯度下降算法进行迭代
def MBGD(x,y):
error0 = 0
error1 = 0
n = 0
m = len(x)
esp = 1e-6
step_size = 0.01 #选择合理的步长
a = random.randint(0,10) #给a,b赋初始值
b = random.randint(0,10)
while True:
trainList = []
for i in range(5): #创建随机的批量
trainList.append(random.randint(0,m-1))
for i in range(5): #对数据进行迭代计算
s = trainList[i]
sum0 = a*x[s]+b-y[s]
sum1 = (a*x[s]+b-y[s])*x[s]
error1 = error1+(a*x[s]+b-y[s])**2
a = a - sum1*step_size/m
b = b - sum0*step_size/m
print('a=%f,b=%f,error=%f'%(a,b,error1))
if error1-error0500:
break
return a, b
if __name__ == '__main__':
x,y = data()
a,b = MBGD(x,y)
X = range(len(x))
Y = [(a*i+b) for i in X]
plt.scatter(x,y,color='red')
plt.plot(X,Y,color='blue')
plt.show()
运行结果为:
这就是三种梯度下降算法了,有什么问题欢迎各位指正