模式識別領域應用機器學習的場景很是多,手寫識別就是其中一種,最簡單的數字識別是一個多類分類問題,咱們借這個多類分類問題來介紹一下google最新開源的tensorflow框架,後面深度學習的內容都會基於tensorflow來介紹和演示python
請尊重原創,轉載請註明來源網站www.shareditor.com以及原始連接地址git
tensor意思是張量,flow是流。算法
張量本來是力學裏的術語,表示彈性介質中各點應力狀態。在數學中,張量表示的是一種廣義的「數量」,0階張量就是標量(好比:0、一、2……),1階張量就是向量(好比:(1,3,4)),2階張量就是矩陣,原本這幾種形式是不相關的,可是都歸爲張量,是由於他們同時知足一些特性:1)能夠用座標系表示;2)在座標變換中遵照一樣的變換法則;3)有着相同的基本運算(如:加、減、乘、除、縮放、點積、對稱……)api
那麼tensorflow能夠理解爲經過「流」的形式來處理張量的一種框架,是由google開發並開源,已經應用於google大腦項目開發ruby
sudo pip install https://storage.googleapis.com/tensorflow/mac/tensorflow-0.9.0-py2-none-any.whl
不一樣平臺找對應的whl包bash
可能遇到的問題:app
發現沒法import tensorflow,問題在於protobuf版本不對,必須先卸載掉,再安裝tensorflow,這樣會自動安裝3.0版本的protobuf框架
sudo pip uninstall protobuf
sudo brew remove protobuf260
sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.9.0-py2-none-any.whl
在http://yann.lecun.com/exdb/mnist/能夠下載手寫數據集,http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz和http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz,下載解壓後發現不是圖片格式,而是本身特定的格式,爲了說明這是什麼樣的數據,我寫了一段程序來顯示這些數字:機器學習
/************************ * author: SharEDITor * date: 2016-08-02 * brief: read MNIST data ************************/ #include <stdio.h> #include <stdint.h> #include <assert.h> #include <stdlib.h> unsigned char *lables = NULL; /** * All the integers in the files are stored in the MSB first (high endian) format */ void copy_int(uint32_t *target, unsigned char *src) { *(((unsigned char*)target)+0) = src[3]; *(((unsigned char*)target)+1) = src[2]; *(((unsigned char*)target)+2) = src[1]; *(((unsigned char*)target)+3) = src[0]; } int read_lables() { FILE *fp = fopen("./train-labels-idx1-ubyte", "r"); if (NULL == fp) { return -1; } unsigned char head[8]; fread(head, sizeof(unsigned char), 8, fp); uint32_t magic_number = 0; uint32_t item_num = 0; copy_int(&magic_number, &head[0]); // magic number check assert(magic_number == 2049); copy_int(&item_num, &head[4]); uint64_t values_size = sizeof(unsigned char) * item_num; lables = (unsigned char*)malloc(values_size); fread(lables, sizeof(unsigned char), values_size, fp); fclose(fp); return 0; } int read_images() { FILE *fp = fopen("./train-images-idx3-ubyte", "r"); if (NULL == fp) { return -1; } unsigned char head[16]; fread(head, sizeof(unsigned char), 16, fp); uint32_t magic_number = 0; uint32_t images_num = 0; uint32_t rows = 0; uint32_t cols = 0; copy_int(&magic_number, &head[0]); // magic number check assert(magic_number == 2051); copy_int(&images_num, &head[4]); copy_int(&rows, &head[8]); copy_int(&cols, &head[12]); uint64_t image_size = rows * cols; uint64_t values_size = sizeof(unsigned char) * images_num * rows * cols; unsigned char *values = (unsigned char*)malloc(values_size); fread(values, sizeof(unsigned char), values_size, fp); for (int image_index = 0; image_index < images_num; image_index++) { // print the label printf("========================================= %d ======================================\n", lables[image_index]); for (int row_index = 0; row_index < rows; row_index++) { for (int col_index = 0; col_index < cols; col_index++) { // print the pixels of image printf("%3d", values[image_index*image_size+row_index*cols+col_index]); } printf("\n"); } printf("\n"); } free(values); fclose(fp); return 0; } int main(int argc, char *argv[]) { if (-1 == read_lables()) { return -1; } if (-1 == read_images()) { return -1; } return 0; }
下載並解壓出數據集文件train-images-idx3-ubyte和train-labels-idx1-ubyte放到源代碼所在目錄後,編譯並執行:函數
gcc -o read_images read_images.c
./read_images
展現出來的效果以下:
一共有60000個圖片,從代碼能夠看出數據集裏存儲的實際就是圖片的像素
咱們在《機器學習教程 十三-用scikit-learn作邏輯迴歸》中介紹了邏輯迴歸模型。邏輯迴歸是用於解決二類分類問題(使用sigmoid函數),而softmax模型是邏輯迴歸模型的擴展,用來解決多類分類問題。
softmax意爲柔和的最大值,也就是若是某個zj大於其餘z,那麼這個映射的份量就逼近於1,其餘的份量就逼近於0,從而將其歸爲此分類,多個份量對應的就是多分類,數學形式和sigmoid不一樣,以下:
它的特色是,全部的softmax加和爲1,其實它表示的是一種機率,即x屬於某個分類的機率。
在作樣本訓練時,這裏的xi計算方法是:
其中W是樣本特徵的權重,xj是樣本的特徵值,bi是偏置量。
詳細來講就是:假設某個模型訓練中咱們設計兩個特徵,他們的值分別是f1和f2,他們對於第i類的權重分別是0.2和0.8,偏置量是1,那麼
xi=f1*0.2+f2*0.8+1
若是全部的類別都計算出x的值,若是是一個訓練好的模型,那麼應該是所屬的那個類別對應的softmax值最大
softmax迴歸算法也正是基於這個原理,經過大量樣原本訓練這裏的W和b,從而用於分類的
tensorflow會使用外部語言計算複雜運算來提升效率,可是不一樣語言之間的切換和不一樣計算資源之間的數據傳輸耗費不少資源,所以它使用圖來描述一系列計算操做,而後一塊兒傳給外部計算,最後結果只傳回一次,這樣傳輸代價最低,計算效率最高
舉個例子:
import tensorflow as tf x = tf.placeholder(tf.float32, [None, 784])
這裏的x不是一個實際的x,而是一個佔位符,也就是一個描述,描述成了二維浮點型,後面須要用實際的值來填充,這就相似於printf("%d", 10)中的佔位符%d,其中第一維是None表示可無限擴張,第二維是784個浮點型變量
若是想定義可修改的張量,能夠這樣定義:
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
其中W的維度是[784, 10],b的形狀是[10]
有了這三個變量,咱們能夠定義咱們的softmax模型:
y = tf.nn.softmax(tf.matmul(x,W) + b)
這雖然定義,可是沒有真正的進行計算,由於這只是先用圖來描述計算操做
其中matmul是矩陣乘法,由於x的維度是[None, 784],W的維度是[784, 10],因此矩陣乘法得出的是[None, 10],這樣能夠和向量b相加
softmax函數會計算出10維份量的機率值,也就是y的形狀是[10]
基於上面定義的x、W、b,和咱們定義的模型:
y = tf.nn.softmax(tf.matmul(x,W) + b)
咱們須要定義咱們的目標函數,咱們以交叉熵(衡量預測用於描述真相的低效性)爲目標函數,讓它達到最小:
其中y'是實際分佈,y是預測的分佈,即:
y_ = tf.placeholder("float", [None,10]) cross_entropy = -tf.reduce_sum(y_*tf.log(y))
利用梯度降低法優化上面定義的Variable:
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
其中0.01是學習速率,也就是每次對變量作多大的修正
按照上面的思路,最終實現的代碼digital_recognition.py(放在文件夾MNIST_data的上一級目錄下)以下:
# coding:utf-8 import sys reload(sys) sys.setdefaultencoding( "utf-8" ) from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf flags = tf.app.flags FLAGS = flags.FLAGS flags.DEFINE_string('data_dir', 'MNIST_data/', 'Directory for storing data') mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True) x = tf.placeholder(tf.float32, [None, 784]) W = tf.Variable(tf.zeros([784,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.InteractiveSession() 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, tf.float32)) print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels}))
運行效果以下:
[root@mymac $] python digital_recognition.py Extracting ./train-images-idx3-ubyte.gz Extracting ./train-labels-idx1-ubyte.gz Extracting ./t10k-images-idx3-ubyte.gz Extracting ./t10k-labels-idx1-ubyte.gz 0.9039
解釋一下
flags.DEFINE_string('data_dir', 'MNIST_data/', 'Directory for storing data')
表示咱們用MNIST_data的上一級目錄做爲訓練數據的存儲目錄,若是咱們沒有提早下好訓練數據和測試數據,程序會自動幫咱們下載到./
mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
這句直接用庫裏幫咱們實現好的讀取訓練數據的方法,無需自行解析
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})
這幾行表示咱們循環1000次,每次從訓練樣本里選取100個樣原本作訓練,這樣咱們能夠修改配置來觀察運行速度
最後幾行打印預測精度,當調整循環次數時能夠發現總訓練的樣本數越多,精度就越高