在 TensorFlow.org 上查看 | 在 Google Colab 中运行 | 在 GitHub 上查看源代码 | 下载笔记本 |
本教程将向您展示如何使用 Estimators 在 TensorFlow 中解决 Iris 分类问题。Estimator 是 TensorFlow 的一个遗留高级表示,代表完整的模型。有关更多详细信息,请参阅 Estimators。
首先
为了开始,您首先需要导入 TensorFlow 和一些您需要的库。
import tensorflow as tf
import pandas as pd
数据集
本文档中的示例程序构建并测试了一个模型,该模型根据鸢尾花 萼片 和 花瓣 的大小将鸢尾花分类为三种不同的物种。
您将使用 Iris 数据集训练模型。Iris 数据集包含四个特征和一个 标签。这四个特征标识了单个鸢尾花的以下植物学特征
- 萼片长度
- 萼片宽度
- 花瓣长度
- 花瓣宽度
根据这些信息,您可以定义一些有用的常量来解析数据
CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth', 'PetalLength', 'PetalWidth', 'Species']
SPECIES = ['Setosa', 'Versicolor', 'Virginica']
接下来,使用 Keras 和 Pandas 下载并解析 Iris 数据集。请注意,您为训练和测试保留了不同的数据集。
train_path = tf.keras.utils.get_file(
"iris_training.csv", "https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv")
test_path = tf.keras.utils.get_file(
"iris_test.csv", "https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv")
train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
您可以检查您的数据,以确保您有四个浮点型特征列和一个 int32 型标签。
train.head()
对于每个数据集,都将标签分离出来,模型将被训练来预测这些标签。
train_y = train.pop('Species')
test_y = test.pop('Species')
# The label column has now been removed from the features.
train.head()
使用 Estimators 进行编程的概述
现在您已经设置了数据集,可以使用 TensorFlow Estimator 定义模型。Estimator 是从 tf.estimator.Estimator
派生的任何类。TensorFlow 提供了一组 tf.estimator
(例如,LinearRegressor
)来实现常见的 ML 算法。除此之外,您还可以编写自己的 自定义 Estimators。建议在刚开始时使用预制 Estimators。
要编写基于预制 Estimators 的 TensorFlow 程序,您必须执行以下任务
- 创建一个或多个输入函数。
- 定义模型的特征列。
- 实例化一个 Estimator,指定特征列和各种超参数。
- 在 Estimator 对象上调用一个或多个方法,将适当的输入函数作为数据源传递。
让我们看看这些任务是如何在 Iris 分类中实现的。
创建输入函数
您必须创建输入函数来提供用于训练、评估和预测的数据。
输入函数是一个返回 tf.data.Dataset
对象的函数,该对象输出以下两个元素的元组
为了演示输入函数的格式,这里有一个简单的实现
def input_evaluation_set():
features = {'SepalLength': np.array([6.4, 5.0]),
'SepalWidth': np.array([2.8, 2.3]),
'PetalLength': np.array([5.6, 3.3]),
'PetalWidth': np.array([2.2, 1.0])}
labels = np.array([2, 1])
return features, labels
您的输入函数可以使用任何您喜欢的方式生成 features
字典和 label
列表。但是,建议使用 TensorFlow 的 Dataset API,它可以解析各种数据。
Dataset API 可以为您处理许多常见情况。例如,使用 Dataset API,您可以轻松地并行地从大量文件中读取记录,并将它们合并成一个数据流。
为了在这个示例中保持简单,您将使用 pandas 加载数据,并从这个内存中的数据构建一个输入管道
def input_fn(features, labels, training=True, batch_size=256):
"""An input function for training or evaluating"""
# Convert the inputs to a Dataset.
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))
# Shuffle and repeat if you are in training mode.
if training:
dataset = dataset.shuffle(1000).repeat()
return dataset.batch(batch_size)
定义特征列
一个 特征列 是一个对象,它描述了模型应该如何使用来自特征字典的原始输入数据。当您构建一个 Estimator 模型时,您会向它传递一个特征列列表,该列表描述了您希望模型使用的每个特征。 tf.feature_column
模块提供了许多用于将数据表示给模型的选项。
对于 Iris,4 个原始特征是数值,因此您将构建一个特征列列表,告诉 Estimator 模型将这四个特征中的每一个都表示为 32 位浮点数。因此,创建特征列的代码是
# Feature columns describe how to use the input.
my_feature_columns = []
for key in train.keys():
my_feature_columns.append(tf.feature_column.numeric_column(key=key))
特征列可以比这里显示的要复杂得多。您可以在 本指南 中阅读有关特征列的更多信息。
现在您已经描述了您希望模型如何表示原始特征,您可以构建估计器。
实例化一个估计器
Iris 问题是一个经典的分类问题。幸运的是,TensorFlow 提供了几个预制的分类器 Estimators,包括
tf.estimator.DNNClassifier
用于执行多类分类的深度模型。tf.estimator.DNNLinearCombinedClassifier
用于宽而深的模型。tf.estimator.LinearClassifier
用于基于线性模型的分类器。
对于 Iris 问题,tf.estimator.DNNClassifier
似乎是最好的选择。以下是您实例化此 Estimator 的方法
# Build a DNN with 2 hidden layers with 30 and 10 hidden nodes each.
classifier = tf.estimator.DNNClassifier(
feature_columns=my_feature_columns,
# Two hidden layers of 30 and 10 nodes respectively.
hidden_units=[30, 10],
# The model must choose between 3 classes.
n_classes=3)
训练、评估和预测
现在您已经有了 Estimator 对象,您可以调用方法来执行以下操作
- 训练模型。
- 评估训练后的模型。
- 使用训练后的模型进行预测。
训练模型
通过调用 Estimator 的 train
方法来训练模型,如下所示
# Train the Model.
classifier.train(
input_fn=lambda: input_fn(train, train_y, training=True),
steps=5000)
请注意,您将 input_fn
调用包装在 lambda
中,以捕获参数,同时提供一个不带参数的输入函数,如 Estimator 所期望的那样。 steps
参数告诉方法在一定数量的训练步骤后停止训练。
评估训练后的模型
现在模型已经训练完毕,您可以获得一些关于其性能的统计数据。以下代码块评估了训练后的模型在测试数据上的准确性
eval_result = classifier.evaluate(
input_fn=lambda: input_fn(test, test_y, training=False))
print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))
与对 train
方法的调用不同,您没有将 steps
参数传递给评估。用于评估的 input_fn
只会生成一个 时期 的数据。
eval_result
字典还包含 average_loss
(每个样本的平均损失)、loss
(每个小批次的平均损失)以及估计器的 global_step
的值(它经历的训练迭代次数)。
从训练后的模型中进行预测(推断)
现在您有一个训练后的模型,可以产生良好的评估结果。现在您可以使用训练后的模型来预测鸢尾花的物种,方法是根据一些未标记的测量结果。与训练和评估一样,您可以使用单个函数调用来进行预测
# Generate predictions from the model
expected = ['Setosa', 'Versicolor', 'Virginica']
predict_x = {
'SepalLength': [5.1, 5.9, 6.9],
'SepalWidth': [3.3, 3.0, 3.1],
'PetalLength': [1.7, 4.2, 5.4],
'PetalWidth': [0.5, 1.5, 2.1],
}
def input_fn(features, batch_size=256):
"""An input function for prediction."""
# Convert the inputs to a Dataset without labels.
return tf.data.Dataset.from_tensor_slices(dict(features)).batch(batch_size)
predictions = classifier.predict(
input_fn=lambda: input_fn(predict_x))
predict
方法返回一个 Python 可迭代对象,为每个示例生成一个预测结果字典。以下代码打印了一些预测及其概率
for pred_dict, expec in zip(predictions, expected):
class_id = pred_dict['class_ids'][0]
probability = pred_dict['probabilities'][class_id]
print('Prediction is "{}" ({:.1f}%), expected "{}"'.format(
SPECIES[class_id], 100 * probability, expec))