Tensorflow2.1入门(基于API)实战3

在复现了两个官网分类实战以后,这一次的实战是一个回归问题(Regression),代码有点多,感觉第一次看还是有点费力。不过耐心的磨了一天感觉还可以。个人本着遇到啥学到哪的原则,回归问题中遇到的参数大多会给出解释(主要是为了方便自己复习)。好的,接下来看看根据API整理的代码吧。传!送!门!

问题描述&数据集介绍:

这次我们的数据集跟车有关,数据集给出了70年代末到80年代初的汽车信息,我们需要构建一个模型,在给定汽车的气缸,排量,马力,重量啊之类的情况下,给出汽车的燃油效率(MPG)。与之前问题的不同之处在于,这是一个回归问题,而非分类问题。好的,让我们开始吧()。

必要包的导入&数据集准备:

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
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
dataset_path = keras.utils.get_file("auto-mpg.data","http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin']

以上是我们这次数据集中汽车设计的关键词名称,包括加速度,重量啊之类的。
然后我们把数据集的csv文件读一下

raw_dataset=pd.read_csv(dataset_path,names=column_names,na_values="?",comment='\t',sep=" ",skipinitialspace=True)
dataset=raw_dataset.copy()
dataset.tail()

可以通过dataset_path读出csv文件所在路径,用记事本打开查看一下。

这里给出读csv文件的注释:(天哪官方给出这个函数的参数将近20个)pd.read_csv(dataset_path,names,na_value,comment,sep)
dataset_path:csv文件所在的路径。
names:关键词序列,按照这个例子来理解,就是重量啊,MPG啊之类的。
na_value:当做无进行处理的值,在文件中用“?”表示的视为空值。
comment:这个参数我也不怎么理解,这个单词先理解为注释吧,他只能是一个符号,视为注释的符号。
sep:间隔符,在这里的csv文件中可以看出就是“ ”。
skipinitialspace:跳过间隔符以后的空格。

为了保护原始数据集,我们不直接使用数据集而是用dataset=raw_dataset.copy()来进行拷贝。
为了保证数据集的完好,用dataset.tail()来查看数据集的尾部数据。
这里提一下,tail()中不加参数默认显示5条,括号中可以加正整数。

数据清洗:

dataset=dataset.dropna()

为了让实例得到简化,我们抛弃了包含未知的数据,即包含na_values的数据。(官网把这一步叫做数据清洗——高级感.jpg)

origin=dataset.pop('Origin')
dataset['USA']=(origin==1)*1.0
dataset['Europe']=(origin==2)*1.0
dataset['Japan']=(origin==3)*1.0
dataset.tail()

在关键词中,有一栏叫做Origin(产地),根据资料我们得知,1表示美国车,2表示欧洲车,3表示日本车。嗯,然后我们将它转化为one_hot编码,输入代码就可以看到运行结果了,Origin一栏变成了三栏。

训练集与测试集:

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

这里我们把数据集进行八二开(frac=0.8),按顺序(random_state=0)分出训练集,用dataset.drop()drop出剩余的数据用于测试集。(是不是很形象)

我们的目的是构建一个模型,使得他可以预测汽油消耗效率,所以我们要把第一栏的MPG去掉,才能构建得到训练集与测试集。(就好像把一份有答案的练习盖掉答案一样,就是一份练习了。)

train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()#转置
train_stats

#describe()的作用只是将数据的格式按照表格表示而已,pop就是将这一栏的数据删除,transpose是求转置,最后输出数据看一看效果。

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

为了方便模型的训练,在训练之前我们将所有的数值都先归一化一下,下面是归一化函数(减去总体均值,除以总体方差,就可以使得样本的均值为0,方差为1)。

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

构建网络:

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

作为输入层,需要设置输入维度的大小,其它层不需要。这里的train_dataset.keys()就是关键词,重量啊,加速度之类的。
optimizer使用的算法是RMSprop算法,这个具体也不是很懂,暂时先用着吧。
损失函数采用的是mean square error(均方差),metrics观测的是mean abstract error(平均误差绝对值)和均方差。

model=build_model()
model.summary()

好了(~ ̄▽ ̄)~。

训练模型:

这里我们使用打印点来表示训练的进度,这里的callbacks我也不是太懂,大概就是用于训练过程中的一个反馈吧。

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()])

这里的print(‘.’,end=’’)问题不大,end是一个跟换行有关的操作,换行时不适用换行符,而是加上一个空字符串。
callbacks中调用了打点函数,验证集(不是测试集)占比0.2。
好啦,我们可以开始对模型进行测试了。

模型测试:

这里做出了训练轮数与绝对偏差,均值方差的曲线

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]')
    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)

![在这里插入图片描述](http


s://img-blog.csdnimg.cn/2020012820571852.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDMyMjgyNA==,size_16,color_FFFFFF,t_70)

# 回调调试:

这里我们可以看到,在训练次数超过一定程度时,误差反而上升了,很可能存在overfitting(过拟合),因此我们使用回调函数,让误差在开始上升以前停止。

```python
model=build_model()
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()])

patience=10,意味着在10轮训练中若val_loss(验证集损失)不再下降,停止迭代。

测试集测试:

loss,mae,mse=model.evaluate(normed_test_data,test_labels,verbose=2)
print("Testing set Mean Abs Error:{:5.2f}MPG".format(mae))

好了,终于得到了我们的测试结果,接下来我们把结果用图表表示下。

图表表示:

test_predictions=model.predict(normed_test_data).flatten()
plt.scatter(test_labels,test_predictions)#生成散点图
plt.xlabel('True Value[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]) # _表示实线,后面是画出一条x,y范围限定的线条,只是让图显示的明显一些,与计算无关。

在这里插入图片描述好了,终于好了。。。好累啊。

为了让错误预测的分布明显一些,我们用一个柱状图表示,估计的偏差应该是一个随机变量,因此分布大致应该呈现正态分布。

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

结语:

这个在做这个实战的时候,理解还是花了一些时间,但总体而言并没有很多的新内容,亮点如下:
1:对过拟合进行了回调处理。
2:作图的函数得到了应用。
3:csv文件的读取以及pop,drop等处理
4:当然还有这是一个回归,而非分类,在回归中,我们把需要预测的一项参数作为label。(都是supervised learning)
一篇博客写下来还是蛮累的。。但是还是有点成就感哈(虽然是照着API来)O(∩_∩)O
有错误希望大家能帮忙指出啊,(。_。)。谢谢!
改了好多次代码,jupyter notebook跑起来应该没有问题的。。。。。。吧

发布了3 篇原创文章 · 获赞 3 · 访问量 1200

猜你喜欢

转载自blog.csdn.net/weixin_44322824/article/details/104101690