2017年1月18日 星期三

[深度學習練習] [Deep Learning Practice] 神經網路入門(三)- 深度學習實作

上一篇中,講了深度學習的基本架構,

這篇將使用 tensorflow 去實踐深度學習,

並做一個數字辨識的入門小專案。

------------------------------------------------------------------------------------------------------------

一、深度學習的工具介紹及安裝

現在我們知道,在架構一個神經網路時,矩陣運算能力是很重要的,

但不要害怕,已經有許多套件可以幫助我們加速架設神經網路的過程,

我大概列一下我知道的幾個。

1. Theano - 有支援 Windows!第二推薦!

2. Keras - 算是在 Theano and Tensorflow 這種基礎之上的 API

3. Tensorflow - 最推薦!

我自己只有用過 Theano 和 Tensorflow

對我來說呢,Tensorflow 對於深度學習的架構更加完整,學起來更快,

很多複雜的架構只需一行程式碼就可以寫出來,

所以我就決定分享 Tensorflow 給剛進入的大家。

Tensorflow 也是 Google 人工智慧部門釋出的開源碼

他們自己長期也是使用這一套,所以應該是滿厲害的!



關於安裝 Tensorflow 呢,

Mac / Ubuntu 安裝是非常的迅速的,

Windows 系統就要用 docker 或是 virtualenv 去跑,

##############################################

我自己是在 Windows 上安裝 VirtualBox,再在上面安裝 Ubuntu

不要覺得為了 tf 安裝一個 OS 很蠢,Ubuntu 到時可以拿來練習 Hadoop/Spark。

##############################################

網頁裡面都有很詳盡的介紹,因為我覺得安裝很乏味,就麻煩大家自己安裝了。




如果已經安裝好了!

那恭喜,你離架設第一套自己的深度學習模型只差一百行了!

------------------------------------------------------------------------------------------------------------

二、深度學習數字預測小專案

現在我們進行第一個練習,讓機器學習判讀數字

給機器一張圖片,讓他告訴我們這 0~9 數字幾。

好,一樣建立一個新的文字檔叫做 dl_neural_network.py

裡面輸入以下

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
import numpy as np


mnist = input_data.read_data_sets('/tmp/data', one_hot = True)

train_x = mnist.train.images
train_x_pic = np.reshape(train_x[1], (28, 28))
plt.imshow(train_x_pic)
plt.show()

稍微講一下 mnist 是什麼,

mnist 是 TF 給大家練習的資料庫,有 training data 55000 組,test data 10000 組,

data 內容是一堆 28*28 pixel 的 0 ~ 9 數字圖片,所以執行以上程式碼,我們可以看到這個,


















這是數字 3,上面的程式碼只是為了讓大家看一下我們在使用什麼資料,

看完就可以把第七行以下的程式碼 comment out。

現在要開始寫我們的深度學習模型了!

------------------------------------------------------------------------------------------------------------

三、定義神經層

寫之前呢,先構思一下我們寫這神經網路的邏輯,

回顧上一集的重點,


深度學習 = 最佳化 ( Cost )

Cost = Best - ( input * neural * neural * neural )

neural = array * activation function



我們首先定義多個矩陣和矩陣的運算來實現神經網路

寫完神經網路後,我們要再寫一串程式碼來最佳化這套神經網路

然後就大功告成了!開始!

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt
import numpy as np

mnist = input_data.read_data_sets('/tmp/data', one_hot = True)

# 以下三個是我們提前定義三個隱藏層,且每個隱藏層都有 500 個節點。
n_nodes_hl1 = 500
n_nodes_hl2 = 500
n_nodes_hl3 = 500

# n_classes 是指我們最後 output 的維度,那因為我們有 0~9 十個數字,所以是 10。

n_classes = 10
# batch_size 指的是我們訓練資料時,一次要取多少組 Data,這跟上一章講到的隨機最佳化有關。 batch_size = 100

# x 是我們要輸入的矩陣,y 是我們的輸出。這邊提前定義,是 TF 本身的玩法。
# 圖片是 28*28 pixel,我們藉由[None, 784],把他變成 784*1 的一維矩陣,
# 那因為每一個值都還保留,所以這樣的矩陣變形沒有失真問題。(CNN則不然)
x = tf.placeholder('float',[None, 784])
y = tf.placeholder('float')


好,這邊有點複雜,但千萬不要卡在這裡,這只是提前定義神經網路的長相而已,

等看完全部程式碼,再回來細細咀嚼每一解釋,就會更清楚。

再以下繼續加入以下程式碼,

# 這邊我們寫一個方法,把神經網路中每一層定義完整,
# 並且定義出矩陣運算以及每層間是否要 activation function
def neural_network_model(data):


    # 這邊定義每一個神經層的長相,下面詳細解說。
    hidden_1_layer = {'weights':tf.Variable(tf.random_normal([784, n_nodes_hl1])),'biases':tf.Variable(tf.random_normal([n_nodes_hl1]))}


    hidden_2_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl1, n_nodes_hl2])),'biases':tf.Variable(tf.random_normal([n_nodes_hl2]))}


    hidden_3_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl2, n_nodes_hl3])),'biases':tf.Variable(tf.random_normal([n_nodes_hl3]))}

    output_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl3, n_classes])),'biases':tf.Variable(tf.random_normal([n_classes]))}

    # 這邊定義每一層之間的矩陣運算 (
matmul)
    l1 = tf.add(tf.matmul(data, hidden_1_layer['weights']), hidden_1_layer['biases'])
    # 這邊加上 Relu function -> 大於 0 就線性轉換,小於 0 就等於 0。
    l1 = tf.nn.relu(l1)

    l2 = tf.add(tf.matmul(l1, hidden_2_layer['weights']), hidden_2_layer['biases'])
    l2 = tf.nn.relu(l2)

    l3 = tf.add(tf.matmul(l2, hidden_3_layer['weights']), hidden_3_layer['biases'])
    l3 = tf.nn.relu(l3)

    output = tf.matmul(l3, output_layer['weights']) + output_layer['biases']

return output


hidden_1_layer =
{'weights':tf.Variable(tf.random_normal([784,n_nodes_hl1])),
 'biases':tf.Variable(tf.random_normal([n_nodes_hl1]))}

為什麼這個東西就是一個神經層呢?

讓我們回顧一個最簡單線性方程式的長相,

y = ax + b ( y, a, x, b 都是純量)

那如果把它變成廣義維度的運算就是,

y = Ax + b ( y, x, b 都是一維向量,A 則是一個二維矩陣)

* 方便理解才這樣假設,y A x b 可以是任意維度任意大小的向量,只要可以運算即可。

hidden layer 中的 weights 就是 A而 biases 就是 b

藉由 tf.Variable 定義一個變數,藉由 tf.random_normal 定義變數初始化的數值。

可以發現,下方矩陣運算,

l1 = tf.add(tf.matmul(data, hidden_1_layer['weights']), hidden_1_layer['biases'])

就是 y = Ax + b 這一條式子。

( data * hidden_1_layer['weights'] + hidden_1_layer['biases'] = l1 )


------------------------------------------------------------------------------------------------------------

四、最佳化神經網路

理解完神經網路長相是怎麼實現後,

只差最佳化神經網路的方法了。

在程式碼底下繼續,

def train_neural_network(x):
    # 呼叫經過神經網路後的 output 命名為 prediction
    prediction = neural_network_model(x)

    # 將標準答案與 prediction 比較算出 cost
    cost = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(prediction,y))

    # 層層修正回去的演算法,除了 AdamOptimizer 以外還是有很多的

    optimizer = tf.train.AdamOptimizer().minimize(cost)

    # 這個就是我們要走幾次輪迴來學習
    hm_epochs = 10

    # 這是 TF 特別的地方,把要做的事情放到 session 裡面,在一起開始。
    with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())

    # 這邊程式碼比較單純,就是把資料切成 batch 的大小,並將 cost 累計起來。
    for epoch in range(hm_epochs):
        epoch_loss = 0
        for _ in range(int(mnist.train.num_examples/batch_size)):
            epoch_x, epoch_y = mnist.train.next_batch(batch_size)
            _, c = sess.run([optimizer,cost], feed_dict = {x: epoch_x, y: epoch_y})
            epoch_loss += c
        print ('Epoch', epoch, 'completed out of', hm_epochs, 'loss:', epoch_loss)

    correct = tf.equal(tf.argmax(prediction,1), tf.argmax(y,1))

    # 經過 10 個 epochs 後計算出 accuracy
    accuracy = tf.reduce_mean(tf.cast(correct, 'float'))


    print ('Accuracy:' ,accuracy.eval({x:mnist.test.images, y:mnist.test.labels}))

train_neural_network(x)


完成了!!!!

讓我們來跑跑看這短短的幾行程式碼,在判別 0~9 數字時能有多少準確率吧!

在終端機輸入

 python dl_neural_network.py


等待個幾分鐘,應該就可以看到以下結果!











在經歷過 10 次 epochs 的訓練後,

機器可以用 0.95 的準確率判定 0~9 的數字,

這代表什麼意思呢?

代表你可以把這套機器包起來,

寫成自動判讀登入頁面上惱人的數字驗證碼

這樣寫爬蟲的時候,又多克服一個小難關摟~~




這邊附上官方的開源碼 :) Link

和我的有一點不一樣,但想法大同小異!

好!就這樣,基本的神經網路和數字練習,已經完成。

0.95 其實算是中庸表現,在後面 RNN 和 CNN 都可以輕易的達到 0.99 的準確率

期待一下吧!

------------------------------------------------------------------------------------------------------------

Reference

[1] Practical Machine Learning Problem

[2] 圖解機器學習

[3] Coursera - Machine Leanring 

[4] A tour of machine learning algorithms

7 則留言:

  1. 您好 因為圖片失聯了 很像看看結果如何
    可以麻煩您補一下圖片嗎 不好意思

    回覆刪除
  2. 每個隱藏層都有 500 個節點 為何是500?

    回覆刪除
    回覆
    1. 沒有一定要是 500 哦!這邊只是決定矩陣的大小,也就是神經網路的複雜度或說是要給這套演算法的自由度。

      刪除
  3. 為何不用Keras? 他好像有window version.

    回覆刪除
  4. 想要請教一下
    最近在也是在做這個 但是對隱藏層有個疑問
    如下網址
    https://chtseng.wordpress.com/2017/07/31/neural-networks-%E4%BA%8C-keras-mnist/

    輸入層是28*28=784
    輸出是0-9有十種,所以是10
    那隱藏層256怎麼出來的@@??

    有大概要給多少 還是有計算公式呢?
    謝謝

    回覆刪除
    回覆
    1. 我自己的解讀是,一切取決於你要給這個演算法多少自由度, 你要 255 應該也是沒啥差,只要矩陣有辦法運算就可以。
      但有時候自由度給太高就會有 overfitting 的可能性。

      刪除