在上篇笔记中,已经记录了如何进行图片数据格式的转换和生成txt列表清单文件。本篇笔记主要记录如何计算图片数据的均值和理解prototxt配置文件中各个层的参数。
Caffe主要处理两种形式的数据流:
图像和标签在网络上的传输,随着网络的传输,它们转化更高层次的表示,最终以得分或者概率值的形式输出。
第二种数据流,主要保存各个网络层的参数,比如卷积层的weights和bias. 这些值是随着的网络的训练过程不断变化的。
一、二进制格式的均值计算
图片减去均值后,再进行训练和测试,会提高速度和精度。因此,一般在各种模型中都会有这个操作。不过此步骤不是必须的,如果使用txt列表清单文件,则可以不使用db文件和均值文件,此部分内容会在后续进行讲解,此乃后话。
那么这个均值怎么来的呢,实际上就是计算所有训练样本的平均值,计算出来后,保存为一个均值文件,在以后的测试中,就可以直接使用这个均值来相减,而不需要对测试图片重新计算。
在训练过程中,caffe使用的均值数据格式是binaryproto,它是一个二进制格式文件。作者为我们提供了一个计算均值的文件compute_image_mean.cpp,放在caffe根目录下的tools文件夹里面。编译caffe后,生成的可执行文件放在 build/tools/ 目录下,我们可以直接在caffe根目录中使用如下指令:
build/tools/compute_image_mean my-caffe-project/img_train_lmdb my-caffe-project/mean.binaryproto
- 1
带两个参数:
第一个参数:my-caffe-project /img_train_lmdb , 表示需要计算均值的数据,格式为lmdb的训练数据。
第二个参数:my-caffe-project /mean.binaryproto, 计算出来的二进制格式的均值文件。
二、prototxt配置文件
要运行caffe,需要先创建一个模型(model),如比较常用的Lenet,Alex等, 而一个模型由多个屋(layer)构成,每一层又由许多参数组成。所有的参数都定义在caffe.proto这个文件中。要熟练使用caffe,最重要的就是学会配置文件(prototxt)的编写。我们可以直接使用vim编写prototxt文件,也可以使用caffe的python接口编写这个配置文件。但无论如何,都应该先对于模型的各个层有所了解。
层有很多种类型,比如Data,Convolution,Pooling等,层之间的数据流动是以Blobs的方式进行。
caffe一般使用的prototxt配置文件有如下几种:
1.train_test.prototxt文件各层分析
以之前用到的cifar10_quick_train_test.prototxt文件为例进行学习,一层一层进行分析。
part1:
name: "CIFAR10_quick"
- 1
解释:
name:表示该prototxt文件的名称,可以随意取。
part2:
layer {name: "cifar" type: "Data" top: "data" top: "label" include { phase: TRAIN }transform_param {mean_file: "examples/cifar10/mean.binaryproto" }data_param {source: "examples/cifar10/cifar10_train_lmdb" batch_size: 100 backend: LMDB }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
解释:
该layer为用于训练的数据层(Data Layers),具体参数意义如下: name: 表示该层的名称,可随意取;
type:层类型,如果是Data,表示数据来源于LevelDB或LMDB。根据数据的来源不同,数据层的类型也不同(后面会详细阐述)。一般在练习的时候,我们都是采用的LevelDB或LMDB数据,因此层类型设置为Data。
top或bottom:每一层用bottom来输入数据,用top来输出数据。如果只有top没有bottom,则此层只有输出,没有输入。反之亦然。如果有多个top或多个bottom,表示有多个blobs数据的输入和输出。
data 与 label: 在数据层中,至少有一个命名为data的top。如果有第二个top,一般命名为label。这种(data,label)配对是分类模型所必需的。
include:一般训练的时候和测试的时候,模型的层是不一样的。该层(layer)是属于训练阶段的层,还是属于测试阶段的层,需要用include来指定。如果没有include参数,则表示该层既在训练模型中,又在测试模型中。
transform_param:指定一些转换参数。mean_file参数指定生成的均值文件。
data_param:根据数据的来源不同进行不同的设置。该cifar10_quick_train_test.prototxt文件表示数据来源于LevelDB和LMDB。当然,数据也可以来源于内存、HDF5、图片和Windows。
它需要设置的参数如下:
source: 包含数据库的目录名称;
batch_size:每次处理的数据个数;
backend:选择是采用LevelDB还是LMDB, 默认是LevelDB。
part3:
layer {name: "cifar" type: "Data" top: "data" top: "label" include { phase: TEST }transform_param {mean_file: "examples/cifar10/mean.binaryproto" }data_param {source: "examples/cifar10/cifar10_test_lmdb" batch_size: 100 backend: LMDB }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
解释:
该layer为用于测试的数据层(Data Layers)。参数意义同part2。
part4:
layer {name: "conv1" type: "Convolution" bottom: "data" top: "conv1" param { lr_mult: 1 }param {lr_mult: 2 }convolution_param {num_output: 32 pad: 2 kernel_size: 5 stride: 1 weight_filler { type: "gaussian" std: 0.0001 }bias_filler {type: "constant" }}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
解释:
该layer为视觉层(Vision Layers),视觉层包括Convolution层、Pooling层、Local Response Normalization (LRN)层、im2col层等。由上可知,本层为视觉层的卷积层(Convolution Layer),它是卷积神经网络(CNN)的核心层。具体参数意义如下:
name、type、bottom、top参数意义同上,type参数表明层类型为Convolution层。
lr_mult:学习率的系数,最终的学习率是这个数乘以solver.prototxt配置文件中的base_lr。如果有两个lr_mult,则第一个表示权值的学习率,第二个表示偏置项的学习率。一般偏置项的学习率是权值学习率的两倍。
在后面的convolution_param中,我们可以设定卷积层的特有参数。
必须设置的参数:
num_output: 卷积核(filter)的个数;
kernel_size: 卷积核的大小。如果卷积核的长和宽不等,需要用kernel_h和kernel_w分别设定;
其它参数:
stride: 卷积核的步长,默认为1。也可以用stride_h和stride_w来设置;
pad: 扩充边缘,默认为0,不扩充。扩充的时候是左右、上下对称的,比如卷积核的大小为5*5,那么pad设置为2,则四个边缘都扩充2个像素,即宽度和高度都扩充了4个像素,这样卷积运算之后的特征图就不会变小。也可以通过pad_h和pad_w来分别设定;
weight_filler:权值初始化。默认为“constant”,值全为0,很多时候我们用”xavier”算法来进行初始化,也可以设置为”gaussian”;
bias_filler: 偏置项的初始化。一般设置为”constant”,值全为0;
bias_term:是否开启偏置项,默认为true, 开启;
group:分组,默认为1组。如果大于1,我们限制卷积的连接操作在一个子集内。如果我们根据图像的通道来分组,那么第i个输出分组只能与第i个输入分组进行连接。
Convolution层运算方法:
输入: n*c0*w0*h0
输出: n*c1*w1*h1
其中,c1就是参数中的num_output,生成的特征图个数:
w1=(w0+2*pad-kernel_size)/stride+1;h1=(h0+2*pad-kernel_size)/stride+1;
- 1
- 2
如果设置stride为1,前后两次卷积部分存在重叠。如果设置pad=(kernel_size-1)/2,则运算后,宽度和高度不变。
part5:
layer {name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 3 stride: 2 }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
解释:
该layer为视觉层(Vision Layers)的池化层(Pooling Layer),该层是为了减少运算量和数据维度而设置的一种层。
name、type、bottom、top参数意义同上,type参数表明层类型为Pooling层。
在后面的pooling_param中,我们可以设定池化层的特有参数。
必须设置的参数:
- kernel_size: 池化的核大小。也可以用kernel_h和kernel_w分别设定。
其它参数:
pool: 池化方法,默认为MAX。目前可用的方法有MAX, AVE, 或STOCHASTIC;
pad: 和卷积层的pad的一样,进行边缘扩充。默认为0;
stride: 池化的步长,默认为1。一般我们设置为2,即不重叠。也可以用stride_h和stride_w来设置。
pooling层的运算方法基本是和卷积层是一样的。
输入: n*c*w0*h0
输出: n*c*w1*h1
和卷积层的区别就是其中的c保持不变:
w1=(w0+2*pad-kernel_size)/stride+1;h1=(h0+2*pad-kernel_size)/stride+1;
- 1
- 2
如果设置stride为2,前后两次卷积部分不重叠。100*100的特征图池化后,变成50*50。
part6:
layer {name: "relu1" type: "ReLU" bottom: "pool1" top: "pool1" }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解释:
该layer为激活层(Activation Layers),在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的。从bottom得到一个blob数据输入,运算后,从top输入一个blob数据。在运算过程中,没有改变数据的大小,即输入和输出的数据大小是相等的。
- name、type、bottom、top参数意义同上,type参数表明层类型为使用ReLU激活函数的激活曾层。
可选参数:
- negative_slope:默认为0。对标准的ReLU函数进行变化,如果设置了这个值,那么数据为负数时,就不再设置为0,而是用原始数据乘以negative_slope。
激活曾层的运算方法:
输入: n*c*h*w
输出: n*c*h*w
常用的激活函数有sigmoid, tanh,relu等。该激活曾使用ReLU激活函数,ReLU层支持in-place计算,这意味着bottom的输出和输入相同以避免内存的消耗。
part7:
layer {name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" param { lr_mult: 1 }param {lr_mult: 2 }convolution_param {num_output: 32 pad: 2 kernel_size: 5 stride: 1 weight_filler { type: "gaussian" std: 0.01 }bias_filler {type: "constant" }}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
解释:
该layer为卷积层,同part4。
part7:
layer {name: "relu2" type: "ReLU" bottom: "conv2" top: "conv2" }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解释:
该layer为池化层,同part5。
part8:
layer {name: "conv3" type: "Convolution" bottom: "pool2" top: "conv3" param { lr_mult: 1 }param {lr_mult: 2 }convolution_param {num_output: 64 pad: 2 kernel_size: 5 stride: 1 weight_filler { type: "gaussian" std: 0.01 }bias_filler {type: "constant" }}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
解释:
该layer为卷积层,同part4。
part9:
layer {name: "relu3" type: "ReLU" bottom: "conv3" top: "conv3" }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解释:
该layer为激活层,同part6。
part10:
layer {name: "pool3" type: "Pooling" bottom: "conv3" top: "pool3" pooling_param { pool: AVE kernel_size: 3 stride: 2 }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
解释:
该layer为池化层,同part5。
part11:
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" }}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
解释:
该layer为全连层(Inner Product),全连接层,把输入当作成一个向量,输出也是一个简单向量(把输入数据blobs的width和height全变为1)。
name、type、bottom、top参数意义同上,type参数表明层类型为全连层。
在后面的inner_product_param中,我们可以设定卷积层的特有参数。
必须设置的参数:
- num_output: 过滤器(filfter)的个数
其它参数:
weight_filler: 权值初始化。默认为“constant”,值全为0,很多时候我们用”xavier”算法来进行初始化,也可以设置为”gaussian”;
bias_filler: 偏置项的初始化。一般设置为”constant”,值全为0;
bias_term: 是否开启偏置项,默认为true, 开启。
全连层的计算方法:
输入: n*c0*h*w
输出: n*c1*1*1
全连接层实际上也是一种卷积层,只是它的卷积核大小和原数据大小一致。因此它的参数基本和卷积层的参数一样。
part12:
layer {name: "ip2" type: "InnerProduct" bottom: "ip1" top: "ip2" param { lr_mult: 1 }param {lr_mult: 2 }inner_product_param {num_output: 10 weight_filler { type: "gaussian" std: 0.1 }bias_filler {type: "constant" }}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
解释:
该layer为全连层,同part11。
part13:
layer {name: "accuracy" type: "Accuracy" bottom: "ip2" bottom: "label" top: "accuracy" include { phase: TEST }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
解释:
该layer为精度输出层(Accuracy Layer),该层输出分类(预测)精确度,只有test阶段才有,include参数表型测试阶段使用。
part14:
layer {name: "loss" type: "SoftmaxWithLoss" bottom: "ip2" bottom: "label" top: "loss" }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
解释:
该layer为softmax-loss层,sotfmax-loss计算公式为:
感觉这类似于决策树中用到的香农熵的计算。
- name、type、bottom、top参数意义同上,type参数表明层类型为softmax-loss层。
2.结尾
在Caffe中,不仅这些层,还有很多层,并且在持续更新中,这里不在继续讲解。
更为详细的内容,可查看官网:
URL:http://caffe.berkeleyvision.org/tutorial/layers.html
下篇笔记将记录如何使用caffe提供的python接口编写train.protxt和test.prototxt文件。