训练超参数
在MNIST例程中,通过执行Shell脚本(./examples/mnist/train_lenet.sh)启动模型训练。train_lenet.sh内容如下:
#!/usr/bin/env sh
set -e
./build/tools/caffe train --solver=examples/mnist/lenet_solver.prototxt $@
改脚本调用了build/tools/caffe 可执行文件,参数–solver=examples/mnist/lenet_solver.prototxt制定了训练超参数,文件内容如下
# 定义用于训练/测试的网络描述文件(ProtoBuffer格式)
net: "examples/mnist/lenet_train_test.prototxt"
# 预测阶段迭代次数。在MNIST例程下,预测样本组(test batch)大小为100,
# 设置跌带100次可以刚好覆盖10000个样本
test_iter: 100
# 每500次迭代进行一次测试。
test_interval: 500
# 网络的基本学习率、动量和权重衰减
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
# 学习速率的衰减策略
lr_policy: "inv"
gamma: 0.0001
power: 0.75
# 每100次迭代打印一次log
display: 100
# 最大迭代次数
max_iter: 10000
# 每迭代5000次保存一次中间结果
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
# 求解模式,CPU或GPU
solver_mode: CPU
LeNet-5 模型
在lenet_solver.prototxt文件中制定了网络描述文件为examples/mnist/lenet_train_test.prototxt 内容如下:
name: "LeNet" // 网络名称为LeNet
layer { // 定义一个层
name: "mnist" // 层名称为mnist
type: "Data" // 层类型为数据层
top: "data" // 层的输出有两个,data和label
top: "label"
include {
phase: TRAIN // 该层只用于训练阶段
}
transform_param {
scale: 0.00390625 // 数据变换使用的数据缩放因子
}
data_param { // 数据层参数
source: "examples/mnist/mnist_train_lmdb" //数据路径
batch_size: 64 // 批量数据,一次读取64张图
backend: LMDB // 数据格式为LMDB
}
}
layer { //定义一个层,与上一个层类似,只用于测试阶段
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TEST
}
transform_param {
scale: 0.00390625
}
data_param {
source: "examples/mnist/mnist_test_lmdb"
batch_size: 100
backend: LMDB
}
}
layer { // 定义一个卷积层
name: "conv1" // 层名称为conv1
type: "Convolution" // 层类型为卷积层
bottom: "data" // 层的输入为上一层的输出"data"
top: "conv1" // 层的输出为conv1
param {
lr_mult: 1 // 层的学习速率是全局参数的1倍
}
param {
lr_mult: 2 // bias学习速率是全局参数的2倍
}
convolution_param { // 卷积计算参数
num_output: 20 // 输出feature map数为20
kernel_size: 5 // 卷积核大小为5*5
stride: 1 // 卷积输出跳跃间隔,1表示连续输出
weight_filler {
type: "xavier" // 权值使用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 { // 定义新的卷积层,与conv1层类似
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 { //定义新的下采样层,与pool1类似
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 // 该层输出元素个数为500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer { // 定义非线性层
name: "relu1"
type: "ReLU" // 用ReLU方法
bottom: "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 // 输出个数为10,对应手写数字输出的0-9
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer { // 分类准确率层,用于计算分类的准确率
name: "accuracy"
type: "Accuracy"
bottom: "ip2"
bottom: "label"
top: "accuracy"
include {
phase: TEST
}
}
layer { // 损失层
name: "loss"
type: "SoftmaxWithLoss"
bottom: "ip2"
bottom: "label"
top: "loss"
}
通过LeNet网络结构图可以看到,mnist层负责从lmdb数据库中读取图像数据data和标签label,图像送入CNN结构中处理。CNN结构包括一组用卷积层和下采样层交替形成特征层,以及ip1和ip2两个全连接层。ip2和标签对比,计算出分类的准确率(accuracy)和损失值(loss)。LeNet的设计蕴含了CNN的精髓。