? 前情回顾
MLK | 那些常见的特征工程
MLK | 模型评估的一些事
MLK | 机器学习的降维”打击“
MLK | 非监督学习最强攻略
MLK | 机器学习采样方法大全
MLK | 一文理清 深度学习前馈神经网络
MLK | Keras 入门深度学习逢看必会
上一篇文章讲解了如何简易入门Keras,大致给出了一个深度学习模型,但对于模型如何调参就没有太过于深入讲解,今天继续写一篇文章来整理下 Keras 深度学习模型的调参教程,希望可以对大家有所帮助。
00- 初始化一个NN模型
我们还是使用 MNIST 数据集,这一次训练和测试数据的样本量都一样,都是10000。
代码语言:javascript复制# 导入相关库
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense,Dropout,Activation
from keras.optimizers import SGD,Adam
from keras.utils import np_utils
from keras.datasets import mnist
# 封装数据读取及预处理的代码
def load_data():
(x_train,y_train),(x_test,y_test)=mnist.load_data()
number=10000
x_train=x_train[0:number]
y_train=y_train[0:number]
x_train=x_train.reshape(number,28*28)
x_test=x_test.reshape(x_test.shape[0],28*28)
x_train=x_train.astype('float32')
x_test=x_test.astype('float32')
y_train=np_utils.to_categorical(y_train,10)
y_test=np_utils.to_categorical(y_test,10)
x_train=x_train
x_test=x_test
x_train=x_train/255
x_test=x_test/255
return (x_train,y_train),(x_test,y_test)
# 调用方法
(x_train,y_train),(x_test,y_test)=load_data()
print(x_train.shape)
print(x_test.shape)
'''
随便初始化一个NN模型
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='mse',optimizer=SGD(lr=0.1),metrics=['accuracy'])
model.fit(x_train,y_train,batch_size=100,epochs=20)
train_result = model.evaluate(x_train,y_train,batch_size=10000)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
output:
可以看出结果还是很烂的,Train 和 Test都只是有13%左右的准确度。
01- Loss Function 入手
尝试着从损失函数开始入手,原模型参数的Loss Function为 MSE,如果对损失函数的原理比较清晰的同学可能就会发现了问题,MSE为均方误差,往往都是用于线性回归的损失函数,而这里是多分类问题,当然就不是十分适合了,所以我们可以换成 categorical_crossentropy 。
代码语言:javascript复制'''
修改下 Loss Function
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
output:
可以看出,换了合适的Loss Function,模型效果有了很大的提升,看来机器学习还是需要懂些理论知识的,不然盲目调参并不是明智的选择。
02- batch_size 入手
这个参数在Keras深度学习模型中还是蛮重要的,我们在深度学习模型中做 梯度下降,并不是真的就是 minimize total loss(最小化总损失),而通常的做法是会把训练数据随机分成 N 个 mini-batch,并行训练模型。在了解这个参数前,先介绍下 mini-batch 的原理。
Mini-batch 指的是从一堆训练数据中,随机取出 N/batch_size 个数据来计算偏微分并更新参数,可以参考下面的步骤:
1)随机初始化神经网络的参数(与 Stochastic gradient descent一样)
2)随机选择第一个batch,计算其 loss,计算偏微分,根据 L` 更新参数
3)继续随机选择一个batch,计算其 loss,计算偏微分,根据 L`` 更新参数
4)重复上述2-3步,直到所有的batch都被更新了一次,一个epoch才算结束
代码语言:javascript复制'''
增大 batch_size
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=1000,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
output:
设置太大的batch_size,训练效率是超级快了,但是效果却很差。而按照batch_size的原理,如果减小batch_size的值,效率会变慢很多,但效果还蛮不错。
代码语言:javascript复制'''减小 batch_size'''
model.fit(x_train,y_train, batch_size=10, epochs=20)
03- deep layer 入手
所谓深度学习,正常来说“越深越好”,但也要看实际情况,太深的话其实对资源的消耗也很大,同时也不一定可以得到比较好的结果,也就是所谓的“性价比低”。先前的隐含层都只有2层,下面我们用for循环增加隐含层到 10 层 ,看看效果。
代码语言:javascript复制'''
增加隐含层数量至10
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='sigmoid'))
for _ in range(10):
model.add(Dense(units=633,activation='sigmoid'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
output:
效果是出奇的差,从原先的85%左右掉到11%左右,于是我试着变少一些,比如3层、5层什么的,效果也都还是不行,看来并不是盲目地增加隐含层数量来提升效果的哦。
04- activation function 入手
这里是激活函数,还是建议阅读先前的理论文章《MLK | 一文理清 深度学习前馈神经网络》,看下几种激活函数的差异,主要有Sigmoid、Tanh、ReLU激活函数,这里我把 Sigmoid都换成了 relu。
代码语言:javascript复制'''
修改下 Loss Function
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='relu'))
for _ in range(2):
model.add(Dense(units=633,activation='relu'))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=SGD(lr=0.1),
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
output:
效果杠杠的,可以达到95% 了。
05- optimizer 入手
优化器的选择有好多种,比如我们一开始用的 SGD,除此之外还有:Adam、RMSprop、Adagrad、Adamax、Nadam,这些都是gradient descent的变形体,我们换另一个优化器看看,比如Adam:
代码语言:javascript复制model.compile(loss='categorical_crossentropy',
optimizer='Adam',
metrics=['accuracy'])
output:
效果还是蛮不错的。
06- Dropout 入手
dropout其实就是为了减少过拟合情况,是最简单的神经网络正则化方法,可以应用于输入层和隐含层,取值在0-1之间,一般会在0.2-0.7之间比较好。
代码语言:javascript复制'''
修改下 Dropout
'''
model=Sequential()
model.add(Dense(input_dim=28*28,units=633,activation='relu'))
model.add(Dropout(0.7))
for _ in range(2):
model.add(Dense(units=633,activation='relu'))
model.add(Dropout(0.7))
model.add(Dense(units=10,activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='Adam',
metrics=['accuracy'])
model.fit(x_train,y_train,
batch_size=100,
epochs=20)
train_result = model.evaluate(x_train,y_train)
test_result = model.evaluate(x_test,y_test)
print('TRAIN Accuracy:',train_result[1])
print('TEST Accuracy:',test_result[1])
output:
我拿的是上面小节的代码,加了0.7的Dropout,效果有所下降,但确实Train和Test的差距会变小很多。
References
[1] 【Keras】减少过拟合的秘诀——Dropout正则化
https://www.jianshu.com/p/3745827decdf
[2] 台大 李宏毅机器学习 19节