【tf.keras】官方教程一 Keras overview
Sequential Model:(the simplest type of model)
Getting started with the Keras Sequential model
之前在研讀MobileNet V3的原始碼時,其程式碼在基於TensorFlow框架中使用了tf.keras。在基於tf.keras下,模型的構建更加容易,也略顯高階。再次附上MobileNet V3程式碼:https://github.com/Bisonai/mobilenetv3-tensorflow。
官方教程:https://tensorflow.google.cn/guide/keras/overview
tf.keras是TensorFlow實現的keras API規範。這是一個用於構建和訓練模型的高階API,包含對tensorflow特定功能的支援。
1 import tf.keras 2 # form tensorflow import keras
Keras 2.2.5是最後一個支援TensorFlow1.的版本,也是2.2.*最後一個用Keras實現的版本。最新的版本是Keras2.3.0,其對API進行了重大的改進,並新增對TensorFlow 2.0的支援。
**************************************Keras使用基礎*****************************************
Sequential Model:(the simplest type of model)
Sequential 模型就是多個網路層的線性堆疊
1 from keras.models import Sequential 2 from keras.layers import Dense 3 model = Sequential() 4 model.add(Dense(units=64, activation="relu", input_dim=100)) 5 model.add(Dense(units=10, activation="softmax"))
一旦模型搭建完成,可以通過.compile()配置它的學習過程。
1 model.compile(loss='categorical_crossentropy', 2 optimizer='sgd', 3 metrics=['accuracy']
如果需要,也可以優化配置,如下所述。此時,損失、優化器的設定將會顯式的呼叫方法,而不是通過某欄位:
1 model.compile(loss=keras.losses.categorical_crossentropy, 2 optimizer=keras.optimizers.SGD(lr=0.01, momentum=0.9, nesterov=True))
訓練階段:
然後,可以將資料輸入模型,並進行訓練。自動將輸入資料劃分為batch進行訓練:
model.fit(x_train, y_train, epoch=5, batch_size=32)
當然,也可以手動將batch資料集輸入到模型中(這種情況通常是在需要手動建立樣本對時,如siamese network):
model.train_on_batch(x_batch, y_batch)
訓練時,驗證模型:
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=128)
測試階段:
classes = model.predict(x_test, batch_size=128)
以上是最簡明的Keras教程。
Getting started with the Keras Sequential model
Sequential model 就是一些層的線性堆疊。
堆疊的方式包含兩種:
- 通過一個由層例項構成的列表:
1 from keras.models import Sequential 2 from keras.layers import Dense, Activation 3 4 model = Sequential([ 5 Dense(32, input_shape=(784,)), 6 Activation('relu'), 7 Dense(10), 8 Activation('softmax'), 9 ])
將由層構成的列表新增到Sequential中。
- 簡單的通過.add()函式新增層
1 model = Sequential() 2 model.add(Dense(32, input_dim=784)) 3 model.add(Activation('relu'))
一般會直接把啟用函式新增到層中:
model.add(Dense(units=10, activation="softmax"))
Specifying the input shape
模型需要明確輸入形狀(就像TensorFlow中佔位符tf.placeholder()的宣告)。
因此,序列模型中的第一層(只有第一層,因為後續層可以進行自動形狀推斷)需要接收關於其輸入形狀的資訊。Keras有幾種可能的方法來做到這一點:
- 將input_shape引數傳遞給第一層。這是一個形狀元組(一個整數或無項的元組,其中None表示可能期望任何正整數)。在input_shape中,不包括批處理維度。
1 model = Sequential() 2 model.add(Dense(32, input_shape=(784,)))
如上所示,將input_shape傳遞給第一層中。
- 一些2D層(如Dense)通過引數input_dim傳遞輸入的形狀;一些3D層支援引數input_dim和input_length。
1 model = Sequential() 2 model.add(Dense(32, input_dim=784))
如上所示,Dense中既包含input_dim引數的傳遞,也包含input_shape引數的傳遞。
- 也可以將batch_size新增到輸入形狀中。batch_size=32和input_shape=(6,8)傳遞給一個層,那麼它將期望每批輸入都具有批處理形狀(32,6,8)。 --這一部分與TensorFlow幾乎一致
Compilation
在訓練模型之前,需要配置訓練過程的一些引數,通過compile函式完成。必需傳遞的三個引數:
optimizer:
可以使用現存優化器的字串或者是一個優化器類的例項來識別。
1 from keras import optimizers 2 3 model = Sequential() 4 model.add(Dense(64, kernel_initializer='uniform', input_shape=(10,))) 5 model.add(Activation('softmax')) 6 # 情形1: 類的例項 7 sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) 8 model.compile(loss='mean_squared_error', optimizer=sgd) 9 # 情形2:字串 10 model.compile(loss='mean_squared_error', optimizer='sgd')
優化器中可以新增clipnorm和clipvalue引數對梯度進行截斷。
1 from keras import optimizers 2 3 # All parameter gradients will be clipped to 4 # a maximum norm of 1. 5 sgd = optimizers.SGD(lr=0.01, clipnorm=1.)
1 from keras import optimizers 2 3 # All parameter gradients will be clipped to 4 # a maximum value of 0.5 and 5 # a minimum value of -0.5. 6 sgd = optimizers.SGD(lr=0.01, clipvalue=0.5)
常用的優化方式包括SGD、RMSprop、Adagrad、Adadelta、Adam、Adamax、Nadam。具體使用詳見:https://keras.io/optimizers/
loss funtion:
同樣可以通過字串或類例項來識別。
1 from keras import losses 2 # 情形1 字串 3 model.compile(loss='mean_squared_error', optimizer='sgd') 4 # 情形2 類例項 5 model.compile(loss=losses.mean_squared_error, optimizer='sgd')
可以獲取到的損失函式詳見:https://keras.io/losses/
metrics:
對於任何分類問題,需要設定一些metrics=['accuracy'],也是通過字串和類例項識別。
1 from keras import metrics 2 # 情形1 字串 3 model.compile(loss='mean_squared_error', 4 optimizer='sgd', 5 metrics=['mae', 'acc']) 6 # 情形2 類例項 7 model.compile(loss='mean_squared_error', 8 optimizer='sgd', 9 metrics=[metrics.mae, metrics.categorical_accuracy])
可以獲得的metrics詳見:https://keras.io/metrics/
Training
Keras訓練通過Numpy陣列作為輸入資料。
1 # For a single-input model with 2 classes (binary classification): 2 3 model = Sequential() 4 model.add(Dense(32, activation='relu', input_dim=100)) 5 model.add(Dense(1, activation='sigmoid')) 6 model.compile(optimizer='rmsprop', 7 loss='binary_crossentropy', 8 metrics=['accuracy']) 9 10 # Generate dummy data 11 import numpy as np 12 data = np.random.random((1000, 100)) 13 labels = np.random.randint(2, size=(1000, 1)) 14 15 # Train the model, iterating on the data in batches of 32 samples 16 model.fit(data, labels, epochs=10, batch_size=32)
one-hot操作:
1 # Convert labels to categorical one-hot encoding 2 one_hot_labels = keras.utils.to_categorical(labels, num_classes=10)
更多Keras中函式引數使用詳見:https://keras.io/models/sequential/
後端使用詳見:https://keras.io/backend/
************************************************************************************************************
上面介紹了一些關於Keras的使用,這是使用tf.keras的基礎。
言歸正傳,回到tf.keras的道路上...
tf.keras是TensorFlow實現的keras API規範。這是一個用於構建和訓練模型的高階API,包括對tensorflow特定功能(如eager execution、tf.data和Estimators) tf.keras使TensorFlow更易於使用,同時又不犧牲靈活性和效能。
eager execution、tf.data和Estimators會在TensorFlow的介紹中詳細解讀,tf.keras中暫不作詳述。
首先,匯入需要的一些設定:
1 from __future__ import absolute_import, division, print_function, unicode_literals 2 import tensorflow as tf 3 from tensorflow import keras
tf.keras中可以執行與Keras相容的任意程式碼,但需要注意的是:
- 版本是否相容,需要通過tf.keras.version確認版本資訊
- 模型儲存問題,tf.keras預設使用 checkpoint format格式,而keras模型的儲存格式HDF5需要借用函式save_format='h5'
使用tf.keras建立一個簡易的模型
仿照Keras中的Sequential()方法,此時,在TensorFlow中也可以使用這種線性堆疊的方法:tf.keras.Sequentials()
1 import tensorflow as tf 2 from tensorflow.keras import layers 3 4 model = tf.keras.Sequential() 5 # Adds a densely-connected layer with 64 units to the model: 6 model.add(layers.Dense(64, activation='relu')) 7 # Add another: 8 model.add(layers.Dense(64, activation='relu')) 9 # Add an output layer with 10 output units: 10 model.add(layers.Dense(10))
tf.keras.layers中提供了一些可用的層,詳見:https://tensorflow.google.cn/api_docs/python/tf/keras/layers
這些層會包含一些共同的引數:
- activation: 設定啟用函式。 預設情況下為無啟用函式。
- kernel_initializer 和 bias_initializer:初始化權重和偏執。通過這個操作,便不再需要手動為每一層的權重和偏執進行初始化。預設情況下是"Glorot uniform"初始化方式。這個在tensorflow的slim API中會包含。
- kernel_regularizer 和 bias_regularizer : 權重和偏執正則化。通過這個操作,可以實現神經網路結構的正則化,防止過擬合的現象,可以使用L1正則化和L2正則化。預設情況下是不新增正則化。這個在tensorflow 的 slim API中也會包含。 --- 這個是需要手動新增的
1 # 建立一個啟用函式是relu的全連線層: 2 layers.Dense(64, activation='relu') 3 # 也可以通過 類例項 設定啟用函式: 4 layers.Dense(64, activation=tf.nn.relu) 5 6 # 建立一個對權重使用L1正則化,並且引數為0.01的全連線層: 7 layers.Dense(64, kernel_regularizer=tf.keras.regularizers.l1(0.01)) 8 9 # 建立一個對偏執使用L2正則化,並且引數為0.01的全連線層: 10 layers.Dense(64, bias_regularizer=tf.keras.regularizers.l2(0.01)) 11 12 # 對權重選擇orthogonal的初始化方式 13 layers.Dense(64, kernel_initializer='orthogonal') 14 15 # 將偏執初始化為2.0 16 layers.Dense(64, bias_initializer=tf.keras.initializers.Constant(2.0))
在模型搭建完成後,便可以配置訓練過程的引數,這些過程與Keras一致,只不過是通過tf.keras來呼叫。
1 model.compile(optimizer=tf.keras.optimizers.Adam(0.01), 2 loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), 3 metrics=['accuracy'])
在compile可以設定run_eager=True ,to make sure the model trains and evaluates eagerly。
使用Numpy陣列進行訓練:
不需要將資料喂到張量中,可以直接將資料輸入到.fit()函式中。
1 import numpy as np 2 3 data = np.random.random((1000, 32)) 4 labels = np.random.random((1000, 10)) 5 6 model.fit(data, labels, epochs=10, batch_size=32
tf.keras.Model.fit()函式中包含3個重要引數:
- epochs: 訓練代數
- batch_size:一個批次的資料量。當傳遞NumPy資料時,模型將資料分割成更小的批。這個值指定每個批處理的大小。請注意,如果樣本總數不能被批次大小整除,那麼最後一批可能會很小。
- validation_data:在構建模型原型時,希望在某些驗證資料上方便地監視它的效能。傳遞這個引數(輸入和標籤的元組)允許模型在每個epoch結束時以推理模式顯示傳遞的資料的損失和度量。 當然,不設定也可以。 ---- 此處應該有推理代數的設定,每個epoch結束都進行驗證,會延長訓練時間,而且實際上也沒有必要。
1 import numpy as np 2 3 data = np.random.random((1000, 32)) 4 labels = np.random.random((1000, 10)) 5 6 val_data = np.random.random((100, 32)) 7 val_labels = np.random.random((100, 10)) 8 9 model.fit(data, labels, epochs=10, batch_size=32, 10 validation_data=(val_data, val_labels))
使用tf.data 資料集進行訓練
此處只是簡單的介紹,tf.data是讀取資料的API,可以實現資料在多裝置上的訓練。可以通過tf.data.Dataset例項獲取資料,並將資料傳入到 .fit 方法中。
詳見:https://tensorflow.google.cn/guide/data
1 dataset = tf.data.Dataset.from_tensor_slices((data, labels)) 2 dataset = dataset.batch(32) 3 4 model.fit(dataset, epochs=10)
由於Dataset生成(yeild)批量資料,因此model.fit()中不再需要batch_size引數的設定。同時,Dataset也可以用於驗證資料的生成:
1 dataset = tf.data.Dataset.from_tensor_slices((data, labels)) 2 dataset = dataset.batch(32) 3 4 val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels)) 5 val_dataset = val_dataset.batch(32) 6 7 model.fit(dataset, epochs=10, 8 validation_data=val_dataset)
驗證和預測
tf.keras.Model.evaluate和tf.keras.Model.predict方法可以使用Numpy資料和tf.data.Dataset資料進行驗證和預測。
.evaluate
1 # With Numpy arrays 2 data = np.random.random((1000, 32)) 3 labels = np.random.random((1000, 10)) 4 5 model.evaluate(data, labels, batch_size=32) 6 7 # With a Dataset 8 dataset = tf.data.Dataset.from_tensor_slices((data, labels)) 9 dataset = dataset.batch(32) # 此處按照batch劃分 10 11 model.evaluate(dataset) # 此處不再需要batch引數
.predict
1 result = model.predict(data, batch_size=32) 2 print(result.shape)
詳見:https://tensorflow.google.cn/guide/keras/train_and_evaluate
使用tf.keras構建複雜模型
也許在上面的介紹中,你可能會覺得這只是在tensorflow中呼叫keras,搞出來了一個tf.keras這麼個東東,還不如直接用Keras來的實惠。這只是建立簡單的模型,在本節中,將會見到tf.keras的奇妙之處,也是在MobileNet V3原始碼中廣泛使用的模型子類化(Model subclassing)和自定義層(Custom layers) ,一起揭開其神祕的面紗。
The functional API
使用tf.keras.Sequential構建模型是一種層與層之間簡單堆疊式的方式,其不能表徵任意的模型。使用Keras functional API可以建立複雜的模型,例如:
- 多輸入模型
- 多輸出模型
- 擁有共享層的模型(同一層被呼叫多次)
- 不具有序列化輸入的模型(殘差網路的連線)
建立一個由functional API 構建的模型需要如下幾步:
- 層例項是可以呼叫的,並且返回一個張量;
- 輸入張量和輸出張量用於定義tf.keras.Model例項。
- 模型訓練的方式如同Sequential 模型。
下面的全連線網路例項便是使用的the functional API,在其中,可以隱約的看到keras版的YOLO v3的影子:
1 inputs = tf.keras.Input(shape=(32,)) # Returns an input placeholder 2 3 # 1. 層例項可以回撥一個張量,也可以返回一個張量 --- 完成模型的構建 4 x = layers.Dense(64, activation='relu')(inputs) 5 x = layers.Dense(64, activation='relu')(x) 6 predictions = layers.Dense(10)(x) 7 # 2. 通過給定輸出 輸出 例項化一個模型 8 model = tf.keras.Model(inputs=inputs, outputs=predictions) 9 10 # 3. 通過與sequential模型相同的訓練方式訓練模型 11 model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001), 12 loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), 13 metrics=['accuracy']) 14 15 # Trains for 5 epochs 16 model.fit(data, labels, batch_size=32, epochs=5)
模型子類化(Model subclassing)
通過tf.keras.Model子類化和定義前向過程的方式完全自主的建立model。在_init__方法中建立層,並將它們設定為類例項的屬性。在call方法中定義前向過程。
當啟用了立即執行時,模型子類化特別有用,因為它允許強制地編寫正向傳遞。
下面的例項中展示了一個使用子類化tf.keras.Model,並且自定義前向過程的模型:
1 class MyModel(tf.keras.Model): 2 3 def __init__(self, num_classes=10): 4 super(MyModel, self).__init__(name='my_model') 5 self.num_classes = num_classes 6 # Define your layers here. 7 self.dense_1 = layers.Dense(32, activation='relu') # __init__中定義層 8 self.dense_2 = layers.Dense(num_classes) 9 10 def call(self, inputs): # call 函式中定義前向過程 11 # Define your forward pass here, 12 # using layers you previously defined (in `__init__`). 13 x = self.dense_1(inputs) 14 return self.dense_2(x)
例項化建立的MyModel類,那並進行編譯訓練:
1 model = MyModel(num_classes=10) 2 3 # The compile step specifies the training configuration. 4 model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001), 5 loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), 6 metrics=['accuracy']) 7 8 # Trains for 5 epochs. 9 model.fit(data, labels, batch_size=32, epochs=5)
上面的使用過程可以描述為以下幾個步驟:
- 為模型建立一個類;
- 模型中層的定義在__init__函式中;
- 前向的過程在call函式中定義;
- 例項化類,並使用與sequential相同的方式編譯 訓練模型。
定製層(Custom layers)
通過子類化tf.keras.layers來建立一個自定義層。使用以下方法實現:
- __init__ :可選地定義此層要使用的子層(類的繼承);
- build:生成層的權重,使用add_weights方法新增權重;
- call:定義前向過程;
- 可選地,可以通過實現get_config方法和from_config類方法來序列化層。 (引數的儲存與匯入)
下面是一個自定義層的例子,它實現了一個帶有核矩陣的輸入矩陣:
1 class MyLayer(layers.Layer): 2 3 def __init__(self, output_dim, **kwargs): 4 self.output_dim = output_dim # 輸出個數的定義 5 super(MyLayer, self).__init__(**kwargs) # 初始化layers.Layer變數。 6 7 def build(self, input_shape): # 新增權重矩陣 8 # Create a trainable weight variable for this layer. 9 self.kernel = self.add_weight(name='kernel', 10 shape=(input_shape[1], self.output_dim), 11 initializer='uniform', 12 trainable=True) 13 14 def call(self, inputs): # 定義前向過程 15 return tf.matmul(inputs, self.kernel) 16 17 def get_config(self): 18 base_config = super(MyLayer, self).get_config() 19 base_config['output_dim'] = self.output_dim 20 return base_config 21 22 @classmethod 23 def from_config(cls, config): 24 return cls(**config)
使用自定義的層,建立一個模型:
1 model = tf.keras.Sequential([ 2 MyLayer(10)]) 3 4 # The compile step specifies the training configuration 5 model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001), 6 loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True), 7 metrics=['accuracy']) 8 9 # Trains for 5 epochs. 10 model.fit(data, labels, batch_size=32, epochs=5)
更加細緻的內容詳見: https://tensorflow.google.cn/guide/keras/custom_layers_and_models
Callbacks
回撥是傳遞給模型的物件,用於在訓練期間自定義和擴充套件其行為。編寫自己的自定義回撥,或者使用內建的tf.keras.callbacks,包括: ---- callbacks 引數是在.fit()中應用。
- tf.keras.callbacks.ModelCheckpoint:每個一定代數定期的儲存權重;
- tf.keras.callbacks.LearningRateScheduler: 動態地改變學習率 lr;
- tf.keras.callbacks.EarlyStopping: 關於earlystop的設定
- tf.keras.callbacks.TensorBoard: 關於tensorboard的設定;
1 callbacks = [ 2 # Interrupt training if `val_loss` stops improving for over 2 epochs 3 tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'), 4 # Write TensorBoard logs to `./logs` directory 5 tf.keras.callbacks.TensorBoard(log_dir='./logs') 6 ] 7 model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks, 8 validation_data=(val_data, val_labels))
模型的儲存與匯入
只儲存權重
- tf.keras.Model.save_weights()儲存權重;
- tf.keras.Model.load_weights()匯入權重
1 # Save weights to a TensorFlow Checkpoint file 2 model.save_weights('./weights/my_model') 3 4 # Restore the model's state, 5 # this requires a model with the same architecture. 6 model.load_weights('./weights/my_model')
上述函式預設儲存的模型權重是TensorFlow的checkpoint(.ckpt)格式。也可以儲存為Keras版的HDF5格式,只需要修改儲存格式引數即可:
1 # Save weights to a HDF5 file 2 model.save_weights('my_model.h5', save_format='h5') 3 4 # Restore the model's state 5 model.load_weights('my_model.h5')
只儲存模型的配置檔案:
非訓練過程調整的引數儲存,如yolo中的cfg檔案。可以儲存為JSON和YAML兩種格式:
1 # Serialize a model to JSON format 2 json_string = model.to_json() # 儲存 為json 3 yaml_string = model.to_yaml() # 儲存 為yaml
匯入
1 import json 2 import pprint 3 pprint.pprint(json.loads(json_string))
復現模型:
1 fresh_model = tf.keras.models.model_from_json(json_string) # 由json復現 2 fresh_model = tf.keras.models.model_from_yaml(yaml_string) # 由yaml復現
儲存完整的模型在一個檔案中
1 # Save entire model to a HDF5 file 2 model.save('my_model') 3 4 # Recreate the exact same model, including weights and optimizer. 5 model = tf.keras.models.load_model('my_model')
更多關於儲存模型內容詳見:https://tensorflow.google.cn/guide/keras/save_and_serialize