日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

如何用 Keras 搭建深度學(xué)習(xí)模型

 silence_33 2017-08-24

在這篇小文章中,我們將簡要討論如何使用KERAS這個現(xiàn)在最新的深度學(xué)習(xí)框架來構(gòu)造實(shí)用的深度學(xué)習(xí)模型。

深度學(xué)習(xí)是目前最熱門的高級分析技術(shù)之一,在很多方面表現(xiàn)出了超越傳統(tǒng)機(jī)器學(xué)習(xí)方法的有效性。但是在常用的TensorFlow,CNTK,Theano等計算環(huán)境中實(shí)現(xiàn)不同的深度學(xué)習(xí)模型仍然需要耗費(fèi)很多時間來編寫程序。KERAS的出現(xiàn)提供了一個高度抽象的環(huán)境來搭建深度學(xué)習(xí)模型,特別是其簡單易用,跟網(wǎng)絡(luò)結(jié)構(gòu)一一對應(yīng)的特點(diǎn)使得其迅速在數(shù)據(jù)科學(xué)家這個使用人群中流行起來。

什么是KERAS

KEARS是Google工程師Fran?ois Chollet為主創(chuàng)人員,基于Python開發(fā)和維護(hù)的一個抽象的神經(jīng)網(wǎng)絡(luò)建模環(huán)境,提供了一系列的API供用戶調(diào)用構(gòu)造自己的深度學(xué)習(xí)網(wǎng)絡(luò)。KERAS的出發(fā)點(diǎn)就是為用戶提供一個能夠快速實(shí)現(xiàn)模型的手段,從而縮短建模迭代的時間,加快模型試驗(yàn)的頻率。用KERAS開發(fā)者的話說,就是要做好的科研必須盡可能地縮短從想法到實(shí)現(xiàn)結(jié)果的時間。在業(yè)界工作中這也是成功的關(guān)鍵要素之一。

相比較于常見的深度學(xué)習(xí)環(huán)境,比如TensorFlow,CNTK,Theano,Caffe等,KERAS有以下幾個不同:

  1. 設(shè)計初衷就是方便以模塊化地方式快速構(gòu)造深度學(xué)習(xí)模型的原型。

  2. 可以很方便地在CPU和GPU之間切換。

  3. KERAS本身只是描述模型的環(huán)境,其計算平臺目前依賴于TensorFlow,CNTK和Theano這三種,以后會拓展到其他流行的計算平臺上,比如mxNet等。

  4. KERAS的拓展性既可以通過自定義KERAS里的激活函數(shù)或者損失函數(shù)等能自定義的部分進(jìn)行,也可以通過引用對應(yīng)的計算平臺的自定義部分進(jìn)行,具有一定的靈活性。

跟這些流行的計算平臺一樣,KERAS也支持常見的深度學(xué)習(xí)模型,比如卷積神經(jīng)網(wǎng)絡(luò),循環(huán)神經(jīng)網(wǎng)絡(luò)以及二者的組合等。

使用KERAS構(gòu)造深度神經(jīng)網(wǎng)絡(luò)有一系列相對固定的步驟:

  • 首先要將原始數(shù)據(jù)處理成KERAS的API能夠接受的格式,一般是一個張量的形式,通常在維度上表示為(批量數(shù),[單一樣本對應(yīng)張量的維度])。這里[單一樣本對應(yīng)張量的維度] 是一個通用的說法,對應(yīng)于不同類型的模型,數(shù)據(jù)有不同的要求。

    通常,如果是一個簡單的全鏈接模型,則單一樣本對應(yīng)張量的維度就是特征個數(shù);如果是一維的時間序列數(shù)據(jù),并要用循環(huán)神經(jīng)網(wǎng)絡(luò)模型訓(xùn)練的話,則單一樣本對應(yīng)張量的維度是時間步和每個時間步對應(yīng)的回看序列長度;如果輸入數(shù)據(jù)是圖像,并使用卷積神經(jīng)網(wǎng)絡(luò)模型進(jìn)行訓(xùn)練,則單一樣本張量對應(yīng)圖像的高,寬和色彩頻道三個維度。但是如果是使用全連接模型訓(xùn)練圖像數(shù)據(jù),則單一樣本對應(yīng)張量是該圖像扁化(Flatten)以后的向量長度,其為高,寬和色彩頻道各個維度數(shù)量的乘積。一般卷積神經(jīng)網(wǎng)絡(luò)最靠近輸出層的那層都設(shè)置一個全連接層,因此也需要扁化輸入張量。

  • 其次要構(gòu)造需要的深度學(xué)習(xí)模型。這一步又分為以下兩個步驟:

    選擇模型的類型。KERAS里定義了兩大類模型:1)序列模型(Sequential); 2)通用模型(Model)。

    序列模型指的是深度模型每一層之間都是前后序列關(guān)系,如下圖所示:

    Figure 1:MLP是一個典型的序列模型,圖片來源

    可以看到從左到右,輸入層到隱含層到輸出層每一層之間都是前后依次相連的簡單關(guān)系。這個簡單的網(wǎng)絡(luò)結(jié)構(gòu)可以用三句KERAS命令實(shí)現(xiàn):

    model=Sequential()model.add(Dense(5, input_shape=(4,), activation=’sigmoid’))model.add(Dense(1, activation=’sigmoid’))

    而通用模型則是對應(yīng)更廣義的模型,具備更大的靈活性。上面提到的序列模型也可以用通用模型來表達(dá),這個我們在后一節(jié)詳解。

    當(dāng)然通用模型更能用來描述層與層之間有較復(fù)雜關(guān)系的情況,比如非相鄰的層之間進(jìn)行連接,或者多個神經(jīng)網(wǎng)絡(luò)的合并等。比如我們可以使用通用模型進(jìn)行矩陣分解:

    user_in = Input(shape=(1,), dtype='int64', name='user_in')u = Embedding(n_users, n_factors, input_length=1)(user_in)movie_in = Input(shape=(1,), dtype='int64', name='movie_in')v = Embedding(n_movies, n_factors, input_length=1)(movie_in)x = merge([u, v], mode='dot')x = Flatten()(x)model = Model([user_in, movie_in], x)model.compile(Adam(0.001), loss='mse')

    這里構(gòu)造了一個基于矩陣分解的推薦系統(tǒng)的一個深度學(xué)習(xí)模型,其對應(yīng)的網(wǎng)絡(luò)結(jié)構(gòu)如下圖所示:

    Figure 2:矩陣分解的深度學(xué)習(xí)模型

    細(xì)化模型的結(jié)構(gòu)。其實(shí)上面已經(jīng)展示了模型結(jié)構(gòu)細(xì)化之后的情況。一般來說,確定了模型類型以后,其結(jié)構(gòu)不外乎每層的類型是什么,是全連接層還是卷積層還是放棄(Dropout)層;每層的其他參數(shù)是什么,比如如果需要指定激活函數(shù),那么使用什么樣的激活函數(shù),如果是卷積層,那么需要多少過濾器,每個過濾器的大小是怎樣的?等等這些都可以通過設(shè)定不同的參數(shù)進(jìn)行細(xì)化。

  • 然后對模型進(jìn)行編譯,編譯完成以后可以查看模型的基本信息,特別是參數(shù)的數(shù)量;

  • 最后帶入數(shù)據(jù)對模型進(jìn)行擬合。一般來講,如果數(shù)據(jù)是靜態(tài)的張量數(shù)據(jù),通過使用fit方法。如果數(shù)據(jù)特別大,可是使用可迭代的data generator對象,并使用fit_generator方法來擬合。

KERAS和深度學(xué)習(xí)模型的對應(yīng)關(guān)系

KERAS既然是開發(fā)出來快速構(gòu)造深度學(xué)習(xí)模型的工具,那么它的API和深度學(xué)習(xí)模型的要素都有很強(qiáng)的對應(yīng)關(guān)系。

正如上面所說,目前的深度學(xué)習(xí)模型都可以納入序列模型或者通用模型的,那么我們用圖示的方式來表示這個對應(yīng)關(guān)系,方便讀者理解。這里網(wǎng)絡(luò)圖為了方便與按行排列的代碼對應(yīng),對每一層都進(jìn)行了標(biāo)注。

下圖展示的是一個典型的全連接序列模型:

這個序列模型可以使用如下的KERAS命令快速搭建:

Model = Sequential()Model.add(Dense(10, activation=’sigmoid’,                   input_shape=(8, ))           【隱含層1+輸入層】Model.add(Dense(8, activation=’relu’))          【隱含層2】Model.add(Dense(10, activation=’relu’))         【隱含層3】Model.add(Dense(5, activation=’softmax’))       【輸出層】

上面的序列模型也可以用通用模型的API描述的結(jié)果,其與圖中的網(wǎng)絡(luò)結(jié)構(gòu)有更強(qiáng)的對應(yīng)關(guān)系:

x = Input(shape=(8,))                        【輸入層】b = Dense(10, activation=’sigmoid’)(x)       【隱含層1】c = Dense(8, activation=’relu’)(b)           【隱含層2】d = Dense(10, activation=’relu’)(c )         【隱含層3】out = Dense(5, activation=’softmax’)(d)      【輸出層】model = Model(inputs=x, outputs=out)

上面也舉了另外的比較復(fù)雜的例子。在后面的具體案例中,我們也會強(qiáng)調(diào)網(wǎng)絡(luò)結(jié)構(gòu)和對應(yīng)的KERAS命令,使讀者能建立起較強(qiáng)的聯(lián)系。

使用KERAS構(gòu)造深度推薦系統(tǒng)

推薦系統(tǒng)是機(jī)器學(xué)習(xí)最廣泛的應(yīng)用領(lǐng)域之一,大家熟悉的亞馬遜、迪士尼、谷歌、Netflix 等公司都在網(wǎng)頁上有其推薦系統(tǒng)的界面,幫助用戶更快、更方便地從海量信息中找到有價值的信息。比如亞馬遜(www.amazon.com)會給你推薦書、音樂等,迪士尼(video.disney.com)給你推薦最喜歡的卡通人物和迪士尼電影,谷歌搜索更不用說了, Google Play、 Youtube 等也有自己的推薦引擎、推薦視頻和應(yīng)用等。下面是我登陸亞馬遜之后的一個推薦頁面,可見我之前應(yīng)該是購買了咖啡機(jī),所以會有相關(guān)的產(chǎn)品推薦出來。

Figure 4:亞馬遜的推薦頁面局部

推薦系統(tǒng)的最終目的是從百萬甚至上億內(nèi)容或者商品中把有用的東西高效地顯示給用戶,這樣可以為用戶節(jié)省很多自行查詢的時間,也可以提示用戶可能忽略的內(nèi)容或商品,使用戶更有黏性,更愿意花時間待在網(wǎng)站上,從而使商家可以從內(nèi)容或者商品中賺取更多的利潤,即使流量本身也會使商家從廣告中受益。

傳統(tǒng)上,推薦系統(tǒng)是基于矩陣分解的協(xié)同過濾算法,前面也展示了這樣的一個簡單模型。下面我們著重介紹深度學(xué)習(xí)推薦系統(tǒng)。這個模型除了能將用戶和可選產(chǎn)品聯(lián)系起來意外,還能將其他輔助數(shù)據(jù),比如用戶年齡,地區(qū),上網(wǎng)設(shè)備以及各種產(chǎn)品屬性,聯(lián)系起來。這里通過嵌入(Embedding)這種技術(shù)將不同的信息串在一起作為輸入層,再繼續(xù)搭建不同的神經(jīng)網(wǎng)絡(luò)模型,最后一層用預(yù)測評分作為輸出層。雖然這里的數(shù)據(jù)只有用戶編碼和電影產(chǎn)品編碼,但是這樣的結(jié)構(gòu)可以拓展到包含其他相關(guān)數(shù)據(jù)。下圖展示了這樣的一個深度模型的結(jié)構(gòu)示意圖:

Figure 5:深度模型

有了這個示意圖,我們就可以很方便地用KERAS依次構(gòu)造。這里我們假設(shè)已經(jīng)將用戶和電影產(chǎn)品做了按照One Hot編碼形式組織好了。

首先用嵌入層對用戶和電影進(jìn)行嵌入映射:

k = 128model1 = Sequential()model1.add(Embedding(n_users + 1, k, input_length = 1))model1.add(Reshape((k,)))model2 = Sequential()model2.add(Embedding(n_movies + 1, k, input_length = 1))model2.add(Reshape((k,)))

這里的k是映射到的空間的維度。在一般的業(yè)務(wù)系統(tǒng)中我們可能有上百萬的用戶和產(chǎn)品,經(jīng)過嵌入映射到128維的實(shí)數(shù)域上以后顯著地降低了整個系統(tǒng)的維度和大小。

以上幾句命令實(shí)現(xiàn)了上圖從最低下到“用戶嵌入”和“電影嵌入”這一階段的編程。

其次,我們需要用第三個神經(jīng)網(wǎng)絡(luò)把前面的兩個嵌入網(wǎng)絡(luò)映射所得到的向量疊加在一起:

model = Sequential()model.add(Merge([model1, model2], mode = 'concat'))

至此完成了到第一個粗箭頭的網(wǎng)絡(luò)構(gòu)造。兩個網(wǎng)絡(luò)已經(jīng)合并為一個網(wǎng)絡(luò)。

下面的命令依次完成“隱含層128”和“隱含層32”的構(gòu)造:

model.add(Dropout(0.2))model.add(Dense(k, activation = 'relu'))model.add(Dropout(0.5))model.add(Dense(int(k/4), activation = 'relu'))model.add(Dropout(0.5))

下面繼續(xù)構(gòu)造“隱含層8”:

model.add(Dense(int(k/16), activation = 'relu'))model.add(Dropout(0.5))

隱含層構(gòu)造完畢之后,需要構(gòu)造輸出層。因?yàn)槭穷A(yù)測連續(xù)變量評分,最后一層直接上線性變化:

model.add(Dense(1, activation = 'linear'))

至此,模型構(gòu)造完畢,可以編譯了:

model.compile(loss = 'mse', optimizer = 'adam')

這里使用了均方差(MSE)作為損失函數(shù),并使用了ADAM優(yōu)化算法。

下面,為了能訓(xùn)練模型,需要將數(shù)據(jù)構(gòu)造為[users, movies]的形式:

users = ratings['user_id'].valuesmovies = ratings['movie_id'].valuesX_train = [users, movies]

最后訓(xùn)練模型:

model.fit(X_train, y_train, batch_size = 100, epochs = 50)

使用movielens的用戶觀看電影評分?jǐn)?shù)據(jù)進(jìn)行訓(xùn)練和驗(yàn)證,我們發(fā)現(xiàn)這個模型的誤差在0.8226左右,大約一個評分等級不到。即使這樣一個簡單的模型,效果還是比較好的。如果進(jìn)一步優(yōu)化結(jié)構(gòu),或者引入其他信息,誤差還可以進(jìn)一步降低。

使用KERAS構(gòu)造圖像識別系統(tǒng)

圖像識別是深度學(xué)習(xí)最典型的應(yīng)用之一。關(guān)于深度學(xué)習(xí)的圖像識別可以追溯很長的歷史,其中最具有代表性的例子是手寫字體識別和圖片識別。手寫字體識別主要是用機(jī)器正確區(qū)別手寫體數(shù)字 0~9。銀行支票上的手寫體識別技術(shù)就是基于這個技術(shù)。圖片識別的代表作就是 ImageNet。這個比賽需要團(tuán)隊(duì)識別圖片中的動物或者物體,把它們正確地分到一千個類別中的其中一個。

圖像識別有很多種技術(shù)可以實(shí)現(xiàn),目前最主流的技術(shù)是深度神經(jīng)網(wǎng)絡(luò),其中尤以卷積神經(jīng)網(wǎng)絡(luò)(CNN)最為出名。卷積神經(jīng)網(wǎng)絡(luò)(見圖1)是一種自動化特征提取的機(jī)器學(xué)習(xí)模型。從數(shù)學(xué)的角度看,任何一張圖片都可以對應(yīng)到 224 × 224 × 3 或者 32 × 32 × 3 等三維向量,這取決于像素。我們的目標(biāo)是把這個三維向量(又被稱為張量)映射到 N個類別中的一類。神經(jīng)網(wǎng)絡(luò)就是建立了這樣一個映射關(guān)系,或者稱為函數(shù)。它通過建立網(wǎng)狀結(jié)構(gòu),輔以矩陣的加、乘等運(yùn)算,最后輸出每個圖像屬于每個類別的概率,并且取概率最高的作為我們的決策依據(jù)。 下面是一個典型的序列卷積神經(jīng)網(wǎng)絡(luò)模型的結(jié)構(gòu):

Figure 6:卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)。來源于CNTK教程。

上面這個網(wǎng)絡(luò)依次展示了卷積網(wǎng)絡(luò)模型的主要要素:

  • 輸入層的圖像;

  • 卷積操作;

  • 激活函數(shù)的應(yīng)用;

  • 池化操作;

  • 將數(shù)據(jù)展平(Flatten),為輸出到全連接層做準(zhǔn)備;

  • 全連接層準(zhǔn)備輸出;

  • softmax應(yīng)用于分類問題的全連接層作為輸出層。

下面詳細(xì)介紹一下在KERAS中如何對應(yīng)地進(jìn)行編程處理。

  • 首先,這是一個序列模型,因此先要聲明一個序列模型的對象:

    model=Sequential()
  • 卷積是應(yīng)用一個局部的過濾器到原始數(shù)據(jù)的過程,比如下圖就展示了一個3x3的過濾器應(yīng)用在一個7x7的圖像上過程。假設(shè)在當(dāng)前步,這個過濾器的權(quán)重經(jīng)過學(xué)習(xí)得到如圖所示的權(quán)重結(jié)果,在當(dāng)前步繼續(xù)進(jìn)行卷積操作就是將這個3x3的過濾器從左上角每次要么向右要么向下移動一格,和對應(yīng)的圖像局部的3x3的區(qū)域進(jìn)行依元素點(diǎn)乘求和得到卷積的結(jié)果。因?yàn)橐来我苿樱阶钸吷系臅r候過濾器會超出圖像的邊界,一般會將這些對應(yīng)的卷積結(jié)果刪除,從而卷積后的張量維度會少于原始圖像。比如這個例子中原圖為7x7,使用一個3x3的過濾器卷積之后最后兩列和兩行進(jìn)行卷積的時候會使過濾器超過邊界,因此最后的卷積結(jié)果是一個5x5的圖像。這里可以使用多個過濾器,每個過濾器應(yīng)用一次,每次應(yīng)用產(chǎn)生的卷積結(jié)果構(gòu)成隱含層的一層。比如采用16個過濾器,如果不刪除邊界的過濾結(jié)果,則得到新的[7x7x16]的張量。

Figure 7:卷積演示,來源于CNTK教程。

在KERAS里,對于圖像這種二維數(shù)據(jù),一般使用Conv2D這個二維卷積層。Conv2D有幾個必備的參數(shù):

  1. 首先指定過濾器數(shù)量 filters,是一個整數(shù);

  2. 第二是要指定二維過濾器的大小,比如(3,3);

  3. 第三要指定步長,即延某軸移動的時候是依次移動一個像素還是多個像素,默認(rèn)為1;

  4. 第四要指定補(bǔ)齊策略padding,即是否要將在邊界的卷積結(jié)果去掉。如果值為”same”,則不去掉,卷積結(jié)果和輸入圖像有同樣的高和寬;如果值為”valid”,則不會處理過濾器會超出邊界的像素。

  5. 最后,如果卷積層是第一層,那么還需要指明輸入數(shù)據(jù)的維度input\_shape。因?yàn)橐话阌肨ensorFlow或者CNTK做后臺,輸入數(shù)據(jù)要求是channel_last,因此輸入的原始維度為[樣本量,高,寬,頻道],那么這里的維度只需要去掉樣本量即可,即為[高,寬,頻道數(shù)],一般用X.shape[1:]即可得到。

對于上面的例子,KERAS里的典型寫法是:

model.add(Conv2D(filters=16, kernel_size=(3, 3),                  strides=1, padding=”valid”,                  input_shape=xtrain.shape[1:]))
  • 再次要添加激活層引入激活函數(shù),通常是一個非線性的函數(shù)。激活函數(shù)既可以通過在Conv2D里面指定activation=參數(shù)引入,也可以通過單獨(dú)添加Activation層引入。卷積神經(jīng)網(wǎng)絡(luò)常用的激活函數(shù)是Rectified Linear Unit, 簡稱relu。該函數(shù)其實(shí)就是max(0, x),在層次較深的網(wǎng)絡(luò)中比以前常用的取值區(qū)間在(0,1)或者(-1, 1)之間的sigmoid類激活函數(shù)效果好,因?yàn)椴淮嬖谔荻认У膯栴}。

    如果是通過參數(shù),則上面的代碼改寫為:

    model.add(Conv2D(filters=16, kernel\_size=(3, 3),             strides=1, padding=”valid”,             activation=’relu’)

    如果通過添加激活層引入,則在上面的代碼后添加:

    model.add(Activation(‘relu’))
  • 然后進(jìn)行的池化操作是在卷積神經(jīng)網(wǎng)絡(luò)中對圖像特征的一種處理,通常在卷積操作和激活函數(shù)之后進(jìn)行。池化操作是將原有輸入按照一定大小切分成互不交叉的局部區(qū)域,目的是為了計算特征在局部的充分統(tǒng)計量,從而降低總體的特征數(shù)量,防止過度擬合和減少計算量。下圖展示了最大池化方法的應(yīng)用。在一個6x6的圖像上應(yīng)用3x3的池化操作,將原輸入矩陣切割為不相交叉的2x2區(qū)域,每個區(qū)域的取值是對應(yīng)原輸入局部的最大值。

Figure 8:最大池化操作

對應(yīng)于圖像的最大池化層通過MaxPooling2D,KERAS也支持平均池化層,區(qū)別在于取對應(yīng)局部的平均值作為池化后結(jié)果,方法為AveragePooling2D。對應(yīng)上面的例子,KERAS的命令如下:

model.add(MaxPooling2D(pool_size=(3, 3))
  • 為了輸出到全連接層,先要對數(shù)據(jù)進(jìn)行展平(Flatten)。這是因?yàn)槿B接層只處理包含樣本數(shù)在內(nèi)一共二維的數(shù)據(jù),要求第一維是樣本數(shù),第二維是所有特征的個數(shù)。因此對于一個包含2000個樣本,每個樣本是28x28x3的小圖像的數(shù)據(jù),展平之后是一個2000x2352的矩陣,其中2352是28,28,3的乘積。在KERAS里進(jìn)行展平非常簡單,在上面的MaxPooling2D層之后添model.add(Flatten())即可,KERAS能自己分析出輸入和輸出的維度。

  • 在前面這些處理之后,但是在輸出之前,通常會添加一個或者多個全連接層進(jìn)一步處理數(shù)據(jù)。全連接層可以通過Dense指出,指明輸出神經(jīng)元個數(shù)和激活函數(shù)即可:

    model.add(Dense(1000, activation=’relu’))
  • 最后使用一個全連接層作為輸出層,同樣要求使用softmax激活函數(shù),并使用跟輸出類別同樣多的神經(jīng)元個數(shù)。比如識別0—9十個數(shù)字,那么就應(yīng)該寫作:

    model.add(Dense(10, activation=’relu’))

把所有步驟組合到一起,我們就可以將圖6顯示的一個卷積神經(jīng)網(wǎng)絡(luò)模型相應(yīng)地寫為KERAS代碼了:

model=Sequential()model.add(Conv2D(filters=32, kernel_size=(3, 3),          padding='same',          input_shape=X_train.shape[1:],          activation='relu'))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Conv2D(filters=64, kernel_size=(3, 3), padding='valid'))model.add(Activation('relu'))model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Flatten())model.add(Dense(128, activation='relu'))model.add(Dense(num_classes, activation='softmax'))

是不是很簡單?

要訓(xùn)練這個模型非常簡單。我們先編譯這個模型并顯示其關(guān)鍵信息:

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

Figure 9:模型信息

我們看到這個模型一共有421642個參數(shù),大多來自于倒數(shù)第二層的全連接層。

擬合這個模型也很簡單:

model.fit(X_train, y_train,          epochs=20, verbose=1,          batch_size=10,          validation_data = (X_test, y_test))

這里使用最標(biāo)準(zhǔn)的fit方法。其中指定幾個核心參數(shù):

  1. 訓(xùn)練用特征數(shù)據(jù)X_train

  2. 訓(xùn)練用結(jié)果數(shù)據(jù)y_train

  3. 迭代次數(shù)epochs

  4. 批量大小用batch_size指定

  5. verbose表示顯示訓(xùn)練過程的信息,如果值為0不顯示任何中間信息,如果為1顯示按批量擬合的進(jìn)度,如果為2則顯示擬合結(jié)果信息。

  6. 另外讀者還可以指定驗(yàn)證數(shù)據(jù)集,用validation_data這個參數(shù)表示,其包含一個tuple,第一個元素是驗(yàn)證用特征數(shù)據(jù),第二個是驗(yàn)證用結(jié)果數(shù)據(jù)。

下面我們使用這個模型訓(xùn)練識別0-9這十個數(shù)字,使用著名的MNIST數(shù)據(jù)。不過在訓(xùn)練之前還需要提及對數(shù)據(jù)的處理:

  • 首先將數(shù)據(jù)重塑為[樣本數(shù),高,寬,色彩通道數(shù)]的格式。這個可以通過numpy.reshape方法來實(shí)現(xiàn)。因?yàn)閗eras自帶的MNIST數(shù)據(jù)已經(jīng)是numpy的多維矩陣,并且是單色的,因此色彩通道數(shù)為1,因此數(shù)據(jù)重塑可以用下面的命令實(shí)現(xiàn)。讀者可自行重塑驗(yàn)證用數(shù)據(jù)。

    X_train = X_train.reshape(X_train.shape[0],                      X_train.shape[1],                      X_train.shape[2], 1).astype(float)
  • 其次,需要將數(shù)據(jù)的取值壓縮到[0, 1]之間。這有利于擬合時用的隨機(jī)梯度遞降算法的穩(wěn)定和收斂。這可以使用X_train /= 255.0 來實(shí)現(xiàn)。

  • 最后要將結(jié)果數(shù)據(jù)變?yōu)镺ne Hot Code形式。KERAS提供了一個非常方便的方法to_categorical來實(shí)現(xiàn)這個功能:

    y_train = keras.utils.to_categorical(y_train, len(set(y_train)))

下圖的結(jié)果顯示即使是這個非常簡單的模型,其在驗(yàn)證數(shù)據(jù)上的預(yù)測準(zhǔn)確率都是非常高的,達(dá)到了99.14%。

使用KERAS可以非常方便的構(gòu)造自己的卷積神經(jīng)網(wǎng)絡(luò),對于比較復(fù)雜的情況,也可以使用已經(jīng)訓(xùn)練好的一些常見的高效模型,比如VGG16,Xception 等做遷移訓(xùn)練來擬合自己的數(shù)據(jù)。

Figure 11: VGG16結(jié)構(gòu),來源

上圖是著名的VGG16模型的結(jié)構(gòu)。根據(jù)剛才的學(xué)習(xí)結(jié)果,讀者可以很快地模仿這個結(jié)構(gòu)搭建自己的類似模型,但是KERAS在application庫里已經(jīng)提供了現(xiàn)成訓(xùn)練好的VGG16模型供讀者讀入使用。讀者可以引用這個模型,將頂層去掉用自己的數(shù)據(jù)重新訓(xùn)練,但是底層的參數(shù)借用VGG16已經(jīng)訓(xùn)練好的權(quán)重。這就是遷移學(xué)習(xí)的思路,可以大大降低需要訓(xùn)練的參數(shù)數(shù)量,加快新模型的開發(fā)。這里使用了通用模型以便在現(xiàn)有的VGG16模型上進(jìn)行修改:

model_vgg = VGG16(include_top = False,                  weights = 'imagenet',                  input_shape =(224,224,3))model = Flatten(name = 'flatten')(model_vgg.output)model = Dense(10, activation = 'softmax')(model)model_vgg_mnist = Model(model_vgg.input, model,                        name = 'vgg16')

這里首先引用VGG16模型,但是通過參數(shù)include_top=False指定遷移除頂層以外的其余網(wǎng)絡(luò)結(jié)構(gòu)到自己的模型中。Weights=’imagenet’表示借用的權(quán)重是用ImageNet數(shù)據(jù)訓(xùn)練出來的額。

其次,通過函數(shù)方法在修改過的VGG16模型上構(gòu)造一個新的扁平層用來連接新構(gòu)造的全連接層,這個全連接層跟前面的模型沒有區(qū)別。最后把修改過的VGG16模型和新的頂層疊加起來并賦予新的名字vgg16。這樣就得到了一個基于VGG16的新模型。

使用KERAS構(gòu)造時間序列預(yù)測模型

時間序列是在商業(yè)數(shù)據(jù)或者工程數(shù)據(jù)中經(jīng)常出現(xiàn)的一種數(shù)據(jù)形式,是以時間為次序排列,用來描述和計量一系列過程或者行為的數(shù)據(jù)的統(tǒng)稱。比如每天商店的收入流水或者某個工廠每小時的產(chǎn)品產(chǎn)出都是時間序列數(shù)據(jù)。一般研究的時間序列數(shù)據(jù)有兩種類型。最常見的是跟蹤單一的計量數(shù)據(jù)隨時間變化的情況,即每個時間點(diǎn)上收集的數(shù)據(jù)是一個一維變量,這種是最常見的,通常的時間序列默認(rèn)就是這種數(shù)據(jù),也是本章研究的對象。另外一種時間序列數(shù)據(jù)是多個對象或者多個維度的計量數(shù)據(jù)隨時間變化的情況,即每個時間點(diǎn)上收集的數(shù)據(jù)是一個多維變量,這種一般也被稱為縱向數(shù)據(jù)(Longitudinal Data),但是不屬于這里介紹的對象。

在這里我們介紹如何搭建一個LSTM深度學(xué)習(xí)模型來對在漢口測量的長江每月流量數(shù)據(jù)進(jìn)行預(yù)測建模。該數(shù)據(jù)來源于DataMarket 的時間序列數(shù)據(jù)庫,由澳大利亞莫納什大學(xué)的統(tǒng)計學(xué)教授Rob Hyndman 創(chuàng)建,收集了數(shù)十個公開的時間序列數(shù)據(jù)集。

漢口長江月流量數(shù)據(jù)包含從 1865 年 1 月到 1978 年 12 月在漢口記錄的長江每月的流量,總計 1368 個數(shù)據(jù)點(diǎn)。計量單位未知。

Figure 12:長江月度流量時間序列

在一般的時間序列建模中,都需要檢驗(yàn)數(shù)據(jù)的平穩(wěn)性,因?yàn)閭鹘y(tǒng)時間序列建模都是建立在平穩(wěn)數(shù)據(jù)的假設(shè)之上。這個數(shù)據(jù)具備非常強(qiáng)的年度周期性。使用傳統(tǒng)的統(tǒng)計技術(shù)建模的時候都需要偵測周期性,并消除之,對消除周期性之后的數(shù)據(jù)運(yùn)用ARIMA模型建模。

Figure 13:長江月度流量局部和移動平滑結(jié)果

我們可以通過周期圖譜法(Periodogram)來得到主要的周期幅度。在Python中可以使用scipy.signal.periodogram來得到周期圖譜。在這里我們不是使用原始數(shù)據(jù),而是使用原始數(shù)據(jù)的自相關(guān)函數(shù)的周期圖譜來計算主要周期,這樣可以抵消噪音的影響。對讀入pandas DataFrame的原始數(shù)據(jù)ts運(yùn)行下面的程序我們可以得到如下的周期圖譜和計算得到的主要周期長度。

import statsmodels.api as smfrom statsmodels.tsa.stattools import acffrom scipy import signalimport peakutils as peakacf_x, acf_ci = acf(ts, alpha=0.05, nlags=36)fs=1f, Pxx_den = signal.periodogram(acf_x, fs)index = peak.indexes(Pxx_den)cycle=(1/f[index[0]]).astype(int)fig = plt.figure()ax0 = fig.add_subplot(111)plt.vlines(f, 0, Pxx_den)plt.plot(f, Pxx_den, marker='o', linestyle='none', color='red')plt.title('Identified Cycle of %i' % (cycle))plt.xlabel('frequency [Hz]')plt.ylabel('PSD [V**2/Hz]')plt.show()print( index, f, Pxx_den)

Figure 14:周期圖譜

很明顯有一個周期為 12 個月的季節(jié)性。雖然考慮到這個數(shù)據(jù)的本質(zhì)是長江水文資料, 12 個月的周期是非常自然的預(yù)期,但是這個方法展示了對 ACF 序列運(yùn)用周期圖法(periodogram)找季節(jié)性周期的可靠性。在傳統(tǒng)方法里,這里需要通過取間隔為12 的差分來消除周期性,得到一個盡可能平穩(wěn)的時間序列,進(jìn)而采用ARIMA模型建模。在Python里,單周期的時間序列數(shù)據(jù),知道周期的長度以后可以直接使用季節(jié)性ARIMA模型(SARIMA)來訓(xùn)練。

但是在使用循環(huán)神經(jīng)網(wǎng)絡(luò)模型的時候我們不用考慮這些情況,可以直接使用長短記憶模型。此外,在使用LSTM這種序列模型的時候在使用LSTM對這種單一時間序列進(jìn)行建模的時候,一般通過一下步驟:

  1. 將數(shù)據(jù)標(biāo)準(zhǔn)化為[0,1]區(qū)間。

  2. 按照LSTM的要求,將輸入數(shù)據(jù)組織為[樣本數(shù),時間步,特征變量數(shù)]的三位格式來組織。

  3. 定義一個LSTM深度學(xué)習(xí)模型,通常為一個序列模型對象,逐層添加LSTM層或者其他層,最后通過一個全連接層輸出到輸出層。

  4. 最后對需要的時間段進(jìn)行預(yù)測。

首先對數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化,我們使用sklearn包里的MinMaxScaler函數(shù):

scaler = MinMaxScaler(feature_range=(0, 1))trainstd = scaler.fit_transform(train.values.astype(float).reshape(-1, 1))teststd = scaler.transform(test.values.astype(float).reshap

其次,我們將訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)組織成需要的格式,這個格式與我們將要建立的LSTM模型有關(guān)。這里我們對每個輸入構(gòu)造一個LSTM神經(jīng)元,一個60個輸入單元,每一個對應(yīng)一個時間步。這60個單元的輸出會作為一個全連接層的輸入,這個全連接層直接產(chǎn)生下K個連續(xù)時間步的輸出預(yù)測。作為防止過度擬合的正則化手段,我們在LSTM層和全連接層 之間加了一個Dropout層。這個Dropout層在訓(xùn)練的時候會隨機(jī)放棄一部分權(quán)重的更新,但是在進(jìn)行預(yù)測的時候所有權(quán)重都會被用到。

Figure 15:LSTM網(wǎng)絡(luò)結(jié)構(gòu) (修改自CNTK Tutorial)

對于這樣的網(wǎng)絡(luò)結(jié)構(gòu),我們需要如下的一個函數(shù)來定義我們的數(shù)據(jù),即將數(shù)據(jù)組織成為[批量數(shù),時間步數(shù),滯后特征數(shù)]的形式。這個可以通過如下的函數(shù)來實(shí)現(xiàn):

def create_dataset(dataset, timestep=1, look_back=1, look_ahead=1):    from statsmodels.tsa.tsatools import lagmat    import numpy as np    ds = dataset.reshape(-1, 1)        dataX = lagmat(dataset,                   maxlag=timestep*look_back,                   trim='both', original='ex')    dataY = lagmat(dataset[(timestep*look_back):],                  maxlag=look_ahead,                  trim='backward', original='ex')    dataX = dataX.reshape(dataX.shape[0],                          timestep, look_back)[:-(look_ahead-1)]    return np.array(dataX), np.array(dataY[:-(look_ahead-1)])

執(zhí)行下面的命令就可以生成所需數(shù)據(jù):

lookback=1lookahead=24timestep=60trainX, trainY = create_dataset(trainstd,                        timestep=timestep,                        look_back=lookback,  look_ahead=lookahead)trainX, trainY = trainX.astype('float32'), trainY.astype('float32')truthX, truthY = create_dataset(truthstd,                        timestep=timestep,                        look_back=lookback, look_ahead=lookahead)

有了如圖15的網(wǎng)絡(luò)圖以后,就可以開始定義我們的LSTM深度學(xué)習(xí)模型。

batch_size=100model = Sequential()model.add(LSTM(48, batch_size=batch_size, \input_shape=(timestep, lookback), kernel_initializer='he_uniform'))model.add(Dropout(0.15))model.add(Dense(lookahead))model.compile(loss='mean_squared_error', optimizer='adam')

調(diào)用fit方法就可以快速的訓(xùn)練這個模型。我們指定迭代20次,小批量數(shù)為100):

model.fit(trainX, trainY, epochs=20, batch_size=batch_size, verbose=1)

下圖展示了擬合過程的信息:

Figure 16:LSTM擬合過程信息

那么這個模型的擬合效果如何呢?

Figure 17:LSTM擬合結(jié)果

我們看到擬合效果還不錯。平均絕對誤差百分比(MAPE)只有25%不到,比用傳統(tǒng)的SARIMA模型效果要好點(diǎn)。其次,LSTM模型一次輸出未來24個時間點(diǎn)的預(yù)測值,使用起來比用SARIMA迭代預(yù)測方便很多。另外需要指出的是我們也可以直接在模型中指定損失函數(shù)為MAPE,這樣更好優(yōu)化衡量指標(biāo)。

小結(jié)

在這篇短文中,我們介紹了一個目前正在流行起來的深度學(xué)習(xí)建模環(huán)境KERAS。這個建模環(huán)境相對于傳統(tǒng)的計算環(huán)境,比如CNTK,TensorFlow,Theano等具有抽象性高,易用性好的特點(diǎn),同時又依托于這幾種計算環(huán)境,具有一定的可拓展性,非常適合于從事深度學(xué)習(xí)的實(shí)踐者使用。

我們看到使用KERAS可以非常直觀地描述神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),幾乎可以達(dá)到所見即所得的情況。我們在文中還分別介紹了三種流行的應(yīng)用領(lǐng)域,分別是:

  • 深度推薦模型,運(yùn)用嵌入技術(shù)可以將不同類型的信息有機(jī)結(jié)合在一起構(gòu)造一個深度神經(jīng)網(wǎng)絡(luò)推薦系統(tǒng)。

  • 圖像識別模型,運(yùn)用多層卷積神經(jīng)網(wǎng)絡(luò)對圖像進(jìn)行切割分析,得到一個精度很好的手寫數(shù)字分類器。同樣的技術(shù)和模型可以直接移植到其他物體識別數(shù)據(jù)上,比如CIFAR10等。我們也介紹了運(yùn)用已經(jīng)訓(xùn)練好的現(xiàn)成模型進(jìn)行遷移學(xué)習(xí)的手段,減少擬合的參數(shù)量,在保持一定精度的情況下提高訓(xùn)練速度。

  • 簡單時間序列預(yù)測模型,運(yùn)用長短記憶(LSTM)神經(jīng)網(wǎng)絡(luò)模型來有效預(yù)測具備一定周期性的時間序列模型。一個非常簡單的單層LSTM模型既可以達(dá)到定制的SARIMA模型的預(yù)測精度。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多