tensorflow 回归的例子,包括保存模型和重新预测

import pathlib

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

import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)
2.5.0

Auto MPG 数据集
该数据集可以从 UCI机器学习库 中获取.

获取数据
首先下载数据集。

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
'C:\\Users\\xiahuadong\\.keras\\datasets\\auto-mpg.data'

使用 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()
MPGCylindersDisplacementHorsepowerWeightAccelerationModel YearOrigin
39327.04140.086.02790.015.6821
39444.0497.052.02130.024.6822
39532.04135.084.02295.011.6821
39628.04120.079.02625.018.6821
39731.04119.082.02720.019.4821

数据清洗
数据集中包括一些未知值。

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” 列实际上代表分类,而不仅仅是一个数字。所以把它转换为独热码 (one-hot):

origin = dataset.pop('Origin')
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
dataset.tail()
MPGCylindersDisplacementHorsepowerWeightAccelerationModel YearUSAEuropeJapan
39327.04140.086.02790.015.6821.00.00.0
39444.0497.052.02130.024.6820.01.00.0
39532.04135.084.02295.011.6821.00.00.0
39628.04120.079.02625.018.6821.00.00.0
39731.04119.082.02720.019.4821.00.00.0

拆分训练数据集和测试数据集
现在需要将数据集拆分为一个训练数据集和一个测试数据集。

我们最后将使用测试数据集对模型进行评估。

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

数据检查
快速查看训练集中几对列的联合分布。

sns.pairplot(train_dataset[["MPG", "Cylinders", "Displacement", "Weight"]], diag_kind="kde")
<seaborn.axisgrid.PairGrid at 0x1c44c40c3c8>


在这里插入图片描述

也可以查看总体的数据统计:

train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()
train_stats
countmeanstdmin25%50%75%max
Cylinders314.05.4777071.6997883.04.004.08.008.0
Displacement314.0195.318471104.33158968.0105.50151.0265.75455.0
Horsepower314.0104.86942738.09621446.076.2594.5128.00225.0
Weight314.02990.251592843.8985961649.02256.502822.53608.005140.0
Acceleration314.015.5592362.7892308.013.8015.517.2024.8
Model Year314.075.8980893.67564270.073.0076.079.0082.0
USA314.00.6242040.4851010.00.001.01.001.0
Europe314.00.1783440.3834130.00.000.00.001.0
Japan314.00.1974520.3987120.00.000.00.001.0

从标签中分离特征
将特征值从目标值或者"标签"中分离。 这个MPG标签是你使用训练模型进行预测的值。

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

数据规范化
再次审视下上面的 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)

我们将会使用这个已经归一化的数据来训练模型。

警告: 用于归一化输入的数据统计(均值和标准差)需要反馈给模型从而应用于任何其他数据,以及我们之前所获得独热码。这些数据包含测试数据集以及生产环境中所使用的实时数据。

模型
构建模型
让我们来构建我们自己的模型。这里,我们将会使用一个“顺序”模型,其中包含两个紧密相连的隐藏层,以及返回单个、连续值得输出层。模型的构建步骤包含于一个名叫 ‘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()

检查模型
使用 .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.1933    ],
       [-0.25311732],
       [-0.02922729],
       [-0.5366153 ],
       [ 0.4857128 ],
       [-0.21365601],
       [ 0.42698506],
       [ 0.08424012],
       [-0.02653636],
       [ 0.5320365 ]], dtype=float32)

它似乎在工作,并产生了预期的形状和类型的结果

训练模型
对模型进行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 对象中存储的统计信息可视化模型的训练进度。

hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()
lossmaemseval_lossval_maeval_mseepoch
9953.0875441.1343953.0875449.5150592.4068359.515059995
9963.0966641.1045483.0966649.5709502.3190989.570950996
9972.8798611.0820192.8798619.1765762.3206669.176576997
9983.2362471.1766153.2362479.3287442.3198039.328744998
9992.8606101.0793062.8606109.6246942.4170649.624694999
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)


在这里插入图片描述

在这里插入图片描述

该图表显示在约100个 epochs 之后误差非但没有改进,反而出现恶化。 让我们更新 model.fit 调用,当验证值没有提高上是自动停止训练。 我们将使用一个 EarlyStopping callback 来测试每个 epoch 的训练条件。如果经过一定数量的 epochs 后没有改进,则自动停止训练。

model = build_model()

# patience 值用来检查改进 epochs 的数量
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)
...............................................................


在这里插入图片描述

在这里插入图片描述

如图所示,验证集中的平均的误差通常在 +/- 2 MPG左右。 这个结果好么? 我们将决定权留给你。

让我们看看通过使用 测试集 来泛化模型的效果如何,我们在训练模型时没有使用测试集。这告诉我们,当我们在现实世界中使用这个模型时,我们可以期望它预测得有多好。

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

print("Testing set Mean Abs Error: {:5.2f} MPG".format(mae))
3/3 - 0s - loss: 6.1135 - mae: 1.9469 - mse: 6.1135
Testing set Mean Abs Error:  1.95 MPG

做预测
最后,使用测试集中的数据预测 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])


在这里插入图片描述

这看起来我们的模型预测得相当好。我们来看下误差分布。

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


在这里插入图片描述

它不是完全的高斯分布,但我们可以推断出,这是因为样本的数量很小所导致的。

保存模型

# 将整个模型另存为 SavedModel。
!mkdir -p saved_model
model.save('saved_model/my_model')
INFO:tensorflow:Assets written to: saved_model/my_model\assets

加载模型

new_model = tf.keras.models.load_model('saved_model/my_model')

# 检查其架构
new_model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_3 (Dense)              (None, 64)                640       
_________________________________________________________________
dense_4 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 65        
=================================================================
Total params: 4,865
Trainable params: 4,865
Non-trainable params: 0
_________________________________________________________________

使用加载的模型运行评估和预测:

# 评估还原的模型
loss, mae, mse = new_model.evaluate(normed_test_data, test_labels, verbose=2)
print("Testing set Mean Abs Error: {:5.2f} MPG".format(mae))

print(new_model.predict(normed_test_data).flatten())
3/3 - 0s - loss: 6.1135 - mae: 1.9469 - mse: 6.1135
Testing set Mean Abs Error:  1.95 MPG
[15.950223 11.906551 13.651723 23.469954 22.04727  13.736511 13.821402
 13.882218 19.949888 29.83001  25.609768 23.88941  14.762226 27.626661
 12.877979 14.100545 14.56788  13.823403 18.663124 13.434064 14.543681
 25.861021 19.464455 20.61747  29.81171  23.989405 15.671101 22.278788
 16.624363 18.864603 27.515078 21.540775 18.333206 21.339361 25.85737
 16.033829 18.962055 31.172125 30.270668 16.95118  30.575659 28.744806
 15.829894 36.230034 35.275005 36.141514 20.530663 22.33277  20.97685
 25.696512 31.300652 19.108814 32.386936 19.010128 18.176157 18.21755
 33.371098 35.176353 23.383959 25.030981 38.75675  33.535957 27.707935
 28.233677 32.559654 40.08075  37.19079  35.192795 33.99096  30.45808
 23.353868 24.008827 29.738144 30.408558 36.347446 36.74043  38.7237
 30.379595]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏华东的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值