简单线性回归训练实现(Tensorflow)

 

一、算法简介

1.1 什么是回归分析

回归分析是一种预测性的建模技术,它研究的是因变量(目标)和自变量(预测器)之间的关系。这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。通常使用曲线/线来拟合数据点,目标是使曲线到数据点的距离差异最小。

1.2 线性回归

线性回归是回归问题中的一种,线性回归假设目标值与特征之间线性相关,即满足一个多元一次方程。通过构建损失函数,来求解损失函数最小时的参数w和b。通长我们可以表达成如下公式:

y^为预测值,自变量x和因变量y是已知的,而我们想实现的是预测新增一个x,其对应的y是多少。因此,为了构建这个函数关系,目标是通过已知数据点,求解线性模型中w和b两个参数。

1.3 目标/损失函数

求解最佳参数,需要一个标准来对结果进行衡量,为此我们需要定量化一个目标函数式,使得计算机可以在求解过程中不断地优化。

针对任何模型求解问题,都是最终都是可以得到一组预测值y^ ,对比已有的真实值 y ,数据行数为 n ,可以将损失函数定义如下:

即预测值与真实值之间的平均的平方距离,统计中一般称其为MSE(mean square error)均方误差。把之前的函数式代入损失函数,并且将需要求解的参数w和b看做是函数L的自变量,可得

现在的任务是求解最小化L时w和b的值,

即核心目标优化式为

求解方式有两种:

1)最小二乘法(least square method)

求解 w 和 b 是使损失函数最小化的过程,在统计中,称为线性回归模型的最小二乘“参数估计”(parameter estimation)。我们可以将 L(w,b) 分别对 w 和 b 求导,得到

令上述两式为0,可得到 w 和 b 最优解的闭式(closed-form)解:

 

2)梯度下降(gradient descent)

梯度下降核心内容是对自变量进行不断的更新(针对w和b求偏导),使得目标函数不断逼近最小值的过程

这里不做展开讲解。本文将使用Tensorflow中自带的梯度下降函数,来实现简单的线性回归训练。

二、实现过程

2.1 获得训练集(已知数据点)

我们假设有这样的一个多元一次方程,y=0.8x+0.7这个方程展示在坐标系内,是一条直线。

我们现在需要获得100个随机的,但是要符合上面方程特征的一个数据集,来做为我们的已知数据点

这部分操作在python代码里这样操作:

import tensorflow as tf


def test():
    # 1.获得100个随机数据集 y = 0.8x + 0.7
    # 随机数 X 是 二维矩阵 [100,1] x 0.8 + 0.7
    X = tf.random_normal([100, 1], mean=0.0, stddev=1.0, name='get_data_X')
    # 进行矩阵运算,0.8 需要是二维数组
    y_true = tf.matmul(X, [[0.8]]) + [[0.7]]

代码解释:首先我们需要使用tensorflow中创建随机张量的函数tf.random_normal()来创建随机张量X,函数第一个参数表示张量的形状,是一个100行1列的一个二维矩阵,mean参数代表着随机数符合正态分布的均值,说白话就是正态分布钟形曲线的x轴中心点,这个值默认为0。stddev参数表示正态分布曲线的标准差σ,它会影响正态分布曲线的高度,这个值默认为1。name参数表示该操作的名称,可自由定义。

其次我们需要创建一个计算,tf.matmul()函数提供了让两个张量相乘的操作,上面说到,随机张量X是一个二维矩阵,为了能做计算,算式中的0.8需要转换为二维张量,即一个1行1列的二维矩阵,代码中表示为[[0.8]]。同样后面相加的0.7也做相同处理,此时我们就得到了一个符合y=0.8x+0.7这个算式的,100行1列的二维矩阵,这个就是我们需要的真实值。要是还不太懂,可看下图:

2.2创建一个线性回归模型

这个回归模型比较简单,从上图我们可以得知,模型需要符合最基本的特征,那就是[100,1]*[1,1]+[1,1]这个意思就是一个100行1列的二维张量乘以一个1行1列的二维张量,最后再与一个1行1列的二维张量相加,这个就是模型的基本样式。

直接上代码:

import tensorflow as tf

def test():
    # 1.获得100个随机数据集 y = 0.8x + 0.7
    # 随机数 X 是 二维矩阵 [100,1] x 0.8 + 0.7
    X = tf.random_normal([100, 1], mean=0.0, stddev=1.0, name='get_data_X')
    # 进行矩阵运算,0.8 需要是二维数组
    y_true = tf.matmul(X, [[0.8]]) + [[0.7]]
    # 2.建立回归模型
    # 模型是 [100,1] * [1,1] + [1,1]
    # 两个参数 (W,0.8) (D,0.7)
     W = tf.Variable(initial_value=(tf.random_normal([1, 1])), name='w')
     B = tf.Variable(initial_value=(tf.random_normal([1, 1])), name='b')
    # 进行矩阵运算
    y_predict = tf.matmul(X, W) + B

在tensorflow中可训练的数据叫做变量,我们需要训练的两个参数,W和B,模型的表达式就为 y=Wx+B,这里可能会有人疑惑,上面不是讲了,y=0.8x+0.7了嘛,为什么还要求W和D呢?

事实上,在训练中很常见的一个场景就是,我们拥有一个数据集,其中的X值Y值都知道,但是有时候需要了解Y是怎么从X变成的一个过程,这时,我们只能创建这样的一个模型。

所以我们使用tf.Variable()函数创建变量,其中参数initial_value代表变量的初始值,初始值是一个随机的形状为1行1列的二维张量。name表示变量的名称,在tensorboard可视化流程的时候会用到。

同样,创建完了变量以后代入运算函数,得到Y值的预测值。

2.3计算损失函数

说到损失,需要有一个标准,是相对于谁损失,在本文中,这个损失是我们得到得y的预测值,与y的真实值的偏差有多少,叫做损失。

依据上节1.3的公式:其中n为数据的行数,我们有100行,y^为预测值,y为真实值。

依照公式,我们代码可得: 

loss = tf.reduce_mean(tf.square(y_predict - y_true))

其中tf.reduce_mean()是求平均值函数,tf.square()是求平方函数。

 2.4梯度训练减小误差

tensorflow提供了梯度训练的函数来让我们不用深入明白数学原理,即可完成训练操作。

代码如下:

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)

 其中learning_rate参数为学习率,这个学习率为固定学习率,关于固定学习率的优点缺点不在此文讨论,这里我把学习率设置为0.01,后面minimize()函数参数传入我们需要减小的误差张量。

三、执行操作

以上四步完成之后,我把完整版的源码贴出

import tensorflow as tf


def test():
    # 1.获得100个随机数据集 y = 0.8x + 0.7
    # 随机数 X 是 二维矩阵 [100,1] x 0.8 + 0.7
    with tf.variable_scope('get_data'):
        X = tf.random_normal([100, 1], mean=0.0, stddev=1.0, name='get_data_X')
        # 进行矩阵运算,0.8 需要是二维数组
        y_true = tf.matmul(X, [[0.8]]) + [[0.7]]
    # 2.建立回归模型
    # 模型是 [100,1] * [1,1] + [1,1]
    # 两个参数 (W,0.8) (D,0.7)
    with tf.variable_scope('create_model'):
        W = tf.Variable(initial_value=(tf.random_normal([1, 1])), name='w')
        B = tf.Variable(initial_value=(tf.random_normal([1, 1])), name='b')
        # 进行矩阵运算
        y_predict = tf.matmul(X, W) + B
    # 3.确定误差
    with tf.variable_scope('get_loss'):
        loss = tf.reduce_mean(tf.square(y_predict - y_true))
    # 4.梯度训练学习,减小误差
    with tf.variable_scope('study'):
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)

    init = tf.global_variables_initializer() # 初始化变量

    with tf.Session() as sess: # 创建会话
        sess.run(init) #会话执行初始化
        for i in range(1000): # 循环执行1000次训练
            sess.run(optimizer) # 会话执行梯度训练
            wid = sess.run(W)
            bias = sess.run(B)
            loss1 = sess.run(loss)
            print('\n第%s次训练,本次权重%s' % (i, wid))
            print('第%s次训练,本次偏置%s' % (i, bias))
            print('第%s次训练,本次误差%s\n' % (i, loss1))
            if loss1 <= 0.00000001: # 如果误差小于这个数值,则停止
                 return

    return None


if __name__ == '__main__':
    test()

变量在使用前需要先进行初始化,tensorflow中执行操作需要在会话中执行,所以也需要创建会话。自此一个简单的基于tensorflow的梯度下降训练程序编写完成,可自行复制代码测试,也可看下图:

可以看到仅用了492次训练,误差就缩小到了10的-9次方,权重W的值极为接近真实值0.8,偏置也接近真实值0.7,这展示了我们训练的成果。

非常感谢阅读!下节我将给大家介绍,如何把训练好的模型保存,使我们方便使用,以及如何使用tensorboard工具来使代码程序可视化。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值