Keras API
目前為止裙戏,介紹的神經(jīng)網(wǎng)絡(luò)模型都是通過(guò)Sequential模型來(lái)實(shí)現(xiàn)的团搞。Sequential模型假設(shè)神經(jīng)網(wǎng)絡(luò)模型只有一個(gè)輸入一個(gè)輸出整葡,而且模型的網(wǎng)絡(luò)層是線性堆疊在一起的虏缸。
這是一個(gè)經(jīng)過(guò)驗(yàn)證的假設(shè);配置非常普遍沧卢,到目前為止已經(jīng)能夠使用Sequential模型類(lèi)覆蓋許多任務(wù)和實(shí)際應(yīng)用程序蚁堤。但在許多情況下,這套假設(shè)過(guò)于僵化但狭。一些網(wǎng)絡(luò)模型需要幾個(gè)獨(dú)立的輸入披诗,其他需要多個(gè)輸出,并且一些網(wǎng)絡(luò)在層之間具有內(nèi)部分支立磁,使得它們看起來(lái)像層的圖形而不是線性堆疊層呈队。
例如,某些任務(wù)需要多模式輸入:它們合并來(lái)自不同輸入源的數(shù)據(jù)唱歧,使用不同類(lèi)型的神經(jīng)層處理每種類(lèi)型的數(shù)據(jù)宪摧。想象一下深度學(xué)習(xí)模型試圖使用以下輸入來(lái)預(yù)測(cè)二手服裝的最可能的市場(chǎng)價(jià)格:用戶提供的元數(shù)據(jù)(例如商品的品牌,使用時(shí)長(zhǎng)等)颅崩,用戶提供的文字說(shuō)明和項(xiàng)目圖片几于。如果只有可用的元數(shù)據(jù),可以對(duì)其進(jìn)行一次熱編碼沿后,并使用密集連接的網(wǎng)絡(luò)來(lái)預(yù)測(cè)價(jià)格沿彭。如果只有可用的文本說(shuō)明,則可以使用RNN或1D convnet得运。如果只有圖片膝蜈,則可以使用2D convnet。但是怎么能同時(shí)使用這三個(gè)呢熔掺?一種方法是訓(xùn)練三個(gè)單獨(dú)的模型饱搏,然后對(duì)它們的預(yù)測(cè)進(jìn)行加權(quán)平均。但這可能不是最理想的置逻,因?yàn)槟P吞崛〉男畔⒖赡苁侨哂嗟耐品小8玫姆椒ㄊ峭ㄟ^(guò)使用可以同時(shí)查看所有可用輸入模態(tài)的模型來(lái)共同學(xué)習(xí)更準(zhǔn)確的數(shù)據(jù)模型:具有三個(gè)輸入分支的模型。
同樣,某些任務(wù)需要預(yù)測(cè)輸入數(shù)據(jù)的多個(gè)目標(biāo)屬性鬓催。鑒于小說(shuō)或短篇小說(shuō)的文本肺素,可能希望按類(lèi)型(例如浪漫或驚悚)自動(dòng)對(duì)其進(jìn)行分類(lèi),同時(shí)可以預(yù)測(cè)它的大致日期宇驾”睹遥可以訓(xùn)練兩個(gè)獨(dú)立的模型:一個(gè)用于分類(lèi),一個(gè)用于與預(yù)測(cè)時(shí)間课舍。但由于這些屬性在統(tǒng)計(jì)上并不獨(dú)立塌西,因此可以通過(guò)學(xué)習(xí)同時(shí)預(yù)測(cè)類(lèi)型和日期來(lái)構(gòu)建更好的模型。這樣的聯(lián)合模型將具有兩個(gè)輸出筝尾。
另外捡需,許多最近開(kāi)發(fā)的神經(jīng)架構(gòu)需要非線性網(wǎng)絡(luò)拓?fù)洌簶?gòu)造為有向非循環(huán)圖的網(wǎng)絡(luò)。當(dāng)僅使用Keras中的Sequential模型類(lèi)時(shí)筹淫,多輸入模型站辉,多輸出模型和類(lèi)圖模型這三個(gè)重要的用例是不可能實(shí)現(xiàn)的。但是Keras還有另一種更通用和靈活的方式:function API损姜。
Function API介紹
在function API中饰剥,可以直接操作張量,并將圖層用作使用張量和返回張量的函數(shù)薛匪。
from keras import Input,layers
input_tensor = Input(shape=(32,))#輸入張量
dense = layers.Dense(32,activation='relu')#網(wǎng)絡(luò)層:函數(shù)形式
output_tensor = dense(input_tensor)#網(wǎng)絡(luò)層對(duì)輸入張量操作捐川,返回運(yùn)行結(jié)果張量
Sequential和Function API對(duì)比:
from keras.models import Sequential,Model
from keras import layers
from keras import Input
seq_model = Sequential()
seq_model.add(layers.Dense(32, activation='relu', input_shape=(64,)))
seq_model.add(layers.Dense(32, activation='relu'))
seq_model.add(layers.Dense(10, activation='softmax'))
input_tensor = Input(shape=(64,))
x = layers.Dense(32, activation='relu')(input_tensor)
x = layers.Dense(32, activation='relu')(x)
output_tensor = layers.Dense(10, activation='softmax')(x)
model = Model(input_tensor, output_tensor)#Model類(lèi)將輸入張量和輸出張量轉(zhuǎn)換為模型。
看起來(lái)有點(diǎn)神奇的唯一部分是僅使用輸入張量和輸出張量實(shí)例化Model對(duì)象逸尖。Keras檢索從input_tensor到output_tensor的所有參與層,將它們組合成一個(gè)類(lèi)似圖形的數(shù)據(jù)結(jié)構(gòu)---一個(gè)模型瘸右。當(dāng)然娇跟,它工作的原因是output_tensor是通過(guò)重復(fù)轉(zhuǎn)換input_tensor獲得的。如果嘗試從不相關(guān)的輸入和輸出構(gòu)建模型太颤,則會(huì)出現(xiàn)RuntimeError異常苞俘。
多輸入模型
Function API可用于構(gòu)建具有多個(gè)輸入的模型。通常龄章,此類(lèi)模型在某些時(shí)候使用可以組合多個(gè)張量的圖層合并它們的不同輸入分支:通過(guò)添加吃谣,連接等操作。通常通過(guò)Keras合并操作完成做裙,例如keras.layers.add岗憋,keras.layers.concatenate等。一個(gè)多輸入模型的一個(gè)非常簡(jiǎn)單的例子:?jiǎn)柎鹉P汀?br>
典型的問(wèn)答模型有兩個(gè)輸入:自然語(yǔ)言問(wèn)題和提供用于回答問(wèn)題的信息文本片段(例如新聞文章)锚贱。然后仔戈,模型必須產(chǎn)生答案:在最簡(jiǎn)單的設(shè)置中,這是通過(guò)softmax在某些預(yù)定義詞匯表上獲得的單字答案。
Function API實(shí)現(xiàn)兩個(gè)輸入的問(wèn)答模型
from keras.models import Model
from keras import layers
from keras import Input
text_vocabulary_size = 10000
question_vocabulary_size = 10000
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)#兩個(gè)輸入處理結(jié)果聯(lián)系起來(lái)
answer = layers.Dense(answer_vocabulary_size,activation='softmax')(concatenated)
model = Model([text_input, question_input], answer)#模型聲明
model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['acc'])#compile階段
現(xiàn)在监徘,如何訓(xùn)練這個(gè)雙輸入模型晋修?有兩種方法:可以為模型提供Numpy數(shù)組列表作為輸入,或者可以為其提供將輸入名稱(chēng)映射到Numpy數(shù)組的字典凰盔。當(dāng)然墓卦,只有在為輸入命名時(shí),后一個(gè)選項(xiàng)才可用户敬。
送入數(shù)據(jù)訓(xùn)練
import numpy as np
num_samples = 1000
maxlen = 100
text = np.random.randint(1,text_vocabulary_size,size=(num_samples,maxlen))#訓(xùn)練數(shù)據(jù)
question = np.random.randint(1,question_vocabulary_size,size=(num_samples,maxlen))
answers = np.random.randint(0,1,size=(num_samples,answer_vocabulary_size))#標(biāo)簽
model.fit([text,question],answers,epochs=10,batch_size=128)
model.fit({'text':text,'question':question},answers,epochs=10,batch_size=128)
多輸出模型
以同樣的方式趴拧,可以使用Function API來(lái)構(gòu)建具有多個(gè)輸出的模型。一個(gè)簡(jiǎn)單的例子是試圖同時(shí)預(yù)測(cè)數(shù)據(jù)的不同屬性的網(wǎng)絡(luò)模型山叮,例如從一個(gè)匿名人員那里獲取一系列社交媒體帖子作為輸入的網(wǎng)絡(luò)著榴,并試圖預(yù)測(cè)該人的屬性,例如年齡屁倔,性別和收入水平等脑又。
Function API 3個(gè)輸出模型
from keras.models import Model
from keras import layers
from keras import Input
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])#列表定義輸出內(nèi)容
重要的是,訓(xùn)練這樣的模型需要能夠?yàn)榫W(wǎng)絡(luò)的不同輸出指定不同的損失函數(shù):例如锐借,年齡預(yù)測(cè)是標(biāo)量回歸任務(wù)问麸,但性別預(yù)測(cè)是二元分類(lèi)任務(wù),需要不同的訓(xùn)練過(guò)程钞翔。但由于梯度下降要求最小化一個(gè)標(biāo)量严卖,因此必須將這些損失合并為單個(gè)值才能訓(xùn)練模型。結(jié)合不同損失的最簡(jiǎn)單方法是將它們?nèi)考悠饋?lái)布轿。在Keras中哮笆,可以在編譯中使用列表或損失字典來(lái)為不同的輸出指定不同的優(yōu)化函數(shù);所產(chǎn)生的損失值總計(jì)為全局損失,在訓(xùn)練期間最小化汰扭。
多輸出模型訓(xùn)練
model.compile(optimizer='rmsprop',loss=['mse','categorical_crossentropy', 'binary_crossentropy'])
model.compile(optimizer='rmsprop',loss={'age': 'mse','income': 'categorical_crossentropy','gender': 'binary_crossentropy'})
請(qǐng)注意稠肘,非常不平衡的損失貢獻(xiàn)將導(dǎo)致模型表示優(yōu)先針對(duì)具有最大個(gè)體損失的任務(wù)進(jìn)行優(yōu)化,而犧牲其他任務(wù)萝毛。為了解決這個(gè)問(wèn)題项阴,可以為損失值分配不同程度的重要性。如果損失值取值范圍不同笆包,這種方法尤其有用环揽。例如,用于年齡回歸任務(wù)的均方誤差(MSE)損失通常取約3-5的值庵佣,而用于性別分類(lèi)任務(wù)的交叉熵?fù)p失可低至0.1歉胶。在這種情況下,為了平衡不同損失的貢獻(xiàn)秧了,可以為交叉線損失指定10的權(quán)重跨扮,并為MSE損失指定0.25的權(quán)重。
多輸出模型:權(quán)衡損失函數(shù)
model.compile(optimizer='rmsprop',loss=['mse', 'categorical_crossentropy', 'binary_crossentropy'],
loss_weights=[0.25, 1., 10.])
model.compile(optimizer='rmsprop',loss={'age': 'mse','income': 'categorical_crossentropy',
'gender': 'binary_crossentropy'},loss_weights={'age': 0.25,'income': 1.,'gender': 10.})
與多輸入模型的情況一樣,可以通過(guò)數(shù)組列表或通過(guò)數(shù)組字典將Numpy數(shù)據(jù)傳遞給模型進(jìn)行訓(xùn)練衡创。
多輸出模型訓(xùn)練
model.fit(posts, [age_targets, income_targets, gender_targets],epochs=10, batch_size=64)
model.fit(posts, {'age': age_targets,'income': income_targets,'gender': gender_targets},
epochs=10, batch_size=64)
有向非循環(huán)圖
使用Function API帝嗡,不僅可以構(gòu)建具有多個(gè)輸入和多個(gè)輸出的模型,還可以實(shí)現(xiàn)具有復(fù)雜內(nèi)部拓?fù)涞木W(wǎng)絡(luò)璃氢。Keras中允許神經(jīng)網(wǎng)絡(luò)層是任意有向無(wú)環(huán)圖哟玷。“非循環(huán)”很重要:這些圖不能有循環(huán)一也。張量x不可能成為生成x的其中一個(gè)層的輸入巢寡。允許的唯一處理循環(huán)(即循環(huán)連接)是循環(huán)層內(nèi)部的循環(huán)。
幾個(gè)常見(jiàn)的神經(jīng)網(wǎng)絡(luò)組件被實(shí)現(xiàn)為圖形椰苟。兩個(gè)值得注意的是Inception模塊和殘差連接抑月。為了更好地理解function API如何用于構(gòu)建圖層圖,看一下如何在Keras中實(shí)現(xiàn)它們舆蝴。
Inception 模塊
Inception是卷積神經(jīng)網(wǎng)絡(luò)的一種流行的網(wǎng)絡(luò)架構(gòu)谦絮。它由一堆模塊組成,這些模塊本身看起來(lái)像小型獨(dú)立網(wǎng)絡(luò)洁仗,分成幾個(gè)并行分支层皱。Inception模塊的最基本形式有三到四個(gè)分支,以1×1卷積開(kāi)始赠潦,然后是3×3卷積叫胖,最后是結(jié)果特征的串聯(lián)。此設(shè)置有助于網(wǎng)絡(luò)分別學(xué)習(xí)空間特征和通道特征她奥,這比聯(lián)合學(xué)習(xí)它們更有效瓮增。更復(fù)雜的Inception模塊版本也是可能的,通常涉及池化操作方淤,不同的空間卷積大卸ち蕖(例如,在某些分支上為5×5而不是3×3)携茂,以及沒(méi)有空間卷積的分支(僅1×1)卷積)。
Function API實(shí)現(xiàn)Inception模塊
from keras import layers
branch_a = layers.Conv2D(128, 1,activation='relu', strides=2)(x)#x 4D 張量
branch_b = layers.Conv2D(128, 1, activation='relu')(x)
branch_b = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_b)
branch_c = layers.AveragePooling2D(3, strides=2)(x)
branch_c = layers.Conv2D(128, 3, activation='relu')(branch_c)
branch_d = layers.Conv2D(128, 1, activation='relu')(x)
branch_d = layers.Conv2D(128, 3, activation='relu')(branch_d)
branch_d = layers.Conv2D(128, 3, activation='relu', strides=2)(branch_d)
output = layers.concatenate([branch_a, branch_b, branch_c, branch_d], axis=-1)
完整的Inception V3架構(gòu)在Keras中可用,keras.applications.inception_v3.InceptionV3诅岩,包括在ImageNet數(shù)據(jù)集上預(yù)先訓(xùn)練的權(quán)重系數(shù)讳苦。作為Keras應(yīng)用程序模塊的一部分提供的另一個(gè)密切相關(guān)的模型是Xception。Xception是一個(gè)由Inception啟發(fā)的convnet架構(gòu)吩谦。它采用了將通道和空間特征的學(xué)習(xí)分離到其邏輯極值的想法鸳谜,并用深度可分離卷積替換初始模塊,該卷積由深度卷積(每個(gè)輸入通道單獨(dú)處理的空間卷積)跟隨通過(guò)逐點(diǎn)卷積(1×1卷積),其中空間特征和通道特征完全分離式廷。Xception與Inception V3具有大致相同數(shù)量的參數(shù)咐扭,但由于更有效地使用模型參數(shù),它在ImageNet以及其他大型數(shù)據(jù)集上顯示出更好的運(yùn)行時(shí)性能和更高的準(zhǔn)確性。
Residual殘差連接
殘差連接是許多2015年后網(wǎng)絡(luò)架構(gòu)中常見(jiàn)的類(lèi)似圖形的網(wǎng)絡(luò)組件蝗肪,如Xception袜爪。通常,將殘余連接添加到任何具有10層以上的模型可能是有益的薛闪。
殘差連接包括使較早層的輸出可用作后續(xù)層的輸入辛馆,從而有效地在順序網(wǎng)絡(luò)中創(chuàng)建快捷方式。不是將其連接到后來(lái)的激活值上豁延,而是將較早的輸出與后面的激活值相加昙篙,后者假定兩個(gè)激活值的大小形狀相同。如果它們的大小不同诱咏,則可以使用線性變換將較早的激活值重新整形為目標(biāo)形狀(例如苔可,沒(méi)有激活函數(shù)的全連接層,或者對(duì)于卷積特征映射袋狞,沒(méi)有激活函數(shù)的1×1卷積)焚辅。
from keras import layers
x = ...
y = layers.Conv2D(128, 3, activation='relu', padding='same')(x)
y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)
y = layers.Conv2D(128, 3, activation='relu', padding='same')(y)
y = layers.add([y, x])
網(wǎng)絡(luò)層權(quán)重共享
Function API的一個(gè)更重要的特性是能夠多次重用層實(shí)例。當(dāng)調(diào)用圖層實(shí)例兩次時(shí)硕并,不是為每個(gè)調(diào)用實(shí)例化一個(gè)新圖層法焰,而是在每次調(diào)用時(shí)重復(fù)使用相同的權(quán)重。這允許構(gòu)建具有共享分支的模型---幾個(gè)分支都具有相同的知識(shí)并執(zhí)行相同的操作倔毙。也就是說(shuō)埃仪,它們共享相同的特征表示并同時(shí)為不同的輸入集學(xué)習(xí)這些特征表示。
Function API實(shí)現(xiàn)
from keras import layers
from keras import Input
from keras.models import Model
lstm = layers.LSTM(32)
left_input = Input(shape=(None, 128))
left_output = lstm(left_input)
right_input = Input(shape=(None, 128))
right_output = lstm(right_input)#lstm重用兩次
merged = layers.concatenate([left_output, right_output], axis=-1)
predictions = layers.Dense(1, activation='sigmoid')(merged)
model = Model([left_input, right_input], predictions)
model.fit([left_data, right_data], targets)
模型作為網(wǎng)絡(luò)層
在Function API中陕赃,可以將模型視為“更大的圖層”卵蛉,這意味著可以在輸入張量上調(diào)用模型并檢索輸出張量:
y = model(x)
如果模型有多個(gè)輸入和輸出:
y1,y2 = model([x1,x2])
當(dāng)調(diào)用模型實(shí)例時(shí),將重用模型的權(quán)重--與調(diào)用圖層實(shí)例時(shí)的情況完全相同么库。調(diào)用實(shí)例傻丝,無(wú)論是層實(shí)例還是模型實(shí)例,都將重用實(shí)例的現(xiàn)有特征表示诉儒。
通過(guò)重用模型實(shí)例可以構(gòu)建的一個(gè)簡(jiǎn)單實(shí)用示例是使用雙攝像頭作為其輸入的視覺(jué)模型:兩個(gè)并行攝像頭葡缰,相距幾厘米。這樣的模型可以感知深度忱反,這在許多應(yīng)用中是有用的泛释。在合并兩個(gè)輸入之前,不需要兩個(gè)獨(dú)立的模型來(lái)從左相機(jī)和右相機(jī)中提取視覺(jué)特征温算。這種低級(jí)處理可以在兩個(gè)輸入之間共享:即怜校,通過(guò)使用相同權(quán)重的層來(lái)完成,從而共享相同的表示注竿。以下是在Keras實(shí)現(xiàn)Siamese視覺(jué)模型(共享卷積基礎(chǔ))的方法:
from keras import layers
from keras import applications
from keras import Input
xception_base = applications.Xception(weights=None,include_top=False)
left_input = Input(shape=(250, 250, 3))
right_input = Input(shape=(250, 250, 3))
left_features = xception_base(left_input)
right_input = xception_base(right_input)
merged_features = layers.concatenate([left_features, right_input], axis=-1)
使用Keras回調(diào)和TensorBoard檢查和監(jiān)控深度學(xué)習(xí)模型
訓(xùn)練過(guò)程中使用回調(diào)
在訓(xùn)練模型時(shí)茄茁,有很多事情從一開(kāi)始就無(wú)法預(yù)測(cè)魂贬。特別是,無(wú)法確定需要多少個(gè)epochs才能獲得最佳驗(yàn)證損失裙顽。到目前為止付燥,這些例子都是訓(xùn)練足夠的epochs,讓模型過(guò)度擬合锦庸;使用第一次運(yùn)行來(lái)估計(jì)適當(dāng)?shù)挠?xùn)練eopchs机蔗,然后最終使用這個(gè)最佳數(shù)字從頭開(kāi)始新的訓(xùn)練運(yùn)行。這種方法效率低甘萧。
處理此問(wèn)題的更好方法是在測(cè)量驗(yàn)證損失不再改善時(shí)停止訓(xùn)練萝嘁。這可以使用Keras回調(diào)函數(shù)來(lái)實(shí)現(xiàn)。回調(diào)callback是一個(gè)對(duì)象(實(shí)現(xiàn)特定方法的類(lèi)實(shí)例)扬卷,它在調(diào)用fit中傳遞給模型牙言,并且在訓(xùn)練期間由模型在各個(gè)點(diǎn)調(diào)用。它可以訪問(wèn)有關(guān)模型狀態(tài)及其性能的所有可用數(shù)據(jù)怪得,并且可以執(zhí)行操作:中斷訓(xùn)練咱枉,保存模型,加載不同的權(quán)重或以其他方式更改模型的狀態(tài)徒恋。
使用callbacks的幾種方法:
- Model checkpointing:在訓(xùn)練期間在不同點(diǎn)保存模型的當(dāng)前權(quán)重;
- 提前停止early stopping:當(dāng)驗(yàn)證損失不再改進(jìn)時(shí)蚕断,中斷訓(xùn)練(保存訓(xùn)練期間獲得的最佳模型);
- 在訓(xùn)練期間動(dòng)態(tài)調(diào)整某些參數(shù)的值:如學(xué)習(xí)率入挣;
- 在訓(xùn)練期間記錄訓(xùn)練和驗(yàn)證指標(biāo)亿乳,或者可視化模型在更新時(shí)學(xué)習(xí)的特征表示:Keras進(jìn)度條就是一種callback。
keras.callbacks模塊包含許多內(nèi)置callbacks對(duì)象径筏。
keras.callbacks.ModelCheckpoint
keras.callbacks.EarlyStopping
keras.callbacks.LearningRateScheduler
keras.callbacks.ReduceLROnPlateau
keras.callbacks.CSVLogger
...
ModelCheckPoint和EarlyStopping callbacks
一旦監(jiān)測(cè)的目標(biāo)指標(biāo)在固定數(shù)量的epochs中停止改進(jìn)葛假,就可以使用EarlyStopping回調(diào)來(lái)中斷訓(xùn)練過(guò)程。例如滋恬,這個(gè)回調(diào)允許在開(kāi)始過(guò)度擬合時(shí)立即中斷訓(xùn)練聊训,從而避免以較少epochs重新訓(xùn)練模型。這個(gè)回調(diào)通常與ModelCheckpoint結(jié)合使用恢氯,它允許在訓(xùn)練期間不斷保存模型(并且带斑,可選地,僅保存當(dāng)前最佳模型:在訓(xùn)練時(shí)期結(jié)束時(shí)獲得最佳性能的模型版本) :
import keras
#通過(guò)模型的fit函數(shù)的callbacks參數(shù)傳遞callbacks類(lèi)列表
callbacks_list = [
keras.callbacks.EarlyStopping(monitor='acc',patience=1,),
keras.callbacks.ModelCheckpoint(filepath='my_model.h5',monitor='val_loss',save_best_only=True,)
]
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['acc'])
model.fit(x, y,epochs=10,batch_size=32,callbacks=callbacks_list,validation_data=(x_val, y_val))
ReduceLROnPlateau callbacks
當(dāng)驗(yàn)證損失已經(jīng)停止改進(jìn)時(shí)勋拟,可以使用此回調(diào)來(lái)降低學(xué)習(xí)速率遏暴。降低或提高學(xué)習(xí)率是在訓(xùn)練期間擺脫局部最小值的有效策略。
callbacks_list = [
keras.callbacks.ReduceLROnPlateau(monitor='val_loss',factor=0.1,patience=10,)]#監(jiān)測(cè)val_loss,10倍率減少指黎,如果10個(gè)epochs后loss都沒(méi)有減少,學(xué)習(xí)率減小
model.fit(x, y,epochs=10,batch_size=32,callbacks=callbacks_list,validation_data=(x_val, y_val))
TensorBoard:TensorFlow可視化工具
要進(jìn)行良好的研究或開(kāi)發(fā)好的模型州丹,需要在實(shí)驗(yàn)過(guò)程中對(duì)模型內(nèi)部發(fā)生的事情進(jìn)行豐富醋安,頻繁的反饋杂彭。這就是運(yùn)行實(shí)驗(yàn)的重點(diǎn):獲取有關(guān)模型執(zhí)行情況的信息。結(jié)果改善是一個(gè)迭代過(guò)程:從一個(gè)想法開(kāi)始吓揪,并將其表達(dá)為一個(gè)實(shí)驗(yàn)亲怠,試圖驗(yàn)證或使想法無(wú)效。運(yùn)行此實(shí)驗(yàn)并處理它生成的信息柠辞。這激發(fā)了下一個(gè)想法团秽。能夠運(yùn)行的這個(gè)循環(huán)的迭代次數(shù)越多,最終的想法就越精確叭首。Keras能在最短的時(shí)間內(nèi)從創(chuàng)意到實(shí)驗(yàn)习勤,快速GPU可以從實(shí)驗(yàn)到結(jié)果的時(shí)間盡可能短。TensorBoard可以用來(lái)觀察實(shí)驗(yàn)結(jié)果變換焙格。
TensorBoard图毕,一個(gè)基于瀏覽器的可視化工具,與TensorFlow一起打包眷唉。請(qǐng)注意予颤,當(dāng)將Keras與TensorFlow后端一起使用時(shí),它能適用于Keras框架冬阳。
TensorBoard的主要目的是有助于在訓(xùn)練期間直觀地監(jiān)控模型內(nèi)部的所有內(nèi)容蛤虐。TensorBoard可以在瀏覽器中訪問(wèn),有幾個(gè)簡(jiǎn)潔的功能:
- 可視化訓(xùn)練過(guò)程中的監(jiān)測(cè)指標(biāo)肝陪;
- 可視化模型架構(gòu)驳庭;
- 可視化激活函數(shù)和梯度值的直方圖;
- Exploring embeddings in 3D.
模型優(yōu)化
如果只需要一些可行的東西见坑,那么使用模型的默認(rèn)值即可滿足要求嚷掠。但如果要求更高,必須采用其他的技巧對(duì)模型進(jìn)行調(diào)整荞驴。
高級(jí)架構(gòu)模式
更復(fù)雜的設(shè)計(jì)模式:殘差連接不皆、規(guī)范化normalization和深度可分離卷積depthwise separate convolution。當(dāng)構(gòu)建高性能深度網(wǎng)絡(luò)時(shí)熊楼,這些模式尤為重要霹娄,而且它們也常見(jiàn)于許多其他類(lèi)型模型的體系結(jié)構(gòu)中。
Batch Normalization
歸一化是一種廣泛的方法類(lèi)別鲫骗,旨在使機(jī)器學(xué)習(xí)模型看到的不同樣本彼此更相似犬耻,這有助于模型學(xué)習(xí)和概括新數(shù)據(jù)。最常見(jiàn)的數(shù)據(jù)歸一化形式:通過(guò)從數(shù)據(jù)中減去平均值將數(shù)據(jù)居中于0执泰,并通過(guò)將數(shù)據(jù)除以其標(biāo)準(zhǔn)差得到單位標(biāo)準(zhǔn)差枕磁。實(shí)際上,這假設(shè)數(shù)據(jù)遵循正態(tài)(或高斯)分布术吝,并確保此分布居中并縮放到單位方差:
normalized_data = (data - np.mean(data, axis=...)) / np.std(data, axis=...)
之前的示例在將數(shù)據(jù)輸入模型之前對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理计济。但是茸苇,在網(wǎng)絡(luò)運(yùn)行地每次轉(zhuǎn)換之后,數(shù)據(jù)規(guī)范化層成為一個(gè)新的問(wèn)題:也沒(méi)有理由預(yù)期先驗(yàn)數(shù)據(jù)會(huì)出現(xiàn)高斯分布的情況(即使進(jìn)入全連接或Conv2D網(wǎng)絡(luò)的數(shù)據(jù)具有0均值和單位方差)沦寂。
批量標(biāo)準(zhǔn)化Batch Normalization是一個(gè)網(wǎng)絡(luò)層(Keras中的BatchNormalization)学密,即使平均值和方差在訓(xùn)練期間隨時(shí)間變化,它也可以自適應(yīng)地標(biāo)準(zhǔn)化數(shù)據(jù)传藏。批量歸一化的主要影響是它有助于梯度傳播腻暮,因此允許更深的網(wǎng)絡(luò)。一些非常深的網(wǎng)絡(luò)只有在包含多個(gè)BatchNormalization層時(shí)才能被訓(xùn)練毯侦。
BatchNormalization層通常在卷積或全連接層之后使用:
conv_model.add(layers.Conv2D(32, 3, activation='relu'))
conv_model.add(layers.BatchNormalization())#卷積層后
dense_model.add(layers.Dense(32, activation='relu'))
dense_model.add(layers.BatchNormalization())#全連接層后
BatchNormalization圖層采用axis參數(shù)哭靖,該參數(shù)指定應(yīng)規(guī)范化的特征軸。參數(shù)默認(rèn)為-1叫惊,即輸入張量中的最后一個(gè)軸款青。
使用Dense層,Conv1D層霍狰,RNN層和Conv2D層并且data_format設(shè)置為“channels_last”時(shí)抡草。但是在將data_format設(shè)置為“channels_first”的Conv2D層中,特征軸是軸1;因此蔗坯,BatchNormalization中的axis參數(shù)應(yīng)設(shè)置為1康震。
深度可分離卷積depthwise separate convolution
如果有一個(gè)層可以用作Conv2D的替代品,這將使模型更輕量(可訓(xùn)練的重量參數(shù)更少)和更快速(更少的浮點(diǎn)運(yùn)算)并使任務(wù)結(jié)果提升幾個(gè)百分點(diǎn)宾濒?這正是深度可分離卷積層的作用(SeparableConv2D)腿短。在通過(guò)逐點(diǎn)卷積(1×1卷積)混合輸出通道之前,該層獨(dú)立地在其輸入的每個(gè)通道上執(zhí)行空間卷積绘梦。這相當(dāng)于將空間特征的學(xué)習(xí)與通道特征的學(xué)習(xí)分開(kāi)橘忱,如果假設(shè)輸入中的空間位置高度相關(guān),但不同的通道是相當(dāng)獨(dú)立的卸奉,這就很有意義钝诚。它需要的參數(shù)明顯更少,計(jì)算量更少榄棵,因此可以實(shí)現(xiàn)更小凝颇,更快的模型。并且因?yàn)樗菆?zhí)行卷積的更具代表性的有效方式疹鳄,所以它傾向于使用更少的數(shù)據(jù)來(lái)學(xué)習(xí)更好的表示拧略,從而產(chǎn)生性能更好的模型。
當(dāng)在有限的數(shù)據(jù)上從頭開(kāi)始訓(xùn)練小型模型時(shí)瘪弓,這些優(yōu)勢(shì)變得尤為重要垫蛆。例如,在小型數(shù)據(jù)集上為圖像分類(lèi)任務(wù)(softmax分類(lèi)分類(lèi))構(gòu)建輕量級(jí),深度可分離的卷積網(wǎng)絡(luò):
from keras.models import Sequential, Model
from keras import layers
height = 64
width = 64
channels = 3
num_classes = 10
model = Sequential()
model.add(layers.SeparableConv2D(32, 3,activation='relu',input_shape=(height, width, channels,)))
model.add(layers.SeparableConv2D(64, 3, activation='relu'))
model.add(layers.MaxPooling2D(2))
model.add(layers.SeparableConv2D(64, 3, activation='relu'))
model.add(layers.SeparableConv2D(128, 3, activation='relu'))
model.add(layers.MaxPooling2D(2))
model.add(layers.SeparableConv2D(64, 3, activation='relu'))
model.add(layers.SeparableConv2D(128, 3, activation='relu'))
model.add(layers.GlobalAveragePooling2D())
model.add(layers.Dense(32, activation='relu'))
model.add(layers.Dense(num_classes, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
超參數(shù)優(yōu)化
在構(gòu)建深度學(xué)習(xí)模型時(shí)月褥,必須做出許多看似隨意的決策:應(yīng)該堆疊多少層弛随?每層應(yīng)該有多少個(gè)單位或卷積核?使用relu作為激活函數(shù)宁赤,還是使用其他的激活函數(shù)?在給定圖層后使用BatchNormalization栓票?等等决左。這些體系結(jié)構(gòu)級(jí)參數(shù)稱(chēng)為超參數(shù),以將它們與模型的參數(shù)[通過(guò)反向傳播進(jìn)行訓(xùn)練]區(qū)分開(kāi)來(lái)走贪。
在實(shí)踐中佛猛,經(jīng)驗(yàn)豐富的機(jī)器學(xué)習(xí)工程師和研究人員隨著時(shí)間的推移不斷積累經(jīng)驗(yàn),了解在這些選擇中哪些有效坠狡,哪些無(wú)效继找。
但是沒(méi)有正式的規(guī)則。如果你想達(dá)到給定任務(wù)可以達(dá)到的最優(yōu)解逃沿,必須調(diào)整超參數(shù)值婴渡。可以通過(guò)手動(dòng)調(diào)整它們并重復(fù)重新訓(xùn)練模型來(lái)改進(jìn)選擇----這就是機(jī)器學(xué)習(xí)工程師和研究人員花費(fèi)大部分時(shí)間做的事情凯亮。但是边臼,作為一個(gè)人類(lèi),你不應(yīng)該整天擺弄超級(jí)參數(shù)---這最好留給機(jī)器[???]假消。
優(yōu)化超參數(shù)的過(guò)程通常如下所示:
- 選擇一組超參數(shù);
- 構(gòu)建相應(yīng)的模型;
- 使其適合于訓(xùn)練數(shù)據(jù)柠并,并測(cè)量驗(yàn)證數(shù)據(jù)集上的表現(xiàn);
- 選擇下一組超參數(shù)富拗;
- 重復(fù)臼予;
- 最后,測(cè)量測(cè)試數(shù)據(jù)的性能啃沪。
此過(guò)程的關(guān)鍵是使用的算法粘拾,在給定各種超參數(shù)集,通過(guò)驗(yàn)證集上的監(jiān)測(cè)指標(biāo)選擇要評(píng)估的下一組超參數(shù)谅阿“胗矗可能有許多不同的技術(shù):貝葉斯優(yōu)化,遺傳算法签餐,簡(jiǎn)單隨機(jī)搜索等寓涨。
在大規(guī)模進(jìn)行自動(dòng)超參數(shù)優(yōu)化時(shí)要記住的一個(gè)重要問(wèn)題是驗(yàn)證集上模型過(guò)擬合。因?yàn)榛谑褂抿?yàn)證數(shù)據(jù)計(jì)算的信號(hào)更新超參數(shù)氯檐,所以可以有效地對(duì)驗(yàn)證數(shù)據(jù)進(jìn)行訓(xùn)練戒良,因此它們會(huì)快速過(guò)擬合驗(yàn)證數(shù)據(jù)。
模型集成
另一種在處理任務(wù)中獲得最佳結(jié)果的強(qiáng)大技術(shù)是模型集成冠摄。集成包括將一組不同模型的預(yù)測(cè)匯集在一起??糯崎,以產(chǎn)生更好的預(yù)測(cè)結(jié)果几缭。
集成依賴(lài)于假設(shè),獨(dú)立訓(xùn)練的不同優(yōu)秀模型可能偏愛(ài)于某種特定的特征:每個(gè)模型都會(huì)查看數(shù)據(jù)的略微不同的方面來(lái)進(jìn)行預(yù)測(cè)沃呢,獲得“真相”的一部分但不是全部年栓。如盲人摸象,盲人本質(zhì)上是機(jī)器學(xué)習(xí)模型薄霜,試圖通過(guò)自己的假設(shè)(由模型的獨(dú)特架構(gòu)和獨(dú)特的隨機(jī)權(quán)重初始化提供)從各自的角度理解訓(xùn)練數(shù)據(jù)的多樣性某抓。他們每個(gè)人都獲得了數(shù)據(jù)真實(shí)性的一部分,但不是全部真相惰瓜。通過(guò)將它們的視角匯集在一起??否副,可以獲得更準(zhǔn)確的數(shù)據(jù)描述。大象是各個(gè)部分的組合:沒(méi)有任何一個(gè)盲人得到正確結(jié)果崎坊,但是备禀,一起采訪,他們可以說(shuō)出一個(gè)相當(dāng)準(zhǔn)確的大象形象奈揍。
以分類(lèi)為例曲尸。匯集一組分類(lèi)器預(yù)測(cè)最簡(jiǎn)單方法是模型預(yù)測(cè)時(shí),平均預(yù)測(cè)結(jié)果:
preds_a = model_a.predict(x_val)
preds_b = model_b.predict(x_val)
preds_c = model_c.predict(x_val)
preds_d = model_d.predict(x_val)
final_preds = 0.25 * (preds_a + preds_b + preds_c + preds_d)
只有當(dāng)分類(lèi)器預(yù)測(cè)效果大致相當(dāng)時(shí)打月,才有效队腐。如果其中一個(gè)明顯比其他分類(lèi)器差,那么最終的預(yù)測(cè)可能不如該群體的最佳分類(lèi)器奏篙。
集成工作的關(guān)鍵是分類(lèi)器的多樣性柴淘。 Diversity is strength.如果所有的盲人都只觸摸了大象的軀干,他們會(huì)同意大象像蛇一樣秘通,他們會(huì)永遠(yuǎn)不知道大象的真面目为严。多樣化是使集成工作的原因。在機(jī)器學(xué)習(xí)方面肺稀,如果所有模型都以相同的方式偏向某種特征第股,那么整體將保持同樣的認(rèn)知。如果模型以不同的方式學(xué)習(xí)话原,則偏差將相互抵消夕吻,并且整體將更加穩(wěn)健和更準(zhǔn)確。
出于這個(gè)原因繁仁,應(yīng)該盡可能集合盡可能好的不同類(lèi)別模型涉馅。這通常意味著使用非常不同的架構(gòu)甚至不同類(lèi)別的機(jī)器學(xué)習(xí)方法。一個(gè)不值得做的方法是從不同的隨機(jī)初始化中獨(dú)立訓(xùn)練多次相同的網(wǎng)絡(luò)模型黄虱。如果模型之間的唯一區(qū)別在于它們的隨機(jī)初始化以及訓(xùn)練數(shù)據(jù)的順序稚矿,那么模型是低多樣性的,并且僅比任何單個(gè)模型結(jié)果稍好一點(diǎn)。
一種有效的集成方法是使用基于樹(shù)的方法(例如隨機(jī)森林或梯度提升樹(shù))和深度神經(jīng)網(wǎng)絡(luò)的集合晤揣。值得注意的是桥爽,整體中的一個(gè)模型起源于與其他模型不同的方法(它是一個(gè)正規(guī)化的貪婪森林)并且得分明顯低于其他模型。不出所料昧识,它在整體中被分配了一個(gè)小重量钠四。但令我們驚訝的是,事實(shí)證明它可以通過(guò)一個(gè)很大的因素來(lái)改善整體效果滞诺,因?yàn)樗c其他模型完全不同:它提供了其他模型無(wú)法訪問(wèn)的信息形导。這恰恰是整合的重點(diǎn)。這不是關(guān)于你最好的模型有多好;這是關(guān)于你的候選模型集的多樣性习霹。
最近,在實(shí)踐中非常成功的一種基本集成風(fēng)格是使用類(lèi)別廣泛而深度的模型炫隶,將深度學(xué)習(xí)與淺層學(xué)習(xí)相結(jié)合淋叶。這些模型包括聯(lián)合訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)和大型線性模型。一系列不同模型的聯(lián)合訓(xùn)練是實(shí)現(xiàn)模型集成的另一種選擇伪阶。