学习内容
本文对caffe 相关配置网络结构的各层代码进行了详细的介绍,并对solver超参数配置详解。
开发环境
ubantu 16.04、VMwave
网络结构相关知识
一般来说,对于卷积神经网络,涉及到神经元、卷积、池化、激活函数等相关概念。这里里简单的进行说明介绍。
神经元: 类似于大脑的神经网络,各个神经元之间连接方式组成不同的网络结构。如下图所示。
在日常生活中,当我们要思考或者回想一些之前记忆过的内容时,脑子里会出现与之相关的信息,这些在脑子里预留的和该事件有关的信息可以说对于的是在神经网络中的权重(weights)和偏置(bias)。这两个是神经网络中的重要参数。
由抽象的概念对应出一个数学关系可以表示为最简单的线型关系,
这里a代表输入,w代表权重值,b代表偏置值。而对输入和权重值相乘再相加的过程表示为卷积。在上述的公式中的求和后得到的z是传递到下个神经元的响应。一般在神经网络中经过卷积层后要进行池化操作,这样的主要目的是为了缩小数据的尺度,加快训练的速度,防止过拟合。传送到下一个神经元后,神经元经过激活函数判断是否是有效输出。常用的激活函数如下所示:
综上所述,以一个实际例子进行说明,在我们进行回想事物或者进行记忆时,要在大脑中使用相关神经元进行建立记忆的网络,并在反复记忆后在脑子里留下相关的记忆信息。对应卷积神经网络,即为:
- 初始化网络结构
- 初始化weights和biases参数
同时在神经网络训练中和实际记忆训练中,我们总是希望自己的准确度越高越好,这里在神经网络中实际上输出的准确度和标准情况的偏差值称为loss。所以在实际记忆中和神经网络训练中,我们总是想保持loss尽可能小,所以要选用特殊的记忆结构(在神经网络中也就是对应选取特定函数,选取最优的weights和biases参数),使得得到的参数尽可以能满足自己的高准确度的期望。
网络配置详解
Caffe层的定义由2部分组成:层属性与层参数。在一个神经网络中首先输入整个网络的是输入层,所以首先介绍关于输入层的相关配置信息。
输入层
对于一个网络的输入层来说,输入数据类型,输入的相关数据信息,以及相关输入的处理的配置信息。这里举出一个例子进行简单参考(主要参考example里面的cifar10的例子)。并对网络的输入层的相关参数进行说明。
layer {
name: "cifar"#层名字
type: "Data"#数据类型
##一般用bottom表示输入,top表示输出,多个top表示有多个输出
top: "data"
top: "label"
##训练网络中分为训练阶段和自测试阶段,如果没有include则表示该层即在测试中,又在训练中
include {
phase: TRAIN
}
##用一个配置文件来进行均值操作
transform_param {
mean_file: "examples/cifar10/mean.binaryproto"
transform_param {
##归一化参数
scale: 0.00390625
##1表示开启镜像,0表示关闭镜像 (也可以用ture和false表示)
mirror: 1
##剪切一个227×227的图块,在训练阶段随机裁剪,在测试阶段从中间裁剪
crop_size:227
}
}
data_param {
source: "examples/cifar10/cifar10_train_lmdb" #数据库来源
batch_size: 100 #每批次处理的个数
backend: LMDB #选用数据的名称
}
}
##HDF5的数据源
layer {
name: "data"
type: "HDF5Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
hdf5_data_param {
source: "examples/hdf5_classification/data/train.txt"
batch_size: 10
}
}
在网络层配置中,首先命名层级名字,数据类型,然后bottom
表示输入,top
表示输出。使用include{}
进行指向该层存在于训练中还是测试中,使用transform_param {}
对输入层的数据进行处理进行操作配置,包括输入数据镜像功能,随机裁剪,均值处理,归一化等操作。最后在data_param {}
中对数据的来源,输入的批次大小以及选取的数据名称进行配置。
卷积层
卷积层例子如下:
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
#设置学习率的系数
#最终的学习率是该系数乘solver.prototext中配置文件的学习率参数,
#比如bias的学习率在solver.prototext中为0.4,这里的学习率系数为2,
#所以最后的bias学习率为0.8。
##如果lr_mult有两个,则第一个表示权值的学习率,第二个表示偏置值的学习率,
##一般偏置项的学习率是权值学习率的两倍。
param {
lr_mult: 1
}
param {
lr_mult: 2
}
#卷积相关参数
convolution_param {
num_output: 32 #卷积核(filter)的个数
pad: 2 #扩充边缘,默认为0,不填充,这里为2是填充两圈
kernel_size: 5 #卷积核的大小5X5,深度由上一层决定
stride: 1 #卷积核的步长,默认为1
weight_filler {
type: "gaussian" #权值初始化,默认为constant,值为全0,很多时候可以用xavier,或者gaussian进行初始化
#type:"xavier"
}
bias_filler {
type: "constant" #偏置初始化,默认为constant,值为全0
}
}
}
在卷积层需要设置的是学习率的相关参数,使用param { lr_mult: 1 }
进行配置权值和偏置值的相关学习率系数。 convolution_param {}进行配置卷积的相关参数,包括是否填充、卷积核的大小,卷积的步长等,并加载权重值和偏置值的初始化设置。
在经过一层卷积后数据的输入输出会发生如下变化:假设输入数据为n X channel X width X height
,设经过卷积层后的conv_width
和 conv_height
为(width + 2 X pad - kernel_size)/stride +1
;对于输出的channel为num_output
。
池化层
池化层例子如下:
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
#选择池化的模式:MAX 常用的是MAX AVE;(最大池化、平均池化)
pool: MAX
#池化的核大小
kernel_size: 3
#池化步长大小 默认为1,可以设置为2,也即不重叠
stride: 2
}
}
经过池化层后的数据变化和卷积层类似假设输入数据为n X channel X width X height
,设经过池化层后的conv_width
和 conv_height
为(width + 2 X pad - kernel_size)/stride +1
;对于输出的channel为上一层的输出的channel数。因为池化大多数情况是用于进行减小数据尺度的,所以在池化的步长通常设置为2,或者别的大于1的数值,使得数据尺度变小。
激活函数层
激活函数层,对输入的数据进行激活操作。在每一个卷积池化层后连接一层激活函数。例子和讲解如下:
{
name: "relu1"
type: "ReLU"
bottom: "pool1"
top: "pool1"
}
全连接层
全连接层的输出是一个简单的向量,参数和卷积层一样,或者换句话说全连接是特殊的卷积层。如果该层为整个网络的最后一层的话,num_output的值就是输出的分类的各个种类的预测值,例子如下:
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool3"
top: "ip1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 64
weight_filler {
type: "gaussian"
std: 0.1
}
bias_filler {
type: "constant"
}
}
}
在输出测试时,可以进行检测输入的准确率。
layer {
name: "accuracy"
type: "Accuracy"
bottom: "ip2"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
softmax-loss层
例子如下,下面的例子分别输出的是loss值和似然值
##输出loss值
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "loss"
}
##输出似然值
layer {
name: "prob"
type: "Softmax"
bottom: "cls3_fc"
top: "prob"
}
reshape层
有时候,我们希望在不改变数据的时候改变输入的维度,所以可以使用reshape进行调整输入数据的参数,例子如下:
layer {
name: "reshape"
type: "Reshape"
top: "data"
reshape_param {
shape: {
dim: 0
dim: 3
dim: 32
dim: -1
}
}
}
参数解释:在shape中使用参数进行指定输入的数据的大小通道数和批次个数。
dim:0 表示维度不变,和原来相同
dim:3 把原来的维度变成3
dim: -1
由上述的例子可以假设输入了10张3通道的64X32的彩色图片),
根据上述的数据设置,批次大小没有改变,然后通道数仍然为32数据的宽为32,高自动计算和原来总量一直,因为原来为64X32,调整宽为32,这里计算后高变为了64。
dropout层
为了防止过拟合,设置dropout层。这里只需要进行配置一个参数dropout_ratio,即可完成dropout的配置,dropout就是随机挑选一些数据进行不使能,模拟神经元遗忘的过程。
layer {
name: "drop"
type: "Dropout"
top: fc1"
bottom:"fc1"
dropout_param{
dropout_ratio: 0.5
}
}
solver超参数配置详解
因为神经网络的函数往往都是都是非凸的,也就是无法通过数学解析式的方式找到最优解,这时就需要对该网络下的训练参数进行调整设置,已达到更好的训练效果。这里把网络的参数配置文件单独放在了solver.prototxt中,方便对参数进行调整优化。
在例程中给出solver的一个例子,然后对例子进行分析。
# reduce the learning rate after 8 epochs (4000 iters) by a factor of 10
# The train/test net protocol buffer definition
net: "examples/cifar10/cifar10_quick_train_test.prototxt"
# test_iter specifies how many forward passes the test should carry out.
# In the case of MNIST, we have test batch size 100 and 100 test iterations,
# covering the full 10,000 testing images.
test_iter: 100
# Carry out testing every 500 training iterations.
test_interval: 500
# The base learning rate, momentum and the weight decay of the network.
base_lr: 0.0001
momentum: 0.9
weight_decay: 0.004
# The learning rate policy
lr_policy: "fixed"
# Display every 100
display: 100
# The maximum number of iterations
max_iter: 500
# snapshot intermediate results
snapshot: 500
snapshot_format: HDF5
snapshot_prefix: "examples/cifar10/cifar10_quick"
# solver mode: CPU or
solver_mode:
首先在之前的网络配置文件中,我们配置好了各层的网络的结构,所以这里要首先进行指定网络模型文件:
##网络模型的描述文件
#也可以进行训练和测试分别指定
#train_net="xxxxxxxxxxx"
#test_net ="xxxxxxxxxxx"
net: "examples/cifar10/cifar10_quick_train_test.prototxt"
然后定义测试的间隔和训练次数,训练次数这个参数要和test_layer结合考虑,如果在test_layer的每批次的大小是100而总共的测试数据为10000张,那么参数为10000/100=100。
test_iter: 100
#每训练500次进行一次测试
test_interval: 500
接着定义学习率、动力、权重值的衰减率等参数。
#学习率
base_lr: 0.0001
#动力
momentum: 0.9
对于优化算法的选择可以忽略,默认为SGD,不同的优化算法差别不是很大。
#在caffe中一共有6种优化算法可以选择
- Stochastic Gradient Descent (type: SGD)
- AdaDelta (type: AdaDelta)
- Adaptive Gradient (type: AdaGrad)
- Adam (type: Adam)
- Nesterov’s Accelerated Gradient (type: Nesterov)
- RMSprop (type: RMSPorp)
权重衰减项,就是正则化项,作用是防止过度拟合。
weight_decay: 0.004
学习率的调整策略:
- fixed :保持base_lr不变
- step :如果设置为step,则需要设置一个strpsize,返回值为:
base_lr X gamma ^(floor (iter / stepsize))
,iter 为迭代次数。 - exp : 返回值为
base_lr X gamma ^i ter
,iter 为迭代次数。 - inv :如果设置为了inv则还需要设置power和gamma项,返回值为
base_lr * (1 + gamma * iter ) ^ (- power )
,iter 为迭代次数。 - multistep : 如果设置multistep ,还需要设置stepvalue,这个参数和step相似,step是均匀等间隔变化,而multistep 是根据stepvalue值变化。
- poly :学习率进行多项式误差。返回:
base_lr ( 1 - iter / max_iter )^ (power )
,iter 为迭代次数。 - sigmoid : 学习率进行sigmoid 衰减,返回:
base_lr (1 / ( 1 + exp ( -gamma X(iter - stepsize))))
每训练100次进行一次屏幕显示,设置为0则不显示。
display: 100
最大迭代次数:
max_iter: 500
#快照,在训练每100次的时候保存一次,如果设置0则为不保存。
snapshot: 100
snapshot_format: HDF5
snapshot_prefix: "examples/cifar10/cifar10_quick"
#选择运行模式
solver_mode: