使用 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.csvboston_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 ,请查看以下资源:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容