跑完caffe example目录下自带的mnist和cifar后,想利用现有的模型构建自己的项目文件夹。由于近期仿真一篇关于图像中值滤波取证的文件,因此文件夹命名为:“Median_Filtering_Forensics”,如下图所示:
一、项目文件夹的基本组成文件
总的来说一个完整的example下的项目文件由三部分组成:训练模型文件(train_val.prototxt)、训练超参数文件(solver.prototxt)、制作好的数据集。训练模型文件是准备利用的模型,如LeNet、AlexNet等;训练超参数文件定义了训练过程中的参数,比如是否用GPU,生成的模型存放的位置等;制作好的数据集一般是LEVELDB或LMDB格式的。此外,还有一个deploy文件,具体用处还没弄清。我们可以从caffemaster底下的model中找到我们所需要的模型及相应的文件,如图:
通过阅读文献,发现我要仿的文章用的是caffenet或AlexNet模型,只是在这个模型的基础上新加了一个Filter Layer层,用来提取输入图像的中值滤波谱残差(MFR)。CaffeNet和AlexNet模型大的框架是相同的,有些细微的地方比如池化和归一化的顺序不同,有兴趣的同学可以查阅研究一下这两个模型的区别联系。此处我们用CaffeNet模型。
如图是caffenet模型文件夹中的文件:
我们将这些文件全部复制粘贴到example目录下我们新建的项目文件夹“Median_Filtering_Forensics”中,并将之前制作好的train_leveldb和test_leveldb文件以及数据集制作时用到的bat文件也一同粘贴到这个新建的项目文件夹中(数据集的制作请参照上篇博文)。由于我要修改一下原模型文件,这里在train_val.prototxt中加了个1以示区别。至此一个项目文件夹中的基本组成文件齐全了,如图所示:
二、修改训练模型文件和训练超参数文件
下面要做的就是修改训练模型文件和训练超参数文件中的内容。
(1)训练模型文件的修改
先粘一下caffenet模型文件的源代码(修改的部分在注释中写出):
name: "CaffeNet"
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
//下面的部分是导入均值文件并设置参数,由于图像取证方向跟目标识别不太一样,不需要这一步,去掉这一部分
transform_param {
mirror: true
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
}
# mean pixel / channel-wise mean instead of mean image
# transform_param {
# crop_size: 227
# mean_value: 104
# mean_value: 117
# mean_value: 123
# mirror: true
# }
data_param {
source: "examples/imagenet/ilsvrc12_train_lmdb"//制作好的训练文件所在的目录,最好写上完整的路径
batch_size: 256
backend: LMDB//训练文件的格式:LEVELDB或者LMDB
}
}
layer {
name: "data"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
//跟train的一样,把有关均值文件的部分去掉
transform_param {
mirror: false
crop_size: 227
mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"
}
# mean pixel / channel-wise mean instead of mean image
# transform_param {
# crop_size: 227
# mean_value: 104
# mean_value: 117
# mean_value: 123
# mirror: false
# }
data_param {
source: "examples/imagenet/ilsvrc12_val_lmdb"//测试文件所在的目录,最好写上完整路径
batch_size: 50
backend: LMDB//测试集文件的格式:LEVELDB或者LMDB
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 96//输出端个数,这里我按照文章中的设置
kernel_size: 11
stride: 4
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "conv1"
top: "conv1"
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3//按照文章中的设置,下面的层中这个参数都按文章中的设置
stride: 2
}
}
layer {
name: "norm1"
type: "LRN"
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "norm1"
top: "conv2"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 256
pad: 2
kernel_size: 5
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu2"
type: "ReLU"
bottom: "conv2"
top: "conv2"
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layer {
name: "norm2"
type: "LRN"
bottom: "pool2"
top: "norm2"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layer {
name: "conv3"
type: "Convolution"
bottom: "norm2"
top: "conv3"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "relu3"
type: "ReLU"
bottom: "conv3"
top: "conv3"
}
layer {
name: "conv4"
type: "Convolution"
bottom: "conv3"
top: "conv4"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu4"
type: "ReLU"
bottom: "conv4"
top: "conv4"
}
layer {
name: "conv5"
type: "Convolution"
bottom: "conv4"
top: "conv5"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 256
pad: 1
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu5"
type: "ReLU"
bottom: "conv5"
top: "conv5"
}
layer {
name: "pool5"
type: "Pooling"
bottom: "conv5"
top: "pool5"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layer {
name: "fc6"
type: "InnerProduct"
bottom: "pool5"
top: "fc6"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 4096
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu6"
type: "ReLU"
bottom: "fc6"
top: "fc6"
}
layer {
name: "drop6"
type: "Dropout"
bottom: "fc6"
top: "fc6"
dropout_param {
dropout_ratio: 0.5
}
}
layer {
name: "fc7"
type: "InnerProduct"
bottom: "fc6"
top: "fc7"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 4096
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu7"
type: "ReLU"
bottom: "fc7"
top: "fc7"
}
layer {
name: "drop7"
type: "Dropout"
bottom: "fc7"
top: "fc7"
dropout_param {
dropout_ratio: 0.5
}
}
layer {
name: "fc8"
type: "InnerProduct"
bottom: "fc7"
top: "fc8"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 1000//这里caffenet是为ImageNet所设计的模型,ImageNet是1000个分类,这里我们是一个二分类的问题,因此将1000改为2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "accuracy"
type: "Accuracy"
bottom: "fc8"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "fc8"
bottom: "label"
top: "loss"
}
下面贴出修改后的模型文件:
name: "CaffeNet"
layer {
name: "Median_Filtering_Forensics"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
data_param {
source: "E:/platform/caffe-master/examples/Median_Filtering_Forensics/train_MFF_leveldb"
batch_size: 256
backend: LEVELDB
}
}
layer {
name: "Median_Filtering_Forensics"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
data_param {
source: "E:/platform/caffe-master/examples/Median_Filtering_Forensics/test_MFF_leveldb"
batch_size: 50
backend: LEVELDB
}
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 128
kernel_size: 5
stride: 4
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "conv1"
top: "conv1"
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layer {
name: "norm1"
type: "LRN"
bottom: "pool1"
top: "norm1"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "norm1"
top: "conv2"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 256
pad: 2
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu2"
type: "ReLU"
bottom: "conv2"
top: "conv2"
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layer {
name: "norm2"
type: "LRN"
bottom: "pool2"
top: "norm2"
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layer {
name: "conv3"
type: "Convolution"
bottom: "norm2"
top: "conv3"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "relu3"
type: "ReLU"
bottom: "conv3"
top: "conv3"
}
layer {
name: "conv4"
type: "Convolution"
bottom: "conv3"
top: "conv4"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu4"
type: "ReLU"
bottom: "conv4"
top: "conv4"
}
layer {
name: "conv5"
type: "Convolution"
bottom: "conv4"
top: "conv5"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 256
pad: 1
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu5"
type: "ReLU"
bottom: "conv5"
top: "conv5"
}
layer {
name: "pool5"
type: "Pooling"
bottom: "conv5"
top: "pool5"
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layer {
name: "fc6"
type: "InnerProduct"
bottom: "pool5"
top: "fc6"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 5120
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu6"
type: "ReLU"
bottom: "fc6"
top: "fc6"
}
layer {
name: "drop6"
type: "Dropout"
bottom: "fc6"
top: "fc6"
dropout_param {
dropout_ratio: 0.5
}
}
layer {
name: "fc7"
type: "InnerProduct"
bottom: "fc6"
top: "fc7"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 5120
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layer {
name: "relu7"
type: "ReLU"
bottom: "fc7"
top: "fc7"
}
layer {
name: "drop7"
type: "Dropout"
bottom: "fc7"
top: "fc7"
dropout_param {
dropout_ratio: 0.5
}
}
layer {
name: "fc8"
type: "InnerProduct"
bottom: "fc7"
top: "fc8"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer {
name: "accuracy"
type: "Accuracy"
bottom: "fc8"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "fc8"
bottom: "label"
top: "loss"
}
(2)训练超参数文件的修改
还是先贴出caffenet里的超参数文件:
net: "models/bvlc_reference_caffenet/train_val.prototxt"//调用训练模型,即caffe自带的caffenet模型,已经被我们复制粘贴到我们的项目文件夹下,因此路径要修改
test_iter: 1000
test_interval: 1000
base_lr: 0.01//基础学习率,后来还要不断调参已得到最优模型,学习率太高可能会使得训练过程中的Loss值一直是87.3
lr_policy: "step"
gamma: 0.1
stepsize: 100000
display: 20
max_iter: 450000
momentum: 0.9
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "models/bvlc_reference_caffenet/caffenet_train"//很重要的修改地方,该路径存放将来训练的到的模型文件,注意路径中是'/'而不是‘\’
solver_mode: GPU//选择训练模式,这里选择GPU
下面贴出修改后的文件:
net: "E:/platform/caffe-master/examples/Median_Filtering_Forensics/train_val1.prototxt"
test_iter: 1000
test_interval: 1000
base_lr: 0.01
lr_policy: "step"
gamma: 0.1
stepsize: 100000
display: 20
max_iter: 450000
momentum: 0.9
weight_decay: 0.0005
snapshot: 10000
snapshot_prefix: "examples/Median_Filtering_Forensics/mine"//“mine”代表训练得到的模型文件名称前缀
solver_mode: GPU
全部修改好后即可建立bat文件训练模型了。在caffemaster目录下建立bat文件,如下:
.\Build\x64\Release\caffe.exe train --solver=E:\platform\caffe-master\examples\Median_Filtering_Forensics\solver.prototxt
pause
如果不在caffemaster目录下运行bat文件可能会出错,运行后就开始训练了。
我们的训练数据集有20000张图片,测试集也是20000张图片。在i7,GT650M,windows下跑整个模型大概用了两个小时。贴出训练结束时的cmd窗口:
遗憾的是,训练出的模型是不能用的...看到Loss值一直是87.3365,原因是计算过程中出现了float溢出等异常,说明Softmax得到的概率值出现了0。具体的原因及解决方法参照: http://blog.youkuaiyun.com/yan_joy/article/details/53608519,这里还没有来得及解决。不过应该是修改参数的问题。大体流程没问题。
最后贴出训练得到的模型文件及训练后的文件夹:
其中mine_iter_10000.caffemodel就是我们得到的模型文件,mine_iter_10000.solverstate则存放这训练参数。把loss值的问题解决后模型就应该可以用了。
PS:接下来就是要按照文章的做法在CNN的卷基层前面加一个提取图片MFR(中值滤波谱残差)的层了,感觉很难啊..要看懂caffe源码么?c++的功底不够啊,网上这方面也大多介绍的是caffe源码的解读,具体加层的套路没有具体介绍啊,无助...