在這篇小文章中,我們將簡要討論如何使用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é)家這個使用人群中流行起來。 什么是KERASKEARS是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有以下幾個不同:
跟這些流行的計算平臺一樣,KERAS也支持常見的深度學(xué)習(xí)模型,比如卷積神經(jīng)網(wǎng)絡(luò),循環(huán)神經(jīng)網(wǎng)絡(luò)以及二者的組合等。 使用KERAS構(gòu)造深度神經(jīng)網(wǎng)絡(luò)有一系列相對固定的步驟:
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)品推薦出來。
推薦系統(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)示意圖:
有了這個示意圖,我們就可以很方便地用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):
上面這個網(wǎng)絡(luò)依次展示了卷積網(wǎng)絡(luò)模型的主要要素:
下面詳細(xì)介紹一下在KERAS中如何對應(yīng)地進(jìn)行編程處理。
在KERAS里,對于圖像這種二維數(shù)據(jù),一般使用Conv2D這個二維卷積層。Conv2D有幾個必備的參數(shù):
對于上面的例子,KERAS里的典型寫法是: model.add(Conv2D(filters=16, kernel_size=(3, 3), strides=1, padding=”valid”, input_shape=xtrain.shape[1:]))
對應(yīng)于圖像的最大池化層通過MaxPooling2D,KERAS也支持平均池化層,區(qū)別在于取對應(yīng)局部的平均值作為池化后結(jié)果,方法為AveragePooling2D。對應(yīng)上面的例子,KERAS的命令如下: model.add(MaxPooling2D(pool_size=(3, 3))
把所有步驟組合到一起,我們就可以將圖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()
我們看到這個模型一共有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ù):
下面我們使用這個模型訓(xùn)練識別0-9這十個數(shù)字,使用著名的MNIST數(shù)據(jù)。不過在訓(xùn)練之前還需要提及對數(shù)據(jù)的處理:
下圖的結(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ù)。
上圖是著名的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)。計量單位未知。
在一般的時間序列建模中,都需要檢驗(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模型建模。
我們可以通過周期圖譜法(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)
很明顯有一個周期為 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)行建模的時候,一般通過一下步驟:
首先對數(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)重都會被用到。
對于這樣的網(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) 下圖展示了擬合過程的信息:
那么這個模型的擬合效果如何呢?
我們看到擬合效果還不錯。平均絕對誤差百分比(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)域,分別是:
|
|
來自: silence_33 > 《人工智能》