笔记(一):Caffe 训练中用到的一些关键文件,以及这些文件的内容和作用。
Caffe 训练模型时,需要两个文件:train.prototxt
和 solver.prototxt
,其中:
另外,还有 deploy.prototxt
定义了发布时使用的网络结构,使用这个网络来计算结果,与 train.prototxt 差不多,只是修改了输入输出层。
xxx.caffemodel
文件是训练的输出结果,保存了各个网络层的参数,搭配 deploy.prototxt
服用,可以用于最终的预测(TEST)。
Caffe 已经实现了很多 layer,可以直接拿来用,但是如果想要自定义 layer,就需要了解一下 Caffe 每个 layer 都需要包含什么东西。
Caffe 每个 Layer 包含三个基本操作:
层类型(type):一般都是 Data
【这个类型说明数据来自于数据库,如 LMDB 和 LEVELDB】
Caffe 有 7 种数据层(即支持输出的数据类型:Data、MemoryData、HDF5Data、HDF5Output、ImageData、WindowData、DummyData),除此之外还可以自定义数据层(自定义数据层就需要自己写代码了)。
数据层必须设置的参数:
其他参数含义说明:
定义数据层:
在 train.prototxt 文件中定义数据层(VGG16模型的部分代码)
name: "VGG16"
layer {
name: "data"
type: "Data" #输入的数据类型
top: "data"
top: "label"
include {
phase: TRAIN
}
#数据预处理,来增强数据
transform_param {
mirror: true
crop_size: 224
mean_value: 103.939
mean_value: 116.779
mean_value: 123.68
}
data_param {
source: "data/ilsvrc12_shrt_256/ilsvrc12_train_leveldb" #数据库文件路径
batch_size: 64 #网络单次输入数据数量
backend: LEVELDB #选择使用LevelDB还是LMDB
}
}
自定义数据层:
layer{
name: "data" #层的名字,可以随便取
type: "Python" #类型为python时需要caffe开启python layer的支持,即在caffe的Makefile.config中去掉WITH_PYTHON_LAYER=1
top: "data" #该层的输出,在数据层中,至少要有一个名为data的top
top: "label" #该层的输出,且可以有多个
python_param{
module: "my_data_layer"
layer: "ImageDataLayer"
param_str:"{\'source\':\'../data/preproc/data/112/landmark_aug.txt\', \'batch_size\':384, \'shuffle\':True, \'size\':(112,112)}"
}
include: {phase: TRAIN}
}
layer{
name: "data"
type: "Python"
top: "data"
top: "label"
python_param{
module: "my_data_layer"
layer: "ImageDataLayer"
param_str:"{\'source\':\'../data/preproc/data/112/landmark_aug.txt\', \'batch_size\':384, \'shuffle\':False, \'size\':(112,112)}"
}
include: {phase: TEST}
}
Q1:为什么要使用均值文件?
可以减少图像波动
Q2:用均值文件生成的均值和自己计算的均值有什么不一样?
使用 imageNet 数据集的均值文件,由于 imageNet 的数据量非常大,所以它的均值具有一定代表性,可以使用它来表示我们数据集的均值
Q3:各个数据源格式有什么不同?
Q4:batch 有什么用?
批次表示每次训练时,一次性调用多少张图像。调用的图像越多,训练的结果越具有代表性,但是同时对显存(如果使用的是GPU)的要求越大,如果批次的数量过大,超过系统的最大显存,可能会导致运行报错。
层类型(type):Convolution
layer {
bottom: "data"
top: "conv1_1"
name: "conv1_1"
type: "Convolution"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 64
pad: 1
kernel_size: 3
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
卷积层必须设置的参数:
其他参数含义说明:
为了减少运算量和数据维度而设置的一种层。
层类型(type):Pooling
layer {
bottom: "conv1_2"
top: "pool1"
name: "pool1"
type: "Pooling"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
池化层必须设置的参数:
其他参数含义说明:
在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的。从bottom得到一个blob数据输入,运算后,从top输入一个blob数据。在运算过程中,没有改变数据的大小,即输入和输出的数据大小是相等的。
常用的激活函数有sigmoid,tanh,relu 等。
layer {
bottom: "conv2_2"
top: "conv2_2"
name: "relu2_2"
type: "ReLU" #常用激活函数,除此之外还有Sigmoid
}
layer{
name: "landmark_pred"
type: "InnerProduct"
bottom: "prelu5"
top: "landmark_pred"
param{
lr_mult: 1
}
param{
lr_mult: 2
}
inner_product_param{
num_output: 254
weight_filler:{
type: "xavier"
}
bias_filler{
type: "constant"
}
}
}
参数含义信息:
# Softmax loss
# 多分类问题
layer {
bottom: "fc8"
bottom: "label"
top: "loss"
name: "loss"
type: "SoftmaxWithLoss"
}
# SigmoidCrossEntropyLoss
# S形交叉熵损失,用于目标概率分布和多标签多分类任务,各概率相互独立
layer {
name:"loss"
type:" SigmoidCrossEntropyLoss"
bottom:"loss3/classifier"
bottom:"label"
top:"loss"
}
# EuclideanLoss
# 欧式距离损失,适用于实数值回归问题
layer {
name:"loss"
type:" EuclideanLoss "
bottom:"loss3/classifiersigmoid"
bottom:"label"
top:"loss"
}
layer{
name: "landmark_loss"
type: "Python"
top: "landmark_loss"
bottom: "landmark_pred"
bottom: "label"
python_param{
module: "wing_loss_layer"
layer: "WingLossLayer"
param_str : "{\'w\':1.0, \'eplison\':0.2}"
}
# set loss weight so Caffe knows this is a loss layer.
# since PythonLayer inherits directly from Layer, this isn't automatically
# known to Caffe
loss_weight: 1
}
自定义 Loss 代码:
import caffe
import numpy as np
class WingLossLayer(caffe.Layer):
def setup(self, bottom, top):
if len(bottom) != 2:
raise Exception("Need two bottom for WingLossLayer")
params = eval(self.param_str)
self.w = params['w']
self.eplison = params['eplison']
def reshape(self, bottom, top):
if bottom[0].count != bottom[1].count:
raise Exception("Inputs must have the save dimension")
self.diff = np.zeros_like(bottom[0].data, dtype=np.float32)
top[0].reshape(1)
def forward(self, bottom, top):
#tag,need reshape bottom[0] and bottom[1],maybe lmdb don't need
self.diff = bottom[0].data - bottom[1].data
idx = np.abs(self.diff) < self.w
idx1 = np.abs(self.diff) >= self.w
top[0].data[...] = (\
np.sum(self.w * np.log(1.0/self.eplison * np.abs(self.diff[idx]) + 1.)) +\
np.sum(np.abs(self.diff[idx1]) - (self.w - self.w * np.log(1.0 + self.w/self.eplison)))\
) / bottom[0].num
def backward(self, top, propagate_down, bottom):
idx0 = (0. < self.diff) & (self.diff < self.w)
idx1 = (-self.w < self.diff) & (self.diff < 0.)
idx2 = self.diff >= self.w
idx3 = self.diff <= -self.w
#print "idx2"
for i in range(0,2):
if not propagate_down[i]:
continue
if i == 0:
sign = 1
else:
sign = -1
bottom[i].diff[idx0] = sign * 1.0 * (self.w / (1. + 1.0/self.eplison * np.abs(self.diff[idx0]))) / bottom[i].num
bottom[i].diff[idx1] = sign * (-1.0) * (self.w / (1. + 1.0/self.eplison * np.abs(self.diff[idx1]))) / bottom[i].num
bottom[i].diff[idx2] = sign * 1.0 / bottom[i].num
bottom[i].diff[idx3] = sign * (-1.0) / bottom[i].num
Caffe的BN层由 BatchNorm 层和 Scale 层组成。BatchNorm 减均值,Scale 层除方差。示例如下:
layer{
name: "conv1/bn"
type: "BatchNorm"
bottom: "conv1"
top: "conv1/bn"
batch_norm_param{
moving_average_fraction: 0.997
eps: 1e-3
}
}
layer{
name: "conv1/scale"
type: "Scale"
bottom: "conv1/bn"
top: "conv1/scale"
scale_param{
bias_term: true
}
}
防止模型过拟合;训练模型时,随机让网络某些隐含层节点的权重不工作。
layer{
name:"drop7"
bottom:""
top:""
dropout_param{
dropout_ratio:0.5 # 杀死50%的神经元
}
}
layer{
name:"pro"
type:"Softmax"
bottom:"ip"
top:"pro"
}
Caffe 模型的训练参数在 solver.prototxt 文件中,该文件是 caffe 的核心,它交替调用前向算法和反向传播算法来更新参数,使 loss 的值达到最小。
net: "landmark.prototxt"
test_iter: 100
test_interval: 500
base_lr: 0.0001
momentum: 0.9
momentum2: 0.999
type: "Adam"
lr_policy: "fixed"
display: 100
max_iter: 30000
snapshot: 5000
snapshot_prefix: "../../checkpoint/caffe"
solver_mode: GPU
执行训练:caffe.bin train --solver=solver.prototxt -gpu
net: "train_val.prototxt"
test_iter: 833
# make test net, but don't invoke it from the solver itself
test_interval: 1000
display: 200
average_loss: 100
base_lr: 1e-5
lr_policy: "step"
gamma: 0.1
stepsize: 5000
# lr for unnormalized softmax -- see train_val definition
# high momentum
momentum: 0.9
# no gradient accumulation
clip_gradients: 10000
iter_size: 1
max_iter: 80000
weight_decay: 0.02
snapshot: 4000
snapshot_prefix: "weight/VGG_item"
test_initialization: false
参考:
Caffe学习系列(2):数据层及参数
caffe网络模型各层详解
Caffe学习系列(10):命令行解析
Caffe 网络在线可视化工具:http://ethereon.github.io/netscope/#/editor