Google开源框架之MNIST入门
本博客基于google开源框架tensorflow所做的笔记,便于以后参考。这段代码放在github中github/hadxu 。
2015年11月,google公司开源了人工智能框架Tensorflow,发布当天,其github就超过10k的star,可见nb程度。本人抱着学习的心态,入门一下该开源框架的学习,如有不足之处,还望大家评论。
MNIST数据集入门
MNIST是计算机视觉的入门数据集 —— [ MNIST ]
人眼直接看图片直接就可以知道数字为多少,我们的任务就是让计算机能够看懂数字。
MNIST数据集
这里官方提供了一个获取数据的脚本,我将其放在我的github中input_data.py 。 那么你就可以像下面的代码一样使用该脚本
<code class="hljs python has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> input_data
mnist = input_data.read_data_sets(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"MNIST_data/"</span>, one_hot=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
这段代码作用将数据集分为训练集和测试集,分别为60000与10000。
Softmax回归介绍
这里我引用极客学院的关于这个回归的介绍:
我们知道MNIST的每一张图片都表示一个数字,从0到9。我们希望得到给定图片代表每个数字的概率。比如说,我们的模型可能推测一张包含9的图片代表数字9的概率是80%但是判断它是8的概率是5%(因为8和9都有上半部分的小圆),然后给予它代表其他数字的概率更小的值。
这是一个使用softmax回归(softmax regression)模型的经典案例。softmax模型可以用来给不同的对象分配概率。即使在之后,我们训练更加精细的模型时,最后一步也需要用softmax来分配概率。
softmax回归(softmax regression)分两步:第一步
为了得到一张给定图片属于某个特定数字类的证据(evidence),我们对图片像素值进行加权求和。如果这个像素具有很强的证据说明这张图片不属于该类,那么相应的权值为负数,相反如果这个像素拥有有利的证据支持这张图片属于这个类,那么权值是正数。
evidence i = ∑ j W i , j x j + b i
然后将所求得的和进行概率统计。
y = softmax ( evidence )
根据概率最大的值就很可能能为对应的标签。
softmax ( x ) = normalize ( exp ( x ) )
展开
softmax ( x ) i = exp ( x i ) ∑ j exp ( x j )
我们根据矩阵,可以将其展开成:
最后,更一般的:
将其写成一般化数学公式为:
y = softmax ( W x + b )
实现回归模型
现在到了我们实现的步骤了,tensorflow提供了大量的数值计算的库,准确的来说,并不是数值计算,而是符号计算,对于符号计算,我也是刚刚才了解这种符号化计算方式。连google最新的支持的API是python的,所以当时决定学习python作为脚本语言是明智的选择,臭美中。。。 首先我们先导入该框架:
<code class="hljs haskell has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-import" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> tensorflow <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> tf</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
接下来,我们通过操作符号变量来描述这些可交互的操作单元,可以用下面的方式创建一个:
<code class="hljs mathematica has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">x = tf.placeholder(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"float"</span>, [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">784</span>])</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
x不是一个特定的值,而是一个占位符placeholder,我们在TensorFlow运行计算时输入这个值。我们希望能够输入任意数量的MNIST图像,每一张图展平成784维的向量。我们用2维的浮点数张量来表示这些图,这个张量的形状是[None,784 ]。(这里的None表示此张量的第一个维度可以是任何长度的。 )
我们的模型也需要权重值和偏置量,当然我们可以把它们当做是另外的输入(使用占位符),但TensorFlow有一个更好的方法来表示它们:Variable 。 一个Variable代表一个可修改的张量,存在在TensorFlow的用于描述交互性操作的图中。它们可以用于计算输入值,也可以在计算中被修改。对于各种机器学习应用,一般都会有模型参数,可以用Variable表示。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">W = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Variable</span>(tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.zeros</span>([<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">784</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>]))
b = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Variable</span>(tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.zeros</span>([<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>]))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
现在,我们可以实现我们的模型啦。只需要一行代码!
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span> = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.nn</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.softmax</span>(tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.matmul</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>,W) + b)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
首先,我们用tf.matmul(X,W)表示x乘以W,对应之前等式里面的(Wx),这里x是一个2维张量拥有多个输入。然后再加上b,把和输入到tf.nn.softmax函数里面。
训练模型
对于接触过机器学习的同学来说,交叉熵作为损失评估是再也常见不过了
H y ′ ( y ) = − ∑ i y ′ i log ( y i )
为了计算交叉熵,我们首先需要添加一个新的占位符用于输入正确值:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">y_ = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.placeholder</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"float"</span>, [None,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>])
cross_entropy = -tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.reduce</span>_sum(y_*tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
下面我们就用上面的代码构建训练算法,这里使用了反向传播算法,对于算法的细节我们不需要理解太多,我们首先会使用即可。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">train_step = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.train</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GradientDescentOptimizer</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.01</span>)<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.minimize</span>(cross_entropy)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
现在,我们已经设置好了我们的模型。在运行计算之前,我们需要添加一个操作来初始化我们创建的变量:
<code class="hljs fix has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">init </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> tf.initialize_all_variables()</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
现在我们可以在一个Session里面启动我们的模型,并且初始化变量:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">sess = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Session</span>()
sess<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(init)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
然后开始训练模型,这里我们让模型循环训练1000次!
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">for i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>):
batch_xs, batch_ys = mnist<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.train</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.next</span>_batch(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>)
sess<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(train_step, feed_dict={<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>: batch_xs, y_: batch_ys})</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
评估我们的模型
训练模型已经完成,那我们怎么知道该模型的好坏呢?
首先让我们找出那些预测正确的标签。tf.argmax 是一个非常有用的函数,它能给你在一个张量里沿着某条轴的最高条目的索引值。比如,tf.argmax(y,1) 是模型认为每个输入最有可能对应的那些标签,而 tf.argmax(y_,1) 代表正确的标签。 我们可以用 tf.equal 来检测我们的预测是否真实标签匹配。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">correct_prediction = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.equal</span>(tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.argmax</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">y</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>), tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.argmax</span>(y_,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>))
accuracy = tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.reduce</span>_mean(tf<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.cast</span>(correct_prediction, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"float"</span>))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
最后将正确率输出:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">print sess<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.run</span>(accuracy, feed_dict={<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">x</span>: mnist<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.test</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.images</span>, y_: mnist<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.test</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.labels</span>})</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
最后在我的阿里云服务器上得到的结果为91.8%,看起来不是特别好,别着急,我们接下来会使用卷积神经网络来构建模型。
总结
学会了使用tensorflow构建简单的浅层网络,并将整个浅层网络搭建起来,并将代码放在github中。接下来使用卷积神经网络。