章节索引 :

使用预设的 Estimator 模型

在之前的学习中,我们学习到了如何使用 Keras 来快速、简洁地构建网络模型,我们也认识到了使用 tf.keras 构建模型的优点。但是在 TensorFlow 之中构建网络模型的方式远远不止 Keras 一种方式,那么这节课开始我们便开始学习如何使用 Estimator 来构建模型。

1. 什么是 Estimator

Estimator 是 TensorFlow 之中模型的一种高级表示,也就是说,我们可以像使用 Keras 一样来创建自己的模型,并进行训练、评估等操作。Estimator 主要可以提供的功能包括:

  • 模型的训练;
  • 模型的评估;
  • 使用模型进行预测。

在 TensorFlow 之中,Estimator 的大部分 API 都集中在 tf.estimator 之中

在 API 层面上,Keras 与 Estimator 处于相同的层面,与 Keras 相似,Estimator 也是一种模型层面的高阶 API,因此也可以和 Keras 一样快捷、方便地使用。
但是与 Keras 不同的是,Estimator 在 TensorFlow1.1 版本的时候就已经被引入了 TensorFlow,也正因如此,TensorFlow 对于 Estimator 的支持也较好一些。

2. 使用 Estimator 构建模型的一般步骤

在 TensorFlow 之中,使用 Estimator 进行模型训练大致需要经过四个步骤,它们分别是:

  • 定义特征列
  • 定义输入函数
  • 创建(实例化)一个 Estimator 模型
  • 训练并进行相应的评估等操作

对于这四个步骤,相信特征列和输入函数这两个名词对于大家都很陌生,那么我们便来进行相应解释:

  • 特征列:

    “特征列(feature columns)是一个对象,用于描述模型应该如何使用特征字典中的原始输入数据”——官方定义

    简单来说,特征列就是来告诉模型你要使用数据中的哪些数据列,其中哪些数据列为离散值,哪些数据列为连续值

  • 输入函数:简单来说,输入函数是一个函数,它返回的是一个数据集,其中的每条数据都是(特征,标签)的形式。我们可以将输入函数理解为“模型用来取数据的地方,通过输入函数,模型可以不断取得新的数据”。

因为 TensorFlow 内部提供了很多内置的 Estimator 模型,因此这节课我们会采用其预设的模型来进行分类学习。

对于这四步的具体细节,我们会在接下来的示例过程中具体演示。

3. 实例-使用 Estimator 进行泰坦尼克生存预测

首先我们需要先获取数据集,也就是泰塔尼克数据集,我们采用之前相同的方式来获取数据集:

import pandas as pd
import tensorflow as tf

train_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")

columns = ['survived', 'sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']

categorical = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck', 'embark_town', 'alone']
numeric = ['age', 'fare']

train_df = pd.read_csv(train_file, names=columns)

其中我们 columns 变量定义了全部的列,同时我们定义了 categorical 和 numeric 两个数据列,分别代表离散值以及连续值,这便于我们后面的编码处理。

然后我们进行测试集与训练集的划分:

test_df = train_df.sample(frac=0.2)
train_df = train_df[~train_df.index.isin(test_df.index)]

train_df_y = train_df.pop('survived')
test_df_y = test_df.pop('survived')

print(len(train_df), len(test_df))

在这里,我们使用 train_df.sample() 方法来按照 0.2 的采样率进行随机采样,从来获取我们的测试集,然后我们将原来集合中的测试集去掉,得到剩下的训练集。然后我们又采用 pop 的方式来获取到标签值。这里我们按照传统的8:2的比例进行分割。

我们可以得到输出:

502, 125

然后我们就进行特征列的构造,在这里我们将特征列分为连续值与离散值,对于离散值,我们进行了独热编码的处理,因为独热编码在训练的过程中较大的优势:

def transfer2one_hot(feature, feature_vocab):
  return tf.feature_column.indicator_column(tf.feature_column.categorical_column_with_vocabulary_list(feature, feature_vocab))

features = []
for feature in categorical:
  features.append(
      transfer2one_hot(feature, train_df[feature].unique())
    )

for feature in numeric:
  features.append(
      tf.feature_column.numeric_column(feature, dtype=tf.float32)
    )

在这里我们使用到了三个非常重要的函数:

  • tf.feature_column.numeric_column,将某一列作为连续值视作数据特征;
  • tf.feature_column.indicator_column,将某一离散列作为独热编码视作数据列;
  • tf.feature_column.categorical_column_with_vocabulary_list,接收第一个参数为某一离散特征列,第二个参数为该离散特征列的所有取值情况,将一个普通列视作离散数据列(未经过独热编码)。

然后我们便可以定义我们的输入函数,在这里我们将输入函数分为训练时的输入函数以及测试时的输入函数,具体来说:

def train_input_fn(features, labels, batch_size=8):
    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) 
    dataset = dataset.shuffle(len(train_df))
    dataset = dataset.repeat(30000)   
    return dataset.batch(batch_size)
def test_input_fn(features, labels, batch_size=8):
    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))    
    return dataset.batch(batch_size)

train_fn = lambda: train_input_fn(train_df, train_df_y)
test_fn = lambda: test_input_fn(test_df, test_df_y)

在输入函数之中,我们使用参数中的 features 和 labels 创建了一个数据集,并且将其返回。并且对于训练集,我们采用了数据增强,也就是随机化以及重复操作,在这里,30000 就是我们要训练的 Steps 数量(我们所使用的 batch_size 的数量,这里是8)。

最后因为输入函数是一个函数,因此我们需要定义一个 lambda 函数来返回一个输入函数,否则输入函数将直接返回一个数据集,这是我们不希望看到的。

再者我们就可以载入一个内置的模型:

classifier = tf.estimator.DNNClassifier(
    feature_columns=feature_columns,
    hidden_units=[50, 30, 20],
    n_classes=2)

在这里我们定义了一个 Estimator 内置的分类器,它的三个参数如下:

  • feature_columns,特征列,就是我们刚刚处理过的特征列,包含连序列与离散列;
  • hidden_units,隐藏单元的数量,在这里我们定义了三层;
  • n_classes,输出的种类,这里我们只有生存和不能生存两类。

最后我们便可以进行模型的训练与测试,具体的实现细节非常简单:

classifier.train(input_fn=train_fn, steps=30000)

test_result = classifier.evaluate(input_fn=test_fn)
print(test_result)

我们首先进行了训练,输入函数为我们之前定义的训练的输入函数,然后训练 Steps 为 30000 ,然后我们便进行了测试,此时的输入函数为我们为测试专门定制的输入函数。我们可以得到结果:

......
INFO:tensorflow:global_step/sec: 861.581
INFO:tensorflow:loss = 0.4950667, step = 47500 (0.114 sec)
INFO:tensorflow:global_step/sec: 885.82
INFO:tensorflow:loss = 0.30664578, step = 47600 (0.113 sec)
INFO:tensorflow:global_step/sec: 879.637
INFO:tensorflow:loss = 0.82413065, step = 47700 (0.116 sec)
INFO:tensorflow:global_step/sec: 814.178
INFO:tensorflow:loss = 0.5236651, step = 47800 (0.123 sec)
INFO:tensorflow:global_step/sec: 829.556
INFO:tensorflow:loss = 0.4500552, step = 47900 (0.118 sec)
......

{'accuracy': 0.724, 'accuracy_baseline': 0.7624, 'auc': 0.5004091, 'auc_precision_recall': 0.43117255, 'average_loss': 1.7417283, 'label/mean': 0.376, 'loss': 2.7342584, 'precision': 0.0, 'prediction/mean': 0.025458882, 'recall': 0.0, 'global_step': 0}

我们可以看到,最后我们在测试集上的准确率为 0.72 ,也是一个不错的结果。

4. 小结

在这节课之中,我们学习了什么是 Estimator,同时也了解了使用 Estimator 进行训练的一般步骤,最后我们也学习了如何在实战中使用 Estimator 模型。

图片描述

TensorFlow 简介、安装与快速入门
TensorFlow 简介 TensorFlow 安装 - CPU TensorFlow 安装 - GPU TensorFlow 快速入门示例
TensorFlow 模型的简洁表示-Keras
Keras 简介 使用 tf.keras 进行图片分类 使用 Keras 进行文本分类 使用 Keras 进行回归 在 Keras 中保存与加载模型 在 Keras 中进行模型的评估 Keras 中的Masking 与 Padding
TensorFlow 中的数据格式
TensorFlow 中的数据核心 使用 TensorFlow 加载 CSV 数据 使用 TensorFlow 加载 Numpy 数据 使用 TF 加载 DateFrame 数据 使用图像数据来训练模型 在 TensorFlow 之中使用文本数据 TF 之中的 Unicode 数据格式的处理
TensorFlow模型的高级表示-Estimat
使用预设的 Estimator 模型 将Keras模型转化为Estimator模型 Estimator实现BoostingTree模型
TensorFlow 高级技巧
过拟合问题 TensorFlow 中的回调函数 文本数据嵌入 在 TensorFlow 之中使用卷积神经网络 在 TensorFlow 之中使用循环神经网络 在 TensorFlow 之中使用注意力模型 在 TensorFlow 之中进行迁移学习 在 TensorFlow 之中进行数据增强 在 TensorFlow 之中进行图像分割 如何进行多 GPU 的分布式训练? 使用 tf.function 提升效率 使用 TF HUB 进行模型复用
TensorFlow高级技巧-自定义
使用 TensorFlow 进行微分操作 在 TensorFlow 之中自定义网络层与模型 在 TensorFlow 之中自定义训练
TF 框架中的可视化工具-TensorBoard
TensorBoard 的简介与快速上手 使用 TensorBoard 记录训练中的各项指标 在 TensorBoard 之中查看模型结构图 在 TensorBoard 之中记录图片数据