2017年5月20日 星期六

深度學習(4)--使用Tensorflow實現類Lenet5手寫數字辨識


    這一節介紹一完整的手寫數字辨識的範例,使用Tensorflow來實現類似Lenet5的架構。除了使用MNIST數據集來做訓練與測試外,我們將訓練好的模型儲存起來,並用微軟小畫家自行手寫幾張數字來進行實際的辨識預測,最後使用Kaggle網站上的手寫數字數據進行預測,並將結果上傳至kaggle網站上打分數,得到預測的成績。

   本文主要提供程式實作,不會再提到太多相關的理論,有關相關的理論,大多可以在最底下之前提過的文章或參考資料閱讀相關理論。這個程式的建立環境是python 3.5 +tensorflow1.10 win10底下使用GPU加速運算,估計跑在Linux或是純CPU運算應該也沒太大問題。


首先來回顧Lenet5的經典架構,如下<圖一>
Lenet5模型是Yann LeCun教授於1998年在論文Gradient-based learning applied to document recognition中提出的,它是第一個成功應用於數字識別問題的卷積神經網路。在MNIST數據集上,Lenet5模型可以達到大約99.2%的正確率,Lenet5模型總共有7層。

有關CNN卷積神經網路的介紹可參閱之前文章:
深度學習(2)--使用Tensorflow實作卷積神經網路(Convolutional neural network,CNN)

<圖一>Lenet5架構


第一層 卷積層(Convolution)
    這一層的輸入就是原始圖像像素,Lenet5接受的輸入層大小為32x32x1。第一個卷積層filter的尺寸為5x5,深度為6,不使用zero padding,步長(Stride)為1,故這一層輸出的尺寸為32-5+1=28,深度為6。總共有5x5x1x6+6=156個參數,其中6為bias偏誤。因下一層節點矩陣有28x28x6=4704個節點,每個節點和5x5=25個節點相連,所以本層卷積層總共有4707x(25+1)=122304個連接。

第二層 池化層(Pooling)
    這一層的輸入為第一層的輸出,是一28x28x6的節點矩陣,本層採用的filter為2x2,stride=2,故輸出矩陣大小為14x14x6。

第三層 卷積層(Convolution)
    本層的輸入矩陣大小為14x14x6,使用的filter為5x5,深度為16,不使用Zero padding,stride=1,本層的輸出矩陣大小為10x10x6。因此本層應該有5x5x6x16+16=2416個參數,
10x10x16x(25+1)=41600個連接。

第四層 池化層(Pooling)
    本層的輸入矩陣大小為10x10x16,採用filter為2x2,stride為2,本層的輸出矩陣大小為5x5x16。

第五層 卷積層(Convolution)
    本層的輸入矩陣大小為5x5x16,在Lenet5模型的論文終將這一層稱為卷積層,但是因為filter大小即為5x5,所以和全連接層沒有區別,如果將5x5x16節點拉成一個向量,那麼這一層就和全連接層一樣,本層的輸出節點數為120,總共有5x5x16x120+120=48120個參數。

第六層 全連接層
    本層的輸入節點數為120個,輸出節點數為84個,參數總共為120x84+84=10164個。

第七層 全連接層
    本層的輸入節點數為84個,輸出節點為10個,參數總共為84x10+10=850個。

底下會使用Tensorflow來實現類似Lenet5的架構如下<圖二>
在卷積層因為使用了Zero padding所以,圖像尺寸不會縮小
在程式裡是以padding='SAME'來宣告。
conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')

<圖二>

2017年5月7日 星期日

深度學習(3)--循環神經網絡(RNN, Recurrent Neural Networks)


    本節介紹最簡單的循環神經網路,稱之為Simple-RNN,它是LSTM的基礎。Simple-RNN與BP一樣都有前饋層與反饋層。但是Simple-RNN引入了基於時間(狀態)的循環機制。

    下圖一所示為Simple-RNN的神經網路示意圖。神經網路為A,通過讀取某個時間(狀態)的
輸入xt,然後輸出一個值ht,循環可以使得信息從當前時間步傳遞到下一時間步。
    這些循環使得RNN可以被看作同一網路在不同時間步的多次循環,每個神經元會把更新的結果傳遞給下一個時間步,下圖一右側即為循環展開的情形。


<圖一>


2017年3月26日 星期日

深度學習(2)--使用Tensorflow實作卷積神經網路(Convolutional neural network,CNN)


    卷積神經網路(Convolutional neural network,CNN),是一多層的神經網路架構,是以類神經網路實現的深度學習,在許多實際應用上取得優異的成績,尤其在影像物件識別的領域上表現優異。

     傳統的多層感知器(Multilayer Perceptron,MLP)可以成功的用來做影像識別,如之前
所介紹,可以用來做MNIST 手寫數字辨識,但是由於多層感知器(Multilayer Perceptron,MLP)在神經元之間採用全連接的方式(Full connectivity),當使用在較高解析度或是較高維度的影像或資料時,便容易發生維度災難而造成過度適合(Overfitting)

     例如,考慮MNIST的手寫輸入資料為28x28解析度,考慮神經元全連接的方式
(Full connectivity),連接到第一個隱藏層神經元便需要28x28=784個權重(Weight)。如果考慮一
RGB三通道色彩圖像輸入,如CIFAR-10為32x32x3的圖像解析度,連接到第一個隱藏層神經
元便需32x32x3=3072個權重(Weight)。那麼如果是200x200x3的圖像解析度,便需要120000
個權重,而這只是連接到隱含層的第一個神經元而已,如果隱含層有多個神經元,那麼連
接權重的數量必然再倍數增加。
     像這樣子的網路架構,沒有考慮到原始影像資料各像素(pixel)之間的遠近,或是密集關係,只是一昧的將全部像素(pixel)當各個輸入的特徵值,連接到隱含層神經元,造成爆量增加的權重不僅是一種浪費,因為實際上不須這麼多的權重,效果不僅沒增加,只是增加了運算的負荷,而且很可能會造成過度適合(Overfitting)。而卷積神經網路(Convolutional neural network,
CNN)被提出來後,可以有效的解決此一問題。

    事實上卷積神經網路(Convolutional neural network,CNN)設計的目標就是用來處理以多陣列型態表達的資料,如以RGB三通道表達的彩色圖片。CNN和普通神經網路之間的一個實質差別在於,CNN是對原始圖像直接做操作,而傳統神經網路是人為的先對影像提取特徵(例如灰階化,二值化)才做操作。

CNN有三個主要的特點。

1.感知區域(Receptive field):可採用3維的圖像資料(width,height,depth)與神經元連接方式,
    實際上也可以直接採用2維的圖像資料,但隱含層內部的神經元只與原本圖像的某一小塊
    區域做連結。該區塊我們稱之為感知區域(Receptive field)

2.局部連結採樣(Local connectivity):根據上述感知區域(Receptive field)的概念,CNN使用過濾
  器(filters)增強與該局部圖形空間的相關性,然後堆疊許多這樣子的層,可以達到非線性
   濾波的功能,且擴及全域,也就是允許網路架構從原圖小區塊的較好的特徵值代表性,組
   合後變成大區塊的特徵值代表性。

3.共享權重(Shared weights):使用的過濾器(filters)是可以重複使用的,當在原始圖像產生一
    特徵圖(Feature Map)時,其權重向量(weights vector)及偏誤(bias)是共用的。這樣可以確保
    在該卷積層所使用的神經元會偵測相同的特徵。並且即使圖像位置或是有旋轉的狀態,
    仍然可以被偵測。

        這三個特點使得CNN在圖像辨識上有更好的效果。在實際操作上的三個基礎分別是:
    區域感知域(Local Receptive field),卷積(Convolutional ),池化(pooling)。
    我們可以從下面圖形化的實際操作來理解它的意思。

卷積層(Convolutional Layer )

      下圖1,2說明在卷積層的運作方式,假設原始影像為一32x32x3維度,我們可以任意給定一
卷積核(filter),其卷積核的值即為權重(weight)。其大小可以為5x5x3,3為與原影像有一樣的深度(RGB三通道),如果輸入影像為一灰階單通道色彩,那麼卷積核大小5x5即可。卷積核大小3x3或5x5或7x7...等等可以自訂,通常為奇數維度。
    接著與原圖像相同的小區域計算點積,得到的一個值便是在新的feature Map的一個新元素值。卷積核會在原始的圖像或者前一個圖像(Map)按照Stride(步伐)的設定移動,直到掃描完全部圖像區域,這樣便會產生一個新的Feature Map。便是下圖圖3~圖5所示,在這個步驟中產生單一新feature Map所使用的權重W,也就是卷積核是共用的,並且共用同一個偏誤(bias),通常初始預設偏誤(bias)可以為0。這樣確保這一新的feature map偵測的是該原始圖像同一特徵。

<圖1>

2017年3月12日 星期日

機器學習(9)--大數據競賽平台Kaggle入門,練習手寫數字辨識

     我們這次利用多層感知器MLP所作的手寫數字辨識,來練習大數據競賽平台Kaggle的投稿方式。在Kaggle上有多項有獎金的項目正在進行,這些項目想必難度很高。另外也有提供入門的練習項目是沒有獎金的,但是有提供了相關數據可以下載,也有人分享了他們實作該競賽項目的方法,這些可以供我們練習及參考。
     接下來我們就練習從Kaggle下載它所提供的手寫數字數據,利用MLP辨識完後把結果上傳回Kaggle平台,它就會馬上幫我們算出辨識準確率及在該項目的排名。

     這邊直接省略註冊步驟,註冊是免費的而且可以直接使用Facebook 或是google+帳號即可,故我們直接從如何下載手寫數字數據開始。
進入Kaggle平台網頁上方選擇[Competitions],底下往下拉即可以看到目前正在進行的競賽項目。
Kaggle平台連結:https://www.kaggle.com/competitions

     如下圖,它有幾種分類,Featured 及Research都是有獎金的,至於新手入門可以從Playground及Getting Started 做起。我們在這邊直接選擇最下方Digit Recognizer 進去。


2017年3月11日 星期六

機器學習(8)--實作多層感知器(Multilayer Perceptron,MLP)手寫數字辨識


    在這章節,我們使用Python實作一多層感知器(Multilayer Perceptron,MLP)來做手寫數字辨識功能。使用MNIST的數據集及反向傳遞演算法(Backpropagation)做模型訓練及測試。並將訓練好的權重存成檔案,以便對新的數據直接作預測,不須每次都重新訓練模型。最後練習使用windows內建的"小畫家"自己手畫數字進行辨識。結果如下圖所示:

<圖一>第1、3列為使用windows小畫家手繪出的手寫數字,第2,4列為相對應的預測結果。




    有關反向傳遞演算法(Backpropagation)的公式推導,可以參閱底下連結:
該連結範例為有帶值的手解計算,作者:Matt Mazur已解釋的非常清楚了,
建議大家可以跟著做一次。
https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/

補充:對於啟動函數sigmoid 的求導推導有疑慮的,可以參考我下面手寫證明的方式:



2017年3月6日 星期一

英文單字學習機


     由於自己讀國小的小朋友有學習英文背單字的困擾,故用python開發了這個簡易的背英文單字程式,幫助小朋友練習單字。功能雖簡單卻都很實用,自從有了這個英文單字學習機後,我就再也不用盯著小朋友背單字了,頂多只需幫他們用excel建立好單字表。

目前建立的功能有:
1.可自行建立單字表,可利用excel編輯後,存成.csv檔。
2.測驗過程錯誤的單字,會重複提示,直到輸入正確才會進行下一個單字
3.測驗過程錯誤的所有單字會被記錄,可以按儲存功能,存成另一個.csv檔,下次可以直接開
    啟這個錯誤的單字檔在練習即可。
4.具有支援TTS 中文及英文發音,並在過程中會幫你加油打氣。
5.具有測驗拼字單字,單字撥放發音,及單字選擇題功能,期望達到聽、說、讀、寫方式記憶
   單字。
6.每範圍單字測驗結束後會自動按單字數量比例計分,成績優良,會語音給予讚美加油打氣
 ,讓使用者更有興趣動力繼續玩單字背單字。

安裝方式:

下載後不需安裝,只需將所有檔案放在同一資料夾,接著直接執行主程式Abu_words.exe即可

[2017/04/07]更新V1.01.00 ,增加中級及中高級單字表

免費下載連結:
https://drive.google.com/file/d/0BxWViAuJxH7gZl9tbEdDbkFfbms/view?usp=sharing

建議執行環境:Windows 10,使用windows 10才能獲得內建中文及英文發音支援(TTS),使用win7可能只有英語發音。
本程式絕無病毒及木馬請安心使用。

下載解壓縮後,第一次執行如果出現如下畫面,請點"其他資訊"然後選仍要執行


2017年2月25日 星期六

機器學習(7)--利用核主成分分析(Kernel PCA)處理非線性對應


    在這之前所探討的輸入數據都是假設為可線性分離的,如果輸入數據不是線性可分離的,實務上的數據往往是這樣,那麼標準PCA,所設計的線性轉換技術就不是最好的選擇,在本節介紹核PCA(kernel PCA),它與核支援向量機(kernel SVM)類似,利用核技巧來將非線性分離的數據轉換到一個新的特徵子空間,而轉換之後便可以做線性分離。


核函數與核技巧:

    類似核SVM的作法,透過核函數與核技巧,將原始數據投影到更高維的新特徵空間,而在新特徵空間,數據類別是可以線性分離的。要轉換d維空間的樣本到更高維的k維空間,我們需要定義一個非線性對應函數Φ:
    如下方式,原本數據X有兩個特徵行向量,為2維d=2。利用函數Φ可以對應到3維空間k=3。
       

    整體上來說就是,透過核PCA,我們執行一個非線性對應函數將數據轉換到一個更高維的空間,並在這個高維的空間,使用標準PCA,再將數據投影回到一個較低維度的子空間,在這個低維度的子空間中,樣本即可使用線性分類器來分離。
    這個方法的缺點是非常耗費計算資源,因此我們可以使用核技巧,使用核技巧,我們可以計算兩個由原始的特徵空間所產生的高維特徵向量之間的相似度。
    套用之前標準PCA的推導(此略),我們可以定義一核矩陣(相似度矩陣)K:
核函數k則可以替代原本需使用的非線性對應函數Φ:
    這樣我們就不用去計算原本需由非線性對應函數Φ去處理的樣本中兩兩數據點的內積(公式右側),因此核函數也可以理解為,一個計算兩個向量內積的函數,也就是計算相似度的函數。而不像標準PCA,會建立一個轉換矩陣,經過核PCA處理之後,所得到的是已經投影完成的樣本。
 
    在此我們使用的核函數為RBF(Radial Basis Function Kernel):
實作一個「RBF核」(Radial Basis Function Kernel)PCA,我們可以定義如下的三個步驟:



2017年2月23日 星期四

機器學習(6)--主成分分析(Principal component analysis,PCA)



    這一篇介紹主成分分析(Principal component analysis,PCA),是一種特徵提取的技術,利用特徵降維來避免因維度災難所造成的過度適合(Overfitting)現象。就是說假如訓練資料集裡有很多個特徵數據,我們可以利用主成分分析(Principal component analysis,PCA)來選取最有影響的幾個特徵來做分類器模型的訓練而不需要使用所有的特徵數據來做訓練。
    在這個範例裡,我們將使用葡萄酒數據集來做示範,把原本有的13個特徵,利用PCA分析後只找出兩個主要的特徵值作為分類器模型分類的特徵依據。

    PCA著眼在高維度的數據,"最大化變異數"並投影到與原數據及相同維數或較低維數的"新特徵子空間"。新特徵子空間的正交軸即是"主成分"。

<圖一>x1,x2軸維原本的,PC1,PC2為主成分




2017年2月18日 星期六

機器學習(5)--邏輯斯迴歸,過度適合與正規化( Logistic regression,overfitting and regularization)


  本節介紹邏輯斯迴歸模型(Logistic regression)過度適合(overfitting)正規化(regularization)。邏輯斯迴歸模型(Logistic regression)能處裡線性和二元分類的問題,要注意的是這裡所要說的邏輯斯迴歸模型(Logistic regression)是分類模型而無關於"迴歸"。

邏輯斯迴歸模型(Logistic regression):

首先來看一下邏輯斯迴歸模型(Logistic regression),如下圖跟前一章所介紹的
適應線性神經元模型類似,但是其所使用的啟動函數不同,成本函數也不同。

<圖一>邏輯斯迴歸模型(Logistic regression)


2017年2月15日 星期三

機器學習(4)--資料標準常態化與隨機梯度下降法( standardization & Stochastic Gradient descent)


    這篇承接上一篇適應線性神經元與梯度下降法,講述隨機梯度下降法(Stochastic Gradient descent,簡稱SGD)與資料標準常態化(standardization)
    有關適應線性神經元與梯度下降法可先閱讀底下連結:
機器學習(3)--適應線性神經元與梯度下降法(Adaline neuron and Gradient descent)

首先資料標準常態化(standardization)是一種特徵縮放方法,標準化後,特徵值會滿足標準常態分佈,並且每個平均值都是0,標準差都是1。例如,若要標準化樣本x第j個特徵,只要將樣本減去平均值μ,再除以標準差σ,就完成了,計算方式如下:

可以簡單的使用Numpy的mean與std方法便可快速,簡單的完成標準化工作,程式如下:
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()
print("標準化特徵值0:X_std[:, 0]",X_std[:, 0] )
print("標準化特徵值1:X_std[:, 1]",X_std[:, 1] )

結果如下圖一:特徵值0及特徵值1分別是上一篇所使用鳶尾花的花萼長及花瓣長。原本的資料單位為公分,可以看出原始資料比1.0或0.0大很多,而標準化後的資料皆在正負0~2之間,以直觀的數學來說這會比原本的資料容易做訓練及運算。因此資料在做過標準常態化的特徵縮放後可以獲得較佳的效能。

<圖一>未標準化與標準化後的資料


下圖二是使用上一節適應線性神經元與梯度下降法做資料標準化後的收斂速度比較,在上半
圖為標準化後的資料,學習速率設定為0.01在15輪的迭代後,成本即收斂至最佳化,而在下
圖為資料未標準化,學習速率設定為0.0001,需要150輪迭代後,成本才收斂至最佳化,為
何學習速率設定不也設定在0.01呢?因這個例子來講當資料未標準化,將學習速率設定為0.01,會發現成本函數無法收斂至最佳化也就是上一節所說的,當學習速率過大時會衝過全域最小值而無法收斂。故資料標準化後配合適當的學習速率便可得到好的訓練效能。


<圖二>未標準化與標準化後訓練資料收斂的速度比較