tensorflow学习笔记(2):创建自定义Estimator

详细教程:https://www.tensorflow.org/get_started/custom_estimators
预创建的 Estimator 是 tf.estimator.Estimator 基类的子类,而自定义 Estimator 是 tf.estimator.Estimator 的实例:
预创建的 Estimator 和自定义 Estimator 都是 Estimator。
模型函数(即 model_fn)会实现机器学习算法。采用预创建的 Estimator 和自定义 Estimator 的唯一区别是:

  • 如果采用预创建的 Estimator,则有人已为您编写了模型函数。
  • 如果采用自定义 Estimator,则您必须自行编写模型函数。

步骤

  • 编写输入函数
  • 创建特征列
  • 编写模型函数
  • 定义模型
  • 实现训练、评估和预测

1. 编写输入函数

def train_input_fn(features, labels, batch_size):
    """An input function for training"""
    # Convert the inputs to a Dataset.
    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

    # Shuffle, repeat, and batch the examples.
    dataset = dataset.shuffle(1000).repeat().batch(batch_size)

    # Return the read end of the pipeline.
    return dataset.make_one_shot_iterator().get_next()

此输入函数会构建可以生成批次 (features, labels) 对的输入管道,其中 features 是字典特征。

2. 创建特征列

定义模型的特征列来指定模型应该如何使用每个特征。
以下代码为每个输入特征创建一个简单的 numeric_column,表示应该将输入特征的值直接用作模型的输入:

# Feature columns describe how to use the input.
my_feature_columns = []
for key in train_x.keys():
    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

3. 编写模型函数

我们要使用的模型函数具有以下调用签名:

def my_model_fn(
   features, # This is batch_features from input_fn
   labels,   # This is batch_labels from input_fn
   mode,     # An instance of tf.estimator.ModeKeys
   params):  # Additional configuration

前两个参数是从输入函数中返回的特征和标签批次;也就是说,features 和 labels 是模型将使用的数据的句柄。mode 参数表示调用程序是请求训练、预测还是评估。
调用程序可以将 params 传递给 Estimator 的构造函数。传递给构造函数的所有 params 转而又传递给 model_fn。在 custom_estimator.py 中,以下行会创建 Estimator 并设置参数来配置模型。

classifier = tf.estimator.Estimator(
    model_fn=my_model,
    params={
        'feature_columns': my_feature_columns,
        # Two hidden layers of 10 nodes each.
        'hidden_units': [10, 10],
        # The model must choose between 3 classes.
        'n_classes': 3,
    })

要实现一般的模型函数,您必须执行下列操作:

  • 定义模型。
  • 分别为三种不同模式指定其他计算:
    • 预测
    • 评估
    • 训练

4. 定义模型

4.1 定义输入层

model_fn 的第一行调用 tf.feature_column.input_layer,以将特征字典和 feature_columns 转换为模型的输入,如下所示:

    # Use `input_layer` to apply the feature columns.
    net = tf.feature_column.input_layer(features, params['feature_columns'])

4.2 定义隐藏层

如果您要创建深度神经网络,则必须定义一个或多个隐藏层。Layers API 提供一组丰富的函数来定义所有类型的隐藏层,包括卷积层、池化层和丢弃层。
对于鸢尾花,我们只需调用 tf.layers.dense 来创建隐藏层,并用 params[‘hidden_layers’] 定义维度。在 dense 层中,每个节点都连接到前一层中的各个节点。下面是相关代码:

    # Build the hidden layers, sized according to the 'hidden_units' param.
    for units in params['hidden_units']:
        net = tf.layers.dense(net, units=units, activation=tf.nn.relu)

    units 参数定义指定层中输出神经元的数量。
    activation 参数定义激活函数 - 在这种情况下为 Relu。

这里的变量 net 表示网络的当前顶层。在第一次迭代中,net 表示输入层。在每次循环迭代时,tf.layers.dense 使用变量 net 创建一个新层,该层将前一层的输出作为其输入。

4.3 定义输出层

我们再次调用 tf.layers.dense 来定义输出层,这次不使用激活函数:

    # Compute logits (1 per class).
    logits = tf.layers.dense(net, params['n_classes'], activation=None)

在这里,net 表示最后的隐藏层。因此,所有的层将连接在一起。
定义输出层时,units 参数会指定输出的数量。因此,通过将 units 设置为 params[‘n_classes’],模型会为每个类别生成一个输出值。输出向量的每个元素都将包含针对相关鸢尾花类别(山鸢尾、变色鸢尾或维吉尼亚鸢尾)分别计算的分数或“对数”。

之后,tf.nn.softmax 函数会将这些对数转换为概率。

5. 实现训练、评估和预测

每当有人调用 Estimator 的 train、evaluate 或 predict 方法时,就会调用模型函数。您应该记得,模型函数的签名如下所示:

def my_model_fn(
   features, # This is batch_features from input_fn
   labels,   # This is batch_labels from input_fn
   mode,     # An instance of tf.estimator.ModeKeys, see below
   params):  # Additional configuration

重点关注第三个参数 mode。模型函数必须提供代码来处理全部三个 mode 值。如下表所示,当有人调用 train、evaluate 或 predict 时,Estimator 框架会调用模型函数并将 mode 参数设置为如下所示的值:

Estimator 方法 Estimator 模式
train() ModeKeys.TRAIN
evaluate() ModeKeys.EVAL
predict() ModeKeys.PREDICT

对于每个 mode 值,您的代码都必须返回 tf.estimator.EstimatorSpec 的一个实例,其中包含调用程序需要的信息。

5.1预测

predictions 存储的是下列三个键值对:

  • class_ids 存储的是类别 ID(0、1 或 2),表示模型对此样本最有可能归属的品种做出的预测。
  • probabilities 存储的是三个概率(在本例中,分别是 0.02、0.95 和 0.03)
  • logit 存储的是原始对数值(在本例中,分别是 -1.3、2.6 和 -0.9)
# Compute predictions.
predicted_classes = tf.argmax(logits, 1)
if mode == tf.estimator.ModeKeys.PREDICT:
    predictions = {
        'class_ids': predicted_classes[:, tf.newaxis],
        'probabilities': tf.nn.softmax(logits),
        'logits': logits,
    }
    return tf.estimator.EstimatorSpec(mode, predictions=predictions)

5.2 计算损失

我们可以通过调用 tf.losses.sparse_softmax_cross_entropy 来计算损失。此函数返回的值将是最低的,接近 0,而正确类别的概率(索引为 label)接近 1.0。随着正确类别的概率不断降低,返回的损失值越来越大。

此函数会针对整个批次返回平均值。

# Compute loss.
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

5.3 评估

TensorFlow 提供一个指标模块 tf.metrics 来计算常用指标。为简单起见,我们将只返回准确率。tf.metrics.accuracy 函数会将我们的预测值与真实值进行比较,即与输入函数提供的标签进行比较。tf.metrics.accuracy 函数要求标签和预测具有相同的形状。下面是对 tf.metrics.accuracy 的调用:

# Compute evaluation metrics.
accuracy = tf.metrics.accuracy(labels=labels,
                               predictions=predicted_classes,
                               name='acc_op')

针对评估返回的 EstimatorSpec 通常包含以下信息:

  • loss:这是模型的损失
  • eval_metric_ops:这是可选的指标字典。

我们将创建一个包含我们的唯一指标的字典。如果我们计算了其他指标,则将这些指标作为附加键值对添加到同一字典中。然后,我们将在 tf.estimator.EstimatorSpec 的 eval_metric_ops 参数中传递该字典。具体代码如下:

metrics = {'accuracy': accuracy}
tf.summary.scalar('accuracy', accuracy[1])

if mode == tf.estimator.ModeKeys.EVAL:
    return tf.estimator.EstimatorSpec(
        mode, loss=loss, eval_metric_ops=metrics)

tf.summary.scalar 会在 TRAIN 和 EVAL 模式下向 TensorBoard 提供准确率。

5.4 训练

构建训练指令需要优化器。我们将使用 tf.train.AdagradOptimizer,因为我们模仿的是 DNNClassifier,它也默认使用 Adagrad。tf.train 文件包提供很多其他优化器,您可以随意尝试它们。

下面是构建优化器的代码:

optimizer = tf.train.AdagradOptimizer(learning_rate=0.1)

接下来,我们使用优化器的 minimize 方法,根据我们之前计算的损失构建训练指令。

minimize 方法还具有 global_step 参数。TensorFlow 使用此参数来计算已经处理过的训练步数(以了解何时结束训练)。此外,global_step 对于 TensorBoard 图能否正常运行至关重要。只需调用 tf.train.get_global_step 并将结果传递给 minimize 的 global_step 参数即可。

下面是训练模型的代码:

train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())

针对训练返回的 EstimatorSpec 必须设置了下列字段:

  • loss:包含损失函数的值。
  • train_op:执行训练步。

下面是用于调用 EstimatorSpec 的代码:

return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

模型函数现已完成。

6. 自定义 Estimator

通过 Estimator 基类实例化自定义 Estimator,如下所示:

    # Build 2 hidden layer DNN with 10, 10 units respectively.
    classifier = tf.estimator.Estimator(
        model_fn=my_model,
        params={
            'feature_columns': my_feature_columns,
            # Two hidden layers of 10 nodes each.
            'hidden_units': [10, 10],
            # The model must choose between 3 classes.
            'n_classes': 3,
        })

在这里,params 字典与 DNNClassifier 的关键字参数用途相同;即借助 params 字典,您无需修改 model_fn 中的代码即可配置 Estimator。

使用 Estimator 训练、评估和生成预测要用的其余代码与预创建的 Estimator 一章中的相同。例如,以下行将训练模型:

# Train the Model.
classifier.train(
    input_fn=lambda:iris_data.train_input_fn(train_x, train_y, args.batch_size),
    steps=args.train_steps)

猜你喜欢

转载自blog.csdn.net/weixin_38493025/article/details/80667422
今日推荐