本教程将向您介绍Tensorflow的数据预处理(如何在tf.estimator中创建输入函数)。您将会看到如何构建一个input_fn
预处理并将数据输入到模型中。然后,你会实现一个input_fn
用于将训练、评估、预测数据输入神经网络回归器以预测房屋中值。
用input_fn自定义输入管道
input_fn
用于将特征和目标数据传递给Estimator
的方法:train
,evaluate
,和predict
。用户可以在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)
剖析一个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
(或SparseTensor
s)包含相应的特征数据。 labels
- 一个
Tensor
包含您的标签(目标)值:您的模型旨在预测的值。
将特征数据转换为张量
如果你的特征/标签数据是一个Python数组或存储在 Pandas DataFrame或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]
指定二维3×6张量,dense_shape=[2,3,4]
指定一个三维 2x3x4张量,和dense_shape=[9]
指定具有9个元素的一维张量。 indices
- 张量中包含非零值的元素的索引。获取元素列表,其中每个元素本身是一个包含非零元素索引的列表。 (元素是zero-indexed,即[0,0]是two-dimensional张量中第一行第一列元素的索引值。)例如,
indices=[[1,3], [2,4]]
指定索引为[1,3]和[2,4]的元素具有非零值。 values
- 一个一维张量值。元素
i
在values
对应于元素i
在indices
并指定其值。例如,给出indices=[[1,3], [2,4]]
,参数values=[18, 3.6]
指定张量的元素[1,3]的值为18,张量的元素[2,4]的值为3.6。
以下代码定义了2DSparseTensor
3行5列。索引为[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
。
将input_fn数据传递给您的模型
要将数据提供给您的模型进行训练,只需将您创建的输入函数传递给您的模型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)
然而,如果你想能够参数化你的输入函数,还有其他的方法。你可以使用一个不带参数的包装函数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
到evaluate
和predict
操作,只需更改数据集参数,例如:
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_epochs
和shuffle
,控制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)
波士顿房屋价值的神经网络模型
在本教程的其余部分,您将编写一个输入函数,用于预处理从波士顿房屋数据中提取的一个子集UCI住房数据集并用它来向神经网络回归器提供数据来预测房屋中值。
这个波士顿CSV数据集,将用来训练你的神经网络,包含以下内容特征数据:
特征 | 描述 |
---|---|
CRIM | 人均犯罪率 |
ZN | 住宅用地的面积为25,000平方英尺以上 |
INDUS | 是non-retail事业的土地的分数 |
NOX | 一氧化氮浓度每千万分之一 |
RM | 平均每间住宅的房间 |
AGE | 1940年以前建造的自住住宅的部分 |
DIS | 与Boston区域就业中心的距离 |
TAX | 每万美元的房产税税率 |
PTRATIO | Student-teacher比率 |
而你的模型预测的标签是MEDV,自住房房价的中间值,单位是千美元。
Setup
下载以下数据集:boston_train.csv,boston_test.csv,和boston_predict.csv。
以下部分逐步介绍如何创建输入函数,将这些数据集提供给神经网络回归器,训练和评估模型,并进行房屋价值预测。完整的代码在这里。
导入住房数据
开始,设置您的导入(包括pandas
和tensorflow
)并将日志级别设置为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
。为了区分标签和特征,还要定义FEATURES
和LABEL
。然后读入三个CSV(tf.train
,tf.test
,和predict),使用 Pandas
DataFrame
格式:
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)
定义FeatureColumns并创建回归模型
接下来,创建一个列表FeatureColumn
s输入数据,正式指定用于训练的一组特征。由于住房数据集中的所有特征都是连续值,因此您可以创建自己的FeatureColumn
,使用的tf.contrib.layers.real_valued_column()
函数:
feature_cols = [tf.feature_column.numeric_column(k) for k in FEATURES]
注:有关特征列的更深入概述,请参阅这个介绍,对于类别数据如何定义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")
建立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)
请注意输入数据被传入input_fn
的data_set
参数,这意味着该函数可以处理任何的DataFrame
:training_set
,test_set
,和prediction_set
。
另外两个参数: num_epochs
:控制迭代数据的数量。要进行训练,请设置为None
, 这样
input_fn
保持返回数据,直到达到所需的训练步数。为了评估和预测,设置为1,这样input_fn
将遍历数据一次,然后抛出OutOfRangeError
。那个错误会发信号给Estimator
停止评估或预测。 shuffle
:是否洗牌数据。为了评估和预测,将其设置为False
, 所以input_fn
依次遍历数据。对于训练,请将此设置为True
。
训练回归模型
训练神经网络回归模型,运行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.
评估模型
接下来,看看训练的模型如何在测试数据集运行。执行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
做预测
最后,您可以使用该模型来预测房屋价格的中位数值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)))
您的结果应该包含六个house-value的预测值,例如:
Predictions: [ 33.30348587 17.04452896 22.56370163 34.74345398 14.55953979
19.58005714]
其他资源
本教程着重于创建一个input_fn
神经网络回归器。要了解更多关于使用input_fn
对于其他类型的型号,请查看以下资源:
-
Large-scale Linear Models with TensorFlow: This
introduction to linear models in TensorFlow provides a high-level overview
of feature columns and techniques for transforming input data. -
TensorFlow Linear Model Tutorial: This tutorial covers
creatingFeatureColumn
s and aninput_fn
for a linear classification
model that predicts income range based on census data. -
TensorFlow Wide & Deep Learning Tutorial: Building on
the Linear Model Tutorial, this tutorial covers
FeatureColumn
andinput_fn
creation for a “wide and deep” model that
combines a linear model and a neural network using
DNNLinearCombinedClassifier
.