caffe在 .\examples\mnist文件夹下有一个 lenet.prototxt文件,这个文件定义了一个广义的LetNet-5模型,对这个模型文件逐段分解一下。
name: "LeNet" //网络的名称是LeNet
layer { //定义一个网络层
name: "data" //定义该网络层的名称为 data
type: "Input" //定义网络层的类型是 输入层
top: "data" //定义网络层的输出名称为data
//定义该网络层的训练参数
input_param {
//如果同时读取过多张图片进行训练,训练耗时比较久
//所以CNN中分组读入训练图片
//shape中第一个参数定义每组中包含图片数量
//第二个参数定义组数
//第三和第四个参数定义图片大小
//定义读取数据维度是: 64 1 28 28
shape: { dim: 64 dim: 1 dim: 28 dim: 28 }
}
}
//第一卷积层定义
layer { //定义一个网络层
name: "conv1" //网络层的名称是conv1
type: "Convolution" //网络层的类型是 卷积层
//模型结构图有两种常用画法,一种是从左到右,一种是从下到上
//caffe中使用从下到上画法,所以“bottom”表示的是上一层(输入层)
bottom: "data" //网络层的输入层是 data层
//同理,输出层在上,“top”表示输出
top: "conv1" //该层的输出层名称为conv1
//param定义权重和偏置的学习率,学习率大,迭代速度快,但是容易找不到最优解
//学习率小,迭代速度慢,耗时久
//如果有两个lr_mult参数,第一个表示权重(卷积核)的学习率系数,第二个表示偏置的学习率系数
//lr_mult定义的只是学习率系数,最终的值需要乘以solver.prototxt配置文件中配置的base_lr的值
//一般偏置的学习率系数是权重学习率系数的2倍
param {
lr_mult: 1 //该层权重学习率的系数为1
}
param {
lr_mult: 2 //该层偏置学习率的系数为2
}
//卷积操作的参数设置
convolution_param {
num_output: 20 //卷积输出特征图的数量为20
kernel_size: 5 //卷积核的大小是5*5
stride: 1 //卷积操作的步长是1,即卷积核逐个移动
weight_filler {
type: "xavier" //卷积核参数采用xavier方法初始化
}
bias_filler {
type: "constant" //偏置初始值为0
}
}
} //卷积完成之后,数据的维度变成 64 20 24 24
//第一池化层定义
layer {
name: "pool1" //网络层的名称是pool1
type: "Pooling" //网络层的类型是池化层
bottom: "conv1" //网络层的输入时conv1(第一卷积层)
top: "pool1" //网络层的输出名称是 pool1
//池化操作的参数设置
pooling_param {
pool: MAX //最大值池化
kernel_size: 2 //池化核尺寸 是2*2
stride: 2 //池化步长是2
}
} //第一池化完成之后,数据的维度变成 64 20 12 12
//第二卷积层定义
layer {
name: "conv2" //网络层的名称是conv2
type: "Convolution" //网络层的类型是卷积层
bottom: "pool1" //网络层的输入时 pool1(第一池化层)
top: "conv2" //网络层的输出名称是 conv2
param {
lr_mult: 1 //卷积核的学习率系数是1
}
param {
lr_mult: 2 //偏置的学习率系数是2
}
//第二卷积层参数设置
convolution_param {
num_output: 50 //输出特征图的数量
kernel_size: 5 //卷积核的尺寸是5*5
stride: 1 //卷积操作步长是1
weight_filler {
type: "xavier" //卷积核参数采用xavier方法初始化
}
bias_filler {
type: "constant" //偏置初始值为0
}
}
} //第二卷积操作完成之后,数据维度是 64 50 8 8
//第二池化层
layer {
name: "pool2" //网络层的名称是 pool2
type: "Pooling" //网络层的类型是池化层
bottom: "conv2" //网络层的输入时 conv2(第二卷积层)
top: "pool2" //网络层的输出名称是 pool2
pooling_param {
pool: MAX //池化方式是最大值池化
kernel_size: 2 //池化核大小是2*2
stride: 2 //池化步长是2
}
} //第二池化层完成之后,数据维度是 64 50 4 4
//第一层全连接层定义
layer {
name: "ip1" //网络层的名称是ip1
type: "InnerProduct" //网络层的类型是 全连接层
bottom: "pool2" //网络层的输入时 pool2(第二池化层)
top: "ip1" //网络层的输出名称是ip1
param {
lr_mult: 1 //卷积核的学习率系数是1
}
param {
lr_mult: 2 //偏置的学习率系数是2
}
//第一全连接层参数设置
inner_product_param {
num_output: 500 //输出向量维度,500个输出神经元
weight_filler {
type: "xavier" //卷积核参数采用xavier方法初始化
}
bias_filler {
type: "constant" //偏置初始值为0
}
}
} //第一全连接层完成之后数据的维度是 1 500 1 1
//激活函数层的定义
layer {
name: "relu1" //网络层的名称是relu1
type: "ReLU" //网络层的类型是ReLU激活函数
bottom: "ip1" //网络层的输入时ip1(第一全连接层)
top: "ip1" //网络层的输出名称是 ip1,跟输入名称一样
} //激活层完成之后,数据的维度是 1 500 1 1
//第二全连接层定义
//数据的分类判断在本层完成
layer {
name: "ip2" //网络层的名称是 ip2
type: "InnerProduct" //网络层的类型是全连接层
bottom: "ip1" //网络层的输入时 ip1(激活函数层)
top: "ip2" //网络层的输出名称是 ip2
param {
lr_mult: 1 //卷积核的学习率系数是1
}
param {
lr_mult: 2 //偏置的学习率系数是2
}
//第二全连接层参数设置
inner_product_param {
num_output: 10 //输出维度是10,分别是0~9的数字
weight_filler {
type: "xavier" //卷积核参数采用xavier方法初始化
}
bias_filler {
type: "constant" //偏置初始值为0
}
}
} //第二全连接层完成之后,数据的维度是 1 10 1 1
//输出层定义
layer {
name: "prob" //网络的名称是 prob
type: "Softmax" //网络的类型是损失函数
bottom: "ip2" //网络的输入是 ip2(第二全连接层)
top: "prob" //网络的输出名称是 prob
}
lenet.prototxt模型可视化,可以作为对比: