1. 程式人生 > >深度學習進階:使用keras開發非序列化神經網路

深度學習進階:使用keras開發非序列化神經網路

我們當前所開發的網路都遵循同一個模式,那就是序列化。多個網路層按照前後次序摺疊起來,資料從底層輸入,然後從最高層輸出,其結構如下圖:

1.png

事實上這種形式很不靈活,在很多應用場景中不實用。有些應用場景需要網路同時接收多種輸入,有些應用場景要求網路能同時又多種輸出,有些需要網路內部的網路層傳送分叉,像一顆多叉樹那樣。有一些更復雜的網路結構是,它同時接收來自不同網路的輸出,試想我們想要預測二手車在市場上的售價,此時網路可能要同時接收三種類型的資訊,一種是對車輛的描述,例如車的品牌,型別,使用年限,公里數等;一種是使用者評價產生的文字資料;一種是車輛的圖片。於是我們就可能需要如下形式的網路結構:

2.png

還有一種情況是多型別預測。給定一本小說,我們需要預測這本小說所屬型別,是言情類還是歷史類,同時還需要預測小說的創作年代,於是網路的輸出就必須要有兩個以上的分支:

3.png

對於上面問題,我們可以構造兩個網路去分別預測小說的型別和創造時間,但由於這兩種資料高度相關,知道小說的創作時間很有利於對小說型別的預測,因此把他們整合在一個網路結構裡分析顯然更為合理。同時隨著神經網路應用越來越廣泛,應用場景對網路結構的要求也越來越多樣化,有一類網路叫Inception network,它的特點是輸入資料同時由多個網路層並行處理,然後得到多個處理結果,這些處理結果最後同時歸併到同一個網路層,如下圖:

4.png

谷歌開發的一種強大影象處理網路就屬於上面的結構型別。所有原有的序列化結構無法適應很多複雜的應用場景,因此我們必須使用新的方法構建出類似上面的多樣化神經網路,好在keras匯出很多API,讓我們方便的構建各種型別的深度網路,我們用具體程式碼來看看如何構造各種形態的網路,

from keras.models import Model
from keras import layers
from keras.utils import plot_model
from keras import Input

text_vocabulary_size = 10000
question_vocabulary_size = 1000
answer_vocabulary_size = 500

text_input = Input(shape=(None, ), dtype='int32', name = 'text')
embedded_text = layers.Embedding(64, text_vocabulary_size)(text_input)
encoded_text = layers.LSTM(32)(embedded_text)

question_input = Input(shape = (None, ), dtype='int32', name='question')
embedded_question = layers.Embedding(32, question_vocabulary_size)(question_input)
encoded_question = layers.LSTM(16)(embedded_question)

concatenated = layers.concatenate([encoded_text, encoded_question], axis = -1)
answer = layers.Dense(answer_vocabulary_size, activation='softmax')(concatenated)
model = Model([text_input, question_input], answer)
plot_model(model, to_file='model.png', show_shapes=True)

我們無需輸入資料執行訓練網路,我們只要把握上面網路的拓撲結構即可,上面程式碼的最後一句會把網路影象繪製出來,為了程式碼能正確執行,我們需要安裝一個外掛名為graphviz,通常情況下使用如下命令安裝即可:

pip install graphviz

安裝外掛再執行上面程式碼後,網路的拓撲結構會繪製在model.png圖形檔案裡,它的結構如下所示:

model.png

我們看到該網路並非我們常見的序列結構,最上層是兩個並行分支,其輸出的結果在網路層concatenate_19合併後再輸入最後一層dens_13。這是一個多輸入單輸出的網路,當我們需要構建一個網路,它能讀入資料並預測多種不同型別的數值時,這類網路就是單輸入多輸出的情況,一個具體例子如下:

vocabulary_size = 50000
num_income_groups = 10

posts_input = Input(shape=(None, ), dtype = 'int32', name = 'posts')
embedded_posts = layers.Embedding(256, vocabulary_size)(posts_input)
x = layers.Conv1D(128, 5, activation='relu')(embedded_posts)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.MaxPooling1D(5)(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.Conv1D(256, 5, activation='relu')(x)
x = layers.GlobalMaxPooling1D()(x)
x = layers.Dense(128, activation='relu')(x)

age_prediction = layers.Dense(1, name='age')(x)
income_prediction = layers.Dense(num_income_groups, activation='softmax', name='income')(x)
gender_prediction = layers.Dense(1, activation='sigmoid', name = 'gender')(x)
model = Model(posts_input, [age_prediction, income_prediction, gender_prediction])
model.compile(optimizer='rmsprop', loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'], loss_weights = [0.25, 1. , 10.])
plot_model(model, to_file='model2.png', show_shapes=True)

上面程式碼構建的網路用語讀入個人資料,然後預測該人的年齡,收入以及性別,程式碼執行後,我們得到網路的拓撲圖如下:

model2.png

注意到當網路有多種輸出時,我們必須對每種輸出定義相應的損失函式,keras會把三種輸出結果加總,然後使用梯度下降法修正整個網路的引數。但是這麼做會產生一種情況,如果某個分支輸出誤差較大,那麼網路調整引數時就會更多的去照顧這個分支,從而影響其他分支結果的準確性,處理這個問題的辦法是為每個輸出分支設定一個權重從而影響每個分支在引數調整是所產生的影響。

更多內容,請點選進入csdn學院

更多技術資訊,包括作業系統,編譯器,面試演算法,機器學習,人工智慧,請關照我的公眾號:
這裡寫圖片描述