使用 tf.contrib.learn 构建输入函数

我是一个很懒的人,我想试试

希望我能坚持到最后,把tensorflow的官方教程全部翻译出来

提高自己,也帮助他人

Building Input Functions with tf.estimator

本教程将向你介绍如何使用 tf.estimator 创建输入函数。你将了解如何构建一个 input_fn 来预处理并将数据传入你的模型中。然后你将使用 input_fn 将训练,评估和预测的数据传入到神经网络回归以便预测房屋的中位数价值。

Custom Input Pipelines with input_fn

input_fn 用于将特征和目标数据传递给 Estimatortrainevaluatepredict 方法。用户可以在input_fn进行特征工程或者预处理。以下是从 tf.estimator Quickstart tutorial 得到的一个例子:

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

    键/值对的字典,映射包含了相对应的特征数据的特征 columns 名字到Tensor (或 SparseTensor) 中。

  • labels

    Tensor 包含了你的标签(目标)值:这个值是你的模型需要预测的。

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),
    ...)

对于 sparse, categorical data (其中大部分数据值都是0),你将使用SparseTensor,它使用三个参数实例化:

  • dense_shape

    张量形状。获取一个列表指明每个维度的元素总数。例如,dense_shape=[3,6] 表示一个二维 3x6 张量,dense_shape=[2,3,4] 表示一个三维 2x3x4 张量,而 dense_shape=[9] 表示一个一维的包含9个元素的张量。

  • indices

    张量中包含非零值的元素的索引。获取一个 terms 列表,每个 term 也是一个列表,包含了非零元素的索引。(元素为零的索引——例如[0,0]是一个二维张量第一行第一列的元素的索引值。) 例如,indices=[[1,3], [2,4]] 指索引为 [1,3] 和 [2,4] 的元素有非零值。

  • values

    一维张量值。values 的 term i 对应于 indices 的 term 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])

对应下面的稠密 (dense) 张量:

[[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

提供数据给你的模型以便训练,你传递你创建的输入函数到你的 train 函数中,作为input_fn 参数的值,例如:

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

注意input_fn 参数必须接收一个函数对象(例如,input_fn=my_input_fn),而不是函数调用的返回值(input_fn=my_input_fn()) 。这意味着,如果你尝试在你的train 调用中传递值给input_fn ,如下代码,将产生 TypeError

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

然而,如果你想要能够参数化你的输入函数,还有其他的方法。你可以使用一个 不带参数的 wrapper 函数作为你的 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_fnevaluatepredict 操作而只需要改变数据集参数,例如:

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

这种方法增强了代码的可维护性:不需要为每种操作定义多个input_fn (例如,input_fn_train, input_fn_test, input_fn_predict)。

最后,你可以使用 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

在本教程剩余部分,你将写一个输入函数来预处理从 UCI Housing Data Set 提取出的波士顿房价的子集,并用它传递数据给一个神经网络回归,以便预测房价的中位数。

你将使用 Boston CSV data sets 来训练你的神经网络,包含了以下波士顿郊区的 特征数据 :

特征 描述
CRIM Crime rate per capita
ZN Fraction of residential land zoned to permit 25,000+ sq ft lots
INDUS Fraction of land that is non-retail business
NOX Concentration of nitric oxides in parts per 10 million
RM Average Rooms per dwelling
AGE Fraction of owner-occupied residences built before 1940
DIS Distance to Boston-area employment centers
TAX Property tax rate per $10,000
PTRATIO Student-teacher ratio

你的模型预测的标签是 MEDV,自住住宅的价值的中位数,单位千美元。

Setup

下载以下数据集:boston_train.csv, boston_test.csv 和 boston_predict.csv 。

以下部分提供了逐步介绍如何创建一个输入函数,传递这些数据集给一个神经网络回归,训练和评估模型,并预测房价。最终完整的代码 available here 。

Importing the Housing Data

首先,设置 imports(包含 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。然后读取三个 CSV(tf.train, tf.test, 和predict) 到 pandasDataFrame

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,它指定用于训练的特征 columns 。因为房屋数据集的所有特征含有连续值,可以使用tf.contrib.layers.real_valued_column() 函数创建它们的 FeatureColumn

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

注意:有关特征 columns 更深入的了解,请查看 这个介绍 ,例如说明如何定义 分类数据的FeatureColumns,请查阅 线性模型教程 。

现在,实例化神经网络回归模型 DNNRegressor 。这里你需要提供两个参数:hidden_units,一个超参数,指定每个隐藏层的节点数量(这里,两个包含 10 个节点的隐藏层), feature_columns,包含你定义的一列的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 ,这意味着函数可以处理你导入的任意的DataFrame : training_set, test_set, 和prediction_set

提供另外两个参数:num_epochs:控制迭代所有数据的 epochs 次数 。对于训练,设置这个值为 None,这样input_fn 保持返回数据知道达到所需的训练次数。对于评估和预测,设置这个值为 1,这样input_fn将迭代所有数据一次,然后产生OutOfRangeError错误。这个错误会告诉Estimator停止评估和预测。shuffle:是否打乱数据。对于评估和预测,设置为False,这样input_fn 将顺序迭代所有的数据。对于训练,设置为 True

Training the Regressor

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

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

你将看到类似下面的输入日志,记录了每一百次的训练损失:

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_setinput_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 ,请查看以下资源:

  • Large-scale Linear Models with TensorFlow: 对于线性模型,介绍了在 TensorFlow 中提供了一个高层次的特征 columns 的概述和技术转换输入数据。
  • TensorFlow Linear Model Tutorial: 本教程将介绍如何创建根据人口普查数据预测收入范围的线性分类模型的FeatureColumninput_fn
  • TensorFlow Wide & Deep Learning Tutorial: 基于 Linear Model Tutorial ,本教程介绍使用结合了线性模型和使用DNNLinearCombinedClassifier神经网络的一个“又深又广”的模型,创建FeatureColumninput_fn

你可能感兴趣的:(使用 tf.contrib.learn 构建输入函数)