Tensorflow 2.0 Keras

First of all, Keras != tf.keras.

Custom Layers

详见Code

  • keras.Sequential
  • keras.layers.Layer
  • keras.Model
    • model.trainable_variables
    • model.call()

自定义层需要继承tf.keras.layers.Layer类,并重写__init__buildcall三个方法

class LinearLayer(tf.keras.layers.Layer):
    def __init__(self, units):
        super().__init__()
        self.units = units

    def build(self, input_shape):     # 这里 input_shape 是第一次运行call()时参数inputs的形状
        self.w = self.add_variable(name='w',
            shape=[input_shape[-1], self.units], initializer=tf.zeros_initializer())
        self.b = self.add_variable(name='b',
            shape=[self.units], initializer=tf.zeros_initializer())

    def call(self, inputs):
        y_pred = tf.matmul(inputs, self.w) + self.b
        return y_pred

# 使用自定义的层构建模型
class LinearModel(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.layer = LinearLayer(units=1)

    def call(self, inputs):
        output = self.layer(inputs)
        return output

Layer/Model

  • inherit from keras.layers.Layer, keras.Model
  • __init__
  • call()
  • Model: compile/fit/evaluate

Sequential API

可以使用Sequential方式建立模型,但是这种层叠结构不能表示任意的神经网络结构

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(100, activation=tf.nn.relu),
    tf.keras.layers.Dense(2),
    tf.keras.layers.Softmax()
])

Functional API

inputs = tf.keras.Input(shape=(28, 28, 1))
x = tf.keras.layers.Flatten()(inputs)
x = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)(x)
x = tf.keras.layers.Dense(units=10)(x)
outputs = tf.keras.layers.Softmax()(x)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

Compile & Fit

详见Code

  • compile
  • fit
  • evaluate
  • predict

可以使用Keras Modelcompilefitevaluate方法训练和评估模型,当模型建立完成后,通过tf.keras.Modelcompile方法配置训练过程:

model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
    loss=tf.keras.losses.sparse_categorical_crossentropy,
    metrics=[tf.keras.metrics.sparse_categorical_accuracy]
)

tf.keras.Model.compile 接受 3 个重要的参数:

  • optimizer :优化器,可从tf.keras.optimizers中选择
  • loss :损失函数,可从tf.keras.losses中选择
  • metrics :评估指标,可从tf.keras.metrics中选择

接下来,可以使用tf.keras.Modelfit方法训练模型:

model.fit(data_loader.train_data, data_loader.train_label, epochs=num_epochs, batch_size=batch_size)

tf.keras.Model.fit接受 5 个重要的参数:

  • x :训练数据;
  • y :目标数据(数据标签);
  • epochs :将训练数据迭代多少遍;
  • batch_size :批次的大小;
  • validation_data :验证数据,可用于在训练过程中监控模型的性能。

最后,使用tf.keras.Model.evaluate评估训练效果,提供测试数据及标签即可:

print(model.evaluate(data_loader.test_data, data_loader.test_label))

Metrics

详见Code

  • metrics
  • update_state
  • result().numpy()
  • reset_states

自定义损失函数和评估指标

自定义损失函数需要继承tf.keras.losses.Loss类,重写call方法即可,输入真实值y_true和模型预测值y_pred,输出模型预测值和真实值之间通过自定义的损失函数计算出的损失值。下面的示例为均方差损失函数:

class MeanSquaredError(tf.keras.losses.Loss):
    def call(self, y_true, y_pred):
        return tf.reduce_mean(tf.square(y_pred - y_true))

自定义评估指标需要继承tf.keras.metrics.Metric类,并重写__init__update_stateresult三个方法。下面的示例对前面用到的SparseCategoricalAccuracy评估指标类做了一个简单的重实现:

class SparseCategoricalAccuracy(tf.keras.metrics.Metric):
    def __init__(self):
        super().__init__()
        self.total = self.add_weight(name='total', dtype=tf.int32, initializer=tf.zeros_initializer())
        self.count = self.add_weight(name='count', dtype=tf.int32, initializer=tf.zeros_initializer())

    def update_state(self, y_true, y_pred, sample_weight=None):
        values = tf.cast(tf.equal(y_true, tf.argmax(y_pred, axis=-1, output_type=tf.int32)), tf.int32)
        self.total.assign_add(tf.shape(y_true)[0])
        self.count.assign_add(tf.reduce_sum(values))

    def result(self):
        return self.count / self.total

Save and Load Models

详见Save and load weights 详见Save and load models

  • save/load weights:

    • 仅仅保存模型的权重参数,不包括整个网络结构,因此load权重之前需要重新compile一样结构的模型
    # Save the weights
    model.save_weights('./checkpoints/my_checkpoint')
    # Restore the weights
    model = create_model()
    model.load_weights('./checkpoints/my_checkpoint')
    loss, acc = model.evaluate(test_images, test_labels)
    
  • save/load entire model:

    • 保存整个网络结构和权重,不需要重新定义模型结构
    network.save('model.h5)
    print('saved total model.)
    del network
    
    print('load model from file')
    network = tf.keras.model.load_model('model.h5')
    network.evaluate(v_val, y_val)
    
  • saved_model

    • 主要是用来进行生产环境的部署,ONNX的通用模型格式
    # 生产环境部署
    print('Save served model')
    tf.saved_model.save(network, './model/server_model')
    print('Delete model')
    del network
    
    print('Load served model')
    imported = tf.saved_model.load('./model/server_model')
    f = imported.signatures['serving_default']
    
    # 直接inference输出预测结果
    # 随机生成一个全是1的张量
    pred = f(input_1=tf.ones([1, 784]))
    print(tf.argmax(pred['output_1'], axis=1))
    # 抽取ds_val中第一张图片,扩展为一个张量
    pred = f(input_1=tf.expand_dims(sample[0][0], axis=0))  # 需要扩展为[1, 784]
    print(tf.argmax(pred['output_1'], axis=1))
    # 实际label
    print(tf.argmax([sample[1][0]], axis=1))
    

Reference

  1. TensorFlow-2.x-Tutorials
  2. 简单粗暴Tensorflow 2.0

Note: Cover Picture