回归项目实战:预测燃油效率 (tensorflow2.0官方教程翻译)

最全TensorFlow2.0学习路线 www.mashangxue123.com

回归问题中,我们的目标是预测连续值的输出,如价格或概率。
将此与分类问题进行对比,分类的目标是从类列表中选择一个类(例如,图片包含苹果或橙色,识别图片中的哪个水果)。

本章节采用了经典的Auto MPG 数据集,并建立了一个模型来预测20世纪70年代末和80年代初汽车的燃油效率。为此,我们将为该模型提供该时段内许多汽车的描述,此描述包括以下属性:气缸,排量,马力和重量。

此实例使用tf.keras API,有关信息信息,请参阅Keras指南

# 使用seaborn进行pairplot数据可视化,安装命令
pip install seaborn
from __future__ import absolute_import, division, print_function, unicode_literals

import pathlib

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

# tensorflow2 安装命令 pip install tensorflow==2.0.0-alpha0
import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

1. Auto MPG数据集

该数据集可从UCI机器学习库获得。

1.1. 获取数据

首先下载数据集:

dataset_path = keras.utils.get_file("auto-mpg.data", "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
dataset_path

用pandas导入数据

column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin']
raw_dataset = pd.read_csv(dataset_path, names=column_names,
                      na_values = "?", comment='\t',
                      sep=" ", skipinitialspace=True)

dataset = raw_dataset.copy()
dataset.tail()
MPG Cylinders Displacement Horsepower Weight Acceleration Model Year Origin
393 27.0 4 140.0 86.0 2790.0 15.6 82 1
394 44.0 4 97.0 52.0 2130.0 24.6 82 2
395 32.0 4 135.0 84.0 2295.0 11.6 82 1
396 28.0 4 120.0 79.0 2625.0 18.6 82 1
397 31.0 4 119.0 82.0 2720.0 19.4 82 1

1.2. 清理数据

数据集包含一些未知值

dataset.isna().sum()
MPG             0
Cylinders       0
Displacement    0
Horsepower      6
Weight          0
Acceleration    0
Model Year      0
Origin          0
dtype: int64

这是一个入门教程,所以我们就简单地删除这些行。

dataset = dataset.dropna()

“Origin”这一列实际上是分类,而不是数字。 所以把它转换为独热编码:

origin = dataset.pop('Origin')
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
dataset.tail()
MPG Cylinders Displacement Horsepower Weight Acceleration Model Year USA Europe Japan
393 27.0 4 140.0 86.0 2790.0 15.6 82 1.0 0.0 0.0
394 44.0 4 97.0 52.0 2130.0 24.6 82 0.0 1.0 0.0
395 32.0 4 135.0 84.0 2295.0 11.6 82 1.0 0.0 0.0
396 28.0 4 120.0 79.0 2625.0 18.6 82 1.0 0.0 0.0
397 31.0 4 119.0 82.0 2720.0 19.4 82 1.0 0.0 0.0

1.3. 将数据分为训练集和测试集

现在将数据集拆分为训练集和测试集,我们将在模型的最终评估中使用测试集。

train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

1.4. 检查数据

快速浏览训练集中几对列的联合分布:

sns.pairplot(train_dataset[["MPG", "Cylinders", "Displacement", "Weight"]], diag_kind="kde")
png

另外查看整体统计数据:

train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()
train_stats
count mean std min 25% 50% 75% max
Cylinders 314.0 5.477707 1.699788 3.0 4.00 4.0 8.00 8.0
Displacement 314.0 195.318471 104.331589 68.0 105.50 151.0 265.75 455.0
Horsepower 314.0 104.869427 38.096214 46.0 76.25 94.5 128.00 225.0
Weight 314.0 2990.251592 843.898596 1649.0 2256.50 2822.5 3608.00 5140.0
Acceleration 314.0 15.559236 2.789230 8.0 13.80 15.5 17.20 24.8
Model Year 314.0 75.898089 3.675642 70.0 73.00 76.0 79.00 82.0
USA 314.0 0.624204 0.485101 0.0 0.00 1.0 1.00 1.0
Europe 314.0 0.178344 0.383413 0.0 0.00 0.0 0.00 1.0
Japan 314.0 0.197452 0.398712 0.0 0.00 0.0 0.00 1.0

1.5. 从标签中分割特征

将目标值或“标签”与特征分开,此标签是您训练的模型进行预测的值:

train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')

1.6. 标准化数据

再看一下上面的train_stats块,注意每个特征的范围有多么不同。

使用不同的比例和范围对特征进行标准化是一个很好的实践,虽然模型可能在没有特征标准化的情况下收敛,但它使训练更加困难,并且它使得最终模型取决于输入中使用的单位的选择。

注意:尽管我们仅从训练数据集中有意生成这些统计信息,但这些统计信息也将用于标准化测试数据集。我们需要这样做,将测试数据集投影到模型已经训练过的相同分布中。

def norm(x):
  return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)

这个标准化数据是我们用来训练模型的数据。

注意:用于标准化输入的统计数据(平均值和标准偏差)需要应用于输入模型的任何其他数据,以及我们之前执行的独热编码。这包括测试集以及模型在生产中使用时的实时数据。

2. 模型

2.1. 构建模型

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

def build_model():
  model = keras.Sequential([
    layers.Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
    layers.Dense(64, activation='relu'),
    layers.Dense(1)
  ])

  optimizer = tf.keras.optimizers.RMSprop(0.001)

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

2.2. 检查模型

使用.summary方法打印模型的简单描述

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 64)                640       
_________________________________________________________________
dense_1 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 65        
=================================================================
Total params: 4,865
Trainable params: 4,865
Non-trainable params: 0
_________________________________________________________________

现在试试这个模型。从训练数据中取出一批10个样本数据并在调用model.predict函数。

example_batch = normed_train_data[:10]
example_result = model.predict(example_batch)
example_result
      array([[ 0.3297699 ],
            [ 0.25655937],
            [-0.12460149],
            [ 0.32495883],
            [ 0.50459725],
            [ 0.10887371],
            [ 0.57305855],
            [ 0.57637435],
            [ 0.12094647],
            [ 0.6864784 ]], dtype=float32)

这似乎可以工作,它产生预期的shape和类型的结果。

2.3. 训练模型

训练模型1000个周期,并在history对象中记录训练和验证准确性:

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

EPOCHS = 1000

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

使用存储在history对象中的统计数据可视化模型的训练进度。300

hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()
loss mae mse val_loss val_mae val_mse epoch
995 2.556746 0.988013 2.556746 10.210531 2.324411 10.210530 995
996 2.597973 1.039339 2.597973 11.257273 2.469266 11.257273 996
997 2.671929 1.040886 2.671929 10.604957 2.446257 10.604958 997
998 2.634858 1.001898 2.634858 10.906935 2.373279 10.906935 998
999 2.741717 1.035889 2.741717 10.698320 2.342703 10.698319 999
def plot_history(history):
  hist = pd.DataFrame(history.history)
  hist['epoch'] = history.epoch

  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Abs Error [MPG]')
  plt.plot(hist['epoch'], hist['mae'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mae'],
           label = 'Val Error')
  plt.ylim([0,5])
  plt.legend()

  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Square Error [$MPG^2$]')
  plt.plot(hist['epoch'], hist['mse'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mse'],
           label = 'Val Error')
  plt.ylim([0,20])
  plt.legend()
  plt.show()


plot_history(history)
png
png

该图表显示在约100个周期之后,验证误差几乎没有改进,甚至降低。让我们更新model.fit调用,以便在验证分数没有提高时自动停止训练。我们将使用EarlyStopping回调来测试每个周期的训练状态。如果经过一定数量的周期而没有显示出改进,则自动停止训练。

您可以了解此回调的更多信息 连接.

model = build_model()

# “patience”参数是检查改进的周期量 
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

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

plot_history(history)
png
png

上图显示在验证集上平均误差通常约为+/-2MPG,这个好吗?我们会把这个决定留给你。

让我们看一下使用测试集来看一下泛化模型效果,我们在训练模型时没有使用测试集,这告诉我们,当我们在现实世界中使用模型时,我们可以期待模型预测。

loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=0)

print("Testing set Mean Abs Error: {:5.2f} MPG".format(mae))

Testing set Mean Abs Error: 2.09 MPG

2.4. 预测

最后,使用测试集中的数据预测MPG值:

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

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

png

看起来我们的模型预测得相当好,我们来看看错误分布:

error = test_predictions - test_labels
plt.hist(error, bins = 25)
plt.xlabel("Prediction Error [MPG]")
_ = plt.ylabel("Count")
png

上图看起来不是很高斯(正态分布),很可能是因为样本数据非常少。

3. 结论

本章节介绍了一些处理回归问题的技巧:

  • 均方误差(MSE)是用于回归问题的常见损失函数(不同的损失函数用于分类问题)。

  • 同样,用于回归的评估指标与分类不同,常见的回归度量是平均绝对误差(MAE)。

  • 当数字输入数据特征具有不同范围的值时,应将每个特征独立地缩放到相同范围。

  • 如果没有太多训练数据,应选择隐藏层很少的小网络,以避免过拟合。

  • 尽早停止是防止过拟合的有效技巧。

最新版本:https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_regression.html
英文版本:https://tensorflow.google.cn/alpha/tutorials/keras/basic_regression
最全TensorFlow2.0学习路线 www.mashangxue123.com

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

推荐阅读更多精彩内容