教程 | TensorFlow 1.10 教程 —— 学习使用机器学习 —— 回归

译自:TensorFlow 官方教程


预测房价:回归

在回归问题中,我们的目标是预测连续值的输出,如价格或概率。而分类问题的目标是预测离散标签(例如,图片包含苹果还是橘子)。

本教程构建了一个模型,用于预测 20 世纪 70 年代中期波士顿郊区房屋的中位数价格。为此,我们将为模型提供有关郊区的一些数据,例如犯罪率和当地财产税率。

本示例使用 tf.keras API,有关详细信息,请参阅本指南

from __future__ import absolute_import, division, print_function

import tensorflow as tf
from tensorflow import keras

import numpy as np

print(tf.__version__)

波士顿住房价格数据集

可以在 TensorFlow 中直接访问此数据集。下载并打乱训练集:

boston_housing = keras.datasets.boston_housing

(train_data, train_labels), (test_data, test_labels) = boston_housing.load_data()

# 随机打乱训练集
order = np.argsort(np.random.random(train_labels.shape))
train_data = train_data[order]
train_labels = train_labels[order]
Downloading data from https://s3.amazonaws.com/keras-datasets/boston_housing.npz
57344/57026 [==============================] - 0s 4us/step

样本和特征

这个数据集比我们迄今为止使用的其他数据集小得多:它共有 506 个样本,分为 404 个训练样本和 102 个测试样本:

print("Training set: {}".format(train_data.shape))  # 404 个样本, 13 个特征
print("Testing set:  {}".format(test_data.shape))   # 102 个样本, 13 个特征
Training set: (404, 13)
Testing set:  (102, 13)

该数据集包含 13 个不同的特征:

  1. 人均犯罪率。
  2. 占地面积超过 25,000 平方英尺的住宅用地比例。
  3. 每个城镇非零售业务的比例。
  4. 查尔斯河虚拟变量(如果房屋沿河则为 1,否则为0)。
  5. 一氧化氮浓度(每千万)。
  6. 每栋住宅的平均房间数。
  7. 1940年以前建造的自住单位比例。
  8. 到波士顿五个就业中心的加权距离。
  9. 辐射式公路的可达性指数。
  10. 每10,000美元的全额物业税率。
  11. 城镇的学生教师比。
  12. 1000 *(Bk - 0.63)** 2 其中 Bk 是城镇黑人的比例。
  13. 地位较低人口的百分比。

这些输入数据特征中的每一项的范围都不同。某些特征由 0 到 1 之间的比例表示,其他特征的范围介于 1 到 12 之间,有些特征介于 0 到 100 之间等等。这通常是现实世界数据的情况,了解如何探索和清理此类数据是一项重要的开发技能。

关键点:作为建模人员和开发人员,请考虑如何使用此数据以及模型预测可能带来的潜在好处和危害。像这样的模型可能会加剧社会偏见和差异。某个特征是否与你要解决的问题相关或是否会引入偏差?有关更多信息,请参阅 ML fairness

print(train_data[0])  # 打印样本特征, 注意数据不同的范围
[7.8750e-02 4.5000e+01 3.4400e+00 0.0000e+00 4.3700e-01 6.7820e+00
 4.1100e+01 3.7886e+00 5.0000e+00 3.9800e+02 1.5200e+01 3.9387e+02
 6.6800e+00]

使用 pandas 库可以很方便地在表中显示数据集的前几行:

import pandas as pd

column_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
                'TAX', 'PTRATIO', 'B', 'LSTAT']

df = pd.DataFrame(train_data, columns=column_names)
df.head()
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
0 0.07875 45.0 3.44 0.0 0.437 6.782 41.1 3.7886 5.0 398.0 15.2 393.87 6.68
1 4.55587 0.0 18.10 0.0 0.718 3.561 87.9 1.6132 24.0 666.0 20.2 354.70 7.12
2 0.09604 40.0 6.41 0.0 0.447 6.854 42.8 4.2673 4.0 254.0 17.6 396.90 2.98
3 0.01870 85.0 4.15 0.0 0.429 6.516 27.7 8.5353 4.0 351.0 17.9 392.43 6.36
4 0.52693 0.0 6.20 0.0 0.504 8.725 83.0 2.8944 8.0 307.0 17.4 382.00 4.63

标签

标签是以千为单位的房价。

print(train_labels[0:10])  # 打印前 10 项
[32.  27.5 32.  23.1 50.  20.6 22.6 36.2 21.8 19.5]

归一化特征

建议对使用不同比例和范围的特征进行归一化。对于每个特征,减去特征的平均值并除以标准差:

# 计算均值和标准差时不使用测试数据 

mean = train_data.mean(axis=0)
std = train_data.std(axis=0)
train_data = (train_data - mean) / std
test_data = (test_data - mean) / std

print(train_data[0])  # 打印第一个归一化的训练样本
[-0.39725269  1.41205707 -1.12664623 -0.25683275 -1.027385    0.72635358
 -1.00016413  0.02383449 -0.51114231 -0.04753316 -1.49067405  0.41584124
 -0.83648691]

虽然模型可以在没有特征归一化的情况下收敛,但它使训练更加困难,并且使得模型更依赖于输入中使用的单位的选择。


构建模型

让我们建立模型。这里,我们将使用具有两个密集连接的隐藏层,以及返回单个连续值的输出层的 Sequential 模型。模型构建步骤包含在 build_model 函数中,因为我们稍后将创建第二个模型。

def build_model():
  model = keras.Sequential([
    keras.layers.Dense(64, activation=tf.nn.relu,
                       input_shape=(train_data.shape[1],)),
    keras.layers.Dense(64, activation=tf.nn.relu),
    keras.layers.Dense(1)
  ])

  optimizer = tf.train.RMSPropOptimizer(0.001)

  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae'])
  return model

model = build_model()
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 64)                896       
_________________________________________________________________
dense_1 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 65        
=================================================================
Total params: 5,121
Trainable params: 5,121
Non-trainable params: 0
_________________________________________________________________

训练模型

模型经过 500 个周期的训练,并在 history 对象中记录了训练和验证准确率。

# 每完成一个周期打印一个点,以显示训练进度
class PrintDot(keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs):
    if epoch % 100 == 0: print('')
    print('.', end='')

EPOCHS = 500

# 保存训练时的统计数据
history = model.fit(train_data, train_labels, epochs=EPOCHS,
                    validation_split=0.2, verbose=0,
                    callbacks=[PrintDot()])
....................................................................................................
....................................................................................................
....................................................................................................
....................................................................................................
....................................................................................................

使用存储在 history 对象中的统计信息可视化模型的训练进度。我们希望使用此数据来确定在模型停止提升性能之前要训​​练多长时间。

import matplotlib.pyplot as plt


def plot_history(history):
  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Abs Error [1000$]')
  plt.plot(history.epoch, np.array(history.history['mean_absolute_error']),
           label='Train Loss')
  plt.plot(history.epoch, np.array(history.history['val_mean_absolute_error']),
           label = 'Val loss')
  plt.legend()
  plt.ylim([0, 5])

plot_history(history)

这里写图片描述
该图表显示在约 200 个周期之后模型性能的提升很小。让我们更新 model.fit 方法,以便在验证分数没有提高时自动停止训练。我们将使用一个回调来测试每个周期的训练条件。如果经过一定数量的周期而没有性能提升,则自动停止训练。

你可以在此处了解有关此回调的更多信息。

model = build_model()

# patience 参数是检查性能提升的周期数
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=20)

history = model.fit(train_data, train_labels, epochs=EPOCHS,
                    validation_split=0.2, verbose=0,
                    callbacks=[early_stop, PrintDot()])

plot_history(history)
....................................................................................................
..............................................................................

这里写图片描述

该图显示平均误差约为 2,500 美元。这个好吗?当一些标签只有 15,000 美元时,2,500 美元并不是微不足道的数额。

让我们看看模型在测试集上的表现如何:

[loss, mae] = model.evaluate(test_data, test_labels, verbose=0)

print("Testing set Mean Abs Error: ${:7.2f}".format(mae * 1000))
Testing set Mean Abs Error: $2599.79

预测

最后,使用测试集中的数据预测一些房价:

test_predictions = model.predict(test_data).flatten()

plt.scatter(test_labels, test_predictions)
plt.xlabel('True Values [1000$]')
plt.ylabel('Predictions [1000$]')
plt.axis('equal')
plt.xlim(plt.xlim())
plt.ylim(plt.ylim())
_ = plt.plot([-100, 100], [-100, 100])

这里写图片描述

error = test_predictions - test_labels
plt.hist(error, bins = 50)
plt.xlabel("Prediction Error [1000$]")
_ = plt.ylabel("Count")

这里写图片描述


结论

本教程介绍了一些处理回归问题的技巧。

  • 均方误差(MSE)是用于回归问题的常见损失函数(不同于分类问题)。
  • 同样,用于回归的评估指标也不同于分类。常见的回归指标是平均绝对误差(MAE)。
  • 当输入数据特征具有不同范围的值时,应单独缩放每个特征。
  • 如果训练数据不多,则选择隐藏层较少的小型网络,以避免过拟合。
  • 早停是防止过拟合的有效技术。

猜你喜欢

转载自blog.csdn.net/qq_20084101/article/details/82151151
今日推荐