2016年7月12日 星期二

Keras筆記:implementing Graph object to concatenate multiple CNN example

對於類神經網絡(neural network)的應用,python有兩大支持套件(library): 由 Google主持開發的 Tensorflow以及 Theano。雖然這兩個套件賦予使用者極大的彈性去建立及設定類神經網絡,但對於非主修領域的使用者來說門檻還是太高了,而這也正是 Keras所要解決的問題。


你可以把 Keras想像為以 Tensorflow及 Theano做為運算後臺的前臺使用者介面,讓你能夠在略懂皮毛的知識濃度下就輕鬆地建立起自己需要的類神經網絡。

關於安裝及設定、測試顯示卡(gpu)的訊息,我最推薦這份 Keras的中文文檔,其中展示了不同作業系統下如 Windows及 Linux的範例。此外,建議在安裝以上任何套件前先下載並安裝 Anaconda,它是一套 python科學計算的整合系統,可以省下很多自行摸索的麻煩。

而關於Keras的入門以及詳細參數設定則建議從 Keras官網的「新手入門:30秒學會建立類神經網絡」開始。



接著回到這篇文章的主題,如何建立多個 convolutional neural network(CNN)的結構。我預想會找到這篇文章的朋友應該是對CNN有一定的認識才會產生技術上的需求,但"誤入歧途"的觀眾我非常建議閱讀WILDML部落格的這篇文章對CNN的基本介紹,以及其中所有連結出去的網頁。


=====以下就開始 CNN的程式碼實作=====

假如你看完 Keras官網的教學後,你會發現其中的例子都是 Sequential model,線性式的將層與層之間推疊起來。但若想要建立如下圖中這樣「網狀」的結構時,我們就必須利用 Keras當中 Graph的物件(object)。




from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.embeddings import Embedding
from keras.layers.convolutional import Convolution1D, MaxPooling1D

# 建立 Graph物件
graph = Graph()

# 定義輸入層參數及進行 embedding
graph.add_input(name='input', input_shape=(maxlen,), dtype='int')
graph.add_node(Embedding(maxfeatures, word_dim, input_length=maxlen),
               name='embedding', input='input')

# 第一個CNN、Maxpool、flatetn
graph.add_node(Convolution1D(nb_filter=nb_filter,filter_length=fw[0],activation="relu"),
               name='conv1', input='embedding') 
graph.add_node(MaxPooling1D(pool_length =pool_length[0], border_mode='valid'), name='pool1', input = 'conv1')
graph.add_node(Flatten(), name='flat1', input='conv1')

# 第二個CNN、Maxpool、flatetn
graph.add_node(Convolution1D(nb_filter=nb_filter,filter_length=fw[1],activation="relu"),
               name='conv2', input='embedding') 
graph.add_node(MaxPooling1D(pool_length =pool_length[1], border_mode='valid'), name='pool2', input = 'conv2')
graph.add_node(Flatten(), name='flat2', input='conv2')

# 第三個CNN、Maxpool、flatetn
graph.add_node(Convolution1D(nb_filter=nb_filter,filter_length=fw[2],activation="relu"),
               name='conv3', input='embedding') 
graph.add_node(MaxPooling1D(pool_length =pool_length[2], border_mode='valid'), name='pool3', input = 'conv3')
graph.add_node(Flatten(), name='flat3', input='conv3')

# 將上面三個flat的結果整合
graph.add_node(Dense(hidden_dims,activation='relu'), name='dense1', 
               inputs=['flat1', 'flat2', 'flat3'], merge_mode='concat')
graph.add_node(Dropout(0.5), name='drop1', input='dense1')
graph.add_node(Dense(nb_classes, activation='softmax'), name='softmax', input='drop1')
graph.add_output(name='output', input='softmax')

graph.compile('Adam', loss = {'output': 'categorical_crossentropy'}, metrics=['accuracy'])
history = graph.fit({'input':X_train, 'output':Y_train}, 
                   nb_epoch=nb_epoch,batch_size=batch_size,validation_split=0.2)

在 Graph物件中,原先在 Sequential中的 add方法改名為 add_node。而且特別要注意的是,由於 Graph可以建立非線性疊加的網絡結構,如同我們這個的例子一樣,因此各個連結之間的輸入(input)都必需要標示清楚

圖片特徵的截取是 CNN最常見的應用。但拜 word2vec方法的建立,一個單詞可以被投影至一個虛構的潛在語意空間而成為一個多維向量,而含有許多單詞文本的資料也就可以被轉換為由多個單詞向量堆積而成類似圖片的 2D結構,也就是矩陣,而這樣的動作就稱之為 embedding。

大家可能會注意到這個例子中使用的是 Convolutional1D,可以想像 filter是在一個單詞的向量空間滑動的特徵截取器。但由於向量空間的基底(basis)並沒有具體意義,因此想法上比較隱誨,而經過測試後也證實是有用的。

WILDML這篇以Tensorflow實作CNN的文章以及其他許多的文獻中,實際上採用的是 Convolutional2D,可以想像成類似n-gram的特徵取法,也就是 filter會在詞彙空間中滑動,一次框起 n個詞。

基本上,Convolutional2D的實作只需要將上面程式碼的1D換做2D即可,但需要重新設定filter size、pool size等等參數。其中要特別注意的是,Convolutional2D的 input是吃一個四維的 tensor,而四個維度分別的參數為 (samples, channels, rows, cols)。

由於本身對於CNN的認識還是非常的有限,若有任何錯誤的話也歡迎大家提出來討論!

喜歡這篇文章的話請不要忘了點個
關鍵字:python深度學習, deep learning, Keras CNN example, Keras graph example

2 則留言 :

  1. keras graph model 已經停止更新了
    如果改用新的model functional API 會更好用
    https://keras.io/getting-started/functional-api-guide/

    回覆刪除