Keras函数式API
函數式API簡介
使用函數式API,可以直接對張量進行操作,也可以把層當做函數來使用,接收張量并返回張量。
下面舉一個簡單的示例,并展示一個簡單的Sequential模型以及對應的函數式API實現。
from keras.models import Sequential, Model from keras.layers import Dense from keras import Inputseq_model = Sequential() # Sequential模型 seq_model.add(Dense(32, activation = 'relu', input_shape = (64, ))) seq_model.add(Dense(32, activation = 'relu')) seq_model.add(Dense(10, activation = 'softmax'))input_tensor = Input(shape = (64,)) #一個張量 x = Dense(32, activation = 'relu')(input_tensor) #一個層是一個函數 x = Dense(32, activation = 'relu')(x) output_tensor = Dense(10, activation = 'softmax')(x)model = Model(input_tensor, output_tensor)model.summary() _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) (None, 64) 0 _________________________________________________________________ dense_4 (Dense) (None, 32) 2080 _________________________________________________________________ dense_5 (Dense) (None, 32) 1056 _________________________________________________________________ dense_6 (Dense) (None, 10) 330 ================================================================= Total params: 3,466 Trainable params: 3,466 Non-trainable params: 0 model.compile(optimizer = 'rmsprop', loss = 'categorical_crossentropy') import numpy as np #生成用于訓練的虛構Numpy數據x_train = np.random.random((1000, 64)) y_train = np.random.random((1000, 10)) model.fit(x_train, y_train, epochs = 10, batch_size = 128) score = model.evaluate(x_train, y_train) #評估模型多輸入模型
這里展示一個簡單的多輸入示例:問答模型。
典型的問答模型有兩個輸入:一個自然語言描述的問題和一個文本片段(比如新聞文章),后者提供用于回答的問題信息。然后模型要生成一個回答,在最簡單的情況下,這個回答值包含一個詞,可以通過對某個預定的詞表做softmax得到。
from keras.models import Model form keras import layers from keras import Inputtext_vocabbulary_size = 10000 question_vocabulary_size = 10000 answer_vocabulary_size = 500text_input = Input(shape = (None,), dtype = 'int32', name = 'text') #文本輸入是一個長度可變的序列,可以命別的名字embedded_text = layers.Embedding(text_vocabulary_size, 64)(text_input) #將輸入嵌入為長度64的向量 encoded_text = layers.LSTM(32)(embedded_text) #利用LSTM將向量編碼為單個向量question_input = Input(shape = (None,), dtype = 'int32', name = 'question') #對問題進行相同的處理(使用不同的層實例) embedded_question = layers.Embedding(question_vocabulary_size, 32)(question_input) encoded_question = layers.LSTM(16)(embedded_question)concatenated = layers.concatenate([encoded_text, encoded_question], axis = -1) #將編碼后的問題和文本連在一起,axis = 0,橫著合并。1或-1按列豎著合并answer = layers.Dense(answer_vocabulary_size, activation = 'softmax')(concatenated) #在上面添加一個softmax分類器model = Model([text_input, question_input], answer) #在模型實例化的時候,指定兩個輸入和輸出 model.compile(optimizer = 'rmsprop', loss = 'categorical_crossentropy', metrics = ['acc'])接下來如何訓練這個雙輸入模型呢?有兩個可用的API:我們可以向模型輸入一個由Numpy數組組成的列表,或者也可以輸入一個將輸入名稱映射為Numpy數組的字典。當然,只有輸入具有名稱的時候才可以使用后一種方法。我們這里兩種都展示一下。
另外,我們這里輸入進行訓練的answers標簽是以one-hot編碼形式輸入的。這一點需要留意一下。
import numpy as np import kerasnum_samples = 1000 max_length = 100text = np.random.randint(1, text_vocabulary_size, size = (num_samples, max_length))question = np.random.randint(answer_vocabulary_size, size = (num_samples, max_length))answers = np.random.randint(answer_vocabulary_size, size = (num_samples)) # to_categorical方法用來將標簽轉換為onehot編碼 answers = keras.utils.to_categorical(answers, answer_vocabulary_size)model.fit([text, question], answers, epochs = 10, batch_size = 128) #使用輸入組成的列表來擬合#fit也可以寫成這樣的類型(這兩種都行) # 使用輸入組成的字典來擬合(只有對輸入進行命名之后才能用這種方法) model.fit({'text' : text, 'question' : question}, answers, epochs = 10, batch_size = 128)多輸出模型
使用相同的辦法,我們還可以用函數式API來構建多輸出模型。一個簡單的例子就是網絡試圖同時預測數據額不同性質,比如一個網絡,輸入某個匿名人士的一系列社交媒體發帖,然后嘗試預測那個人的屬性,比如年齡、性別和收入水平。
重要的是,訓練這種模型需要對網絡的各個頭指定不同的損失函數,例如,年齡預測是標量回歸任務,而性別預測是二分類任務,二者需要不同的訓練過程。但是,梯度下降要求將一個標量最小化,所以為了能夠訓練模型,我們必須將這些損失合并為單個標量。合并不同損失函數最簡單的辦法是對所有損失求和。在Keras中,你可以在編譯時使用損失組成的列表或字典來為不同的輸出指定不同的損失,然后將得到的損失值相加得到一個全局損失,并在訓練過程中將這個損失最小化。
from keras import layers from keras import Input from keras.models import Modelvocabulary_size = 50000 num_income_groups = 10posts_input = Input(shape = (None,), dtype = 'int32', name = 'posts') embedded_posts = layers.Embedding(vocabulary_size, 256)(posts_input) x = layers.Conv1D(128, 5, activation = 'relu')(embedded_posts) # 128是卷積核的數目,即輸出的維度 x = layers.MaxPooling1D(5)(x) # 5是池化窗口大小 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.summary()model.compile(optimizer = 'rmsprop', loss = ['mse', 'categorical_crossentropy', 'binary_crossentropy'],loss_weigths = [0.25, 1., 10.])# 兩種complile方法等效,但是只有輸出層具有名稱的時候才能使用第二種方法 model.compile(optimizer = 'rmsprop',loss = {'age':'mse','income':'categorical_crossentropy','gender':'binary_crossentropy'},loss_weigths = {'age':0.25,'income':1.,'gender':10.})model.fit(posts, [age_targets, income_targets, gender_targets],epochs = 10, batch_size = 64)# 兩種fit方法等效,但是只有輸出層具有名稱的時候才能使用第二種方法 model.fit(posts, {'age':age_targets,'income':income_targets,'gender':gender_targets},epochs = 10, batch_size = 64)注意,嚴重不平衡的損失貢獻會導致模型表示針對單個損失最大的任務優先進行優化,而不考慮其他任務的優化。為了解決這個問題,我們可以為每個損失值對最終損失的貢獻分配不同的大小重要性。如果不同的損失具有不同的取值范圍,那個這一方法尤其有用。比如,用于年齡回歸任務的均方誤差(MSE)損失通常在3-5左右,而用于性別分類任務的交叉熵損失可能低至0.1。在這種情況下,為了平衡不同的損失貢獻,我們可以讓交叉熵損失的權重取10,而MSE損失的權重取0.5。
Inception模塊
from keras import layers# 每個分支都有相同的步幅2,這對于保持所有分支輸出都具有相同的尺寸是很重要的,這樣才可以把他們連接在一起 branch_a = layers.Conv2D(128, 1, activation = 'relu', strides = 2)(x)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_d], axis = -1)殘差連接
如果特征圖的尺寸相同,在Keras中實現殘差連接的方法如下。這里例子中我們假設有一個四維輸入張量x
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]) #將原始x與輸出特征相加如果特征圖尺寸不同,實現殘差的方法如下。同樣,我們也假設有一個四維輸入張量x
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.maxPooling2D(2, strides = 2)(y)residual = layers.Conv2D(128, 1, strides = 2, padding = 'same')(x) #使用1*1卷積,將原始x張量線性下采樣為與y具有相同的形狀y = layers.add([y, residual]) #將殘差張量與輸出特征相加總結
以上是生活随笔為你收集整理的Keras函数式API的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Keras方法进行词嵌入
- 下一篇: Keras的回调函数