tensorflow2 auto mpg汽车油耗预测实践(3.5节)

tensorflow2 汽车油耗预测实践

1. 数据集

1.1 Auto MPG

Auto MPG数据集记录了各种汽车效能指标与油耗的关系,一共398项数据,我们使用如下方式下载:

from tensorflow.keras import utils

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

dataset_path就是你下载文件的路径,一般电脑是无法读取.data文件的,我们使用python可以很容易将其变为csv文件用excel查看:

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)
raw_dataset.to_csv(os.getcwd()+"/auto-mpg.csv")
dataset = raw_dataset.copy()

然后我们找到保存的csv文件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkLkONf5-1648267540215)(tensorflow2 汽车油耗预测实践.assets/p1.png)]

我们发现一共有399行数据,其实auto-mpg只有398项数据,第一行是我们在读取数据为csv时加的头:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i3ftXUX9-1648267540216)(tensorflow2 汽车油耗预测实践.assets/p2.png)]

他们的意思如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bYVG4DnX-1648267540217)(tensorflow2 汽车油耗预测实践.assets/p3.png)]

除了产地其他都是数值型数据,产地1表示美国,2表示欧洲,3表示日本。

1.2 数据清洗

如果你仔细看数据集会发现有的地方是空白的,这一行我们就不需要了。

column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
 'Acceleration', 'Model Year', 'Origin']

raw_dataset = pd.read_csv("C:/Users/iu的男票/.keras/datasets/auto-mpg.data",names=column_names,
                          na_values="?", comment="\t",
                          sep=" ",skipinitialspace=True)
dataset = raw_dataset.copy()

然后开始清洗数据:

dataset = dataset.dropna()
#删除空白项
origin = dataset.pop('Origin')
#弹出该列
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
#添加三列

清洗过后变为如下模样(重新保存为另一个csv)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h5uw7fnq-1648267540217)(tensorflow2 汽车油耗预测实践.assets/p4.png)]

不算头有392行数据。把产地变成了01形式。

1.3 数据处理

然后将数据集按8:2的比例分割为训练集和测试集

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

train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')
#pop出正确标签,如此我们就分好了训练集与测试集
train_stats = train_dataset.describe()
train_stats = train_stats.transpose()
#转置

print(train_stats)
#我们获取数据集的描述,打印出来看一下数据的情况,std是标准差,mean是均值
"""
        Cylinders  Displacement  Horsepower  ...         USA      Europe       Japan
count  314.000000    314.000000  314.000000  ...  314.000000  314.000000  314.000000
mean     5.477707    195.318471  104.869427  ...    0.624204    0.178344    0.197452
std      1.699788    104.331589   38.096214  ...    0.485101    0.383413    0.398712
min      3.000000     68.000000   46.000000  ...    0.000000    0.000000    0.000000
25%      4.000000    105.500000   76.250000  ...    0.000000    0.000000    0.000000
50%      4.000000    151.000000   94.500000  ...    1.000000    0.000000    0.000000
75%      8.000000    265.750000  128.000000  ...    1.000000    0.000000    0.000000
max      8.000000    455.000000  225.000000  ...    1.000000    1.000000    1.000000
"""

1.4 标准化

在将我们的数据进行标准化前我们先来看看标准化是在做什么,举个例子

import numpy as np
import matplotlib.pyplot as plt


x = np.array(range(0,100))#横坐标
y = np.random.uniform(0,10,100)#随机值

mean = np.sum(y)/100#y平均值
std = np.sum(np.sqrt((y-mean)**2/100))#y标准差

def norm(x):					#标准化函数
    return (x-mean)/std
	
y1 = norm(y)					#y1是y的标准化

mean1 = np.sum(y1)/100			#y1平均值
std1 = np.sum(np.sqrt((y1-mean1)**2/100))#y1标准差

plt.scatter(x,y,label="y")
plt.scatter(x,y1,c='red',label="y1")
plt.legend()
print(mean)
print(std)
print(mean1)
print(std1)
plt.show()
"""
5.063663136722821
27.100690669906346

-2.969846590872294e-17
0.9999999999999999
"""
#从打印可见标准化是把数据平均值变为接近0,标准差变为接近1,图形如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AG9qte6G-1648267540218)(tensorflow2 汽车油耗预测实践.assets/p5.png)]

由于各个指标的性质不同,比如马力和气缸数,压根不是一个数量级别,当各指标间的水平相差很大时,如果直接用原始指标值进行分析,就会突出数值较高的指标在综合分析中的作用,相对削弱数值水平较低指标的作用。因此,为了保证结果的可靠性,需要对原始指标数据进行标准化处理。最重要的是标准化可以加快收敛,可以得到更好的效果,至于为什么?这似乎是一个大坑,许多理论我们略过这。

然后我们开始对我们的auto-mpg进行标准化:

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

到此我们完成了数据的标准化,接下来我们只要将其转换为tensorflow2提供的Dataset对象即可

train_db = tf.data.Dataset.from_tensor_slices((normed_train_data.values,train_labels.values))
#获得训练集Dataset对象
train_db = train_db.shuffle(100).batch(32)

为了代码看起来整洁,我整理上述代码在GetData.py中为两个函数如下:

import pandas as pd

def MyData():
    column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight',
                    'Acceleration', 'Model Year', 'Origin']

    raw_dataset = pd.read_csv("C:/Users/iu的男票/.keras/datasets/auto-mpg.data", names=column_names,
                              na_values="?", comment="\t",
                              sep=" ", skipinitialspace=True)

    dataset = raw_dataset.copy()
    dataset = dataset.dropna()
    # 删除空白项
    origin = dataset.pop('Origin')
    # 弹出该列
    dataset['USA'] = (origin == 1) * 1.0
    dataset['Europe'] = (origin == 2) * 1.0
    dataset['Japan'] = (origin == 3) * 1.0
    # 添加三列

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

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

    train_stats = train_dataset.describe()
    test_stats = test_dataset.describe()
    train_stats = train_stats.transpose()
    test_stats = test_stats.transpose()


    normed_train_data = norm(train_dataset,train_stats['mean'],train_stats['std'])
    normed_test_data = norm(test_dataset,test_stats['mean'],test_stats['std'])

    return normed_train_data,train_labels,normed_test_data,test_labels


def norm(x, mean, std):
    return (x-mean)/std

2. 搭建神经网络

考虑到Auto MPG数据集规模较小,我们只创建一个3层的全连接网络来完成任务。输入X的特征有9种,因此第一层输入界节点数是9个,第二层、第三层的输入节点数设置为64和64,输出层节点设计为1。

import keras

from tensorflow.keras import layers


class Network(keras.Model):
    def __init__(self):
        super(Network,self).__init__()
        
        self.fc1 = layers.Dense(64,activation = 'relu')
        self.fc2 = layers.Dense(64,activation = 'relu')
        self.fc3 = layers.Dense(1)
        #考虑MPG属于正实数,输出层不需要激活函数
        
    def call(self, inputs, training = None, mask = None):
        
        x = self.fc1(inputs)
        x = self.fc2(x)
        x = self.fc3(x)
        
        return x

一个很简单的神经网络就搭建好了。

3. 训练

首先获得数据,创建网络模型。优化器理论详细见此,RMSprop是一种优于随机梯度下降的方法。

import tensorflow as tf
from GetData import MyData
from NetWorkMPG import Network


normed_train_data,train_labels,normed_test_data,test_labels = MyData()

train_db = tf.data.Dataset.from_tensor_slices((normed_train_data.values,train_labels.values))
train_db = train_db.shuffle(100).batch(32)

model = Network()
model.build(input_shape=(32,9))
#build 作用详细见tensorflow基础2节,就是初始化一下网络模型
optimizer = optimizers.RMSprop(0.001)#创建优化器

然后我们进行训练

loss_list = []

for epoch in range(200):
    for step,(x,y) in enumerate(train_db):
        with tf.GradientTape() as tape:
            out = model(x)
            loss = tf.reduce_mean(losses.MSE(y,out))#使用均方误差

            

        if(step % 100 == 0) :
            print("epoch:",epoch,"step:",step,"loss:",loss)

        grads = tape.gradient(loss,model.trainable_variables)
        optimizer.apply_gradients(zip(grads,model.trainable_variables))
        if(step % 10 == 0) :
            loss_list.append(loss)

4. 画图与结果分析

#loss
plt.figure("loss")
x = np.array(range(0,len(loss_list)))
y = np.array(loss_list)

plt.plot(x,y,label="loss")
plt.legend()
plt.xlabel("batch/10")
plt.ylabel("loss")
#测试集正确值
plt.figure("test and real")
y1 = np.array(test_labels)
shape,= y1.shape
x1 = np.array(range(0,shape))

x2 = np.array(range(0,shape))
y2 = np.array(normed_test_data)
y2 = model(tf.constant(y2)).numpy()

plt.scatter(x1,y1,c='blue',label="real")
plt.scatter(x1,y2,c='red',label='test')

plt.legend()
plt.xlabel("car/kind")
plt.ylabel("mpg")

plt.show()


然后我们看loss图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IGAgsSx8-1648267540218)(tensorflow2 汽车油耗预测实践.assets/p6.png)]

确实在降低,但是最后的loss是50左右,是不是有点太大了?我们再看测试集的真实数据和我们神经网络的输出,横坐标是不同的车型也就是不同的参数,纵坐标是耗油量:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FqG7B4z-1648267540219)(tensorflow2 汽车油耗预测实践.assets/p7.png)]

预测的确实不准,只有少部分基本预测对了。那是不是我们做的不对呢?我们添加2行代码如下:

for epoch in range(200):
    for step,(x,y) in enumerate(train_db):
        with tf.GradientTape() as tape:
            out = model(x)
            loss = tf.reduce_mean(losses.MSE(y,out))
            loss_mae = tf.reduce_mean(losses.MAE(y,out))
           #这一行是我们新加入的,mae计算的是|y-out|的平均值


        grads = tape.gradient(loss,model.trainable_variables)
        optimizer.apply_gradients(zip(grads,model.trainable_variables))
        if(step % 10 == 0) :
            loss_list.append(loss_mae)#改损失函数为mae

    print("epoch:", epoch+1, "loss:", float(loss))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOPhgOA0-1648267540219)(tensorflow2 汽车油耗预测实践.assets/p8.png)]

可以看到停在7左右,也不是很好啊,所以我运行了一下书上的源码,并在源码上加了一张测试数据和神经网络输出的图发现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dCkDw5Jx-1648267540220)(tensorflow2 汽车油耗预测实践.assets/p9.png)]

书上的源码运行的效果也挺垃圾的,就是说我们的网络表达能力有限,数据也太少了,所以效果不怎么好,不过我们的过程以及代码是没什么问题的,也是一次不错的回归问题实战。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值