TensorFlow 线性回归教程 [示例]

⚡ 智能摘要

TensorFlow 中的线性回归用于建立数值特征与连续目标值之间的关系模型。本教程将使用 Pandas、NumPy 和 TensorFlow 原生输入管道(均使用 LinearRegressor 估计器)三种不同的方法训练波士顿房价预测模型。

  • 🔘 模型形式: 线性回归拟合 y = 偏差 + 权重 × x,对于多元问题,可以扩展为更多协变量。
  • ☑️ 训练循环: 梯度下降法通过每次迭代调整权重,直到均方误差不再下降为止。
  • 估算器 API: LinearRegressor 只需要特征列、模型目录和输入函数。
  • 🧪 三条管道: Pandas、NumPy 和原生 TensorFlow 数据集都输入到同一个模型中,并返回相同的预测结果。
  • 🛠️ 示例: 波士顿的九项特征预测房屋中位价,测试损失达到 3215。
  • ⚠️ 现实版本: TensorFlow 2.12 中已弃用估计器,2.16 中已将其移除,因此请将新工作移植到 Keras。

使用 TensorFlow 进行线性回归

什么是线性回归?

线性回归 线性回归是统计学中一种用于建立两个变量之间关系的建模方法。这种建模是在标量响应变量和一个或多个解释变量之间进行的。只有一个解释变量的关系称为简单线性回归,而有多个解释变量的关系称为多元线性回归。

TensorFlow 提供了完全控制计算的工具。这是通过低级 API 实现的。除此之外,TensorFlow 还配备了大量 API 来执行许多 机器学习 算法。这是高级 API,TensorFlow 将它们称为估计器。

  • 低级 API从零开始构建模型架构并进行优化。这对初学者来说很复杂。
  • 高级API定义算法。它非常易于使用。TensorFlow 提供了一个名为 的工具箱。 估计 构建、训练、评估和做出预测。

在本教程中,您将使用 仅限估算器计算速度更快,也更容易实现。第一部分讲解如何使用梯度下降优化器在 TensorFlow 中训练线性回归模型。第二部分将使用波士顿数据集,通过 TensorFlow 估计器预测房价。

下载波士顿数据集

如何训练线性回归模型

在开始训练模型之前,让我们先来看看线性回归究竟是什么。

假设你有两个变量 x 和 y,你的任务是根据 x 的值预测 y 的值。如果你绘制数据图,你可以看到自变量 x 和因变量 y 之间存在正相关关系,如下图所示的散点图。

x 对 y 的散点图显示出正线性关系

你可以观察到,如果 x=1,y 大约等于 6;如果 x=2,y 大约等于 8.5。

这种方法不太准确,容易出错,尤其是在处理包含数十万个数据点的数据集时。

线性回归用方程来评估。变量 y 由一个或多个协变量解释。在您的示例中,只有一个因变量。如果您必须写出此方程,则它将是:

包含偏差项、权重项和误差项的简单线性回归方程

附:

  • 偏差系数符号 是偏差。也就是说,如果 x=0,y=当 x 等于零时,偏差系数的值
  • 与 x 相关的权重系数符号 与 x 相关的权重
  • 残差项符号 残差,或者说模型的误差。它包含了模型无法从数据中学习到的内容。

假设你拟合了模型,并找到了以下解决方案:

  • 拟合偏差系数等于 3.8 = 3.8
  • 拟合权重系数等于 2.78 = 2.78

您可以将这些数字代入等式中,结果变为:

y= 3.8 + 2.78x

现在,您有了更好的方法来找到 y 的值。也就是说,您可以将 x 替换为您想要的任何值来预测 y。在下面的图片中,我们将等式中的 x 替换为数据集中的所有值,并绘制了结果。

图中红色曲线为拟合回归线,穿过绘制的数据点。

红线代表拟合值,即每个 x 值对应的 y 值。您无需知道 x 的具体值即可预测 y 值;对于每个 x 值,红线都对应一个 y 值。您也可以预测 x 值大于 2 的情况。

如果想将线性回归扩展到更多协变量,可以通过向模型中添加更多变量来实现。传统分析和线性回归的区别在于,线性回归考察的是每个独立变量 x 对 y 的影响。

我们来看一个例子。假设你想预测一家冰淇淋店的销售额。数据集包含不同的信息,例如天气(雨天、晴天、阴天)和顾客信息(工资、性别、婚姻状况)。

传统分析方法会尝试通过计算每个变量的平均值来预测销售额,并尝试估算不同情景下的销售额。这种方法会导致预测结果不准确,并且会将分析范围限制在选定的情景内。

如果使用线性回归,则可以写出以下方程:

结合多个加权协变量的多元线性回归方程

该算法将找到权重的最佳解决方案;这意味着它将尝试最小化成本,即拟合线与数据点之间的差异。

该算法是如何工作的

下图总结了算法重复的循环:选择权重,预测 y,测量误差,并纠正权重。

从随机权重到误差最小化的线性回归训练循环流程图

算法将为每个 随机初始化的偏差系数随机初始化的权重系数 并替换 x 的值以获取 y 的预测值。如果数据集有 100 个观测值,则算法会计算 100 个预测值。

我们可以计算误差,记为 损失计算中使用的模型误差项模型的误差,即预测值与实际值之间的差异。正误差表示模型低估了y的预测值,负误差表示模型高估了y的预测值。

用数学符号表示的平方误差最小化目标

你的目标是最小化误差平方。该算法计算误差平方的均值。这一步称为误差最小化。对于线性回归,这就是 均方误差,也称为 MSE。从数学上讲,它是:

均方误差公式(矩阵形式)

地点:

  • MSE公式中使用的权重向量符号 是权重,所以 MSE公式中使用的预测值符号 指预测值
  • y 是实际值
  • m 是观测次数。

需要注意的是 转置权重矩阵表示法 意味着它使用矩阵的转置。 MSE公式中使用的求和与平均值符号 是平均值的数学符号。

目标是找到最好的 使均方误差最小化的最优权重符号 这样可以最大限度地降低均方误差。

如果平均误差很大,则意味着模型表现不佳,权重选择不正确。要纠正权重,需要使用优化器。传统的优化器称为 梯度下降.

梯度下降法通过求导来减小或增大权重。如果导数为正,则减小权重;如果导数为负,则增大权重。模型会更新权重并重新计算误差。这个过程会重复进行,直到误差不再变化为止。每次迭代称为一次迭代。 迭代此外,梯度还要乘以学习率,学习率表示学习的速度。

如果学习率太小,算法需要很长时间才能收敛,因为需要更多的迭代次数。如果学习率太高,算法可能永远无法收敛。下图绘制了该数据集的误差与迭代次数的关系曲线。

损失曲线显示误差在大约二十次迭代后下降并趋于稳定。

从上图可以看出,该模型重复该过程约 20 次后才找到权重的稳定值,从而达到最小误差。

请注意,误差不等于零,而是稳定在 5 左右。这意味着该模型的典型误差为 5。如果要降低误差,需要向模型中添加更多信息,例如更多变量,或者使用不同的估计器。

你还记得第一个等式吗?

使用求解后的权重最终拟合的线性回归方程

最终权重为 3.8 和 2.78。下面的视频展示了梯度下降法如何优化损失函数以找到这些权重。

如何使用 TensorFlow 训练线性回归

现在您对幕后发生的事情有了更好的了解,您可以使用 TensorFlow 提供的估算器 API 来训练您的第一个线性回归。

版本说明: 下面所示的估算器工作流程是基于 TensorFlow 1.x 和早期 2.x 版本编写的。TensorFlow 标记了 tf.estimatortf.feature_column API 已在 2.12 版本中完全弃用,Estimators 已在 2.16 版本中移除。在当前安装的 TensorFlow 1.15 或 2.x 版本中运行此代码。tf.compat.v1 环境,或者将其移植到 Keras,在那里 tf.keras.layers.Dense(1) 此外,预处理层取代了线性回归器和特征列。特征、标签、批次、轮数、均方误差和梯度下降等概念保持不变。

您将使用波士顿数据集,其中包括以下变量。

请按需咨询 描述
犯罪 城镇人均犯罪率
zn 面积超过 25,000 平方英尺的住宅用地比例
梧桐 每个城镇非零售商业用地面积比例。
氮氧化物 一氧化氮浓度
rm 每套住房的平均房间数
年龄 1940 年之前建造的自住房比例
DIS 到波士顿五个就业中心的加权距离
税务 每 10,000 美元全值房产税率
比例 各城镇师生比例
医疗病毒 自住房屋的中位价值(千美元)

您将创建三个不同的数据集:

数据集 目标 塑造
培训实施 训练模型并获取权重 400,10
评价 评估模型在未知数据上的表现 100,10
预测 使用模型根据新数据预测房屋价值 6,10

目标是利用数据集的特征来预测房屋的价值。

在本教程的第二部分,您将学习如何使用 TensorFlow 通过三种不同的方式导入数据:

请注意,这三种方法的结果相同。

您将学习如何使用高级 API 来构建、训练和评估 TensorFlow 线性回归模型。如果您使用的是底层 API,则需要手动定义以下内容:

  • 损失函数
  • 优化器:梯度下降法
  • 矩阵乘法
  • 图和张量

对于初学者来说,这既繁琐又复杂。

熊猫解决方案

您需要导入必要的库来训练模型。

import pandas as pd
from sklearn import datasets
import tensorflow as tf
import itertools

步骤1) 使用导入数据 熊猫.

您需要定义列名并将其存储在 COLUMNS 表中。您可以使用 pd.read_csv() 函数导入数据。

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

将每次调用指向您之前下载的 CSV 文件。

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

您可以打印数据的形状。

print(training_set.shape, test_set.shape, prediction_set.shape)

输出

(400, 10) (100, 10) (6, 10)

请注意,标签(即您的 y 值)已包含在数据集中。因此,您需要定义另外两个列表:一个仅包含特征,另一个仅包含标签名称。这两个列表将告诉您的估计器数据集中包含哪些特征以及哪个列名是标签。

它是通过下面的代码完成的。

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

步骤2) 转换数据

您需要将数值变量转换为正确的格式。TensorFlow 提供了一个转换连续变量的方法:tf.feature_column.numeric_column()。

在上一步中,您定义了要包含在模型中的特征列表。现在,您可以使用此列表将它们转换为数值数据。如果您想从模型中排除某些特征,可以在构建 feature_cols 之前,从 FEATURES 列表中删除一个或多个变量。

请注意,您将使用一个 Python 使用列表推导式和列表 FEATURES 创建一个名为 feature_cols 的新列表。这样可以避免编写九次 tf.feature_column.numeric_column() 函数。列表推导式是一种更快、更简洁的创建新列表的方法。

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

步骤3) 定义估计量

在此步骤中,您需要定义估计器。TensorFlow 提供了六个预构建的现成估计器,其中三个用于分类任务,三个用于 TensorFlow 回归任务:

  • 回归器
    • DNN回归器
    • 线性回归器
    • DNN线性组合回归器
  • 分类
    • DNN分类器
    • 线性分类器
    • DNN线性组合分类器

在本教程中,您将使用线性回归器。要访问此功能,您需要使用 tf.estimator。

该函数需要两个参数:

  • feature_columns:包含模型中要包含的变量
  • model_dir:用于存储图、保存模型参数等的路径

TensorFlow 会在您的工作目录中自动创建一个名为 train 的文件夹。您需要使用此路径来访问它。 张量板如下面的 TensorFlow 回归示例所示。

estimator = tf.estimator.LinearRegressor(
        feature_columns=feature_cols,
        model_dir="train")

输出

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a215dc550>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

使用 TensorFlow 的难点在于如何向模型输入数据。TensorFlow 的设计初衷是用于并行计算和处理海量数据集。由于机器资源的限制,不可能一次性将所有数据输入模型。因此,需要每次分批输入数据。请注意,我们这里讨论的是包含数百万条记录的大型数据集。如果不分批输入数据,最终会导致内存错误。

例如,如果您的数据包含 100 个观测值,并且您将批次大小定义为 10,则意味着模型每次迭代将看到 10 个观测值(10*10)。

当模型处理完所有数据后,就完成了一个训练周期(epoch)。一个训练周期定义了模型处理数据的次数。最好将此步骤设置为“无”,让模型执行预设次数的迭代。

需要补充的第二点信息是,是否要在每次迭代前对数据进行打乱。在训练过程中,打乱数据非常重要,这样模型就不会学习到数据集的特定模式。如果模型学习到了数据潜在模式的细节,它就很难将预测结果推广到未见过的数据上。这被称为过拟合。模型在训练数据上表现良好,但无法正确预测未见过的数据。

TensorFlow 让这两个步骤变得轻松简单。当数据进入管道时,它知道需要多少观测值(批次)以及是否需要对数据进行打乱。

要指示 TensorFlow 如何为模型提供数据,可以使用 pandas_input_fn 函数。该对象需要五个参数:

  • x: 特征数据
  • y:标签数据
  • batch_size:批次。默认128
  • num_epoch:训练轮数,默认值为 1
  • shuffle:是否打乱数据顺序。默认值为 None。

你需要多次向模型输入数据,因此你需要定义一个函数来重复这个过程。将此函数命名为get_input_fn。

def get_input_fn(data_set, num_epochs=None, n_batch = 128, 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),
         batch_size=n_batch,
         num_epochs=num_epochs,
         shuffle=shuffle)

评估模型性能的常用方法是:

  • 训练模型
  • 使用不同的数据集评估模型。
  • 做出预测

TensorFlow 估算器提供了三种不同的函数,可以轻松执行这三个步骤。

步骤4) 训练模型

您可以使用训练估计器方法来拟合模型。训练估计器需要一个输入函数 (input_fn) 和一个训练步数。您可以使用上面创建的函数来输入模型。然后,指示模型迭代 1000 次。请注意,您无需指定训练轮数 (epoch);只需让模型迭代 1000 次即可。如果您将训练轮数设置为 1,则模型将迭代 4 次,因为训练集中有 400 条记录,而批大小为 128。

  1. 128行
  2. 128行
  3. 128行
  4. 16行

因此,可以简单地将 epoch 数设置为 none,然后定义迭代次数,如下面的 TensorFlow 分类示例所示。

estimator.train(input_fn=get_input_fn(training_set,
                                           num_epochs=None,
                                           n_batch = 128,
                                           shuffle=False),
                                           steps=1000)

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train/model.ckpt.
INFO:tensorflow:loss = 83729.64, step = 1
INFO:tensorflow:global_step/sec: 238.616
INFO:tensorflow:loss = 13909.657, step = 101 (0.420 sec)
INFO:tensorflow:global_step/sec: 314.293
INFO:tensorflow:loss = 12881.449, step = 201 (0.320 sec)
INFO:tensorflow:global_step/sec: 303.863
INFO:tensorflow:loss = 12391.541, step = 301 (0.327 sec)
INFO:tensorflow:global_step/sec: 308.782
INFO:tensorflow:loss = 12050.5625, step = 401 (0.326 sec)
INFO:tensorflow:global_step/sec: 244.969
INFO:tensorflow:loss = 11766.134, step = 501 (0.407 sec)
INFO:tensorflow:global_step/sec: 155.966
INFO:tensorflow:loss = 11509.922, step = 601 (0.641 sec)
INFO:tensorflow:global_step/sec: 263.256
INFO:tensorflow:loss = 11272.889, step = 701 (0.379 sec)
INFO:tensorflow:global_step/sec: 254.112
INFO:tensorflow:loss = 11051.9795, step = 801 (0.396 sec)
INFO:tensorflow:global_step/sec: 292.405
INFO:tensorflow:loss = 10845.855, step = 901 (0.341 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train/model.ckpt.
INFO:tensorflow:Loss for final step: 5925.9873.

您可以使用以下命令检查 TensorBoard:

activate hello-tf
# For MacOS
tensorboard --logdir=./train
# For Windows
tensorboard --logdir=train

步骤5) 评估你的模型

您可以使用以下代码评估模型在测试集上的拟合度:

ev = estimator.evaluate(
          input_fn=get_input_fn(test_set,
          num_epochs=1,
          n_batch = 128,
          shuffle=False))

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-13-01:43:13
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-13-01:43:13
INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.15896, global_step = 1000, loss = 3215.896

您可以使用以下代码打印损失:

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

输出

Loss: 3215.895996

该模型的损失为 3215。您可以查看汇总统计信息,以了解误差有多大。

training_set['medv'].describe()

输出

count    400.000000
mean      22.625500
std        9.572593
min        5.000000
25%       16.600000
50%       21.400000
75%       25.025000
max       50.000000
Name: medv, dtype: float64

从上面的汇总统计数据可知,房屋的平均价格为 22 美元,最低价格为 5 美元,最高价格为 50 美元。由于报告的损失是均方误差,因此以原始单位表示的典型误差约为 32.16 的平方根,约为 5.7 美元。

步骤6) 做出预测

最后,您可以使用 TensorFlow predict 方法来估算波士顿六栋房屋的价值。

y = estimator.predict(
         input_fn=get_input_fn(prediction_set,
         num_epochs=1,
         n_batch = 128,
         shuffle=False))

要打印估计值,可以使用以下代码:

predictions = list(p["predictions"] for p in itertools.islice(y, 6))
print("Predictions: {}".format(str(predictions)))

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
Predictions: [array([32.297546], dtype=float32), array([18.96125], dtype=float32), array([27.270979], dtype=float32), array([29.299236], dtype=float32), array([16.436684], dtype=float32), array([21.460876], dtype=float32)]

该模型预测以下数值:

排屋 预测
1 32.29
2 18.96
3 27.27
4 29.29
5 16.43
6 21.46

请注意,我们并不知道这六栋房子的真实价值。在深度学习教程中,您将尝试超越线性模型。

NumPy解决方案

本节介绍如何使用 NumPy 估计器来训练模型,并将数据作为输入。方法相同,只是需要使用 numpy_input_fn 估计器。

读取相同的三个 CSV 文件,但只保留带有 .values 的原始 NumPy 数组。

training_set_n = pd.read_csv("E:/boston_train.csv").values
test_set_n = pd.read_csv("E:/boston_test.csv").values
prediction_set_n = pd.read_csv("E:/boston_predict.csv").values

步骤1) 导入数据

首先,你需要区分特征变量和标签。你需要对训练数据和评估数据都进行这项操作。定义一个函数来分割数据会更快。

def prepare_data(df):
        X_train = df[:, :-3]
        y_train = df[:,-3]
        return X_train, y_train

您可以使用该函数将标签从训练集和评估集的特征中分离出来。

X_train, y_train = prepare_data(training_set_n)
X_test, y_test = prepare_data(test_set_n)

您需要排除预测数据集的最后一列,因为它只包含 NaN 值。

x_predict = prediction_set_n[:, :-2]

确认数组的形状。注意标签不应有第二个维度,即 (400,)。

print(X_train.shape, y_train.shape, x_predict.shape)

输出

(400, 9) (400,) (6, 9)

您可以按如下方式构建特征列:

feature_columns = [      tf.feature_column.numeric_column('x', shape=X_train.shape[1:])]

估计器的定义与之前相同:您指定特征列和图表的保存位置。

estimator = tf.estimator.LinearRegressor(
         feature_columns=feature_columns,
         model_dir="train1")

输出

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train1', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1a218d8f28>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

您可以使用 NumPy 估计器将数据输入模型,然后训练模型。请注意,我们预先定义了 input_fn 函数,以提高代码的可读性。

# Train the estimator
train_input = tf.estimator.inputs.numpy_input_fn(
           x={"x": X_train},
           y=y_train,
           batch_size=128,
           shuffle=False,
           num_epochs=None)
estimator.train(input_fn = train_input,steps=5000)

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train1/model.ckpt.
INFO:tensorflow:loss = 83729.64, step = 1
INFO:tensorflow:global_step/sec: 490.057
INFO:tensorflow:loss = 13909.656, step = 101 (0.206 sec)
INFO:tensorflow:global_step/sec: 788.986
INFO:tensorflow:loss = 12881.45, step = 201 (0.126 sec)
INFO:tensorflow:global_step/sec: 736.339
INFO:tensorflow:loss = 12391.541, step = 301 (0.136 sec)
INFO:tensorflow:global_step/sec: 383.305
INFO:tensorflow:loss = 12050.561, step = 401 (0.260 sec)
INFO:tensorflow:global_step/sec: 859.832
INFO:tensorflow:loss = 11766.133, step = 501 (0.117 sec)
INFO:tensorflow:global_step/sec: 804.394
INFO:tensorflow:loss = 11509.918, step = 601 (0.125 sec)
INFO:tensorflow:global_step/sec: 753.059
INFO:tensorflow:loss = 11272.891, step = 701 (0.134 sec)
INFO:tensorflow:global_step/sec: 402.165
INFO:tensorflow:loss = 11051.979, step = 801 (0.248 sec)
INFO:tensorflow:global_step/sec: 344.022
INFO:tensorflow:loss = 10845.854, step = 901 (0.288 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train1/model.ckpt.
INFO:tensorflow:Loss for final step: 5925.985.
Out[23]:
<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x1a1b6ea860>

使用不同的输入函数重复相同的步骤来评估你的模型。

eval_input = tf.estimator.inputs.numpy_input_fn(
       x={"x": X_test},
       y=y_test,
       shuffle=False,
       batch_size=128,
       num_epochs=1)
   estimator.evaluate(eval_input,steps=None)

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-13-01:44:00
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-13-01:44:00
INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.158947, global_step = 1000, loss = 3215.8945
Out[24]:
{'average_loss': 32.158947, 'global_step': 1000, 'loss': 3215.8945}

最后,您可以计算预测结果。它应该与 Pandas 的结果类似。

test_input = tf.estimator.inputs.numpy_input_fn(
        x={"x": x_predict},
        batch_size=128,
        num_epochs=1,
        shuffle=False)
        y = estimator.predict(test_input)

predictions = list(p["predictions"] for p in itertools.islice(y, 6))
print("Predictions: {}".format(str(predictions)))

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
Predictions: [array([32.297546], dtype=float32), array([18.961248], dtype=float32), array([27.270979], dtype=float32), array([29.299242], dtype=float32), array([16.43668], dtype=float32), array([21.460878], dtype=float32)]

TensorFlow解决方案

最后一部分专门讨论纯粹的 TensorFlow 解决方案。这种方法比其他两种方法稍微复杂一些。

请注意,如果您使用 Jupyter 笔记本您需要重启并清除内核才能运行此会话。

TensorFlow 提供了一个强大的工具,用于将数据传递到管道中。在本节中,您将自行构建 input_fn 函数。

步骤1) 定义数据的路径和格式

首先,你需要声明两个变量,分别存储 CSV 文件的路径。请注意,你有两个文件,一个用于训练集,一个用于测试集。

import tensorflow as tf
df_train = "E:/boston_train.csv"
df_eval = "E:/boston_test.csv"

接下来,您需要定义要从 CSV 文件中使用的列。我们将使用所有列。之后,您需要声明每个变量的类型。

浮点变量由 [0.] 定义。

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

步骤2) 定义 input_fn 函数

该函数可以分为三个部分:

  1. 导入数据
  2. 创建迭代器
  3. 使用数据

以下是定义该函数的整体代码。代码稍后会进行解释。

def input_fn(data_file, batch_size, num_epoch = None):
       # Step 1
          def parse_csv(value):
          columns = tf.decode_csv(value, record_defaults= RECORDS_ALL)
          features = dict(zip(COLUMNS, columns))
          #labels = features.pop('median_house_value')
          labels =  features.pop('medv')
          return features, labels

          # Extract lines from input files using the Dataset API.
          dataset = (tf.data.TextLineDataset(data_file) # Read text file
          .skip(1) # Skip header row
          .map(parse_csv))

          dataset = dataset.repeat(num_epoch)
          dataset = dataset.batch(batch_size)
          # Step 3
          iterator = dataset.make_one_shot_iterator()
          features, labels = iterator.get_next()
          return features, labels

导入数据

对于 CSV 文件,数据集方法一次读取一行。要构建数据集,您需要使用该对象。 TextLine数据集。您的数据集包含一个标题行,因此您需要使用 `skip(1)` 跳过第一行。目前,您只读取数据,并在流程中排除标题行。要将数据输入模型,您需要将特征与标签分离。用于对数据进行任何转换的方法是 `map`。

此方法会调用您创建的函数,以指示如何转换数据。简而言之,您需要将数据传递给该函数。 TextLine数据集对象,排除标题,并应用由函数指示的转换。

Code 解释

  • tf.数据。TextLine数据集(数据文件):此行读取 CSV 文件
  • .skip(1): 跳过标头
  • .map(parse_csv):将记录解析为张量

你需要定义一个函数来指示映射对象。你可以将此函数命名为 parse_csv。

此函数使用 `tf.decode_csv` 方法解析 CSV 文件,并声明特征和标签。特征可以声明为字典或元组。建议使用字典方式,因为它更方便。

Code 解释

  • tf.decode_csv(value, record_defaults= RECORDS_ALL): 方法decode_csv使用 TextLine要读取的 CSV 数据集。`record_defaults` 指示 TensorFlow 列类型。在 TensorFlow 2.x 中,此符号位于 `tf.io.decode_csv`。
  • dict(zip(COLUMNS, columns)): 使用所有列填充字典,例如trac在数据处理过程中
  • features.pop('medv​​'): 从特征变量中排除目标变量,并创建一个标签变量

数据集需要更多元素才能迭代地为张量提供数据。实际上,您需要添加 `repeat` 方法,以便数据集能够无限期地持续为模型提供数据。如果您不添加此方法,模型将只迭代一次,然后抛出错误,因为没有更多数据被输入到管道中。

之后,您可以使用 batch 方法控制批次大小。这意味着您需要告诉数据集每次迭代要向管道传递多少数据。如果设置的批次大小过大,模型运行速度会变慢。

步骤3) 创建迭代器

现在您已准备好进行第二步:创建一个迭代器来返回数据集中的元素。

创建操作符的最简单方法是使用方法 make_one_shot_iterator。

之后,您可以从迭代器创建特征和标签。

步骤4) 使用数据

你可以查看 input_fn 函数的运行情况。你需要在一个会话中调用该函数来处理数据。你可以尝试使用等于 1 的批处理大小。

请注意,它会将特征打印成字典,将标签打印成数组。

它会显示 CSV 文件的第一行。您可以尝试使用不同的批处理大小多次运行此代码。

next_batch = input_fn(df_train, batch_size = 1, num_epoch = None)
with tf.Session() as sess:
     first_batch  = sess.run(next_batch)
     print(first_batch)

输出

({'crim': array([2.3004], dtype=float32), 'zn': array([0.], dtype=float32), 'indus': array([19.58], dtype=float32), 'nox': array([0.605], dtype=float32), 'rm': array([6.319], dtype=float32), 'age': array([96.1], dtype=float32), 'dis': array([2.1], dtype=float32), 'tax': array([403.], dtype=float32), 'ptratio': array([14.7], dtype=float32)}, array([23.8], dtype=float32))

步骤5) 定义特征列

您需要按如下方式定义数值列:

X1= tf.feature_column.numeric_column('crim')
X2= tf.feature_column.numeric_column('zn')
X3= tf.feature_column.numeric_column('indus')
X4= tf.feature_column.numeric_column('nox')
X5= tf.feature_column.numeric_column('rm')
X6= tf.feature_column.numeric_column('age')
X7= tf.feature_column.numeric_column('dis')
X8= tf.feature_column.numeric_column('tax')
X9= tf.feature_column.numeric_column('ptratio')

请注意,您需要将一个桶中的所有变量合并在一起。

base_columns = [X1, X2, X3,X4, X5, X6,X7, X8, X9]

步骤6) 建立模型

您可以使用估计器 LinearRegressor 训练模型。

model = tf.estimator.LinearRegressor(feature_columns=base_columns, model_dir='train3')

输出

INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'train3', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1820a010f0>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

你需要使用一个 拉姆达函数 允许您为函数 input_fn 编写参数。如果您不使用 lambda 函数,则无法训练模型。

# Train the estimator
model.train(steps =1000,
          input_fn= lambda : input_fn(df_train,batch_size=128, num_epoch = None))

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into train3/model.ckpt.
INFO:tensorflow:loss = 83729.64, step = 1
INFO:tensorflow:global_step/sec: 72.5646
INFO:tensorflow:loss = 13909.657, step = 101 (1.380 sec)
INFO:tensorflow:global_step/sec: 101.355
INFO:tensorflow:loss = 12881.449, step = 201 (0.986 sec)
INFO:tensorflow:global_step/sec: 109.293
INFO:tensorflow:loss = 12391.541, step = 301 (0.915 sec)
INFO:tensorflow:global_step/sec: 102.235
INFO:tensorflow:loss = 12050.5625, step = 401 (0.978 sec)
INFO:tensorflow:global_step/sec: 104.656
INFO:tensorflow:loss = 11766.134, step = 501 (0.956 sec)
INFO:tensorflow:global_step/sec: 106.697
INFO:tensorflow:loss = 11509.922, step = 601 (0.938 sec)
INFO:tensorflow:global_step/sec: 118.454
INFO:tensorflow:loss = 11272.889, step = 701 (0.844 sec)
INFO:tensorflow:global_step/sec: 114.947
INFO:tensorflow:loss = 11051.9795, step = 801 (0.870 sec)
INFO:tensorflow:global_step/sec: 111.484
INFO:tensorflow:loss = 10845.855, step = 901 (0.897 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train3/model.ckpt.
INFO:tensorflow:Loss for final step: 5925.9873.
Out[8]:
<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x18225eb8d0>

您可以使用以下代码评估模型在测试集上的拟合度:

results = model.evaluate(steps =None,input_fn=lambda: input_fn(df_eval, batch_size =128, num_epoch = 1))
for key in results:
print("   {}, was: {}".format(key, results[key]))

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-13-02:06:02
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train3/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-13-02:06:02
INFO:tensorflow:Saving dict for global step 1000: average_loss = 32.15896, global_step = 1000, loss = 3215.896
   average_loss, was: 32.158958435058594
   loss, was: 3215.89599609375
   global_step, was: 1000

最后一步是根据特征矩阵的值预测目标值。你可以创建一个字典来存储想要预测的值。你的模型有九个特征,所以你需要为每个特征提供一个值。模型会为每个特征提供一个预测值。

下面的代码中,你需要写入 df_predict CSV 文件中包含的每个特征的值。

由于数据集中没有标签,因此需要编写一个新的 input_fn 函数。您可以使用 Dataset 对象中的 from_tensors API。

prediction_input = {
          'crim': [0.03359,5.09017,0.12650,0.05515,8.15174,0.24522],
          'zn': [75.0,0.0,25.0,33.0,0.0,0.0],
          'indus': [2.95,18.10,5.13,2.18,18.10,9.90],
          'nox': [0.428,0.713,0.453,0.472,0.700,0.544],
          'rm': [7.024,6.297,6.762,7.236,5.390,5.782],
          'age': [15.8,91.8,43.4,41.1,98.9,71.7],
          'dis': [5.4011,2.3682,7.9809,4.0220,1.7281,4.0317],
          'tax': [252,666,284,222,666,304],
          'ptratio': [18.3,20.2,19.7,18.4,20.2,18.4]
     }
     def test_input_fn():
     dataset = tf.data.Dataset.from_tensors(prediction_input)
     return dataset

     # Predict all our prediction_input
     pred_results = model.predict(input_fn=test_input_fn)

最后,打印预测结果。

for pred in enumerate(pred_results):
print(pred)

输出

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train3/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
(0, {'predictions': array([32.297546], dtype=float32)})
(1, {'predictions': array([18.96125], dtype=float32)})
(2, {'predictions': array([27.270979], dtype=float32)})
(3, {'predictions': array([29.299236], dtype=float32)})
(4, {'predictions': array([16.436684], dtype=float32)})
(5, {'predictions': array([21.460876], dtype=float32)})

INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Graph was finalized. INFO:tensorflow:Restoring parameters from train3/model.ckpt-5000 INFO:tensorflow:Running local_init_op. INFO:tensorflow:Done running local_init_op. (0, {'predictions': array([35.60663], dtype=float32)}) (1, {'predictions': array([22.298521], dtype=float32)}) (2, {'predictions': array([25.74533], dtype=float32)}) (3, {'predictions': array([35.126694], dtype=float32)}) (4, {'predictions': array([17.94416], dtype=float32)}) (5, {'predictions': array([22.606628], dtype=float32)})

这三个管道都返回了相同的六个预测结果,这证实了在 Pandas、NumPy 和原生 TensorFlow 数据集之间进行选择是出于便利性考虑,而不是准确性考虑。

常见问题

不。TensorFlow 在 2.12 版本中已将 Estimators 和特征列标记为完全弃用,并在 2.16 版本中将其移除。要运行此代码而不发生任何更改,请使用 TensorFlow 1.15 或 2.15,或者使用 Keras 层重写模型,TensorFlow 团队现在推荐这样做。

加载 CSV 文件 熊猫首先使用归一化层对九个特征进行缩放,然后堆叠一个 Dense(1) 单元。使用优化器和均方误差损失函数进行编译,然后调用 fit 函数。一个没有激活函数的 Dense 单元就是一个线性回归模型。

从 0.01 左右开始,以十倍为单位进行调整。数值太小需要更多的迭代才能收敛,而数值太大则会导致损失曲线波动。绘制损失曲线,并保留曲线仍能平滑下降的最大数值。

出于对人为引入种族变量的伦理担忧,scikit-learn 在 1.2 版本中移除了 load_boston 函数。本教程读取的是纯 CSV 文件,因此下载链接仍然有效,但新项目应改用加州住房数据集或艾姆斯住房数据集。

均方根误差 (RMSE) 恢复了原始单位,平均绝对误差 (MAE) 可以有效抑制异常值,而 R 平方值则反映了方差的解释率。建议同时报告绝对误差指标和 R 平方值,因为即使 R 平方值很高,也可能掩盖较大的个体预测误差。

线性回归用于预测连续数值,例如房价。 线性分类器 预测一个离散的类别标签。两者都拟合特征的加权和,但分类器会将该和值传递给一个决策阈值。

自动化流程会使用 Lasso 正则化、互信息或排列重要性对特征进行评分,然后剔除最弱的特征。AutoML 工具会同时搜索预处理和模型选项,因此您可以减少手动选择哪些列应该包含在 feature_cols 中的时间。

Copilot 可以快速生成样板代码,包括输入函数、特征列列表和评估循环。请将每个建议都视为草稿,因为它经常会生成已弃用的 Estimator 调用。运行之前,请务必根据当前的 TensorFlow API 检查每个生成的符号。

总结一下这篇文章: