前面我们深入分析了 lenet.prototxt 这个网络参数描述文件,但是这是对广义 LetNet-5 网络进行描述的。
在实际训练和测试中,LetNet-5 网络 稍有不同,那么针对 训练和测试, Caffe 又是如何定义 LetNet-5 网络 了?
对应的描述文件是 lenet_train_test.prototxt
下面我们来仔细看看这个文件:
name: "LeNet" // 网络的名称为 LeNet
// 训练时数据层的定义
layer { // 定义一个网络层(Layer)
name: "mnist" // 该网络层的名称为 mnist
type: "Data" // 该网络层的类型是数据层
top: "data" // 层的输出有两个: data 和 label
top: "label"
include {
phase: TRAIN // 该层参数只在训练阶段有效
}
transform_param {
scale: 0.00390625 //将输入图像数据归一化为0-1,参数为1/255
}
data_param { // 数据层参数
source: "examples/mnist/mnist_train_lmdb" //LMDB路径
batch_size: 64 // 一次训练的样本数
backend: LMDB //读入的训练数据格式,默认leveldb
}
}
// 测试(预测)时数据层的定义
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST // 该层的参数只 test 时使用
}
transform_param {
scale: 0.00390625 // 1/255 归一化数据
}
data_param {
source: "examples/mnist/mnist_test_lmdb"//测试数据路径
batch_size: 100 // 一次测试使用100个数据
backend: LMDB
}
}
// 第一卷积层的定义
layer {
name: "conv1" // 该网络层的名称
type: "Convolution" // 该网络层类型:卷积层
bottom: "data" // 输入是 data
top: "conv1" // 输出命名为 conv1
param {
lr_mult: 1 //weights的学习率与全局相同
}
param {
lr_mult: 2 //biases的学习率是全局的2倍
}
convolution_param { // 卷积参数设置
num_output: 20 // 输出 20个 featur maps
kernel_size: 5 // 卷积核 尺寸 5*5
stride: 1 // 卷积步长
weight_filler {
type: "xavier" // 指定权值参数初始化方式
}
bias_filler {
type: "constant" // bias用0初始化
}
}
}
// 第一池化层的定义
layer {
name: "pool1" // 该网络层的名称
type: "Pooling" // 该网络层的类型:池化
bottom: "conv1" // 该网络层的输入
top: "pool1" // 输出的名称
pooling_param { // 池化层的参数设置
pool: MAX // 池化类型: 最大池化
kernel_size: 2 // 2*2区域池化
stride: 2 // 步长
}
}
// 第二卷积层定义
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 50
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
// 第二池化层定义
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 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"
}
}
}
// 激活函数层定义
layer {
name: "relu1"
type: "ReLU" // 使用ReLU激活函数
bottom: "ip1" // 输入输出都是ip1,这么做是为了减少变量
top: "ip1"
}
// 第二全链接层定义,完成分类
layer {
name: "ip2"
type: "InnerProduct" // 网络层类型:全链接层
bottom: "ip1" //输入
top: "ip2" //输出
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 10 // 输出个数 0-9 完成分类
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
//计算分类准确率的层,只在 test 阶段有效
layer {
name: "accuracy"
type: "Accuracy" //类型
bottom: "ip2" // 输入
bottom: "label" //输入
top: "accuracy" //输出
include {
phase: TEST //只在 test 阶段有效
}
}
//损失层
layer {
name: "loss"
type: "SoftmaxWithLoss" //指定采用 SoftmaxWithLoss 损失函数
bottom: "ip2" //输入
bottom: "label" //输入
top: "loss" //输出
}