针对Training LeNet on MNIST with Caffe的Demo分析
1、设置网络文件的存储位置
@CAFFE_ROOT/src/caffe/proto/caffe.proto
设置文件存储在一个.proto文件里面,在这里面设置了我们所要的网络特性和参数
2、定义自己的网络
首先从整理的来看一下,在这个Demo里面我们定义了一下几个Layer(用Type名代替)
Data:
layer {
name: "mnist"
type: "Data"
transform_param {
scale: 0.00390625
#为什么是0.00290625呢,这个值是1/255
#原因是普通图片是RGB格式0~255,而Caffe里面是RBG是0~1故做此操作
}
data_param {
source: "mnist_train_lmdb"
backend: LMDB
batch_size: 64
#直译是批量大小,也就是说一次读入多少张图片
}
top: "data"
top: "label"
#输出到data和label
}
Convolution:(顾名思义就是卷积层,但是这个Blob是存的是“Data”Blob卷积运算后的)
layer {
name: "conv1"
type: "Convolution"
param { lr_mult: 1 }
param { lr_mult: 2 }
#LearnRate 1是整体同步,2是整体2倍(此处理解的还不是很清楚
convolution_param {
num_output: 20
#这次卷积有多少个核函数
kernel_size: 5
#窗口5X5,就是这次运算取了5X5的像素点,
#什么是窗口,我目前对窗口理解就是在图像中取一个小块
stride: 1
#stride步长,一次滑一个像素点
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
#偏移是常量
}
}
bottom: "data"
#数据来源(上一个Blob)是data
top: "conv1"
#输出到conv1 Blob
}
Pooling:
layer {
name: "pool1"
type: "Pooling"
pooling_param {
kernel_size: 2
stride: 2
pool: MAX
#窗口2X2,步长2
}
bottom: "conv1"
top: "pool1"
#输出到pool1这个Blob
}
卷积层输出的是图像的特征图,然后为了解决过度拟化和计算量大的问题,Pooling层对卷积层的输出进行采样,以达到减小特征图分辨率的目的。
InnerProduct:(Fully Connected Layer)(InnerProduct中文是内积)
layer {
name: "ip1"
type: "InnerProduct"
param { lr_mult: 1 }
param { lr_mult: 2 }
inner_product_param {
num_output: 500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
bottom: "pool2"
top: "ip1"
}
这个嘛,这层以目前的理解有点像是ANN里面的分类的过程,之前的Conv和Pooling都是不停的提取特征值,而这里是真正分类的过程。
ReLU:(和tanh和sigmod激活不同另一种激活函数)
layer {
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
ReLU层是激活层的一种类型,参考的AlexNet论文,可以看出和之前的激活函数不同,ReLU的激活函数模仿了自然界中局部神经元会相互抑制的特性,在计算本神经元输出的时候会考虑到周围的神经元的输出(看一眼公式就知道了)。
LossLayer:
layer {
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
}
这个层的目的就是对前向传播以后的结果同预期结果做对比,看之间相差了多少,这个也是反向传播的时候一个重要的依据。在这里它的type主要是改变损失函数,不同的损失函数有不同的效果。损失函数的计算结果会直接的影响反向传播算法中的梯度计算,所以这里算是一个调整参数的重要位置。
在这个层中有一个不设置损失函数,那就是Accuracy类型,这个类型就是单纯的输出测试的准确度的。
loss层不做任何输出,在反向传播的开始的时候使用,原文中的最后一句话问有意思。
“This is where all magic starts”
毕竟梯度计算的最开始就是这里,算出最后一层的梯度以后,之前的梯度都和下一层的的梯度相关。
3、定义Solver
Solver文件以我现在浅薄的理解看来是一个怎么运行网络,定义怎么输出的作用
它存放在以下位置
$CAFFE_ROOT/examples/mnist/lenet_solver.prototxt
# The train/test net protocol buffer definition
net: "examples/mnist/lenet_train_test.prototxt"
test_iter: 100
# 迭代100次,举个例子就是网络中一次读入假设100个图,100次迭代就是读了10000个图
test_interval: 500
# 每500次迭代用Test数据集输出一次测试结果
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
#lr是LearnRate的意思,weight_decay是每次修正多少weight的意思
lr_policy: "inv"
gamma: 0.0001
power: 0.75
# 这个是learning rate policy,gamma和power是inv模式需要的参数(这个大体就是一个函数
display: 100
# Display every 100 iterations
max_iter: 10000
# The maximum number of iterations
# snapshot intermediate results
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
#prefix是前缀的意思
# solver mode: CPU or GPU
solver_mode: GPU
在这部分的base_lr,lr_policy都是调整学习速率用的,也是后期调整参数的重要位置。学习速率是再反向传播算法中出现的,它是公式中用梯度进行调整的时候,梯度前面的参数,类似y=kx+b,前面的k。在公式中一般都记做α。base_lr为基础学习速率,顾名思义就是最最开始的时候学习速率的值,而lr_policy就是调整学习速率的方法,选择不同的方法则下面要跟的参数就不一样。剩下的部分,觉得大概就直接看就能看得懂。
4、训练和测试Model
去相应的位置运行.sh文件即可,Demo中的位置是
cd $CAFFE_ROOT
./examples/mnist/tran_lenet.sh
5、其他细节
在测试的时候,可以根据自己的显卡显存,来调整batch_size的大小,来调整,
可以在运行了一段时间后使用以下代码来查看
nvidia-smi
初次纪录2017/3/16。学长讲解后
记录修正2017/6/10。毕业晚会第二天