三十七-tensorflow中的线性回归
用梯度下降求解线性回归问题是tensorflow最简单的入门例子(10行关键代码),本节结合上一节讲到的tensorflow中的graph来更加形象地了解tensorflow中的线性回归工作原理
10行关键代码实现的线性回归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | # -*- coding: utf-8 -*- import numpy as np import tensorflow as tf # 随机生成1000个点,围绕在y=0.1x+0.3的直线周围 num_points = 1000 vectors_set = [] for i in xrange(num_points): x1 = np.random.normal(0.0, 0.55) y1 = x1 * 0.1 + 0.3 + np.random.normal(0.0, 0.03) vectors_set.append([x1, y1]) # 生成一些样本 x_data = [v[0] for v in vectors_set] y_data = [v[1] for v in vectors_set] # 生成1维的W矩阵,取值是[-1,1]之间的随机数 W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W') # 生成1维的b矩阵,初始值是0 b = tf.Variable(tf.zeros([1]), name='b') # 经过计算得出预估值y y = W * x_data + b # 以预估值y和实际值y_data之间的均方误差作为损失 loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 采用梯度下降法来优化参数 optimizer = tf.train.GradientDescentOptimizer(0.5) # 训练的过程就是最小化这个误差值 train = optimizer.minimize(loss, name='train') sess = tf.Session() # 输出图结构 #print sess.graph_def init = tf.initialize_all_variables() sess.run(init) # 初始化的W和b是多少 print "W =", sess.run(W), "b =", sess.run(b), "loss =", sess.run(loss) # 执行20次训练 for step in xrange(20): sess.run(train) # 输出训练好的W和b print "W =", sess.run(W), "b =", sess.run(b), "loss =", sess.run(loss) # 生成summary文件,用于tensorboard使用 writer = tf.train.SummaryWriter("./tmp", sess.graph) |
整个收敛过程可以从输出结果中看出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | W = [-0.67839384] b = [ 0.] loss = 0.293898 W = [-0.41792655] b = [ 0.30027848] loss = 0.0907883 W = [-0.24463286] b = [ 0.30015084] loss = 0.0407606 W = [-0.12923941] b = [ 0.30006593] loss = 0.0185783 W = [-0.05240078] b = [ 0.30000937] loss = 0.00874262 W = [-0.00123519] b = [ 0.29997173] loss = 0.00438147 W = [ 0.03283515] b = [ 0.29994667] loss = 0.00244773 W = [ 0.05552204] b = [ 0.29992998] loss = 0.00159031 W = [ 0.07062886] b = [ 0.29991883] loss = 0.00121013 W = [ 0.08068825] b = [ 0.29991144] loss = 0.00104155 W = [ 0.08738664] b = [ 0.29990652] loss = 0.000966807 W = [ 0.09184699] b = [ 0.29990324] loss = 0.000933665 W = [ 0.09481706] b = [ 0.29990104] loss = 0.00091897 W = [ 0.09679478] b = [ 0.29989958] loss = 0.000912454 W = [ 0.09811172] b = [ 0.29989862] loss = 0.000909564 W = [ 0.09898864] b = [ 0.29989797] loss = 0.000908283 W = [ 0.09957258] b = [ 0.29989755] loss = 0.000907715 W = [ 0.09996141] b = [ 0.29989725] loss = 0.000907463 W = [ 0.10022032] b = [ 0.29989707] loss = 0.000907352 W = [ 0.10039273] b = [ 0.29989696] loss = 0.000907302 W = [ 0.10050753] b = [ 0.29989687] loss = 0.00090728 |
一张图展示线性回归工作原理 执行上面的代码后会在本地生成一个tmp目录,里面会产生用于tensorboard读取的数据,下面我们执行:
1 | tensorboard --logdir=./tmp/ |
打开http://localhost:6006/的GRAPHS,并展开里面的一系列关键节点,如下图所示:
这张图就是上面这段代码生成的graph结构,这个graph描述了整个梯度下降解决线性回归问题的整个过程,每一个节点都代表了代码中的一步操作,我们来具体看一下每一部分的内容
详细分析线性回归的graph 首先来看我们要训练的W和b,如下图:
我们代码中对W共有三种操作:Assign、read、train。
其中assign是基于random_uniform赋值的,对应着下面这句代码:
1 | W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W') |
这里的tf.random_uniform的graph部分如下:
其中read对应的这句代码:
1 | y = W * x_data + b |
其中train对应的是梯度下降训练过程的操作
我们代码中对b同样也有三种操作:Assign、read、train。与W不同的是它是用zeros赋初始化值的
我们的W和b就是通过梯度下降计算update_W和update_b,从而更新W和b的值的。这里的update_W和update_b都是基于三个输入来计算得出的:学习率learning_rate、W/b当前值、梯度gradients,过程如下图:
最关键的梯度下降过程由下面几个过程实现:
下面我们分析一下详细的计算过程,首先看这句代码:
1 | loss = tf.reduce_mean(tf.square(y - y_data), name='loss') |
这里的y-y_data对应着这部分:
那么tf.squre(y-y_data)对应着那条长长的曲线
下面我们看这里:
这里的右下角是以y-y_data为输入的,但这里的x不是我们的x_data,而是一个临时常量:2。也即是2(y-y_data),这明显是(y-y_data)^2的导数
继续往上看:
这里是以2(y-y_data)为输入经过各种处理最终生成参数b的增量update_b,至此,我们完成了一半了,因为能够更新b了
我们继续往上看:
这里可以生成update_W用来更新W,反向追溯可以看出这个值是依赖于add_grad(也就是基于y-y_data的部分)和W以及y生成的,至此梯度下降整个过程就分析完了,
在这个大图中,详细计算过程如:http://stackoverflow.com/questions/39580427/how-does-tensorflow-calculate-the-gradients-for-the-tf-train-gradientdescentopti所说,一步简单的操作很普遍的被tensorflow转成了很多个节点的图,所以里面有一些细节的节点就不深入分析,因为只是一些操作的图表达,没有太重要的意义