Building Input Functions with tf.estimator

本教程将向您介绍如何在tf.estimator中创建输入函数。 您将了解如何构建input_fn以预处理数据并将数据输入到模型中。 然后,您将执行input_fn,将训练,评估和预测数据输入到神经网络回归器中,以预测房屋中值的中位数。

Custom Input Pipelines with input_fn

input_fn用于将特征和目标数据传递给列车评估预测T4>估算 T4>。 用户可以在input_fn中执行特征工程或预处理。 下面是从tf.estimator快速入门教程中的一个示例:

import numpy as np

training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
    filename=IRIS_TRAINING, target_dtype=np.int, features_dtype=np.float32)

train_input_fn = tf.estimator.inputs.numpy_input_fn(
    x={"x": np.array(training_set.data)},
    y=np.array(training_set.target),
    num_epochs=None,
    shuffle=True)

classifier.train(input_fn=train_input_fn, steps=2000)

Anatomy of an input_fn

以下代码演示了输入函数的基本框架:

def my_input_fn():

    # Preprocess your data here...

    # ...then return 1) a mapping of feature columns to Tensors with
    # the corresponding feature data, and 2) a Tensor containing labels
    return feature_cols, labels

输入函数的主体包含用于预处理输入数据的特定逻辑,例如清理不好的示例或特征缩放

输入函数必须返回以下两个值,其中包含要输入到模型中的最终特征和标签数据(如上面的代码框架所示):

feature_cols
包含将特征列名映射到Tensor s(或SparseTensor)的键/值对的词典,其中包含相应的要素数据。
标签
包含您的标签(目标)值的张量:您的模型旨在预测的值。

Converting Feature Data to Tensors

如果你的特征/标签数据是一个python数组或存储在pandas数据框或numpy数组中,你可以使用以下方法来构造input_fn

import numpy as np
# numpy input_fn.
my_input_fn = tf.estimator.inputs.numpy_input_fn(
    x={"x": np.array(x_data)},
    y=np.array(y_data),
    ...)
import pandas as pd
# pandas input_fn.
my_input_fn = tf.estimator.inputs.pandas_input_fn(
    x=pd.DataFrame({"x": x_data}),
    y=pd.Series(y_data),
    ...)

对于稀疏分类数据(大多数值为0的数据),您将改为填充SparseTensor,该实例使用三个参数实例化:

dense_shape
张量的形状。 获取一个列表,指出每个维度中元素的数量。 例如,dense_shape = [3,6]指定了一个二维3x6张量,dense_shape = [2,3,4]指定了一个三维2x3x4张量,并且dense_shape = [9]指定具有9个元素的一维张量。
指数
张量中包含非零值的元素的索引。 获取术语列表,其中每个术语本身是一个包含非零元素索引的列表。 (元素是零索引的,即,[0,0]是二维张量中第一行第一列元素的索引值。) 例如,indices = [[1,3],[2,4]]指定索引为[1,3]和[2,4]的元素具有非零值。
价值的一维张量。 Term i in values对应于indices中的i项并指定其值。 例如,给定indices = [[1,3],[2,4]],参数values = [18,3.6]指定元素[1,3 ]的张量值为18,张量元素[2,4]的值为3.6。

以下代码定义了具有3行和5列的二维SparseTensor 索引为[0,1]的元素的值为6,索引为[2,4]的元素的值为0.5(所有其他值均为0):

sparse_tensor = tf.SparseTensor(indices=[[0,1], [2,4]],
                                values=[6, 0.5],
                                dense_shape=[3, 5])

这对应于以下稠密张量:

[[0, 6, 0, 0, 0]
 [0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0.5]]

有关SparseTensor的更多信息,请参见tf.SparseTensor

Passing input_fn Data to Your Model

要将数据提供给您的模型进行培训,只需将您创建的输入函数作为input_fn参数的值传递给train操作,例如:

classifier.train(input_fn=my_input_fn, steps=2000)

请注意,input_fn参数必须接收函数对象(即input_fn = my_input_fn),而不是函数调用的返回值(input_fn = my_input_fn / T2>)。 这意味着如果您尝试将参数传递给train调用中的input_fn,如下面的代码所示,它将导致TypeError

classifier.train(input_fn=my_input_fn(training_set), steps=2000)

但是,如果您希望能够对输入函数进行参数化,还有其他方法可以这样做。 你可以使用一个不包含参数的包装函数作为你的input_fn,并用它来调用你所需要的参数的输入函数。 例如:

def my_input_fn(data_set):
  ...

def my_input_fn_training_set():
  return my_input_fn(training_set)

classifier.train(input_fn=my_input_fn_training_set, steps=2000)

或者,您可以使用Python的functools.partial函数构建一个新的函数对象,其中所有参数值都是固定的:

classifier.train(
    input_fn=functools.partial(my_input_fn, data_set=training_set),
    steps=2000)

第三个选项是将input_fn调用包装在lambda中,并将其传递给input_fn参数:

classifier.train(input_fn=lambda: my_input_fn(training_set), steps=2000)

如上所示设计输入流水线的一大优势 - 接受数据集的参数 - 您可以将相同的input_fn传递给evaluatepredict < / t2>操作,只需更改数据集参数即可,例如:

classifier.evaluate(input_fn=lambda: my_input_fn(test_set), steps=2000)

This approach enhances code maintainability: no need to define multiple input_fn (e.g. input_fn_train, input_fn_test, input_fn_predict) for each type of operation.

最后,您可以使用tf.estimator.inputs中的方法从numpy或pandas数据集创建input_fn 额外的好处是你可以使用更多的参数,比如num_epochsshuffle来控制input_fn如何迭代数据:

import pandas as pd

def get_input_fn_from_pandas(data_set, num_epochs=None, shuffle=True):
  return tf.estimator.inputs.pandas_input_fn(
      x=pdDataFrame(...),
      y=pd.Series(...),
      num_epochs=num_epochs,
      shuffle=shuffle)
import numpy as np

def get_input_fn_from_numpy(data_set, num_epochs=None, shuffle=True):
  return tf.estimator.inputs.numpy_input_fn(
      x={...},
      y=np.array(...),
      num_epochs=num_epochs,
      shuffle=shuffle)

A Neural Network Model for Boston House Values

In the remainder of this tutorial, you'll write an input function for preprocessing a subset of Boston housing data pulled from the UCI Housing Data Set and use it to feed data to a neural network regressor for predicting median house values.

波士顿郊区的波士顿CSV数据集您将用于训练您的神经网络包含以下特征数据:<

特征 描述
CRIM 人均犯罪率
ZN 划分为25,000平方英尺以上的住宅用地
INDUS 非零售业务的土地部分
NOX 一氧化氮浓度每1000万份中的一部分
R M 每间住宅的平均房间数
年龄 1940年以前建成的自住住宅部分
DIS 距离波士顿地区的就业中心
每10,000美元的房产税税率
PTRATIO 师生比例

你的模型预测的标签是MEDV,即自住住宅的中值,以千美元计。

Setup

下载以下数据集:boston_train.csvboston_test.csvboston_predict.csv

以下部分将逐步介绍如何创建输入函数,将这些数据集提供给神经网络回归器,训练和评估模型,并进行房屋价值预测。 完整的最终代码在这里可用

Importing the Housing Data

首先,设置您的导入(包括pandastensorflow)并将日志记录详细程度设置为INFO以获取更详细的日志输出:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import itertools

import pandas as pd
import tensorflow as tf

tf.logging.set_verbosity(tf.logging.INFO)

COLUMNS中定义数据集的列名。 为了区分标签中的特征,还要定义FEATURESLABEL Then read the three CSVs (tf.train, tf.test, and predict) into pandas DataFrames:

COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
           "dis", "tax", "ptratio", "medv"]
FEATURES = ["crim", "zn", "indus", "nox", "rm",
            "age", "dis", "tax", "ptratio"]
LABEL = "medv"

training_set = pd.read_csv("boston_train.csv", skipinitialspace=True,
                           skiprows=1, names=COLUMNS)
test_set = pd.read_csv("boston_test.csv", skipinitialspace=True,
                       skiprows=1, names=COLUMNS)
prediction_set = pd.read_csv("boston_predict.csv", skipinitialspace=True,
                             skiprows=1, names=COLUMNS)

Defining FeatureColumns and Creating the Regressor

接下来,为输入数据创建FeatureColumn列表,它正式指定用于训练的一组要素。 Because all features in the housing data set contain continuous values, you can create their FeatureColumns using the tf.contrib.layers.real_valued_column() function:

feature_cols = [tf.feature_column.numeric_column(k) for k in FEATURES]

注意:有关功能列的更深入概述,请参阅本介绍,以及说明如何为分类数据定义FeatureColumns的示例,请参阅线性模型教程

现在,为神经网络回归模型实例化一个DNNRegressor 您需要在这里提供两个参数:hidden_​​units,一个超参数,指定每个隐藏层中的节点数(这里是两个隐藏层,每个隐藏层各有10个节点),feature_columns t1 >,包含您刚定义的FeatureColumns的列表:

regressor = tf.estimator.DNNRegressor(feature_columns=feature_cols,
                                      hidden_units=[10, 10],
                                      model_dir="/tmp/boston_model")

Building the input_fn

要将输入数据传递到regressor,请写入一个接受pandas Dataframe的工厂方法并返回input_fn

def get_input_fn(data_set, num_epochs=None, shuffle=True):
  return tf.estimator.inputs.pandas_input_fn(
      x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
      y = pd.Series(data_set[LABEL].values),
      num_epochs=num_epochs,
      shuffle=shuffle)

请注意,输入数据在data_set参数中传递到input_fn,这意味着该函数可以处理您导入的任何DataFrametraining_settest_setprediction_set

提供了两个附加参数:* num_epochs:控制迭代数据的历元数量。 对于训练,将其设置为None,以便input_fn不断返回数据,直到达到所需的训练步数。 For evaluate and predict, set this to 1, so the input_fn will iterate over the data once and then raise OutOfRangeError. 该错误将会告诉Estimator停止评估或预测。 * 随机播放:是否要洗牌数据。 为了进行评估和预测,将其设置为False,以便input_fn顺序遍历数据。 对于列车,请将此设置为True

Training the Regressor

为了训练神经网络回归器,运行train,并将training_set传递给input_fn,如下所示:

regressor.train(input_fn=get_input_fn(training_set), steps=5000)

您应该看到类似于以下内容的日志输出,该输出每100步报告一次培训损失:

INFO:tensorflow:Step 1: loss = 483.179
INFO:tensorflow:Step 101: loss = 81.2072
INFO:tensorflow:Step 201: loss = 72.4354
...
INFO:tensorflow:Step 1801: loss = 33.4454
INFO:tensorflow:Step 1901: loss = 32.3397
INFO:tensorflow:Step 2001: loss = 32.0053
INFO:tensorflow:Step 4801: loss = 27.2791
INFO:tensorflow:Step 4901: loss = 27.2251
INFO:tensorflow:Saving checkpoints for 5000 into /tmp/boston_model/model.ckpt.
INFO:tensorflow:Loss for final step: 27.1674.

Evaluating the Model

接下来,看看训练的模型如何针对测试数据集执行。 运行evaluate,并且这次将test_set传递给input_fn

ev = regressor.evaluate(
    input_fn=get_input_fn(test_set, num_epochs=1, shuffle=False))

ev结果中检索损失并将其打印输出:

loss_score = ev["loss"]
print("Loss: {0:f}".format(loss_score))

您应该看到类似于以下的结果:

INFO:tensorflow:Eval steps [0,1) for training step 5000.
INFO:tensorflow:Saving evaluation summary for 5000 step: loss = 11.9221
Loss: 11.922098

Making Predictions

最后,您可以使用该模型预测prediction_set的房屋中值,其中包含以下六个示例的特征数据但没有标签:

y = regressor.predict(
    input_fn=get_input_fn(prediction_set, num_epochs=1, shuffle=False))
# .predict() returns an iterator of dicts; convert to a list and print
# predictions
predictions = list(p["predictions"] for p in itertools.islice(y, 6))
print("Predictions: {}".format(str(predictions)))

您的结果应该包含六个以千美元计的房屋价值预测,例如:

Predictions: [ 33.30348587  17.04452896  22.56370163  34.74345398  14.55953979
  19.58005714]

Additional Resources

本教程专注于为神经网络回归器创建input_fn 要详细了解如何将input_fn用于其他类型的模型,请查看以下资源: