【原创】Liu_LongPo
转载请注明出处【CSDN】http://blog.csdn.net/llp1992
注:新版本的keras使用时,可能会报max_pool_2d() got an unexpected keyword argument ‘mode 这个错误,这是旧版本的theano的一个bug,只需要到theano的官网下载最新源码重新编译安装即可
另:这份代码是旧版本的Keras,新版本的keras有较大改动,这份代码已经不能直接运行,可以根据模型自己编写代码即可。
数据库介绍 |
Cifar-10是由Hinton的两个大弟子Alex Krizhevsky、Ilya Sutskever收集的一个用于普适物体识别的数据集。
Cifar-10由60000张32*32的RGB彩色图片构成,共10个分类。50000张训练,10000张测试(交叉验证)。这个数据集最大的特点在于将识别迁移到了普适物体,而且应用于多分类(姊妹数据集Cifar-100达到100类,ILSVRC比赛则是1000类)。
数据集可到 cifar 官网 下载。
同已经成熟的人脸识别相比,普适物体识别挑战巨大,数据中含有大量特征、噪声,识别物体比例不一。
开发工具 |
现在流行的DeepLearning库挺多的,现在 GitHub 上关注最火的应该是 caffe 。不过我个人觉得caffe封装的太死了,很多东西都封装成库,要学习原理的话,还是得去看看 Theano 版本的。
我个人使用的库是朋友推荐的 Keras ,是基于 Theano的,优点是使用方便,可以快速开发。
网络框架 |
网络框架参考 caffe 的cifar-10的框架,但自己做了修改。
框架如下:
layer1 Conv1:
kernel :32 ,kernel size : 5 , activation : relu ,dropout : 0.25
layer2 Conv2:
kernel: 32,kernel size: 5, activation : relu ,dropout : 0.25
layer3 MaxPooling1: poolsize:2
layer4 Conv3:
kernel: 64,kernel size: 3, activation : relu ,dropout : 0.25
layer5 MaxPooling2: poolsize:2
layer6: full connect 512 ,activation :tanh
layer7: softmax
训练结果 |
对比 Alex的论文里 的训练误差图走向,论文里说,用 relu 替换 tanh 作为激活函数可以使算法快速收敛,不过实际中我并不感觉得出可以快多少。
或者说,看loss的走向并没有论文中的那么好,当然我的框架跟作者的不完全相同。
进行 35 次迭代,最终训练准确率为 0.86,交叉验证准确率为: 0.78
感觉已经快过拟合了,于是没有再增加迭代次数。
训练要点 |
- 必须要做的,对cifar-10数据库进行预处理,也就是去均值,归一化以及做白化处理。
- 用 relu 替换 tanh 作为激活函数之后,必须讲learningrate 调低一个数量级,否则会出现过拟合。
- relu 应该使用在什么layer呢?答案是除了最后一层的 softmax 要用tanh之外,其他层都可以。
- 关于Dropout的比例,论文中说是 0.5 ,但是我却发现 0.25 效果更好,这可能需要根据数据进行调整
激活函数 |
深度学习中的激活函数有:sigmoid,tanh,ReLUs,Softplus
目前最好的是 rectified linear units (ReLUs)修正线性单元
多层的神经网络如果用sigmoid或tanh激活函数也不做pre-training的话会因为 gradient vanishing problem 而会无法收敛。使用ReLU则这没有这个问题。
预训练的用处:规则化,防止过拟合;压缩数据,去除冗余;强化特征,减小误差;加快收敛速度。
标准的sigmoid输出不具备稀疏性,需要用一些惩罚因子来训练出一大堆接近0的冗余数据来,从而产生稀疏数据,例如L1、L1/L2或Student-t作惩罚因子。因此需要进行无监督的预训练。
而ReLU是线性修正,公式为:g(x) = max(0, x),函数图如下。它的作用是如果计算出的值小于0,就让它等于0,否则保持原来的值不变。这是一种简单粗暴地强制某些数据为0的方法,然而经实践证明,训练后的网络完全具备适度的稀疏性。而且训练后的可视化效果和传统方式预训练出的效果很相似,这也说明了ReLU具备引导适度稀疏的能力
—Dropout 的作用 |
Dropout: 防止过拟合,做法:在训练时,FP中随机将Hidden layer 中的节点输出值按照比例随机设置为0,同时BP过程中相对应的被置为0的Hidden layer 节点的误差也为0,稀疏化。这样会使得神经元不得不去学习一些更加具备鲁棒性以及更加抽象的features.
训练代码 |
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 27 11:27:34 2015
@author: lab-liu.longpo
"""
from __future__ import absolute_import
from __future__ import print_function
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.optimizers import SGD, Adadelta, Adagrad
from keras.utils import np_utils, generic_utils
import matplotlib.pyplot as plt
import numpy as np
import scipy.io as sio
d = sio.loadmat('data.mat')
data = d['d']
label = d['l']
data = np.reshape(data,(50000,3,32,32))
label = np_utils.to_categorical(label, 10)
print ('finish loading data')
model = Sequential()
model.add(Convolution2D(32, 3, 5, 5, border_mode='valid'))
model.add(Activation('relu'))
#model.add(MaxPooling2D(poolsize=(2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(32, 32, 5, 5, border_mode='valid'))
model.add(Activation('relu'))
model.add(MaxPooling2D(poolsize=(2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(64, 32, 3, 3, border_mode='valid'))
model.add(Activation('relu'))
model.add(MaxPooling2D(poolsize=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(64*5*5, 512, init='normal'))
model.add(Activation('tanh'))
model.add(Dense(512, 10, init='normal'))
model.add(Activation('softmax'))
sgd = SGD(l2=0.001,lr=0.0065, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd,class_mode="categorical")
#checkpointer = ModelCheckpoint(filepath="weight.hdf5",verbose=1,save_best_only=True)
#model.fit(data, label, batch_size=100,nb_epoch=10,shuffle=True,verbose=1,show_accuracy=True,validation_split=0.2,callbacks=[checkpointer])
result = model.fit(data, label, batch_size=50,nb_epoch=35,shuffle=True,verbose=1,show_accuracy=True,validation_split=0.2)
#model.save_weights(weights,accuracy=False)
# plot the result
plt.figure
plt.plot(result.epoch,result.history['acc'],label="acc")
plt.plot(result.epoch,result.history['val_acc'],label="val_acc")
plt.scatter(result.epoch,result.history['acc'],marker='*')
plt.scatter(result.epoch,result.history['val_acc'])
plt.legend(loc='under right')
plt.show()
plt.figure
plt.plot(result.epoch,result.history['loss'],label="loss")
plt.plot(result.epoch,result.history['val_loss'],label="val_loss")
plt.scatter(result.epoch,result.history['loss'],marker='*')
plt.scatter(result.epoch,result.history['val_loss'],marker='*')
plt.legend(loc='upper right')
plt.show()
今天将自己以前实现的机器学习以及深度学习算法放到 GitHub 上,本文的数据集以及数据预处理,训练代码等也将会放到GitHub上,如果觉得有用就请给个star。