我们这里还是使用鸢尾花分类的神经网络模型来进行讲解
1.数据集
共有数据150组,每组包括花萼长、花萼宽、花瓣长、花瓣宽4个输入特征。同时给出了,这一组特征对应的鸢尾花类别。类别包括Setosa Iris(狗尾草鸢尾),Versicolour Iris(杂色鸢尾),Virginica Iris(弗吉尼亚鸢尾)三类,分别用数字0,1,2表示。
下面是训练集的特征数据, 可以看到数据是一个150*4的数组,表示有150组数据, 每组数据有4个特征值. 其实神经网络输入的不管是声音还是图片, 最终都会转化成离散的数据, 也就是一组一组的特征值数字. 比如图片会被转化成RGB值的矩阵数组.
下面是训练集的标签数据, 它的顺序和特征数据的数组一一对应
2.模型
模型有4个输入, 对应4个特征值x1, x2, x3, x4, 3个输出y1, y2, y3,分别对应属于3个分类的概率, 所以模型的公式可以写成如下形式
y1 = w11*x1+w12*x2+w13*x3+w14*x4+b1
y2 = w21*x1+w22*x2+w23*x3+w24*x4+b2
y3 = w31*x1+w32*x2+w33*x3+w34*x4+b3
其中w是权重(weight), b 是偏差(bias).
接下来我们需要通过数据来寻找特定的模型参数值,使模型在数据上的误差尽可能小。这个过程叫作模型训练(model training)。这里我们也就是要求得比较好的w和b,使得预测分类的准确率尽可能的高.
3.损失函数
在模型训练中,我们需要衡量预测值与真实值之间的误差。通常我们会选取一个非负数作为误差,且数值越小表示误差越小。一个常用的选择是平方函数。它在评估索引为 i 的样本误差的表达式为
说白了就是衡量预测值与真实值差距大小的计算公式, 模型根据这个误差不断迭代更新参数, 使得模型的预测误差越来越小.
4.优化函数和学习率
如何不断的调整参数来使loss越来越小的方法,最终令预测尽可能接近真实值,这些方法统称为优化函数, 举例如下
在上式中, |B| 代表每个小批量中的样本个数(批量大小,batch size), η 称作学习率(learning rate)并取正数。需要强调的是,这里的批量大小和学习率的值是人为设定的,并不是通过模型训练学出的,因此叫作超参数(hyperparameter)。我们通常所说的“调参”指的正是调节超参数,例如通过反复试错来找到超参数合适的值。在少数情况下,超参数也可以通过模型训练学出。
学习率 η用来控制w和b迭代更新变化的快慢, 也就是变化增量的大小. 学习率太小, 会导致模型训练速度太慢, 太大可能会导致训练效果不佳, 难以找到最优解.
5.训练模型
cwru_train.py
import os
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import Model
from sklearn import datasets
import numpy as np
import matplotlib.pyplot as plt
#从网络中下载数据
x_train = datasets.load_iris().data
y_train = datasets.load_iris().target
#打乱数据
np.random.seed(116)
np.random.shuffle(x_train)
np.random.seed(116)
np.random.shuffle(y_train)
tf.random.set_seed(116)
#神经网络模型
class IrisModel(Model):
def __init__(self): #构造函数
super(IrisModel, self).__init__()
self.d1 = Dense(3, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2())
def call(self, x):
y = self.d1(x)
return y
model = IrisModel()
#配置模型
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
#加载模型
checkpoint_save_path = "./checkpoint/cnn_flower.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
print('-------------load the model-----------------')
model.load_weights(checkpoint_save_path)
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
save_weights_only=True,
save_best_only=True)
history = model.fit(x_train, y_train, batch_size=32, epochs=500, validation_split=0.2, validation_freq=20, callbacks=[cp_callback])
model.summary() #输出模型各层的参数状况
# 显示训练集和验证集的acc和loss曲线
train_acc = history.history['sparse_categorical_accuracy'] #训练集准确率
val_acc = history.history['val_sparse_categorical_accuracy'] #测试集准确率
train_loss = history.history['loss'] #训练集损失率
val_loss = history.history['val_loss'] #测试集损失率
plt.subplot(1, 2, 1) #画两行一列的第1个子图
plt.plot(train_loss, label='train_loss')
plt.plot(val_loss, label='val_loss')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.legend() #函数主要的作用就是给图加上图例, 要求线条有label
plt.title('Training and Validation loss')
plt.subplot(1, 2, 2) #画两行一列的第1个子图
plt.plot(train_acc, label='train_acc')
plt.plot(val_acc, label='val_acc')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.legend() #函数主要的作用就是给图加上图例, 要求线条有label
plt.title('Training and Validation accuracy')
plt.show()
下面进行一些函数的介绍
1.model.compile
model.compile()方法用于在配置训练方法时,告知训练时用的优化器、损失函数和准确率评测标准.
model.compile( optimizer = 优化器,
loss = 损失函数,
metrics = ["准确率”] )
其中:
1. optimizer可以是字符串形式给出的优化器名字,也可以是函数形式,使用函数形式可以设置学习率、动量和超参数
例如:
“sgd” 或者 tf.optimizers.SGD( lr = 学习率,
decay = 学习率衰减率,
momentum = 动量参数)
“adagrad" 或者 tf.keras.optimizers.Adagrad(lr = 学习率,decay = 学习率衰减率)
”adadelta" 或者 tf.keras.optimizers.Adadelta(lr = 学习率,decay = 学习率衰减率)
“adam" 或者 tf.keras.optimizers.Adam(lr = 学习率,decay = 学习率衰减率)
2. loss可以是字符串形式给出的损失函数的名字,也可以是函数形式
例如:
"mse" 或者 tf.keras.losses.MeanSquaredError()
"sparse_categorical_crossentropy" 或者tf.keras.losses.SparseCatagoricalCrossentropy(from_logits = False)
损失函数经常需要使用softmax函数来将输出转化为概率分布的形式,
在这里from_logits代表是否将输出转为概率分布的形式,为False时表示
转换为概率分布,为True时表示不转换,直接输出
3. Metrics标注网络评价指标
例如:
"accuracy" : y_ 和 y 都是数值,如y_ = [1] y = [1] #y_为真实值,y为预测值
"sparse_accuracy" : y_和y都是以独热码和概率分布表示,如y_ = [0, 1, 0], y = [0.100, 0.600, 0.300]
"sparse_categorical_accuracy" : y_是以数值形式给出,y是以独热码给出,如y_ = [1], y = [0.100, 0.600, 0.300]
2.model.fit
将训练数据在模型中训练一定迭代次数,返回一个历史训练数据,即loss和测量指标
def fit(self,
x=None,
y=None,
batch_size=None,
epochs=1,
verbose=1,
callbacks=None,
validation_split=0.,
validation_data=None,
shuffle=True,
class_weight=None,
sample_weight=None,
initial_epoch=0,
steps_per_epoch=None,
validation_steps=None,
validation_freq=1,
max_queue_size=10,
workers=1,
use_multiprocessing=False,
**kwargs):
参数 | 作用 |
---|---|
x | 输入数据。如果模型只有一个输入,那么x的类型是numpy array,如果模型有多个输入,那么x的类型应当为list,list的元素是对应于各个输入的numpy array |
y | 标签,numpy array |
batch_size | 整数,指定进行梯度下降时每个batch包含的样本数。训练时一个batch的样本会被计算一次梯度下降,使目标函数优化一步。 |
epochs | 整数,训练终止时的epoch值,训练将在达到该epoch值时停止,当没有设置initial_epoch时,它就是训练的总轮数,否则训练的总轮数为epochs - inital_epoch |
verbose | 日志显示,0为不在标准输出流输出日志信息,1为输出进度条记录,2为每个epoch输出一行记录 |
callbacks | list,其中的元素是keras.callbacks.Callback的对象。这个list中的回调函数将会在训练过程中的适当时机被调用,参考回调函数 |
validation_split | 0~1之间的浮点数,用来指定训练集的一定比例数据作为验证集。验证集将不参与训练,并在每个epoch结束后测试的模型的指标,如损失函数、精确度等。注意,validation_split的划分在shuffle之前,因此如果你的数据本身是有序的,需要先手工打乱再指定validation_split,否则可能会出现验证集样本不均匀。 |
validation_data | 形式为(X,y)的tuple,是指定的验证集。此参数将覆盖validation_spilt。 |
shuffle | 布尔值或字符串,一般为布尔值,表示是否在训练过程中随机打乱输入样本的顺序。若为字符串“batch”,则是用来处理HDF5数据的特殊情况,它将在batch内部将数据打乱。 |
class_weight | 字典,将不同的类别映射为不同的权值,该参数用来在训练过程中调整损失函数(只能用于训练) |
sample_weight | 权值的numpy array,用于在训练时调整损失函数(仅用于训练)。可以传递一个1D的与样本等长的向量用于对样本进行1对1的加权,或者在面对时序数据时,传递一个的形式为(samples,sequence_length)的矩阵来为每个时间步上的样本赋不同的权。这种情况下请确定在编译模型时添加了sample_weight_mode=’temporal’。 |
initial_epoch | 从该参数指定的epoch开始训练,在继续之前的训练时有用。 |
steps_per_epoch | 一个epoch包含的步数(每一步是一个batch的数据送入),当使用如TensorFlow数据Tensor之类的输入张量进行训练时,默认的None代表自动分割,即数据集样本数/batch样本数。 |
validation_steps | 在验证集上的step总数,仅当steps_per_epoch被指定时有用 |
validation_freq | 指使用验证集实施验证的频率。当等于1时代表每个epoch结束都验证一次 |
max_queue_size | 整数。仅用于生成器或 keras.utils.Sequence 输入。生成器队列的最大大小。如果未指定,“最大队列大小”将默认为10 |
workers | 整数。仅用于生成器或“keras.utils.Sequence”输入。使用基于进程的线程时,要加速的最大进程数。如果未指明,则将默认为1。如果为0,将在main上执行生成器线程。 |
use_multiprocessing | 布尔型。仅用于生成器或“keras.utils.Sequence”输入。如果为“真”,则使用基于进程的线程。如果未指定,将默认为False。注意,因为这个实现依赖于多重处理,所以您不应该将不可选择的参数传递给生成器,因为它们不容易传递给子进程。 |
**kwargs | 用于向后兼容 |
3.history
history = model.fit, 返回一个History对象, 该对象包含两个属性,分别为epoch和history,epoch为训练轮数。
History所包含的内容是由compile参数的metrics确定的, history对象的history内容(history.history)是字典类型,键的内容受metrics的设置影响,值的长度与epochs值一致。
metrics | history.history |
---|---|
metrics=[‘accuracy’]时 | history字典类型,包含val_loss,loss,val_acc, acc四个key值 |
metrics=[‘sparse_categorical_accuracy’]时 | history字典类型,包含sparse_categorical_accuracy, val_sparse_categorical_accuracy, loss, val_loss四个key值 |
6.进行预测
模型训练后会生成模型文件, 我们就可以使用这个模型进行预测了
cnn_flower_predict.py
import os
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import Model
from sklearn import datasets
import numpy as np
#从网络中加载数据
x_train = datasets.load_iris().data
y_train = datasets.load_iris().target
#打乱数据
np.random.seed(116)
np.random.shuffle(x_train)
np.random.seed(116)
np.random.shuffle(y_train)
tf.random.set_seed(116)
class IrisModel(Model):
def __init__(self): #构造函数
super(IrisModel, self).__init__()
self.d1 = Dense(3, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2())
def call(self, x):
y = self.d1(x)
return y
model = IrisModel()
#模型配置
model.compile(optimizer=tf.keras.optimizers.SGD(lr=0.1),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])
##加载模型文件或新建模型文件, 如果模型不存在就新建模型文件
#如果模型存在, 则在加载使用已有模型文件, 所以当修改神经网络的代码后, 需要将模型文件删除, 否则会出错
checkpoint_save_path = "./checkpoint/cnn_flower.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
print('-------------load the model-----------------')
model.load_weights(checkpoint_save_path)
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
save_weights_only=True,
save_best_only=True)
#取数据集中的前10组数据进行预测
y_pre = model.predict(x_train[0:10])
print("------------预测样本数据----------")
print(x_train[0:10])
print("------------预测结果概率----------")
print(y_pre)
print("------------预测结果分类----------")
print(np.argmax(y_pre, axis=1))
下面进行一些函数的介绍
1.ModelCheckpoint
我们训练完模型之后,一般会需要保存模型或者只保存权重文件。可以利用keras中的回调函数ModelCheckpoint进行保存。
keras.callbacks.ModelCheckpoint(
filepath,
monitor='val_loss',
verbose=0,
save_best_only=True,
save_weights_only=False,
mode='auto',
period=1
)
参数 | 作用 |
---|---|
filepath | 模型保存在本地的路径 |
monitor | 需要监视的值,val_accuracy、val_loss或者accuracy |
verbose | 信息展示模式 |
save_best_only | 当设置为True时,表示当模型这次epoch的训练评判结果(monitor的监测值)比上一次保存训练时的结果有提升时才进行保存。 |
save_weights_only | 若设置为True,占用内存小(只保存模型权重),但下次想调用的话,需要搭建和训练时一样的网络。若设置为False,占用内存大(包括了模型结构和配置信息),下次调用可以直接载入,不需要再次搭建神经网络结构。 |
mode | ‘auto’,‘min’,‘max’之一,在save_best_only=True时决定性能最佳模型的评判准则,例如,当监测值为val_acc时,模式应为max,当检测值为val_loss时,模式应为min。在auto模式下,评价准则由被监测值的名字自动推断。 |
period | 填写 int 值,如果填写 period=3,指模型每训练3个epoch,进行保存一次。 |
2.model.predict
输入数据, 用于预测的函数, 输出预测值
predict(
x,
batch_size=None,
verbose=0,
steps=None,
callbacks=None,
max_queue_size=10,
workers=1,
use_multiprocessing=False
)
参数 | 作用 |
---|---|
x | 输入样本,格式可以是Numpy数组(或类似array的数组)或数组列表(如果模型具有多个输入). TensorFlow张量或张量列表(如果模型具有多个输入), tf.data数据集, 生成器或keras.utils.Sequence实例 |
batch_size | 每个梯度更新的样本数。如果未指定,batch_size将默认为32 |
verbose | 信息展示模式,0或1 |
steps | 宣布预测回合完成之前的步骤总数(样本批次)。忽略默认值None |
callbacks | 预测期间应用的回调函数列表 |
max_queue_size | 仅用于generator或keras.utils.Sequence输入。生成器队列的最大大小。如果未指定,max_queue_size将默认为10 |
workers | 仅用于generator或keras.utils.Sequence输入。使用基于进程的线程时,要启动的最大进程数。如果未指定,worker将默认为1。如果为0,将在主线程上执行生成器 |
use_multiprocessing | 仅用于generator或keras.utils.Sequence输入。如果为True,则使用基于进程的线程。如果未指定,则use_multiprocessing将默认为False。 |
3.model.evaluate
输入数据和标签, 输出损失和精确度. 使用这个函数我们可以得到已生成模型的损失率和准确度 .
loss, accuracy = model.evaluate(x_train, y_train)
print('loss=', loss)
print('accuracy=', accuracy)