機器學習自學筆記09: Keras2.0

by wenwu
0 comment

機器學習自學筆記09: Keras2.0

今日的課程來自於: https://youtu.be/5BJDJd-dzzg
參考筆記:https://github.com/Sakura-gh/ML-notes/blob/master/ML-notes-pdf/10_Keras.pdf

Keras 介紹

Tensorflow 是目前最流行的machine learning庫之一。但是他沒有這麼好用tensorflow 和另一個功能相近的toolkit theano,這兩個都非常flexible ,可以做很多事情,deep learning 或是只做微分也行,也可以算gradient descent等等,但是這麼flexble 的toolkit 學起來是一定有難度的,沒辦法在半小時內學會。

Keras 是很容易學習且有足夠的彈性的,可以用來implement 一個自己的deep learning, Keras 其實是tensorflow和theano 的interface,所以用Keras 就等於在用tensorflow,只是有人幫你把操作tensorflow 這件事情幫妳寫好了。

多數想得到的nerwork,在 Keras 都有現成的function可以使用;因為它背後就是tensorflow or theano,所以如果你想要精進自己的能力的話,你永遠可以去改Keras背後的tensorflow 的code,然後做更厲害的事情


Keras 實作

現在Keras已經成為Tensorflow 的官方API,就像樂高一樣簡單
使用的data是MNIST的Data:http://yann.lecun.com/exdb/mnist/
Keras提供了自動下載MNIST data的function:http://keras.io/datasets/

接下來就依照之前machine learning 的三個步驟 :

首先要先導入keras套件:

from keras.models import Sequential

Step 1: define a set of function — neural network

先建立一個model

model=Squential()
  • 第一層 hidden layer

之後我們要決定neural network要長甚麼樣子: 假設我們想建立的有兩個hidden layer,每個hidden layer 都有500個neuron

model.add(Dense(input_dim=28*28,units=500,activation='sigmoid'))

Dense 表示加一個Fully connected 的layer ( 也可以加別的layer)
input_dim=28*28 表示輸入的是一個28*28=784長度的vector,表示image
units=500 表示該層的hidden layer 要有500個neuron
activation=’sigmoid’ 表示激活函數使用sigmoid function ( 還可以選其他activation function,比如softplus, softsign, relu, tanh, hard_sigmoid, linear …)

  • 第二層 hidden layer

如果要在model裡再加一個layer,就用model.add增加一個dense 全連接層,包誇units和activation參數

model.add(Dense(units=500,activation='sigmoid'))

這裡不用設定input_dim,因為新增的layer的input就等於前一個layer 的output
所以直接設定新加的layer有500的neuron就好了

  • 最後一層 output layer

最後,我們希望的output為10維,所以units=10

model.add(Dense(units=10,activation='softmax'))

如果把output layer當作一個Multi-class classifier 的話,那activation function就用softmax(這樣可以讓output每一維的機率和為1)

Step 2: goodness of function — cross entropy

使用model.compile 去定義你的loss function 是甚麼
比如你要用cross entropy 的話,那你的loss 參數就是 categorical_crossentropy(keras 裡的寫法)

model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])

Step 3: pick the best function

  • configuration(決定好怎麼做gradient descent)

在training之前,你要先下一些configuration 告訴她training 的時候,你打算要怎麼做

你要定義的第一個東西是optimizer,也就是說你要用什麼樣的方式來找最好的function,雖然optimizer後面可以皆不同的方式,但是這些不同的方式,其實都是gradient descent 類似的方法

有一些方法machine 會自動的,根據經驗決定learning rate的值應該是多少,所以這些方法是不需要給它 learning rate的

model.compile(loss='categorical crossentropy',optimizer='adam',metrics=['accuracy'])

optimizer 也可以使用: SGD(gradient descent), RMSprop, Adagrad, Adadelta, Adam, Adamax, Nadam 等方法,這些都是gradient descent

  • training

決定好怎麼做gradient descent 之後,就是實際去做training 了
跑gradient descent 找最優參數,這裡使用的是model.fit 的方法,要給他4個input (假設我們給了10000張image做 Training data )

model.fit(x_train, y_train, batch_size=100, nb_epoch=20)
  1. x_train ( training data)
    在這個case裡,Training data 就是一張一張的image,需要把它存到numpy array裡面,這個numpy array 是兩個維度的matrix。第一個維度,表示有多少個example;第二個維度,表示你的image有多大,有幾個pixel。
    所以這裡面前的狀況是,有一萬個image 做training data,並且每個image有28*28=784個pixel = 10000行*784列
  2. y_train (training data 對應的label)
    我們期望這些image經過training ,機器可以跟我們說這張image 是0~9所對應其中的一個數字,所以y_train的第一個維度應該是example的數量(也就是10000),第二個維度是output的維度(也就是10)
  3. batch_size (告訴Keras我們的batch要多大)
    這裡 batch_size=100 ,表示我們要把100張隨機選擇的image放到一個batch裡面,然後把所有的image分成一個個不同的batch,Keras 會自動幫你完成隨機選擇image的過程,不需要自己coding
  4. nb_epoch (對所有batch的訓練要做幾次)
    這裡 nb_epoch=20,表示要對所有的batch進行20遍gradient descent 的訓練。每看到一個batch就update一次參數,假設現在每一個epoch裡面有100個batch,就對應著update 100 次參數,20個epoch就是update 2000 次參數。

下面有更仔細的batch & epoch的介紹

注意: 若batch_size=1,那就是Stochastic Gradient Descent (隨機梯度下降法),這個在gradint descent有提到,就是每次拿到一個樣本點就update一次參數,而不是每次拿到一批樣本點的error之後才去update參數,因此stochastic gradient descent的好處就是速度比較快,雖然每次update參數的方向是不穩定的,但是天下武功,唯快不破,在別人出一拳的時候,它就已經出了100拳,所以它是比較強的。


Mini-batch

這裡有一個秘密,就是我們在做deep learing 的gradient descent 的時候,並不會真的去minimize total loss,那我們做的是什麼呢? 我們會把Training data分成一個一個的batch,比如training data 有10000張image,每次random選100張image作為一個batch

  • 像gradient descent 一樣,先隨機initialize network的參數
  • 選第一個batch出來,然後計算這個batch裡面的所有element的total loss L’,接下來根據 L’ 去update參數,也就是計算 L’ 對所有參數的偏微分,然後update參數
  • 在選第二個batch出來,現在這個batch 的 total loss 為 L’’ ,接下來根據 L’’ 對所有參數的偏微分,然後update參數
  • 反覆做上面的動作,直到所有的batch都選過一次。所以假設你有100個batch的話,你就把這個參數update 100次,把所有的batch看過一次,這就叫做一個 epoch (全部的batch 為一個epoch)
  • 重複epoch的過程,所以你在train network 的時候,你會需要好幾個epoch,而不是只有一個epoch

整個訓練的過程類似於stochastic gradient descent ,不是將所有數據讀完才開始做gradient descent 的,而是拿到一部份數據就做一次gradient descent


Batch size and Training Speed

接下來來討論設定batch size對training speed 的影響


batch size 太小會導致不穩定,速度上也沒有優勢

前面提到stochastic gradient descent,速度快,表現好。那為何還要使用Mini-batch? 這就提到了一些操作上的問題,我們必須使用Mini-batch

舉例來說現在有50000個example,分成兩種狀況。
如果 batch size = 1 ,也就是stochastic gradient descent,那在一個epoch裡面,就會update 50000次參數。
如果 batch size = 10 ,在一個epoch裡面,就會update 5000次參數。

看起來stochastic gradient descent的速度會比較快,實際上batch size 設置不一樣的話,一個epoch需要的時間是不一樣的。以GTX 980 為例,下圖是對總是為50000筆的training data 設置不同的batch size時,每一個epoch所需的花費時間

  • case1: 如果batch size=1,也就是stochastic gradient descent,一個epoch要花費166秒
  • case2: 如果batch size=10,一個epoch要花費17秒

而第二個需要跑10個epoch ,花費時間約為170秒。如果不同batch size的情況,update參數的次數幾乎是一樣的。

在這個case中,會更傾向選擇 batch size=10,因為會比batch size=1 更穩定(較穩,又update次數多)。因為由更大的數據集計算的梯度能更好的代表樣本總體,從而更準確的朝向極值所在的方向。


Batch size 會受到GPU平行加速的限制,太大可能導致在train的時候卡住

上面的例子的現象產生的原因是我们用了GPU,用了平行運算,所以batch size=10,這十個example是同時運算的,所以你在一個batch裡算10個example的時間跟算一個example的時間幾乎可以是一樣的

那你可能會問,既然batch size越大,它會越穩定,-而且還可以平行運算,那為什麼不把batch size變得超級大呢?這兩有兩個說明:

  1. 如果你把batch開到很大,最終GPU會無法平行運算,它是有極限的。
    也就是說同時考慮10個example和1個example的時間是一樣的。但是跑10000個就不可能跟一個example一樣。因為batch size 需要考慮到硬件限制。
  2. 如果把batch size設的很大,在train gradient descent 的時候,可能跑兩下network就卡住了,就縣道saddle point 或者local minimal
    因為在neural network的error surface 上面,如果你把loss 的圖像可視化出來,它並不是一個convex的optimization problem,不會像理想中那麼光滑
    如果batch size 很大,甚至是full batch,那你走過的路徑會是比較平滑連續的,可能這一條平滑的曲線在走向最低點的過程中就會在坑洞或緩坡上卡住了;如果batch size沒有這麼大,意味著你走的路線沒有這麼光滑,有些步伐是隨機性的,路徑會有一些曲折和波動
    可能在你走的過程中,它的曲折和波動剛好使得你“繞過”了那些saddle point或是local minima的地方;或者當你陷入不是很深的local minima或者没有遇到特别麻煩的saddle point的時候,它步伐的隨機性就可以幫你跳出這個gradient接近於0的區域,於是你更有可能真的走向global minima 的地方

對於 Full batch 的情况,它的路徑是没有隨機性的,是穩定朝著目標下降的,因此在這個時候去 train neural network 其實是有問題的,可能 update兩三次参數就會卡住,所以mini batch是有必要的


不同batch size在梯度下降上的表現

如下圖,左邊是full batch( 全部的training data 做一個batch) 的梯度下降效果,可以看到每一次跌代成本函數都呈現下降趨勢,這是好的現象,說明我們的w和b的設定一直再減少誤差,這樣一直跌代下去就可以找到最佳解;右邊是mini batch的梯度下降效果,它是上下波動的,成本函數的值有時高有時低,但總體還是呈現下降的趨勢,這個也是正常的,因為我們每一次梯度下降都是在mini batch上跑的而不是在整個數據集上,數據的差異可能會導致這樣的波動,但沒關係,因為它整體是呈下降趨勢的。

把下圖看做是梯度下降空間:藍色部分是full batch而紫色部分是mini batch,就像上面所说的mini batch不是每次迭代損失函數都會減少,所以看上去好像走了很多彎路,不過整體還是朝著最優解迭代的,而且由於mini batch 一個 epoch就走了5000步(5000次梯度下降),而 full batch一個epoch只有一步,所以雖然 mini batch走了彎路但還是會快很多

mini batch在update的過程中,步伐具有隨機性,因此紫色的路徑可以在一定程度上繞過或跳出 saddle point、local minima 這些gradient 趨近於0的地方;而藍色的路徑因為缺乏隨機性,只能按照既定的方式朝著目標前進,很有可能就在中途被卡住,永遠也跳不出来了

當然,就像之前討論的一樣,如果batch size太反而會造成速度不僅没有加快反而會導致下降的曲線更加不穩定的情况產生

因此batch size既不能太大,因為它會受到硬體GPU平行加速的限制,導致update次數過於緩慢,並且由於缺少隨機性而很容易在梯度下降的過程中卡在saddle point或是local minima的地方(極端情况是Full batch);而且batch size也不能太小,因為它會導致速度優勢不明顯的情况下,梯度下降曲線過於不穩定,算法可能永遠也不會收斂(極端情况是Stochastic gradient descent)


GPU是如何平行加速的

整個network,不管是Forward pass還是Backward pass,都可以看做是一連串的矩陣運算的结果

那今天我們就可以比較 batch size等於1(stochastic gradient descent)和10(mini batch)的差别

如下圖所示,stochastic gradient descent就是對每一個 input x 進行單獨運算;而 mini batch,則是把同一個 batch 裡面的input全部集合起来,假設現在我們的 batch size是2,那mini batch每一次運算的 input就是把黃色的vector和綠色的vector拼接起來變成一個matrix,再把這個 matrix乘上w1 ,你就可以直接得到 z¹ 和 z²

這兩件事在理論上運算量是一樣多的,但是在實際操作上,對GPU來說,在矩陣裡面相乘的每一個 element都是可以平行運算的,所以圖中stochastic gradient descent 運算的時間反而會變成下一mini batch使用GPU運算速度的兩倍,這就是為甚麼我們要使用mini batch的原因


Save and Load Models

Keras 也是可以幫你save 和load model 的,你可以把train好的 model 存起來,以後再用另一個程式讀出來,它也可以幫你做testing

那要如何用neural network去testing 呢? 有兩個case:

  • case1: Evaluation。比如今天有一組testing set,testing set的答案也是已知的,那 Keras 就可以幫你算現在的正確率有多少。
    這個model.evaluates有兩個input,就是testing的image(x_test) 和testing 的label(y_test)
score = model.evaluation(x_test, y_test)
print('Total loss on Testing Set:',score[0])
print('Accuracy of Testing Set',score[1])
  • case2: Predicion。這個時候model.perdict 函數的input 只有image data 而沒有任何的 label data,output就直接是分類結果
result = model.predict(x_test)

Related Articles

發表迴響