机器学习(7)--梯度下降法(GradientDescent)的简单实现

曾经在  机器学习(1)--神经网络初探  详细介绍了神经网络基本的算法,在该文中有一句
weights[i] += 0.2 * layer.T.dot(delta)  #0.2学习效率,应该是一个小于0.5的数,
同时在  tensorflow实例(2)--机器学习初试 篇文章中用tensorflow实现上述的神经网络算法,该文中也有一句
train=tf.train.GradientDescentOptimizer(0.25).minimize(loss) #梯度下降优化器,0.25学习效率,应该是一个小于0.5的数, 
这两句里都有一个学习率的参数,

在 tensorflow实例(6)--机器学习中学习率的实验 中得到一个结论 

当神经元越多时,我们的学习率应该越小,同时学习次数应该增加

在这三个案例中,都使用到了学习率,同时在第三例中的结论并不完全,因为这里的学习率其实和梯度下降法息息相关


本文将通过一个简单的案例来说演示一组数据在使用梯度下降法后会得到效果,也更容易理解学习率设置差异导致错误的原因
至于梯度下降要深入的话数理模型也是好多好多,想深入了解的朋友可自行百度一下,
本文会虚拟一组由100个样本组成的一元一次方程组的数据,并通过matplotlib.pyplot来演示数据变化,
之所以使用一元一次有以下两个原因,
1、仅使用一次的原因是神经网络使用的都是线性方程,多次的方程也是可以,只是要通过神经网络等方式进行调整,不适合本文的内容

2、使用一元的原因,是为了matplotlib.pyplot显示的了,本文中的梯度下降函数是可适用于多元线性方程的

# -*- coding:utf-8 -*-
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt


#构建数据
#带有后缀_data的变量是简单虚拟出来的数据,相当于实际后的样本数据,
#不含后缀_data的变量就是我们建模时的变量,也就是我们最后的求解
def create_data(a,b):
    '''
    一元一次的方程为y=a*x+b 在构建这个数据时,x_data[:,0]为0-99 代表的是X的坐表,x_data[:,1]为常量1
    ,因为我们后面要用到矩阵乘法和b,相当于留个位给b,用于计算
     y最后np.random.uniform(0,1,[100])*(b/2),产生一个随机数,
     这样使得y的数据更加真实也更能看出梯度下降后的效果,以下是x的值,y值根据a,b的值的不同发生变化
    [[ 0.  1.]
     [ 1.  1.]
     [ 2.  1.]
     ...
     [99.  1.]
    '''
    x=np.array([np.arange(100),np.ones(100)]).T
    y = x[:,0]*a + b + np.random.uniform(-1,1,[100])*b
    return x,y


x_data,y_data=create_data(2,25)
weight=np.ones(x_data.shape[1]) #初始化weight,其实这个weight的最后一个相当于b的位置
xt=x_data.T
weightStep=[]#用于存存下降过程中计算结果,后面绘图需要
for i in range(100000):
    y=np.dot(x_data,weight) #以weight为参数计测试值
    loss=y-y_data   #计算实际值与测试值之间的差额
    #也是cost,并不参于最后计算,这是一种简单方法loss的一个转换,由100个数据转为一个数据
    #简单的公式推导一下就可以发现,如果y和y_data相等时,cost=0,当然因为我们加了随机数,等于0是不可能的
    #可以将这个理解为返映测试值y的好坏的一个值,当这个值越小时说明我们的weight质量越好,
    cost=np.sum(loss ** 2) / (2 * x_data.shape[0])   

    gradient=np.dot(xt,loss) /  x_data.shape[0]    # 计算梯度

    #0.0005就是学习率,如果简单将这个值调大,就会造成weight往无限大的方向扩大,当然太小的话计算次数也需要增加
    #前面说的,当神经元越多时,我们的学习率应该越小,同时学习次数应该增加,,最终原因也在这
    weight=weight-0.0005*gradient 
    if i % 20000==0 or i <10:#每10000次显示一次结果,之所以还i <10因为前期数值变化明显,后面变化其实并不大
        print(i,cost,weight)
        weightStep.append(weight)
weightStep.append(weight)


plt.axis([0,110,0,150]) # 用于定义X,Y轴的范围
plt.scatter(x_data[:,0],y_data,c='b')  # 后面图中蓝色的点为样本数据
plt.ion()#该命令的作用是plt.show()是不暂停,
plt.show()


pltStep=None
for weight in weightStep:
    if pltStep!=None : pltStep.remove();#如果绘制过了红点,则清除,进行下一次的绘制
    y=np.dot(x_data,weight)
    print(weight,y_data[0],y[0])
    pltStep=plt.scatter(x_data[:,0],y,c='r')  # 后面图中红色的点为计算出来的数据,因为是一元一次,组成的应该是一条直线
    plt.pause(0.6)#暂停0.6秒 
#通过图案可以看到一开始的红点直线和原来蓝点毫无关联,但最后,基本中从散点分布的蓝点中间穿过,也证明了我们的梯度降维是有效的


你可能感兴趣的:(python,机器学习)