教程 | TensorFlow 1.10 指南 —— 高级 API —— Keras

译自:TensorFlow官方指南

Keras 是一个用于构建和训练深度学习模型的高级 API,可用于快速原型设计、高级研究和产品生产。Keras 具有三个主要优势:

  • 用户友好
    Keras 具有针对常见事例优化的简单、一致的接口。它为用户错误提供清晰且可执行的反馈。
  • 模块化和可组合性
    通过将可配置的模块连接在一起,从而建立 Keras 模型,几乎没有限制。
  • 易于扩展
    编写自定义模块以表达研究的新想法。创建新的网络层、损失函数并开发最先进的模型。

导入 tf.keras


tf.kerasKeras API 规范的 TensorFlow 实现。这是一个用于构建和训练模型的高级 API,其中包括对 TensorFlow 特定功能的重要支持,例如 eager executiontf.data 管道和 Estimatorstf.keras 使 TensorFlow 更易于使用而不牺牲灵活性和性能。

要使用 Keras,先将 tf.keras 作为 TensorFlow 程序设置的一部分导入:

import tensorflow as tf
from tensorflow import keras

tf.keras 可以运行任何与 Keras 兼容的代码,但请记住:

  • 最新的 TensorFlow 中的 tf.keras 版本可能与 PyPI 中最新的 keras 版本不同。请检查 tf.keras.__version__
  • 保存模型权重时,tf.keras 默认使用 checkpoint 格式。传入 save_format='h5' 以保存为 HDF5 格式。

构建一个简单的模型


序列模型

在 Keras 中,你可以通过集成网络层来构建模型。模型通常是网络层图。最常见的模型类型是序列网络层:即 tf.keras.Sequential 模型。

构建一个简单的全连接网络(例如多层感知机):

model = keras.Sequential()
# 为模型添加具有 64 个单元的密集连接层:
model.add(keras.layers.Dense(64, activation='relu'))
# 添加另外 64 个:
model.add(keras.layers.Dense(64, activation='relu'))
# 添加具有 10 个输出单元的 softmax 层:
model.add(keras.layers.Dense(10, activation='softmax'))

配置网络层

有许多 tf.keras.layers 可用,它们有一些通用的构建参数:

  • activation:设置网络层的激活函数。该参数可由内置函数的名称或可调用对象指定。默认情况下,不使用任何激活函数。
  • kernel_initializerbias_initializer:创建网络层权重和偏差的初始化方案。该参数可以是名称或可调用对象。默认参数为 “Glorot uniform” 初始化器。
  • kernel_regularizerbias_regularizer:应用于网络层权重和偏差的正则化方案,例如 L1 或 L2 正则化。默认情况下,不使用正则化。

下例使用构建参数实例化 tf.keras.layers.Dense 网络层:

# 创建 sigmoid 层:
layers.Dense(64, activation='sigmoid')
# 或者:
layers.Dense(64, activation=tf.sigmoid)

# 对权重使用 L1 正则化的线性层,正则化因子为 0.01:
layers.Dense(64, kernel_regularizer=keras.regularizers.l1(0.01))
# 对偏差使用 L2 正则化的线性层,正则化因子为 0.01:
layers.Dense(64, bias_regularizer=keras.regularizers.l2(0.01))

# 权重初始化为随机正交矩阵:
layers.Dense(64, kernel_initializer='orthogonal')
# 偏差向量初始化为常数 2.0:
layers.Dense(64, bias_initializer=keras.initializers.constant(2.0))

训练和评估


设置训练

建立模型后,通过调用 compile 方法配置其学习过程:

model.compile(optimizer=tf.train.AdamOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

tf.keras.Model.compile 有三个重要参数:

  • optimizer:该对象指定训练过程。传入 tf.train 模块中的优化器实例,例如 AdamOptimizerRMSPropOptimizer,或 GradientDescentOptimizer
  • loss:优化时需要最小化的函数。常见的选择包括均方误差 (mse),categorical_crossentropybinary_crossentropy。损失函数由名称指定或从 tf.keras.losses 模块中传入可调用对象来指定。
  • metrics:用于监控训练过程。可以是 tf.keras.metrics 模块中的字符串名称或可调用对象。

下面显示了配置训练模型的几个示例:

# 配置用于均方误差回归的模型
model.compile(optimizer=tf.train.AdamOptimizer(0.01),
              loss='mse',       # mean squared error
              metrics=['mae'])  # mean absolute error

# 配置用于多类别分类的模型
model.compile(optimizer=tf.train.RMSPropOptimizer(0.01),
              loss=keras.losses.categorical_crossentropy,
              metrics=[keras.metrics.categorical_accuracy])

输入 NumPy 数据

对于小型数据集,使用 NumPy 数组来训练和评估模型,使用 fit 方法训练数据:

import numpy as np

data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))

model.fit(data, labels, epochs=10, batch_size=32)

tf.keras.Model.fit 有三个重要参数:

  • epochs:一个周期(epoch)是对所有输入数据的一次完整迭代(通过更小的批量完成)。
  • batch_size:当传入 NumPy 数据时,模型将数据分成较小的批量,并在训练期间迭代这些批量。该整数指定每个批量的大小。请注意,如果样本总数不能被批量大小整除,则最后一个批量可能会更小。
  • validation_data:在对模型进行设计时,你希望轻松监控其在某些验证数据上的性能。传递这个参数 —— 输入和标签的元组 —— 以允许模型在每个周期结束时对传入的数据进行推断,从而显示损失和指标。

这里有一个使用 validation_data 的例子:

import numpy as np

data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))

val_data = np.random.random((100, 32))
val_labels = np.random.random((100, 10))

model.fit(data, labels, epochs=10, batch_size=32,
          validation_data=(val_data, val_labels))

输入 tf.data 数据集

使用 Datesets API 可以扩展到大型数据集或多设备训练。将 tf.data.Dataset 实例传递给 fit 方法:

# 实例化一个小数据集:
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32)
dataset = dataset.repeat()

# 对一个数据集调用 fit 方法时,不要忘记指定 'step_per_epoch'
model.fit(dataset, epochs=10, steps_per_epoch=30)

这里,fit 方法使用 steps_per_epoch 参数 —— 这是模型在进入到下一个周期之前运行的训练次数。由于 Dataset 产生批量数据,此代码段不需要 batch_size

Dateset 也可用于验证:

dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32).repeat()

val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels))
val_dataset = val_dataset.batch(32).repeat()

model.fit(dataset, epochs=10, steps_per_epoch=30,
          validation_data=val_dataset,
          validation_steps=3)

评估和预测

tf.keras.Model.evaluatetf.keras.Model.predict 方法可以使用 NumPy 数据和 tf.data.Dataset

评估所提供数据的损失和指标:

model.evaluate(x, y, batch_size=32)

model.evaluate(dataset, steps=30)

预测所提供数据在最后一层的输出:

model.predict(x, batch_size=32)

model.predict(dataset, steps=30)

构建高级模型


功能性 API

tf.keras.Sequential 模型是一个简单的网络层堆栈,不能代表任意模型。使用 Keras 功能性 API 可以构建复杂的模型拓扑,例如:

  • 多输入模型
  • 多输出模型
  • 具有共享网络层的模型(同一层被调用多次)
  • 具有非序列数据流的模型(例如残差连接)

使用功能性 API 构建模型的工作方式如下:

  1. 网络层实例可调用并返回张量。
  2. 输入张量和输出张量用于定义 tf.keras.Model 实例。
  3. 和 Sequential 模型一样的训练方式。

以下示例使用功能性 API 构建一个简单的全连接网络:

inputs = keras.Input(shape=(32,))  # 返回一个 placeholder 张量

# 网络层实例可调用张量,并返回一个张量
x = keras.layers.Dense(64, activation='relu')(inputs)
x = keras.layers.Dense(64, activation='relu')(x)
predictions = keras.layers.Dense(10, activation='softmax')(x)

# 给定输入和输出,实例化模型
model = keras.Model(inputs=inputs, outputs=predictions)

# 编译步骤指定训练配置
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 训练 5 个周期
model.fit(data, labels, batch_size=32, epochs=5)

模型子类化

通过创建 tf.keras.Model 的子类并且定义自己的前向传播来构建完全自定义的模型。在 __init__ 方法中创建网络层并将它们设置为类实例的属性。在 call 方法中定义前向传播。

当使用 eager execution 时,模型子类化特别有用,因为可以强制写入前向传播。

关键点:虽然模型子类化提供了灵活性,但其代价是更高的复杂性和更多的错误可能。如果可以,请选择功能性 API。

以下示例显示了使用自定义前向传播的 tf.keras.Model 子类:

class MyModel(keras.Model):

  def __init__(self, num_classes=10):
    super(MyModel, self).__init__(name='my_model')
    self.num_classes = num_classes
    # 定义自己的网络层
    self.dense_1 = keras.layers.Dense(32, activation='relu')
    self.dense_2 = keras.layers.Dense(num_classes, activation='sigmoid')

  def call(self, inputs):
    # 定义前向传播
    # 使用 `__init__` 中定义的网络层
    x = self.dense_1(inputs)
    return self.dense_2(x)

  def compute_output_shape(self, input_shape):
    # 如果希望将子类模型作为函数样式模型的一部分使用
    # 则需要重写此函数
    # 否则,这个方法是可选的
    shape = tf.TensorShape(input_shape).as_list()
    shape[-1] = self.num_classes
    return tf.TensorShape(shape)


# 实例化子类模型
model = MyModel(num_classes=10)

# 编译步骤指定训练配置
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 训练 5 个周期
model.fit(data, labels, batch_size=32, epochs=5)

自定义网络层

通过创建 tf.keras.layers.Layer 的子类并实现以下方法来创建自定义层:

  • build:创建网络层的权重。使用 add_weight 方法添加权重。
  • call:定义前向传播。
  • compute_output_shape:指定如何在给定输入的情况下计算网络层的输出大小。
  • 可选地,可以通过实现 get_config 方法和 from_config 类方法来序列化网络层。

以下示例是一个自定义网络层,使用核矩阵和输入实现 matmul

class MyLayer(keras.layers.Layer):

  def __init__(self, output_dim, **kwargs):
    self.output_dim = output_dim
    super(MyLayer, self).__init__(**kwargs)

  def build(self, input_shape):
    shape = tf.TensorShape((input_shape[1], self.output_dim))
    # 创建可训练权重变量
    self.kernel = self.add_weight(name='kernel',
                                  shape=shape,
                                  initializer='uniform',
                                  trainable=True)
    # 确保在最后调用下述语句
    super(MyLayer, self).build(input_shape)

  def call(self, inputs):
    return tf.matmul(inputs, self.kernel)

  def compute_output_shape(self, input_shape):
    shape = tf.TensorShape(input_shape).as_list()
    shape[-1] = self.output_dim
    return tf.TensorShape(shape)

  def get_config(self):
    base_config = super(MyLayer, self).get_config()
    base_config['output_dim'] = self.output_dim

  @classmethod
  def from_config(cls, config):
    return cls(**config)


# 使用自定义层创建模型
model = keras.Sequential([MyLayer(10),
                          keras.layers.Activation('softmax')])

# 编译步骤指定训练配置
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 训练 5 个周期
model.fit(data, targets, batch_size=32, epochs=5)

回调

回调是传递给模型的对象,用于在训练期间自定义和扩展其行为。你可以编写自己的自定义回调,或使用内置的 tf.keras.callbacks

要使用 tf.keras.callbacks.Callback,请将其传递给模型的 fit 方法:

callbacks = [
  # 当 `val_loss` 在 2 个周期内不再下降,则中断训练
  keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),
  # 将 TensorBoard 日志写入 `./logs` 目录
  keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks,
          validation_data=(val_data, val_targets))

保存和恢复


仅权重

使用 tf.keras.Model.save_weights 保存并加载模型的权重:

# 保存权重至 TensorFlow Checkpoint 文件
model.save_weights('./my_model')

# 恢复模型状态,要求模型具有相同架构
model.load_weights('my_model')

默认情况下,这会以 TensorFlow Checkpoint 文件格式保存模型的权重。权重也可以保存为 Keras HDF5 格式(Keras 的多后端实现的默认格式):

# 保存权重至 HDF5 文件
model.save_weights('my_model.h5', save_format='h5')

# 恢复模型状态
model.load_weights('my_model.h5')

仅配置

可以保存模型的配置 —— 这可以在没有任何权重的情况下序列化模型架构。即使没有定义原始模型的代码,保存的配置也可以重新创建和初始化相同的模型。Keras 支持 JSON 和 YAML 序列化格式:

# 序列化模型至 JSON 格式
json_string = model.to_json()

# 重新创建模型
fresh_model = keras.models.from_json(json_string)

# 序列化模型至 YAML 格式
yaml_string = model.to_yaml()

# 重新创建模型
fresh_model = keras.models.from_yaml(yaml_string)

注意:子类化模型不可序列化,因为它们的架构由 call 方法中的 Python 代码定义。

整个模型

整个模型也可以保存到文件,包括权重、模型配置甚至优化器配置。这允许你检查模型并稍后从完全相同的状态恢复训练,而无需访问源代码。

# 构建一个简单模型
model = keras.Sequential([
  keras.layers.Dense(10, activation='softmax', input_shape=(32,)),
  keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(data, targets, batch_size=32, epochs=5)


# 保存整个模型至 HDF5 文件
model.save('my_model.h5')

# 重新创建完全相同的模型,包括权重和优化器
model = keras.models.load_model('my_model.h5')

Eager execution


Eager execution 是一个重要的编程环境,可以立即评估操作。这不是 Keras 所必需的,但是 tf.keras 支持该操作,对于检查程序和调试很有用。

所有 tf.keras 模型构建 API 都与 eager execution 相兼容。虽然可以使用 Sequential 和功能性 API,但是 eager execution 特别有利于模型子类化和构建自定义层 —— 需要将前向传播作为代码编写的 API(而不是通过组合现有网络层来创建模型的 API)。

有关使用具有自定义训练循环的 Keras 模型和 tf.GradientTape 的示例,请参阅 eager execution 指南

分布式


Estimators

Estimators API 用于在分布式环境中训练模型,针对行业用例,例如在大规模数据集上进行分布式训练,从而导出模型用于生产。

通过使用 tf.keras.estimator.model_to_estimator 将模型转换为 tf.estimator.Estimator 对象,从而可以使用 tf.estimator API 训练 tf.keras.Model 模型。请参阅从Keras 模型创建 Estimators

model = keras.Sequential([layers.Dense(10,activation='softmax'),
                          layers.Dense(10,activation='softmax')])

model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

estimator = keras.estimator.model_to_estimator(model)

注意:启用 eager execution 以调试 Estimator 输入函数 以及检查数据。

多 GPU

tf.keras 模型可以使用 tf.contrib.distribute.DistributionStrategy 在多个 GPU 上运行 。该 API 可以在几乎不对现有代码进行任何更改的情况下在多个 GPU 上提供分布式训练。

当前,tf.contrib.distribute.MirroredStrategy 是唯一支持的分布式策略。MirroredStrategy 在单台机器上使用全规约同步训练进行图内重复实验。要使用 Keras 实现 DistributionStrategy,需要将 tf.keras.Model 转换为 tf.estimator.Estimator,然后训练 estimator。

以下示例将 tf.keras.Model 分布给一台计算机上的多个GPU。

首先,定义一个简单的模型:

model = keras.Sequential()
model.add(keras.layers.Dense(16, activation='relu', input_shape=(10,)))
model.add(keras.layers.Dense(1, activation='sigmoid'))

optimizer = tf.train.GradientDescentOptimizer(0.2)

model.compile(loss='binary_crossentropy', optimizer=optimizer)
model.summary()

定义一个输入管道。input_fn 返回一个 tf.data.Dataset 对象用来将数据分布给多个设备 —— 每个设备处理输入批量的一部分。

def input_fn():
  x = np.random.random((1024, 10))
  y = np.random.randint(2, size=(1024, 1))
  x = tf.cast(x, tf.float32)
  dataset = tf.data.Dataset.from_tensor_slices((x, y))
  dataset = dataset.repeat(10)
  dataset = dataset.batch(32)
  return dataset

接下来,创建一个 tf.estimator.RunConfig 并将 train_distribute 参数设置为tf.contrib.distribute.MirroredStrategy 实例 。创建 MirroredStrategy 时,可以指定设备列表或设置 num_gpus 参数。默认使用所有可用的 GPU,如下所示:

strategy = tf.contrib.distribute.MirroredStrategy()
config = tf.estimator.RunConfig(train_distribute=strategy)

将 Keras 模型转换为 tf.estimator.Estimator 实例:

keras_estimator = keras.estimator.model_to_estimator(
  keras_model=model,
  config=config,
  model_dir='/tmp/model_dir')

最后,传入 input_fnsteps 参数来训练 Estimator 实例:

keras_estimator.train(input_fn=input_fn, steps=10)

猜你喜欢

转载自blog.csdn.net/qq_20084101/article/details/81870064