【Caffe层次结构及参数介绍——以MNIST为例】
要熟练使用caffe,最重要的就是学会配置文件prototxt的编写。
以MNIST为例,其模型的层次结构通过examples/mnist文件目录下的lenet_train_test.prototxt文件来定义。如下图所示:
层(layer)的类型有很多种,比如data(数据层),convolution(卷积层),pooling(池化层)、inner product(全连接层)、softmax-loss(softmax损失层),层之间的数据流动是以Blobs的方式进行(Blobs是一个4维张量,用于存储和交换数据)。接下来,我将以caffe自带的MNIST为例,由浅入深介绍一下caffe的层次结构及参数。
一、数据层
数据层是每一个模型的最底层,由数据定义和数据参数两部分组成。数据层是模型的入口,不仅提供数据的输入,也提供数据的格式转换。通常的数据预处理(减去均值、缩放、剪裁、镜像)也在这一层设置参数实现。
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "examples/mnist/mnist-train-leveldb"
batch_size: 64
backend: LEVELDB
}
}
1.层定义
name:表示该层的名称,可以随意取,这里取为“mnist”
type:表示层类型,如果值设置为“Data”,那么表示数据来源于LEVEDB或者LMDB。根据数据来源的不同,层类型也会不一样。由于我们下载的mnist的数据大都为LEVELDB,所以这里取值为“Data”
top或bottom:每一层用bottom来表示输入数据,用top来输出数据。即“自底而上”。本层只有top没有bottom,表示此层只有输出,没有输入。在数据层,至少有一个top取值为data“”,如果像本例一样有第二个top,那么一般取值为“label”。这种(data,label)组合对是分类模型必须的。
include:“训练\测试”调度器,一般模型的训练和测试所用的模型层是不一样的,因而需要配置include的参数phase,来指定该层是用于测试还是训练。如果没有设置include参数,则表示该层同时兼容训练和预测模型。本例中,include的参数设置为“TRAIN”,即表示该层用于训练。
2.层参数
transform_param:数据的预处理,可以将数据变换到定义的范围内。本例设置为0.00390625,即1/255,表示将输入数据由0-255归一化到0-1之间
data_param:根据数据来源(层类型)不同,来进行不同的设置。本例中层类型为“Data”,故必须要设置的参数source:包含数据库的文件路径,如“examples/mnist/mnist-train-lmdb”;bath_size:每一个批次处理的数据个数,如“64”;backend:支持数据库类型,可以选择是LevelDB还是LMDB,本例为“LevelDB”
二、卷积层
卷积层是CNN的核心层
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
1.层定义
该层的名称为“con1”,层类型为“Convolution”,输入源来自“data”层,在本层“con1”输出。
2.层参数
lr_mult :学习率的系数。而最终的学习率 lr=lr_mult*base_lr,其中base_lr在lenet_solver.prototxt配置文件中(base_lr:0.01);如果有两个lr_mult,则第一个表示为权值的学习率,第二个表示为偏置的学习率。一般后者是前者的两倍。故本例中第二个lr_mult的值为“2”,第一个lr_mult的值为“1”
convolution_param:卷积层的系数,必须包含:num_output:卷积核个数,这里设置为“20”;kernel_size:卷积核的大小;stride:卷积核步长,默认为1;weight_filler:权值初始化,这里设置为“xavier”,即采用“xavier”算法进行初始化。(即“对称区间均匀采样”,为了使网络中的参数更好的流动 ,推荐这篇文档,讲的不错 点击打开链接 );bias_filler,默认为“constant”,即值全部初始化为“0”
三、池化层
池化层,为了减少运算量和数据维度而设置的一种层。
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
1.层参数
pool:池化方法,默认为“Max”,目前可用的方法有MAX(最大池化),AVE(平均池化)
kernel_size:池化核大小,这里设置为“2”
stride:池化步长。默认为1,这里这设置为“2”,目的是不重叠。
四、全连接层
全连接层,把输入当作一个向量,输出也是一个简单向量
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
1.层参数
num_output:过滤器个数。这里设置为500.表示在“pool2”之后每个样本有n(n>500)个特征,那么在经过ip1全连接层后,每个样本的特征数均被“压缩”到500个。同理,在经过ip2全连接层后,特征数被“压缩到”10个(此时就满足了0-9的数字分类需要)
五、激活层
ReLU是目前使用最多的激活函数,主要是因为其收敛更快,并且能保持同样的效果。
layer {
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
可以看出,在caffe的mnist的网络中,ReLU激活函数应用在了全连接层。
六、分类精度层
输出预测精确度,只有test阶段才有,因此需要加入include参数
layer {
name: "accuracy"
type: "Accuracy"
bottom: "ip2"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
七、损失层
softmax-loss层,输出loss值
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "loss"
}
softmax-loss的计算包含2步,首先计算softmax归一化概率,然后计算损失。此外,softmax_loss可支持更高维度的label。这里推荐一篇文档,这方面内容讲的很好softmax_loss