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 相关文章推荐
Centos5.x下升级python到python2.7版本教程
Feb 14 Python
python实现爬虫统计学校BBS男女比例(一)
Dec 31 Python
Python实现购物车功能的方法分析
Nov 10 Python
Python中的探索性数据分析(功能式)
Dec 22 Python
详解python中的Turtle函数库
Nov 19 Python
pygame游戏之旅 计算游戏中躲过的障碍数量
Nov 20 Python
Python文件读写常见用法总结
Feb 22 Python
对Python中画图时候的线类型详解
Jul 07 Python
Python利用WMI实现ping命令的例子
Aug 14 Python
详解基于python-django框架的支付宝支付案例
Sep 23 Python
python 实现return返回多个值
Nov 19 Python
Pycharm添加虚拟解释器报错问题解决方案
Oct 13 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 分库分表hash算法
2009/11/12 PHP
php多用户读写文件冲突的解决办法
2013/11/06 PHP
php+highchats生成动态统计图
2014/05/21 PHP
PHP中使用GD库创建圆形饼图的例子
2014/11/19 PHP
yiic命令时提示“php.exe”不是内部或外部命令的解决方法
2014/12/18 PHP
浅谈php命令行用法
2015/02/04 PHP
PHP面向对象之后期静态绑定功能介绍
2015/05/18 PHP
php操作access数据库的方法详解
2017/02/22 PHP
什么是PHP7中的孤儿进程与僵尸进程
2019/04/14 PHP
javascript 自定义事件初探
2009/08/21 Javascript
用按钮控制iframe显示的网页实现方法
2013/02/04 Javascript
JavaScript中的console.dir()函数介绍
2014/12/29 Javascript
更靠谱的H5横竖屏检测方法(js代码)
2016/09/13 Javascript
如何制作幻灯片(代码分享)
2017/01/06 Javascript
node.js中EJS 模板快速入门教程
2017/05/08 Javascript
详解vue2.0的Element UI的表格table列时间戳格式化
2017/06/13 Javascript
妙用Angularjs实现表格按指定列排序
2017/06/23 Javascript
微信小程序开发之IOS和Android兼容的问题
2017/09/26 Javascript
Vuex 在Vue 组件中获得Vuex 状态state的方法
2018/08/27 Javascript
微信小程序实现收货地址左滑删除
2020/11/18 Javascript
Vue实现验证码功能
2019/12/03 Javascript
vue制作toast组件npm包示例代码
2020/10/29 Javascript
python函数的5种参数详解
2017/02/24 Python
python单向链表的基本实现与使用方法【定义、遍历、添加、删除、查找等】
2019/10/24 Python
在Ubuntu 20.04中安装Pycharm 2020.1的图文教程
2020/04/30 Python
python如何求圆的面积
2020/07/01 Python
python实现登录与注册系统
2020/11/30 Python
喜诗官方在线巧克力店:See’s Candies
2017/01/01 全球购物
亚瑟士美国官网:ASICS美国
2017/02/01 全球购物
Linux如何修改文件和文件夹的权限
2012/06/27 面试题
葡萄牙语专业个人求职信
2013/12/10 职场文书
优秀教师个人总结
2015/02/11 职场文书
财务总监岗位职责范本
2015/04/03 职场文书
钢铁是怎样炼成的读书笔记
2015/06/29 职场文书
如何利用Matlab制作一款真正的拼图小游戏
2021/05/11 Python
Win10本地连接不见了怎么恢复? win10系统电脑本地连接不见了解决方法
2023/01/09 数码科技