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

前言:

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

得到的训练曲线如下:

三、模型的结果测试

这里需要使用到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方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 给keras层命名,并提取中间层输出值,保存到文档的实例

    更新: 感谢评论区提供的方案. 采用model.summary(),model.get_config()和for循环均可获得Keras的层名. 示例如下图 对于keras特定层的命名,只需在层内添加 name 即可 model.add(Activation('softmax',name='dense_1') ) # 注意 name 要放于函数内 #提取中间层 from keras.models import Model import keras layer_name = 'dense_1' #获

  • 浅谈keras中的Merge层(实现层的相加、相减、相乘实例)

    [题目]keras中的Merge层(实现层的相加.相减.相乘) 详情请参考: Merge层 一.层相加 keras.layers.Add() 添加输入列表的图层. 该层接收一个相同shape列表张量,并返回它们的和,shape不变. Example import keras input1 = keras.layers.Input(shape=(16,)) x1 = keras.layers.Dense(8, activation='relu')(input1) input2 = keras.la

  • Keras设定GPU使用内存大小方式(Tensorflow backend)

    通过设置Keras的Tensorflow后端的全局变量达到. import os import tensorflow as tf import keras.backend.tensorflow_backend as KTF def get_session(gpu_fraction=0.3): '''Assume that you have 6GB of GPU memory and want to allocate ~2GB''' num_threads = os.environ.get('OM

  • Keras实现将两个模型连接到一起

    神经网络玩得越久就越会尝试一些网络结构上的大改动. 先说意图 有两个模型:模型A和模型B.模型A的输出可以连接B的输入.将两个小模型连接成一个大模型,A-B,既可以同时训练又可以分离训练. 流行的算法里经常有这么关系的两个模型,对GAN来说,生成器和判别器就是这样子:对VAE来说,编码器和解码器就是这样子:对目标检测网络来说,backbone和整体也是可以拆分的.所以,应用范围还是挺广的. 实现方法 首先说明,我的实现方法不一定是最佳方法.也是实在没有借鉴到比较好的方法,所以才自己手动写了一个.

  • 关于keras.layers.Conv1D的kernel_size参数使用介绍

    今天在用keras添加卷积层的时候,发现了kernel_size这个参数不知怎么理解,keras中文文档是这样描述的: kernel_size: 一个整数,或者单个整数表示的元组或列表, 指明 1D 卷积窗口的长度. 又经过多方查找,大体理解如下: 因为是添加一维卷积层Conv1D(),一维卷积一般会处理时序数据,所以,卷积核的宽度为1,而kernel_size就是卷积核的长度了,这样的意思就是这个卷积核是一个长方形的卷积核. 补充知识:tf.layers.conv1d函数解析(一维卷积) 一维

  • keras小技巧——获取某一个网络层的输出方式

    前言: keras默认提供了如何获取某一个层的某一个节点的输出,但是没有提供如何获取某一个层的输出的接口,所以有时候我们需要获取某一个层的输出,则需要自己编写代码,但是鉴于keras高层封装的特性,编写起来实际上很简单,本文提供两种常见的方法来实现,基于上一篇文章的模型和代码: keras自定义回调函数查看训练的loss和accuracy 一.模型加载以及各个层的信息查看 从前面的定义可知,参见上一篇文章,一共定义了8个网络层,定义如下: model.add(Convolution2D(filt

  • keras 获取某层输出 获取复用层的多次输出实例

    官方文档很全面,搜索功能也很好.但是如果你想单独实现某个功能,根本无从搜寻.于是我写了这个笔记.从功能出发. 两个tensor经过一个layer实例会产生两个输出. a = Input(shape=(280, 256)) b = Input(shape=(280, 256)) lstm = LSTM(32) encoded_a = lstm(a) encoded_b = lstm(b) lstm.output 这个代码有错误,因为最后一行没有指定lstm这个layer实例的那个输出. >> A

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

    前言: keras是一个十分便捷的开发框架,为了更好的追踪网络训练过程中的损失函数loss和准确率accuracy,我们有几种处理方式,第一种是直接通过 history=model.fit(),来返回一个history对象,通过这个对象可以访问到训练过程训练集的loss和accuracy以及验证集的loss和accuracy. 第二种方式就是通过自定义一个回调函数Call backs,来实现这一功能,本文主要讲解第二种方式. 一.如何构建回调函数Callbacks 本文所针对的例子是卷积神经网络

  • android自定义控件和自定义回调函数步骤示例

    自定义控件的步骤: 1 View的工作原理2 编写View类3 为View类增加属性4 绘制屏幕5 响应用户消息6 自定义回调函数 java代码 复制代码 代码如下: private class MyText extends LinearLayout {    private TextView text1; /*     * private String text;     *      * public String getText() { return text; }     *     

  • js自定义回调函数

    背景分析 首先看一段js的代码,主要实现添加的时候首先通过异步请求判断是否存在,如果不存在的话,在进行添加操作: function add(url,data) { var isExited = isExited(data); if(!isExited){ addRequest(url, data); } } 当我添加一个数据的时候,我首先通过判断是否在数据库中存在(当然,如果前后台彻底分离的话,不应该前端进行业务逻辑的判断,前端只应该,用来展示数据),首先,isExited()的请求是ajax请

  • python构建自定义回调函数详解

    回调函数用起来比较爽.特别是在js中,满世界全是回调,那么在python中,怎么来优雅地实现自己的回调函数呢 下面贴一个我写的例子 class BaseHandler(object): def crawl(self, url, **kwargs): if kwargs.get('callback'): callback = kwargs['callback'] if isinstance(callback, basestring) and hasattr(self, callback): fun

  • javascript 自定义回调函数示例代码

    如果你直接在函数a里调用的话,那么这个回调函数就被限制死了.但是使用函数做参数就有下面的好处:当你a(b)的时候函数b就成了回调函数,而你还可以a(c)这个时候,函数c就成了回调函数.如果你写成了functiona(){...;b();}就失去了变量的灵活性. 复制代码 代码如下: function a(index,callback){ callback(index); } function b(index){ alert(index); } a(10000,b);

  • 谈谈JavaScript自定义回调函数

    废话不多说了,直接给大家贴代码了. 背景分析 首先看一段js的代码,主要实现添加的时候首先通过异步请求判断是否存在,如果不存在的话,在进行添加操作: function add(url,data) { var isExited = isExited(data); if(!isExited){ addRequest(url, data); } } 当我添加一个数据的时候,我首先通过判断是否在数据库中存在(当然,如果前后台彻底分离的话,不应该前端进行业务逻辑的判断,前端只应该,用来展示数据),首先,i

  • keras回调函数的使用

    目录 回调函数 fit()方法中使用callbacks参数 模型的保存和加载 通过对Callback类子类化来创建自定义回调函数 [其他]模型的定义 和 数据加载 回调函数 回调函数是一个对象(实现了特定方法的类实例),它在调用fit()时被传入模型,并在训练过程中的不同时间点被模型调用 可以访问关于模型状态与模型性能的所有可用数据 模型检查点(model checkpointing):在训练过程中的不同时间点保存模型的当前状态. 提前终止(early stopping):如果验证损失不再改善,

  • Keras自定义IOU方式

    我就废话不多说了,大家还是直接看代码吧! def iou(y_true, y_pred, label: int): """ Return the Intersection over Union (IoU) for a given label. Args: y_true: the expected y values as a one-hot y_pred: the predicted y values as a one-hot or softmax output label:

  • Kears 使用:通过回调函数保存最佳准确率下的模型操作

    1:首先,我给我的MixTest文件夹里面分好了类的图片进行重命名(因为分类的时候没有注意导致命名有点不好) def load_data(path): Rename the picture [a tool] for eachone in os.listdir(path): newname = eachone[7:] os.rename(path+"\\"+eachone,path+"\\"+newname) 但是需要注意的是:我们按照类重命名了以后,系统其实会按照图

  • javascript回调函数详解

    在高级语言层出不穷的年代, 各个语言都号称有着一切皆为对象的自豪说法, 而 js 作为一门脚本语言却相对于java等传统面向对象语言有很大的不同之处, 除了 js 诡异的继承体系之外, 最令人着迷的一个特性就是回调函数, 当然也有很多人对他诟病, 笔者认为 回调函数 和 异步 是js语言特性的两大最为突出的店, 当然正如所有优点需要满足自我的需求, 这个世界没有银弹, 比如大量的使用回调函数将会使你的代码冗余, 错乱影响代码人的视觉与思维体验. 本文是自己对学习回调函数的的体会, 难免不完善甚至

随机推荐