當我們開始學習程式設計的時候,第一件事往往是學習列印”Hello World”。就好比程式設計入門有Hello World,機器學習入門有MNIST。
MNIST是一個入門級的計算機視覺資料集,它包含各種手寫數字圖片。它也包含每一張圖片對應的標籤,告訴我們這個是數字幾。
詳細內容請參考:http://wiki.jikexueyuan.com/p…
文章末尾會給出相關python程式碼,執行環境是python3.6+anaconda+tensorflow,具體環境搭建本文不做闡述。
一、MNIST簡介
官網連結:http://yann.lecun.com/exdb/mn…
這個MNIST資料庫是一個手寫數字的資料庫,它提供了六萬的訓練集和一萬的測試集。
它的圖片是被規範處理過的,是一張被放在中間部位的28px*28px的灰度圖。
總共4個檔案:
train-images-idx3-ubyte: training set images
train-labels-idx1-ubyte: training set labels
t10k-images-idx3-ubyte: test set images
t10k-labels-idx1-ubyte: test set labels
圖片都被轉成二進位制放到了檔案裡面,
所以,每一個檔案頭部幾個位元組都記錄著這些圖片的資訊,然後才是儲存的圖片資訊。
二、tensorflow手寫數字識別步驟
1、 將要識別的圖片轉為灰度圖,並且轉化為28*28矩陣
2、 將28*28的矩陣轉換成1維矩陣
3、 用一個1*10的向量代表標籤,因為數字是0~9,如數字1對應的矩陣就是:[0,1,0,0,0,0,0,0,0,0]
4、 softmax迴歸預測圖片是哪個數字的概率。
這裡順帶說一下還有一個迴歸:logistic,因為這裡我們表示的狀態不只兩種,因此需要使用softmax
三、標籤介紹(有監督學習/無監督學習)
監督學習:利用一組已知類別的樣本調整分類器的引數,使其達到所要求效能的過程,也稱為監督訓練或有教師學習舉個例子,MNIST自帶了訓練圖片和訓練標籤,每張圖片都有一個對應的標籤,比如這張圖片是1,標籤也就是1,用他們訓練程式,之後程式也就能識別測試集中的圖片了,比如給定一張2的圖片,它能預測出他是2
無監督學習:其中很重要的一類叫聚類舉個例子,如果MNIST中只有訓練圖片,沒有標籤,我們的程式能夠根據圖片的不同特徵,將他們分類,但是並不知道他們具體是幾,這個其實就是“聚類”
標籤的表示
在這裡標籤的表示方式有些特殊,它也是使用了一個一維陣列,而不是單純的數字,上面也說了,他是一個一位陣列,0表示方法[1,0,0,0,0,0,0,0,0,0],1表示[0,1,0,0,0,0,0,0,0,0],………,
主要原因其實是這樣的,因為softmax迴歸處理後會生成一個1*10的陣列,陣列[0,0]的數字表示預測的這張圖片是0的概率,[0,1]則表示這張圖片表示是1的概率……以此類推,這個陣列表示的就是這張圖片是哪個數字的概率(已經歸一化),
因此,實際上,概率最大的那個數字就是我們所預測的值。兩者對應來看,標準的標籤就是表示圖片對應數字的概率為100%,而表示其它數字的概率為0,舉個例子,0表示[1,0,0,0,0,0,0,0,0,0],可以理解為它表示0的概率為100%,而表示別的數字的概率為0.
softmax迴歸
這是一個分類器,可以認為是Logistic迴歸的擴充套件,Logistic大家應該都聽說過,就是生物學上的S型曲線,它只能分兩類,用0和1表示,這個用來表示答題對錯之類只有兩種狀態的問題時足夠了,但是像這裡的MNIST要把它分成10類,就必須用softmax來進行分類了。
P(y=0)=p0,P(y=1)=p1,p(y=2)=p2……P(y=9)=p9.這些表示預測為數字i的概率,(跟上面標籤的格式正好對應起來了),它們的和為1,即 ∑(pi)=1。
tensorflow實現了這個函式,我們直接呼叫這個softmax函式即可,對於原理,可以參考下面的引文,這裡只說一下我們這個MNIST demo要用softmax做什麼。
(注:每一個神經元都可以接收來自網路中其他神經元的一個或多個輸入訊號,神經元與神經元之間都對應著連線權值,所有的輸入加權和決定該神經元是處於啟用還是抑制狀態。感知器網路的輸出只能取值0或1,不具備可導性。而基於敏感度的訓練演算法要求其輸出函式必須處處可導,於是引入了常見的S型可導函式,即在每個神經元的輸出之前先經過S型啟用函式的處理。)
交叉熵
通俗一點就是,方差大家都知道吧,用它可以衡量預測值和實際值的相差程度,交叉熵其實也是一樣的作用,那為什麼不用方差呢,因為看sigmoid函式的影像就會發現,它的兩側幾乎就是平的,導致它的方差在大部分情況下很小,這樣在訓練引數的時候收斂地就會很慢,交叉熵就是用來解決這個問題的,它的公式是 −∑y′log(y) ,其中,y是我們預測的概率分佈,y’是實際的分佈。
梯度下降
上面那步也說了,有個交叉熵,根據大夥對方差的理解,值越小,自然就越好,因此我們也要訓練使得交叉熵最小的引數,這裡梯度下降法就派上用場了,這個解釋見上一篇系列文章吧,什麼叫訓練引數呢,可以想象一下,我們先用實際的值在二位座標上畫一條線,然後我們希望我們預測出來的那些值要儘可能地貼近這條線,我們假設生成我們這條線的公式ax+ax^2+bx^3+…..,我們需要生成這些係數,要求得這些係數,我們就需要各種點代入,然後才能求出,所以其實訓練引數跟求引數是個類似的過程。
預測
訓練結束以後我們就可以用這個模型去預測新的圖片了,大概意思就是輸入對應的值就能獲取相應的結果。
程式碼如下:
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import gzip
import os
import tempfile
import numpy
from six.moves import urllib
from six.moves import xrange # pylint: disable=redefined-builtin
import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets
import tensorflow.examples.tutorials.mnist.input_data
"""MNIST機器學習"""
"""下載並讀取資料來源"""
mnist = read_data_sets("MNIST_data/", one_hot=True)
"""x是784維佔位符,基礎影像28x28=784"""
x = tf.placeholder(tf.float32,[None,784])
"""W表示證據值向量,因為總資料量為0~9,每一維對應不同的數字,因此為10"""
W = tf.Variable(tf.zeros([784,10]))
"""b同理,為10"""
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x,W)+b)
"""初始化交叉熵的值"""
y_ = tf.placeholder("float",[None,10])
"""計算交叉熵"""
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
"""梯度下降演算法"""
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
"""開始訓練模型"""
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
for i in range(1000):
batch_xs,batch_ys = mnist.train.next_batch(100)
sess.run(train_step,feed_dict={x:batch_xs,y_:batch_ys})
"""評估模型"""
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
"""正確率"""
k = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
print(k)