QQ:3020889729 小蔡
这是一个学习例程的学习分享,希望对tensorflow的学习和理解有所帮助,当然还有API-keras本身的认识提升。
(本博客提供数据集下载(备份),是因为原官方数据集在下载时,出现链接超时的失败问题。)
(建议使用jupyter notebook)
(文章较长,还望根据需要合适的阅读——有效利用学习时间。)
与其说什么是回归来促进理解,我觉得了解回归的目的是什么会更有效。
回归是为了,预测出如价格或概率以及某种这样连续值/信息的输出。
比如,我给一段连续时间的食品销售量,然后在相同的条件下去预估接下来一段时间或下一次可能的结果。(这和我们上学时,接触的数学回归问题,得到一个回归方程展示其在具体问题中的实际意义是一样的。)
与分类相比,它的目的是为了预测下一段时间/空间最可能出现的结果,不同于分类需要具体的图像或者感知才进行预测是什么。
本次使用的数据集是Auto MPG数据集——我们将利用它来构建一个用于预测70年代末到80年代初汽车燃油效率的模型。
该数据集包含信息:气缸数,排量,马力以及重量。
数据集下载:https://pan.baidu.com/s/13fCzCHk3Myhdv0X70QL0Fw
提取码:bnoz
关于下载包/模块,需要说明几点(这里默认下载好了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
无论是否是去Auto MPG下载的数据集,都还是调用以下方法加载数据集本地路径:
keras.utils.get_file("auto-mpg.data", "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
如果是通过网盘下载的数据集,我们都需要将数据集放在C盘的user文件夹下的.keras文件夹里的datasets下:即:C->user(也就是用户根目录)->.keras->datasets
如果没有文件就user目录下,创建对应的文件,然后存放数据集。
代码:
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 # 可查看数据——jupyter notebook可直接显示,pycharm需要print
由于读取的数据是是一个data文件,本身就类似于表格,所以我们需要为其读取前,设置好对应的列名-标签。
column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
'Acceleration', 'Model Year', 'Origin']
数据标签含义:
代码:
column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
'Acceleration', 'Model Year', 'Origin']
DataFrame是Pandas中的一个表格型的数据结构,包含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型等),DataFrame即有行索引也有列索引,可以被看做是由Series组成的字典。
需要说明以下主要参数:依次为路径,索引名,空(无效)值设置,指定注释行,分隔符,是否考虑为False的数据
raw_dataset = pd.read_csv(dataset_path, names=column_names,
na_values = "?", comment='\t',
sep=" ", skipinitialspace=True)
参数含义对应展示:
代码:
raw_dataset = pd.read_csv(dataset_path, names=column_names,
na_values = "?", comment='\t',
sep=" ", skipinitialspace=True)
dataset = raw_dataset.copy() # 复制读取的数据,避免修改元数据
dataset.tail() # 显示表格数据——jupyter自显,pycharm需要print
主要是删除无效值和数据分类操作。
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
——如此,仅当对应的标号时,某一列中的数据才为1,满足one-hot定义:[0,0,1,0,0……1,0],只有有效数据为1,其余为零。代码:
dataset.isna().sum() # 显示无效数据分布情况
dataset = dataset.dropna() # 移除无效数据
origin = dataset.pop('Origin') # 获取分类序号——以供one-hot转换需要
dataset['USA'] = (origin == 1)*1.0
# one-hot转换:只有当列数据中值为1时,才设为1,否则为0,也就相当于一整列数据按 (origin == 1)条件转换为1 or 0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
dataset.tail() # 显示表格数据
主要是拆分数据集和获取数据状况分析信息。
代码:
train_dataset = dataset.sample(frac=0.8,random_state=0) # 拆分获得训练数据
test_dataset = dataset.drop(train_dataset.index) # 拆分获得测试数据
train_stats = train_dataset.describe() # 获取数据的一系列描述信息
train_stats.pop("MPG") # 移除MPG的数据列
train_stats = train_stats.transpose() # 行列转换——也就是相当于翻转
train_stats # 显示描述信息——jupyter自显
主要是分离训练数据的标签——从获得的数据中。
代码:
train_labels = train_dataset.pop('MPG') # 将移除的MPG列数据返回,赋值给train_labels
test_labels = test_dataset.pop('MPG')
train_labels # 显示数据
test_labels
在这次的数据中,虽然说只是一些简单数据的分析,但是数据归一化,特征归一化还是很有必要的。这样有助于数据收敛,得到更好的训练结果。
采用的计算方式如下:x为需要归一化的数据,train_stats为当前表格的描述信息——通过以下运算就实现了归一化。(0 or 1)
(x - train_stats['mean']) / train_stats['std']
这样获得的归一化数据,应该是被保留下来用与后边的其它运算。
代码:
(采用函数,方便多次调用,避免公式重复导致可读性,降低人为失误)
def norm(x):
return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset) # 获取训练数据中的归一化数据
normed_test_data = norm(test_dataset) # 获取测试归一化数据
本模型采用线性模型——包含两个紧密相连的隐藏层,以及返回单个、连续值得输出层。
为了代码结构,采用函数式编程:执行模型——网络层结构创建,以及模型编译。
# 第一层Dense的input_shape为输入层大小,前边的64为该全连接层的输出层(隐藏层)——只有最后的全连接层 layers.Dense(1)输出才是输出层,否则为隐藏层。
# activation为激活函数——这里是线性激活
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() # 创建一个模型
model.summary() # 展示模型结构
采用上边创建好的模型进行预测——查看效果。
example_batch = normed_train_data[:10] # 获取十个数据来预测
example_result = model.predict(example_batch)
example_result
效果:(看起来似乎它已经可以用来直接使用了,但其实这还不够,我们一定记得要进行拟合数据才算是一个完整的学习模型的构建完全。)
在这里添加一个输出点的函数——目的是显示训练的进程(提示:本次训练拟合周期(次数)为1000,你也可以进行更多的尝试)
# 通过为每个完成的时期打印一个点来显示训练进度
class PrintDot(keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs):
if epoch % 100 == 0: print('')
print('.', end='')
EPOCHS = 1000 # 拟合次数
# 返回的history为一个对象,内包含loss信息等
history = model.fit(
normed_train_data, train_labels,
epochs=EPOCHS, validation_split = 0.2, verbose=0,
callbacks=[PrintDot()])
拟合fit函数的参数依次为:
hist = pd.DataFrame(history.history) # 返回一个DataFrame对象,包含history的history数据
hist['epoch'] = history.epoch # 末尾添加一列数据包含epoch信息
hist.tail() # 展示表单数据
def plot_history(history):
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
plt.figure() # 创建新窗口
plt.xlabel('Epoch') # x轴标签(名字)
plt.ylabel('Mean Abs Error [MPG]') # y轴标签(名字)
plt.plot(hist['epoch'], hist['mae'],
label='Train Error') # 绘图,label为图例
plt.plot(hist['epoch'], hist['val_mae'],
label = 'Val Error') # 绘图,label为图例
plt.ylim([0,5]) # y轴长度限制
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() # 必须要有show才能显示绘图
有一个问题:也许你的图形不一样,这可能是数据训练和机器相关。
以下模型改进——在jupyter notebook中可以直接进行,而使用pycharm的朋友需要在原来的位置进行替换(early_stop添加在原fit前)
model = build_model() # 重新定义模型
# patience 值用来检查改进 epochs 的数量
# 定义callbacks的操作设置,这里采用了每10次fit,进行一次判断是否停下,判断依据是当val_loss不改变甚至降低。
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)
效果:(看得出,模型有效准确值稳定在了一定范围后,训练就停止了。)
loss, mae, mse = model.evaluate(normed_test_data, test_labels, verbose=2) # 返回第一个数据loss为损失值
print("Testing set Mean Abs Error: {:5.2f} MPG".format(mae)) # mae为我们构建网络归回预测的值——即预测的MPG
test_predictions = model.predict(normed_test_data).flatten()
# 预测信息会被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]) # 画一条y = x的直线,方便分析
error = test_predictions - test_labels # test_labels 是原始的MPG值序列,所以相减得到误差。
plt.hist(error, bins = 25) # 画矩形图——bins表示每次绘图的最大矩形数目
plt.xlabel("Prediction Error [MPG]")
_ = plt.ylabel("Count")
效果:误差主要分布在-2~2之间,0最多。说明训练模型较为合适。
这篇入门讲解到这里就全部结束了。也许我的文章写得不是很好,还有点长长的——希望对阅读到这里的你有所帮助。
如果对函数参数,或者函数方法有疑惑,需要解答的,可以评论,我尽量回答。如果有需要,我后边可以补写一篇关于这部分参数和函数的讲解。(因为这篇文章实在有点太长了。)