假設程式不是使用 sequence 來宣告模型,直接使用 model類別的話,差異在哪裡? 會在文中點出差異。
範例程式:
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model
inputs = Input(shape=(784,))
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
model = Model(inputs=inputs, outputs=predictions)
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) model.fit(data, labels)
layer的另一種設定方法:
首先會至 keras.engine.input_layer.Input 初始化 input張量。其中 會檢查 參數shape是否有指定,如果沒有會發出錯誤例外。也就是 Input layer 一定要指定好它的 shape。經過父類別keras.engine.base_layer.init 與自身的keras.engine.input_layer.init 初始設定後,準備好此物件實例要傳入下一個Dense layer層的call function。
Dense layer建構與初始於前面文章有提過,此處省略。於Dense layer的call是layer的實體所實作的call函式。此函式接收 input layer 參數後,隨後會檢查是否本身layer已經被build過,如果沒有就會進行build的動作。
而以本範例layer本身keras.layers.core.dense是執行 keras.layers.core.dense.build ,build一定會傳入接收的input實體,要明白接收的張量維度為何。然後會利用 keras.engine.base_layer.add_weight 函式分別對 keras.layers.core.dense的 kernel(權重) 與 bias(容錯) 屬性設置對應當初宣告keras.layers.core.dense的參數內容進行初始化(詳看dense layer之文)會判斷是否會讓 input layer 的張量和 自身layer的張量(kernel屬性) 做張量內積,與加上自身的bias張量後、透過activation function 轉換後,回傳自身實體當成下一個Dense layer層的call function 參數。
因為實際上未將資料餵入,只是為了串接層的關聯,所以這必經的過程只會傳初始的張量。依本例直至最後一個 Dense layer層實體形成後 (predictions),將一開始的input layer實體與最終的 predictions實體分別傳入keras.engine.training.Model 類別的建構子之 input 與 output 參數。
此略過層的建構與初始動作,當建立好 input layer 與 最後的 output layer 實體後,傳入 keras.engine.training.Model 類別的建構子產生實體。
在keras.engine.training.Model 類別的建構子,會區分是否為 直接以keras.engine.training.Model 類別宣告的方式,還是類似像 keras.engine.sequential 繼承 keras.engine.functional.Functional 類別的方式(參考Sequence文章)。
依此例 為 直接以keras.engine.training.Model 類別宣告的方式,所以keras.engine.training.Model 類別的建構子會用 keras.engine.functional.Functional 類別建構子回傳Functional 的實體。 這邊做法和 Sequence 類別有差異。
接下來的 keras.engine.functional.Functional.init,主要會執行 keras.engine.functional._init_graph_network 函式,這邊很類似 model.build 文章 最後的部分。 函式一開始會到 keras.engine.functional._map_graph_network 、 keras.engine.functional._build_map 對 output layer 做 Recursive _build_map_helper function,將 input 到 output 過程連結的 node layer 找出來,依序將 layer 存入 _self_tracked_trackables 之 list 屬性 與 layers 之 list 屬性裡。並設定 built為True表示已經將模型 build 過。
差異
keras.engine.training.Model 類別建構子產生實體與 keras.engine.Sequential類別建構子產生的實體差別在,keras.engine.Sequential 加入指定的 layer到自身 _self_tracked_trackables與layers屬性 ,但沒有做模型build的動作;keras.engine.training.Model 類別則是 以傳入input layer 與最後的 output layer,透過keras.engine.functional提供的function來找出層的關聯後,將所有層加入到自身 _self_tracked_trackables與layers屬性,並做好模型build的動作。
另一方面要注意的是,因為keras.engine.training.Model 類別產生實體的過程,就要執行build模型,所以如同本範例在傳入layer物件時,要把關聯設定好,也就是關聯的順序要指定好,如同本範例層的建立方式,這樣在執行build的動作時才能遞迴將層的順序逐一找回建立到內建list屬性中,供之後訓練使用。
keras.engine.Sequential類別產生的實體,並沒有做模型build的動作,所以可以再模型訓練前執行模型build的呼叫,如果沒有則是會在模型初次訓練時會自動補做模型build的動作。