前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【私人笔记】深度学习框架keras踩坑记

【私人笔记】深度学习框架keras踩坑记

作者头像
小草AI
发布2019-05-29 15:06:28
4.3K1
发布2019-05-29 15:06:28
举报

Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行。Keras 的开发重点是支持快速的实验。能够以最小的时间把你的想法转换为实验结果,是做好研究的关键。本人是keras的忠实粉丝,可能是因为它实在是太简单易用了,不用多少代码就可以将自己的想法完全实现,但是在使用的过程中还是遇到了不少坑,本文做了一个归纳,供大家参考。

Keras 兼容的 Python 版本: Python 2.7-3.6。

详细教程请参阅Keras官方中文文档:http://keras-cn.readthedocs.io/en/latest/

1、Keras输出的loss,val这些值如何保存到文本中去:

Keras中的fit函数会返回一个History对象,它的History.history属性会把之前的那些值全保存在里面,如果有验证集的话,也包含了验证集的这些指标变化情况,具体写法:

代码语言:javascript
复制
hist=model.fit(train_set_x,train_set_y,batch_size=256,shuffle=True,nb_epoch=nb_epoch,validation_split=0.1)
with open('log_sgd_big_32.txt','w') as f:
    f.write(str(hist.history))

我觉得保存之前的loss,val这些值还是比较重要的,在之后的调参过程中有时候还是需要之前loss的结果作为参考的,特别是你自己添加了一些自己的loss的情况下,但是这样的写法会使整个文本的取名比较乱,所以其实可以考虑使用Aetros的插件,Aetros网址,这是一个基于Keras的一个管理工具,可以可视化你的网络结构,中间卷积结果的可视化,以及保存你以往跑的所有结果,还是很方便的,就是有些不稳定,有时候会崩。。。

history对象包含两个重要属性:

epoch:训练的轮数

history:它是一个字典,包含val_loss,val_acc,loss,acc四个key。

2、关于训练集,验证集和测试集:

其实一开始我也没搞清楚这个问题,拿着测试集当验证集用,其实验证集是从训练集中抽取出来用于调参的,而测试集是和训练集无交集的,用于测试所选参数用于该模型的效果的,这个还是不要弄错了。。。在Keras中,验证集的划分只要在fit函数里设置validation_split的值就好了,这个对应了取训练集中百分之几的数据出来当做验证集。但由于shuffle是在validation _split之后执行的,所以如果一开始训练集没有shuffle的话,有可能使验证集全是负样本。测试集的使用只要在evaluate函数里设置就好了。

print model.evaluate(test_set_x,test_set_y ,batch_size=256)

这里注意evaluate和fit函数的默认batch_size都是32,自己记得修改。

总结:

验证集是在fit的时候通过validation_split参数自己从训练集中划分出来的;

测试集需要专门的使用evaluate去进行评价。

3、关于优化方法使用的问题之学习率调整

开始总会纠结哪个优化方法好用,但是最好的办法就是试,无数次尝试后不难发现,Sgd的这种学习率非自适应的优化方法,调整学习率和初始化的方法会使它的结果有很大不同,但是由于收敛确实不快,总感觉不是很方便,我觉得之前一直使用Sgd的原因一方面是因为优化方法不多,其次是用Sgd都能有这么好的结果,说明你网络该有多好啊。其他的Adam,Adade,RMSprop结果都差不多,Nadam因为是adam的动量添加的版本,在收敛效果上会更出色。所以如果对结果不满意的话,就把这些方法换着来一遍吧。

(1)方法一:通过LearningRateScheduler实现学习率调整

有很多初学者人会好奇怎么使sgd的学习率动态的变化,其实Keras里有个反馈函数叫LearningRateScheduler,具体使用如下:

代码语言:javascript
复制
def step_decay(epoch):
    initial_lrate = 0.01
    drop = 0.5
    epochs_drop = 10.0
    lrate = initial_lrate * math.pow(drop,math.floor((1+epoch)/epochs_drop))
    return lrate
lrate = LearningRateScheduler(step_decay)
sgd = SGD(lr=0.0, momentum=0.9, decay=0.0, nesterov=False)
model.fit(train_set_x, train_set_y, validation_split=0.1, nb_epoch=200, batch_size=256, callbacks=[lrate])

上面代码是使学习率指数下降,具体如下图:

(2)方式二:最直接的调整学习率方式

当然也可以直接在sgd声明函数中修改参数来直接修改学习率,学习率变化如下图:

代码语言:javascript
复制
sgd = SGD(lr=learning_rate, decay=learning_rate/nb_epoch, momentum=0.9, nesterov=True)
代码语言:javascript
复制

具体可以参考这篇文章Using Learning Rate Schedules for Deep Learning Models in Python with Keras

除此之外,还有一种学利率调整方式,即

(3)方法三:通过ReduceLROnPlateau调整学习率

代码语言:javascript
复制
keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=10, verbose=0, mode='auto', epsilon=0.0001, cooldown=0, min_lr=0)

当评价指标不在提升时,减少学习率。当学习停滞时,减少2倍或10倍的学习率常常能获得较好的效果。该回调函数检测指标的情况,如果在patience个epoch中看不到模型性能提升,则减少学习率

参数

monitor:被监测的量

factor:每次减少学习率的因子,学习率将以lr = lr*factor的形式被减少

patience:当patience个epoch过去而模型性能不提升时,学习率减少的动作会被触发

mode:‘auto’,‘min’,‘max’之一,在min模式下,如果检测值触发学习率减少。在max模式下,当检测值不再上升则触发学习率减少。

epsilon:阈值,用来确定是否进入检测值的“平原区”

cooldown:学习率减少后,会经过cooldown个epoch才重新进行正常操作

min_lr:学习率的下限

代码示例如下:

代码语言:javascript
复制
from keras.callbacks import ReduceLROnPlateau

reduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=10, mode='auto')

model.fit(train_x, train_y, batch_size=32, epochs=5, validation_split=0.1, callbacks=[reduce_lr])
4、如何用 Keras 处理超过内存的数据集?

你可以使用 model.train_on_batch(x,y) 和 model.test_on_batch(x,y) 进行批量训练与测试。请参阅 模型文档。

或者,你可以编写一个生成批处理训练数据的生成器,然后使用

model.fit_generator(data_generator,steps_per_epoch,epochs) 方法。

5、Batchnormalization层的放置问题:

BN层是真的吊,简直神器,除了会使网络搭建的时间和每个epoch的时间延长一点之外,但是关于这个问题我看到了无数的说法,对于卷积和池化层的放法,又说放中间的,也有说池化层后面的,对于dropout层,有说放在它后面的,也有说放在它前面的,对于这个问题我的说法还是试!虽然麻烦。。。但是DL本来不就是一个偏工程性的学科吗。。。还有一点是需要注意的,就是BN层的参数问题,我一开始也没有注意到,仔细看BN层的参数:

代码语言:javascript
复制
keras.layers.normalization.BatchNormalization(epsilon=1e-06, mode=0, axis=-1, momentum=0.9, weights=None, beta_init='zero', gamma_init='one')
代码语言:javascript
复制
  • mode:整数,指定规范化的模式,取0或1 0:按特征规范化,输入的各个特征图将独立被规范化。规范化的轴由参数axis指定。注意,如果输入是形如(samples,channels,rows,cols)的4D图像张量,则应设置规范化的轴为1,即沿着通道轴规范化。输入格式是‘tf’同理。 1:按样本规范化,该模式默认输入为2D

我们大都使用的都是mode=0也就是按特征规范化,对于放置在卷积和池化之间或之后的4D张量,需要设置axis=1,而Dense层之后的BN层则直接使用默认值就好了。

6、在验证集的误差不再下降时,如何中断训练?

你可以使用 EarlyStopping 回调:

代码语言:javascript
复制
from keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(monitor='val_loss', patience=2)
model.fit(x, y, validation_split=0.2, callbacks=[early_stopping])

总结:关于callbacks参数的妙用

(1)查询每隔epoch之后的loss和acc

(2)通过LearningRateScheduler实现衰减学习率或自定义衰减学习率

(3)通过EarlyStopping实现中断训练

(4)我们还可以自己定义回调函数,所为回调函数其实就是在训练完每一个epoch之后我们希望实现的操作。

7.如何「冻结」网络层?

「冻结」一个层意味着将其排除在训练之外,即其权重将永远不会更新。这在微调模型或使用固定的词向量进行文本输入中很有用。有两种方式实现:

方式一:在构造层的时候传递一个bool类型trainable参数,如下:

代码语言:javascript
复制
frozen_layer = Dense(32, trainable=False)

您可以将 trainable 参数(布尔值)传递给一个层的构造器,以将该层设置为不可训练的:

方式二:通过层对象的trainable属性去设置,如下:

代码语言:javascript
复制
x = Input(shape=(32,))
layer = Dense(32)  #构造一个层
layer.trainable = False  #设置层的trainable属性
y = layer(x)

注意:可以在实例化之后将网络层的 trainable 属性设置为 True 或 False。为了使之生效,在修改 trainable 属性之后,需要在模型上调用 compile()。及重新编译模型。

8.如何从 Sequential 模型中移除一个层?

你可以通过调用模型的 .pop() 来删除 Sequential 模型中最后添加的层:

代码语言:javascript
复制
model = Sequential()
model.add(Dense(32, activation='relu', input_dim=784))
model.add(Dense(32, activation='relu'))

print(len(model.layers))  # "2"

model.pop()
print(len(model.layers))  # "1"

总结

这次暂时先写这么多,这里面有些问题是自己遇见过,有些问题是收录自官方文档,自己觉得很有可能会采坑的地方,后面如果在再使用Keras的过程中遇见什么困难,会再进行补充。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器学习与python集中营 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、Keras输出的loss,val这些值如何保存到文本中去:
  • 2、关于训练集,验证集和测试集:
  • 3、关于优化方法使用的问题之学习率调整
  • 4、如何用 Keras 处理超过内存的数据集?
  • 5、Batchnormalization层的放置问题:
  • 6、在验证集的误差不再下降时,如何中断训练?
  • 8.如何从 Sequential 模型中移除一个层?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档