TensorFlow 2.0 模型:Keras 训练流程及自定义组件

在上一篇文章中,我们介绍了循环神经网络的建立方式。本来接下来应该介绍 TensorFlow 中的深度强化学习的,奈何笔者有点咕,到现在还没写完,所以就让我们先来了解一下 Keras 内置的模型训练 API 和自定义组件的方法吧!本文介绍以下内容:
使用 Keras 内置的 API 快速建立和训练模型,几行代码创建和训练一个模型不是梦;

自定义 Keras 中的层、损失函数和评估指标,创建更加个性化的模型。

Keras Pipeline *

在之前的文章中,我们均使用了 Keras 的 Subclassing API 建立模型,即对 tf.keras.Model 类进行扩展以定义自己的新模型,同时手工编写了训练和评估模型的流程。

这种方式灵活度高,且与其他流行的深度学习框架(如 PyTorch、Chainer)共通,是本手册所推荐的方法。不过在很多时候,我们只需要建立一个结构相对简单和典型的神经网络(比如上文中的 MLP 和 CNN),并使用常规的手段进行训练。这时,Keras 也给我们提供了另一套更为简单高效的内置方法来建立、训练和评估模型。

Keras Sequential/Functional API 模式建立模型

最典型和常用的神经网络结构是将一堆层按特定顺序叠加起来,那么,我们是不是只需要提供一个层的列表,就能由 Keras 将它们自动首尾相连,形成模型呢?Keras 的 Sequential API 正是如此。通过向 tf.keras.models.Sequential() 提供一个层的列表,就能快速地建立一个 tf.keras.Model 模型并返回:

1      model = tf.keras.models.Sequential([
2            tf.keras.layers.Flatten(),
3            tf.keras.layers.Dense(100, activation=tf.nn.relu),
4            tf.keras.layers.Dense(10),
5            tf.keras.layers.Softmax()
6        ])

不过,这种层叠结构并不能表示任意的神经网络结构。为此,Keras 提供了 Functional API,帮助我们建立更为复杂的模型,例如多输入 / 输出或存在参数共享的模型。其使用方法是将层作为可调用的对象并返回张量(这点与之前章节的使用方法一致),并将输入向量和输出向量提供给 tf.keras.Model 的 inputs 和 outputs 参数,示例如下:

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

使用 Keras 的内置 API 训练和评估模型
当模型建立完成后,通过 tf.keras.Model 的 compile 方法配置训练过程:

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

tf.keras.Model.compile 接受 3 个重要的参数:
oplimizer :优化器,可从 tf.keras.optimizers 中选择;
loss :损失函数,可从 tf.keras.losses 中选择;
metrics :评估指标,可从 tf.keras.metrics 中选择。
接下来,可以使用 tf.keras.Model 的 fit 方法训练模型:
1 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 :验证数据,可用于在训练过程中监控模型的性能。
Keras 支持使用 tf.data.Dataset 进行训练,详见 tf.data 。

注:tf.data 链接

https://tf.wiki/zh/basic/tools.html#tfdata

最后,使用 tf.keras.Model.evaluate 评估训练效果,提供测试数据及标签即可:
1 print(model.evaluate(data_loader.test_data, data_loader.test_label))

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

可能你还会问,如果现有的这些层无法满足我的要求,我需要定义自己的层怎么办?事实上,我们不仅可以如 前文的介绍 一样继承 tf.keras.Model 编写自己的模型类,也可以继承 tf.keras.layers.Layer 编写自己的层。

自定义层
自定义层需要继承 tf.keras.layers.Layer 类,并重写 init 、 build 和 call 三个方法,如下所示:

1class MyLayer(tf.keras.layers.Layer):
2    def __init__(self):
3        super().__init__()
4        # 初始化代码
5
6    def build(self, input_shape):     # input_shape 是一个 TensorShape 类型对象,提供输入的形状
7        # 在第一次使用该层的时候调用该部分代码,在这里创建变量可以使得变量的形状自适应输入的形状
8        # 而不需要使用者额外指定变量形状。
9        # 如果已经可以完全确定变量的形状,也可以在__init__部分创建变量
10        self.variable_0 = self.add_weight(...)
11        self.variable_1 = self.add_weight(...)
12
13    def call(self, inputs):
14        # 模型调用的代码(处理输入并返回输出)
15        return output

例如,如果我们要自己实现一个 前文 中的全连接层( tf.keras.layers.Dense ),可以按如下方式编写。此代码在 build 方法中创建两个变量,并在 call 方法中使用创建的变量进行运算:

1class LinearLayer(tf.keras.layers.Layer):
2    def __init__(self, units):
3        super().__init__()
4        self.units = units
5
6    def build(self, input_shape):     # 这里 input_shape 是第一次运行call()时参数inputs的形	状
7        self.w = self.add_variable(name='w',
8            shape=[input_shape[-1], self.units], initializer=tf.zeros_initializer())
 9        self.b = self.add_variable(name='b',
10            shape=[self.units], initializer=tf.zeros_initializer())
11
12    def call(self, inputs):
13        y_pred = tf.matmul(inputs, self.w) + self.b
14        return y_pred

在定义模型的时候,我们便可以如同 Keras 中的其他层一样,调用我们自定义的层 LinearLayer:

1class LinearModel(tf.keras.Model):
2    def __init__(self):
3        super().__init__()
4        self.layer = LinearLayer(units=1)
5
6    def call(self, inputs):
7        output = self.layer(inputs)
8        return output

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

1class MeanSquaredError(tf.keras.losses.Loss):
2 def call(self, y_true, y_pred):
3 return tf.reduce_mean(tf.square(y_pred - y_true))
自定义评估指标需要继承 tf.keras.metrics.Metric 类,并重写 init、 update_state 和 result 三个方法。下面的示例对前面用到的 SparseCategoricalAccuracy 评估指标类做了一个简单的重实现:

1class SparseCategoricalAccuracy(tf.keras.metrics.Metric):
2    def __init__(self):
3        super().__init__()
4        self.total = self.add_weight(name='total', dtype=tf.int32, initializer=tf.zeros_initializer())
5        self.count = self.add_weight(name='count', dtype=tf.int32, initializer=tf.zeros_initializer())
6
7    def update_state(self, y_true, y_pred, sample_weight=None):
8        values = tf.cast(tf.equal(y_true, tf.argmax(y_pred, axis=-1, output_type=tf.int32)), tf.int32)
9        self.total.assign_add(tf.shape(y_true)[0])
10        self.count.assign_add(tf.reduce_sum(values))
11
12    def result(self):
13        return self.count / self.total

如果帮到了,希望你们能收藏评论加点赞,一键三连走一波,感谢支持。

原文来自微信公众号,侵删。

你可能感兴趣的:(深度学习)