前言
镇楼:茴字有13种写法其实才是深入学习的有效方式
上篇文章我们基本完成了一个机器学习的标准模板,后续就是如何使用这个模板去解决实际问题。
本章我们尝试把数据复杂一点,先做成一元二次函数(抛物线)试试。
提示:以下是本篇文章正文内容,下面案例可供参考
一、抛物线数据生成
公式 y=-2xx + b , 生成一个100行一列的X二维数组,代码如下:
import numpy as np
import matplotlib.pyplot as plt
# fake data
x = np.linspace(-1, 1, 100)[:, np.newaxis] # shape (100, 1)
noise = np.random.normal(0, 0.2, size=x.shape)
y = -2 *np.power(x, 2) + noise # shape (100, 1) + some noise
plt.scatter(x, y)
运行返回结果如下:
二、机器学习
1.模型修改
这里做一下说明,Dense是机器学习的隐藏层,实质等于 y=wx+b + activeFunc, 之前做一次函数的训练的时候,我们没有给 Dense指定activation参数,因此默认没有激活函数,所以训练的结果就是直线 y=ax+b, 现在要求不必要是直线,所以给予通用的 relu激活函数,后续可以自行体验 不同激活函数对于学习的效果。
机器学习的目的是 拟合数据,并且不需要知道如何拟合,数据公式是什么,这里我们把模型做如下修改:
#构建模型
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(10, activation=tf.nn.relu),
tf.keras.layers.Dense(1)
])
这里我们添加了两个隐藏层, 第一个层有10个神经元,第二层只有1个神经元。神经元的数量,隐藏层的数量都属于超参,可以凭喜好任意决定。由于我们输出的结果只有一个y值,因此最后一层必须是1 。
为展示训练效果,对于PrintDot 函数做如下修改,使得可以展现学习效果的动态变化,代码中,每训练10次,使用model.predict 生成 预测的y值,重新打印一次曲线,我们可以看到曲线跟 原始数据点的拟合程度。
# 最多训练次数
max_num_epoch = 20000
# 当前训练次数
index_epoch = 0
# 在训练的时候输出进度图
class PrintDot(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs):
global index_epoch, max_num_epoch
if (epoch+1) % 10 == 0 or epoch==max_num_epoch-1:
print(epoch, logs['loss'])
y_pred = model.predict(x)
plt.cla()
plt.scatter(x, y)
plt.plot(x, y_pred, 'r-', lw=5)
plt.pause(0.1)
index_epoch = epoch
def on_train_end(self, logs=None):
print(index_epoch, logs)
2.完整代码
完整代码如下:
# -*- coding: utf-8 -*-
"""
Created on Wed Feb 24 14:02:24 2021
@author: huwp001
Dependencies:
tensorflow: 2.0
matplotlib
numpy
构造抛物线数据进行测试
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# fake data
x = np.linspace(-1, 1, 100)[:, np.newaxis] # shape (100, 1)
noise = np.random.normal(0, 0.2, size=x.shape)
y = -2 *np.power(x, 2) + noise # shape (100, 1) + some noise
#plt.scatter(x, y)
x = tf.constant(x, dtype=tf.float32)
y = tf.constant(y, dtype=tf.float32)
# 最多训练次数
max_num_epoch = 20000
# 当前训练次数
index_epoch = 0
# 在训练的时候输出进度图
class PrintDot(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs):
global index_epoch, max_num_epoch
if (epoch+1) % 10 == 0 or epoch==max_num_epoch-1:
print(epoch, logs['loss'])
y_pred = model.predict(x)
plt.cla()
plt.scatter(x, y)
plt.plot(x, y_pred, 'r-', lw=5)
plt.pause(0.1)
index_epoch = epoch
def on_train_end(self, logs=None):
print(index_epoch, logs)
# patience 值用来检查改进 epochs 的数量
# 大约意思是 如果 每次训练 loss的变动 小于 0.0001 ,则为学习没有进展
# 如果连续100次没有进展,结束训练
early_stop = tf.keras.callbacks.EarlyStopping(monitor='loss', min_delta=0.0001, patience=100)
#构建模型
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(10, activation=tf.nn.relu),
tf.keras.layers.Dense(1)
])
# 编译模型,设置了损失函数,优化器,评估工具
model.compile(
optimizer=tf.keras.optimizers.SGD(learning_rate=5e-2),
loss=tf.losses.MeanSquaredError(),
metrics=['mae', 'mse']
)
# 训练模型
# validation_split 表示边训练,边验证的比例。 Fraction of the training data to be used as validation data
history = model.fit(x, y, epochs=max_num_epoch,
# validation_split=0.2,
callbacks=[early_stop, PrintDot()],
use_multiprocessing=True,
verbose=0)
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()
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='mae Train Error')
if 'val_mae' in hist.columns:
plt.plot(hist['epoch'], hist['val_mae'],
label = 'mae Val Error')
plt.legend()
plt.xlabel('Epoch')
plt.ylabel('Mean Square Error [$MPG^2$]')
plt.plot(hist['epoch'], hist['mse'],
label='mse Train Error')
if 'val_mse' in hist.columns:
plt.plot(hist['epoch'], hist['val_mse'],
label = 'mse Val Error')
#plt.ylim([0,20])
plt.legend()
plt.show()
plot_history(history)
3.运行源码
训练后,得到如下两个图。
4.其他
尝试修改下模型的神经元数量和层数,发现基本都能训练出来,结果差距不大。
注意最后一个层,必须是 1, 表示只输出一个结果。
#构建模型v2
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(20, activation=tf.nn.relu),
tf.keras.layers.Dense(1)
])
#构建模型v3
model = tf.keras.models.Sequential([
tf.keras.layers.Dense(30, activation=tf.nn.relu),
tf.keras.layers.Dense(20, activation=tf.nn.relu),
tf.keras.layers.Dense(1)
])
tensorflow 开发环境安装 前往
总结
本章内容完成了抛物线的测试,三次甚至多次函数这样处理基本都一样,下一章我们考虑随意手绘数据进行测试。