keras自定义回调函数查看训练的loss和accuracy方式


Posted in Python onMay 23, 2020

前言:

keras是一个十分便捷的开发框架,为了更好的追踪网络训练过程中的损失函数loss和准确率accuracy,我们有几种处理方式,第一种是直接通过 history=model.fit(),来返回一个history对象,通过这个对象可以访问到训练过程训练集的loss和accuracy以及验证集的loss和accuracy。

第二种方式就是通过自定义一个回调函数Call backs,来实现这一功能,本文主要讲解第二种方式。

一、如何构建回调函数Callbacks

本文所针对的例子是卷积神经网络Lenet-5,数据集是mnist数据集。

1.1 什么是回调函数

回调函数是一个函数的合集,会在训练的阶段中所使用。你可以使用回调函数来查看训练模型的内在状态和统计。你可以传递一个列表的回调函数(作为 callbacks 关键字参数)到 Sequential 或 Model 类型的 .fit() 方法。在训练时,相应的回调函数的方法就会被在各自的阶段被调用。

这里有两个关键的点:

(1)状态和统计:其实就是我们希望模型在训练过程中需要从过程中获取什么信息,比如我的损失loss,准确率accuracy等信息就是训练过程中的状态与统计信息;再比如我希望每一个epoch结束之后打印一些相应的自定义提示信息,这也是状态信息。

(2)各自的阶段:模型的训练一般是分为多少个epoch,然后每一个epoch又分为多少个batch,所以这个阶段可以是在每一个epoch之后执行回调函数,也可以是在每一个batch之后执行回调函数。

1.2 回调函数的本质

其实回调函数只是一个很形象的说法,它的本质是一个类,我们直接通过 history=model.fit()返回的history对象就是一个回调函数History类的对象,而History类又继承自Callback类。

回调函数的基类——Call back,他的定义如下:

class Callback(object): # 用来组建新的回调函数的抽象基类
 
 def __init__(self):
  self.validation_data = None
  self.model = None
 
 def set_params(self, params):
  self.params = params
 
 def set_model(self, model):
  self.model = model
 
 def on_epoch_begin(self, epoch, logs=None):
  pass
 
 def on_epoch_end(self, epoch, logs=None):
  pass
 
 def on_batch_begin(self, batch, logs=None):
  pass
 
 def on_batch_end(self, batch, logs=None):
  pass
 
 def on_train_begin(self, logs=None):
  pass
 
 def on_train_end(self, logs=None):
  pass

属性

params: 它是一个字典类型。训练参数, (例如,verbosity, batch size, number of epochs...)。

model: keras.models.Model 的实例。 指代被训练模型。

被回调函数作为参数的 logs 字典,它会含有于当前批量或训练轮相关数据的键。

特别需要注意的是,上面的每一个函数里面均有一个logs参数,这个参数也是记录训练信息的关键,需要注意以下几个点:

(1)logs是一个字典对象directory;

(2)在不同的方法中这个logs有不同的键值;分别如下:

on_epoch_end: 包括 acc 和 loss 的日志, 也可以选择性的包括 val_loss(如果在 fit 中启用验证),和 val_acc(如果启用验证和监测精确值)。这个用的是最多的。

on_batch_begin: 包括 size 的日志,在当前批量内的样本数量。

on_batch_end: 包括 loss 的日志,也可以选择性的包括 acc

1.3 系统预定义的回调函数

BaseLogger
TerminateOnNaN
ProgbarLogger
History
ModelCheckpoint
EarlyStopping
RemoteMonitor
LearningRateScheduler
TensorBoard
ReduceLROnPlateau
CSVLogger
LambdaCallback

二、keras实现自定义History回调函数记录loss和accuracy

2.1 回调函数的定义

# 写一个LossHistory类,保存训练集的loss和acc
# 当然我也可以完全不这么做,可以直接使用model.fit()方法返回的 history对象去做
'''Callback有6个常用的方法,这里实现其中的四个
 def on_epoch_begin(self, epoch, logs=None):
 def on_epoch_end(self, epoch, logs=None):
 def on_batch_begin(self, batch, logs=None):
 def on_batch_end(self, batch, logs=None):
 def on_train_begin(self, logs=None):
 def on_train_end(self, logs=None):
'''
class LossHistory(Callback): # 继承自Callback类
 
 '''
 在模型开始的时候定义四个属性,每一个属性都是字典类型,存储相对应的值和epoch
 '''
 def on_train_begin(self, logs={}):
  self.losses = {'batch':[], 'epoch':[]}
  self.accuracy = {'batch':[], 'epoch':[]}
  self.val_loss = {'batch':[], 'epoch':[]}
  self.val_acc = {'batch':[], 'epoch':[]}
 
 # 在每一个batch结束后记录相应的值
 def on_batch_end(self, batch, logs={}):
  self.losses['batch'].append(logs.get('loss'))
  self.accuracy['batch'].append(logs.get('acc'))
  self.val_loss['batch'].append(logs.get('val_loss'))
  self.val_acc['batch'].append(logs.get('val_acc'))
 
 # 在每一个epoch之后记录相应的值
 def on_epoch_end(self, batch, logs={}):
  self.losses['epoch'].append(logs.get('loss'))
  self.accuracy['epoch'].append(logs.get('acc'))
  self.val_loss['epoch'].append(logs.get('val_loss'))
  self.val_acc['epoch'].append(logs.get('val_acc'))
 
 def loss_plot(self, loss_type):
  '''
  loss_type:指的是 'epoch'或者是'batch',分别表示是一个batch之后记录还是一个epoch之后记录
  '''
  iters = range(len(self.losses[loss_type]))
  plt.figure()
  # acc
  plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc')
  # loss
  plt.plot(iters, self.losses[loss_type], 'g', label='train loss')
  if loss_type == 'epoch':
   # val_acc
   plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc')
   # val_loss
   plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss')
  plt.grid(True)
  plt.xlabel(loss_type)
  plt.ylabel('acc-loss')
  plt.legend(loc="upper right")
  plt.savefig("mnist_keras.png")
  plt.show()

2.2 模型的搭建以及训练

mnist数据准备

# 训练参数
learning_rate = 0.001
epochs = 10
batch_size = 128
n_classes = 10
 
# 定义图像维度reshape
img_rows, img_cols = 28, 28
 
# 加载keras中的mnist数据集 分为60,000个训练集,10,000个测试集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
 
# 将图片转化为(samples,width,height,channels)的格式
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
 
# 将X_train, X_test的数据格式转为float32
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
# 将X_train, X_test归一化0-1
x_train /= 255
x_test /= 255
 
# 输出0-9转换为ont-hot形式
y_train = np_utils.to_categorical(y_train, n_classes)
y_test = np_utils.to_categorical(y_test, n_classes)

模型的搭建以及训练

# 建立模型
model = Sequential()
 
# lenet-5
model.add(Convolution2D(filters=6, kernel_size=(5, 5), padding='valid', input_shape=(img_rows, img_cols, 1), activation='tanh'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(filters=16, kernel_size=(5, 5), padding='valid', activation='tanh'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(120, activation='tanh'))
model.add(Dense(84, activation='tanh'))
model.add(Dense(n_classes, activation='softmax'))
 
#打印模型# verbose=1显示进度条
model.summary()
 
# 编译模型
model.compile(optimizer=Adam(lr=learning_rate), loss='categorical_crossentropy',metrics=['accuracy'])
 
history = LossHistory() # 这里是使用自定义的Callback回调函数,当然本身fit函数也会返回一个history可供使用
model.fit(x_train, y_train,batch_size=batch_size,epochs=epochs, verbose=1,validation_data=(x_test, y_test),callbacks=[history])
model.save('./models/lenet5_weight.h5')

绘制训练过程loss和acc曲线

#绘制训练的acc-loss曲线

history.loss_plot('epoch') # 每一个epoch展示一次

最终的运行结果如下:

Epoch 1/10
2019-06-23 08:44:32.930737: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 0 with properties:
name: GeForce GTX 950 major: 5 minor: 2 memoryClockRate(GHz): 1.2155
pciBusID: 0000:01:00.0
totalMemory: 2.00GiB freeMemory: 1.64GiB
2019-06-23 08:44:32.937390: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1511] Adding visible gpu devices: 0
2019-06-23 08:44:37.003650: I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-06-23 08:44:37.006358: I tensorflow/core/common_runtime/gpu/gpu_device.cc:988]  0
2019-06-23 08:44:37.008076: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 0: N
2019-06-23 08:44:37.012620: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1388 MB memory) -> physical GPU (device: 0, name: GeForce GTX 950, pci bus id: 0000:01:00.0, compute capability: 5.2)
60000/60000 [==============================] - 18s 302us/step - loss: 0.2979 - acc: 0.9151 - val_loss: 0.0863 - val_acc: 0.9730
Epoch 2/10
60000/60000 [==============================] - 4s 61us/step - loss: 0.0810 - acc: 0.9753 - val_loss: 0.0611 - val_acc: 0.9808
Epoch 3/10
60000/60000 [==============================] - 4s 59us/step - loss: 0.0575 - acc: 0.9826 - val_loss: 0.0518 - val_acc: 0.9849
Epoch 4/10
60000/60000 [==============================] - 4s 59us/step - loss: 0.0451 - acc: 0.9857 - val_loss: 0.0480 - val_acc: 0.9848
Epoch 5/10
60000/60000 [==============================] - 4s 59us/step - loss: 0.0375 - acc: 0.9886 - val_loss: 0.0449 - val_acc: 0.9860
Epoch 6/10
60000/60000 [==============================] - 3s 57us/step - loss: 0.0307 - acc: 0.9907 - val_loss: 0.0392 - val_acc: 0.9863
Epoch 7/10
60000/60000 [==============================] - 4s 68us/step - loss: 0.0242 - acc: 0.9923 - val_loss: 0.0389 - val_acc: 0.9882
Epoch 8/10
60000/60000 [==============================] - 4s 75us/step - loss: 0.0192 - acc: 0.9944 - val_loss: 0.0354 - val_acc: 0.9891
Epoch 9/10
60000/60000 [==============================] - 4s 66us/step - loss: 0.0180 - acc: 0.9942 - val_loss: 0.0385 - val_acc: 0.9885
Epoch 10/10
60000/60000 [==============================] - 4s 67us/step - loss: 0.0143 - acc: 0.9956 - val_loss: 0.0516 - val_acc: 0.9860

得到的训练曲线如下:

keras自定义回调函数查看训练的loss和accuracy方式

三、模型的结果测试

这里需要使用到sklearn库,代码如下:

from keras.models import load_model
from sklearn.metrics import confusion_matrix, f1_score, precision_score, recall_score,accuracy_score
 
# 测试
model=load_model('./models/lenet5_weight.h5')
 
y_predict = model.predict(x_test, batch_size=512, verbose=1)
# y_predict = (y_predict > 0.007).astype(int)
y_predict = (y_predict > 0.01).astype(int)
y_true = np.reshape(y_test, [-1])
y_pred = np.reshape(y_predict, [-1])
 
# 评价指标
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred, average='binary')
f1score = f1_score(y_true, y_pred, average='binary')
 
# Micro F1: 将n分类的评价拆成n个二分类的评价,将n个二分类评价的TP、FP、RN对应相加,计算评价准确率和召回率,由这2个准确率和召回率计算的F1 score即为Micro F1。
# Macro F1: 将n分类的评价拆成n个二分类的评价,计算每个二分类的F1 score,n个F1 score的平均值即为Macro F1。
# 一般来讲,Macro F1、Micro F1高的分类效果好。Macro F1受样本数量少的类别影响大。
micro_f1 = f1_score(y_true, y_pred,average='micro')
macro_f1 = f1_score(y_true, y_pred,average='macro')
 
print('accuracy:',accuracy)
print('precision:',precision)
print('recall:',recall)
print('f1score:',f1score)
print('Macro-F1: {}'.format(macro_f1))
print('Micro-F1: {}'.format(micro_f1))

运行结果是:

10000/10000 [==============================] - 2s 151us/step
accuracy: 0.98813
precision: 0.8956631049654306
recall: 0.9975
f1score: 0.9438425509769599
Macro-F1: 0.9686030934161676
Micro-F1: 0.98813

以上这篇keras自定义回调函数查看训练的loss和accuracy方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中的迭代器与生成器高级用法解析
Jun 28 Python
python 实现对文件夹内的文件排序编号
Apr 12 Python
python TKinter获取文本框内容的方法
Oct 11 Python
python 定时任务去检测服务器端口是否通的实例
Jan 26 Python
python numpy存取文件的方式
Apr 01 Python
利用python3 的pygame模块实现塔防游戏
Dec 30 Python
解决python 找不到module的问题
Feb 12 Python
JupyterNotebook 输出窗口的显示效果调整方法
Apr 13 Python
Python无损压缩图片的示例代码
Aug 06 Python
Python tkinter制作单机五子棋游戏
Sep 14 Python
python函数超时自动退出的实操方法
Dec 28 Python
python利用后缀表达式实现计算器功能
Feb 22 Python
Keras设定GPU使用内存大小方式(Tensorflow backend)
May 22 #Python
tensorflow使用L2 regularization正则化修正overfitting过拟合方式
May 22 #Python
Softmax函数原理及Python实现过程解析
May 22 #Python
Python接口测试文件上传实例解析
May 22 #Python
计算Python Numpy向量之间的欧氏距离实例
May 22 #Python
python numpy矩阵信息说明,shape,size,dtype
May 22 #Python
python查看矩阵的行列号以及维数方式
May 22 #Python
You might like
一个php作的文本留言本的例子(四)
2006/10/09 PHP
php curl的深入解析
2013/06/02 PHP
php之可变变量的实例详解
2017/09/12 PHP
PHP实现的最大正向匹配算法示例
2017/12/19 PHP
固定背景实现的背景滚动特效示例分享
2013/05/19 Javascript
基于jQuery实现网页进度显示插件
2015/03/04 Javascript
JavaScript对象反射用法实例
2015/04/17 Javascript
JavaScript中eval()函数用法详解
2015/12/14 Javascript
Bootstrap布局之栅格系统详解
2016/06/13 Javascript
JavaScript的new date等日期函数在safari中遇到的坑
2016/10/24 Javascript
easyui取消表单实时验证,提交时统一验证的简单实例
2016/11/07 Javascript
利用jQuery.Validate异步验证用户名是否存在(推荐)
2016/12/09 Javascript
javascript 面向对象function详解及实例代码
2017/02/28 Javascript
基于layui数据表格以及传数据的方式
2018/08/19 Javascript
JS实现随机生成10个手机号的方法示例
2018/12/07 Javascript
JS实现简单日历特效
2020/01/03 Javascript
JavaScript实现与web通信的方法详解
2020/08/07 Javascript
python的socket编程入门
2018/01/29 Python
python flask几分钟实现web服务的例子
2019/07/26 Python
如何使用python进行pdf文件分割
2019/11/11 Python
Python求平面内点到直线距离的实现
2020/01/19 Python
python实现坦克大战
2020/04/24 Python
python3环境搭建过程(利用Anaconda+pycharm)完整版
2020/08/19 Python
CSS3中引入多种自定义字体font-face
2020/06/12 HTML / CSS
澳大利亚时尚前卫设计师珠宝在线:Amber Sceats
2017/10/04 全球购物
应届生护士求职信
2013/11/01 职场文书
教育英语专业毕业生的求职信
2014/03/13 职场文书
大学新生军训自我鉴定
2014/03/18 职场文书
《第一朵杏花》教学反思
2014/04/16 职场文书
市政工程技术专业自荐书
2014/07/06 职场文书
2014城乡环境综合治理工作总结
2014/12/19 职场文书
介绍信范文大全
2015/05/07 职场文书
我的兄弟姐妹观后感
2015/06/15 职场文书
HTML5中 rem适配方案与 viewport 适配问题详解
2021/04/27 HTML / CSS
AudioContext 实现音频可视化(web技术分享)
2022/02/24 Javascript
win10识别不了U盘怎么办 win10系统读取U盘失败的解决办法
2022/08/05 数码科技