用Caffe在MNIST上训练LeNet

本文详细介绍如何使用Caffe框架训练LeNet模型以完成MNIST手写数字识别任务,包括数据集准备、网络结构定义、训练及测试流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博客参考: Caffe官方Training LeNet on MNIST with Caffe

数据准备

首先从MNIST网站下载数据集并转换获取的数据格式,运行以下简单的命令脚本

cd $CAFFE_ROOT #$CAFFE_ROOT指的是caffe所在根目录
./data/mnist/get_mnist.sh #从脚本中提供的网址下载数据(.gz格式)并解压、删除已下载的原件,仅保留解压后的数据(如train-images-idx3-ubyte、train-labels-idx1-ubyte)
./examples/mnist/create_mnist.sh #将上述数据转化成lmdb格式

lmdb格式讲解
简述:Caffe中的lmdb数据大约有两类:1. 输入 DataLayer的训练/测试数据集;2. extract_feature输出的特征数据。

lmdb,文件结构简单,一个文件夹里面包含一个数据文件,一个锁文件。数据随意复制,随意传输。访问简单,不需要运行单独的数据库管理进程,只要在访问数据的代码里引用LMDB库,访问时给文件路径即可。


运行完上述的脚本文件后,会在/examples/mnist目录下面得到mnist_train_lmdb和mnist_test_lmdb两个文件夹,每个文件夹下包含有一个数据文件data.lmdb和一个锁文件lock.lmdb。

LeNet:MNIST分类模型

在初始版本的LeNet上稍稍改变:用ReLU替换sigmoid激活函数。已经在$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt中定义了网络结构。

caffe中的protobuf定义,见$CAFFE_ROOT/src/caffe/proto/caffe.proto,官方的protobuf documents参考Google Protobuf,另参考博客protobuf文件的简单使用

定义MNIST网络

在LeNet的示例中,lenet_train_test.prototxt文件描述了LeNet网络的结构:

首先,给网络一个名字

name:"LeNet"

数据层Data Layer

layer {
  name: "mnist" #本层的名字自取
  type: "Data" #层类型
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}
从所指定的lmdb中读取数据;batch size为64,scal输入的像素值到[0,1)256分之1=0.00390625;最后产生(输出)两个blob(data blob和label blob)用于下层。

卷积层Convolution Layer

第一个卷积层:

layer {
  name: "conv1" # 本层的名字自取
  type: "Convolution" # 层类型
  bottom: "data" # 接受来自data layer的data
  top: "conv1" # 输出/产生conv1 blob
  param {
    lr_mult: 1#学习率
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20 #输出的channels数为20
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}
fillers可以随机的初始化weights和bias值。在本层中,对于weights fillers,使用 xavier算法根据输入输出的神经节点数目自动决定初始化的尺度;对于bisa fillers,采用 constant常数填充,这里用0填充。
lr_mults是层中可学习参数的学习率。在该例子中,weight的学习率与运行期间由solver给定的学习率相同,bias学习率是weight学习率的两倍大,这样做通常有更好的收敛率。

池化层Pooling Layer

layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
pooling层相对简单,这里的解释是对来自conv1的blob以max-pooling的方式处理,然后产生名为pool1的blob。如此,可以近似地编写conv2和pool2层。

全连接层Fully Connected Layer

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"
    }
  }
}
这样就定义了对来自pool2的blob进行 InnerProduct以得到一个有500单元输出的blob ip1。

ReLU处理层

layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}
以相同的名字来命名bottom和top,即对输入进行一次 ReLU变换。同理,可以构建 InnerProduct layer ip2层。

Loss Layer

layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}
softmax_loss层实现softmax和多项logistic损失(省时并提高数值稳定性)。它需要两个blob,第一个是预测,第二个是数据层提供的标签。计算损失函数值,在反向传播开始时报告它,并针对ip2启动梯度。

额外注意点:编写层规则

layer {
  // ...layer definition...
  include: { phase: TRAIN }
}

图层的定义可以包含是否以及何时包含在网络定义中的规则中。示例描述的是一个基于当前网络状态来控制网络中的层包含的规则。规则TRAIN说明该层只包含在训练阶段,默认情况下(无规则时)层包含在整个网络中。因此,lenet_train_test.prototxt有两个具有不同batch_size的Data Layers:一个用于训练,另一个用于测试。

layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "ip2"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
此外,还有一个Accurry Layer,仅包含在测试阶段,用于每100次迭代报告模型精度。当然,这里所说的100次是在$CAFFE_ROOT/examples/mnist/lenet_solver.prototxt中描述的。

定义MNIST的Solver

具体描述见$CAFFE_ROOT/examples/mnist/lenet_solver.prototxt

# The train/test net protocol buffer definition
net: "examples/mnist/lenet_train_test.prototxt"
# test_iter specifies how many forward passes the test should carry out.
# In the case of MNIST, we have test batch size 100 and 100 test iterations,
# covering the full 10,000 testing images.
test_iter: 100
# Carry out testing every 500 training iterations.
test_interval: 500
# The base learning rate, momentum and the weight decay of the network.
base_lr: 0.01
momentum: 0.9
weight_decay: 0.0005
# The learning rate policy
lr_policy: "inv"
gamma: 0.0001
power: 0.75
# Display every 100 iterations
display: 100
# The maximum number of iterations
max_iter: 10000
# snapshot intermediate results
snapshot: 5000
snapshot_prefix: "examples/mnist/lenet"
# solver mode: CPU or GPU
solver_mode: GPU
选择GPU训练,solver_model:GPU

训练和测试模型

运行$CAFFE_ROOT/examples/mnist/train_lenet.sh脚本,训练的主要工具就是caffe中的train操作,并以solver prototxt文件作为它的参数。

#!/usr/bin/env sh
set -e

./build/tools/caffe train --solver=examples/mnist/lenet_solver.prototxt $@



由图可知,每层的连接和输出规模,并且可在对应的源文件中追踪,如[...   net.cpp:84]。此外,我们还能知道哪些层需要反向传播计算,有无输出loss。在初始化完成后,开始训练过程。

根据solver的设置,每100 iterations打印输出训练损失,以及每500 iterations测试一次网络,那么可以看到:

I1208 10:02:38.242851  4482 solver.cpp:218] Iteration 100 (653.884 iter/s, 0.152932s/100 iters), loss = 0.21386
I1208 10:02:38.242880  4482 solver.cpp:237]     Train net output #0: loss = 0.21386 (* 1 = 0.21386 loss)
I1208 10:02:38.242887  4482 sgd_solver.cpp:105] Iteration 100, lr = 0.00992565
...
...
I1208 10:02:38.758451  4482 solver.cpp:330] Iteration 500, Testing net (#0)
I1208 10:02:38.809602  4491 data_layer.cpp:73] Restarting data prefetching from start.
I1208 10:02:38.810797  4482 solver.cpp:397]     Test net output #0: accuracy = 0.9726
I1208 10:02:38.810818  4482 solver.cpp:397]     Test net output #1: loss = 0.0893905 (* 1 = 0.0893905 loss)
...
...
I1208 10:02:51.497777  4482 solver.cpp:447] Snapshotting to binary proto file examples/mnist/lenet_iter_10000.caffemodel
I1208 10:02:51.501615  4482 sgd_solver.cpp:273] Snapshotting solver state to binary proto file examples/mnist/lenet_iter_10000.solverstate
I1208 10:02:51.503881  4482 solver.cpp:310] Iteration 10000, loss = 0.00287347
I1208 10:02:51.503899  4482 solver.cpp:330] Iteration 10000, Testing net (#0)
I1208 10:02:51.553721  4491 data_layer.cpp:73] Restarting data prefetching from start.
I1208 10:02:51.555130  4482 solver.cpp:397]     Test net output #0: accuracy = 0.9907
I1208 10:02:51.555150  4482 solver.cpp:397]     Test net output #1: loss = 0.0314041 (* 1 = 0.0314041 loss)
I1208 10:02:51.555155  4482 solver.cpp:315] Optimization Done.
I1208 10:02:51.555158  4482 caffe.cpp:259] Optimization Done.
最终的模型,以2进制protobuf文件的形式存储在lenet_iter_10000.caffemodel中,运行测试文件test_lenet.sh.

#!/usr/bin/env sh

./build/tools/caffe test --model=examples/mnist/lenet_train_test.prototxt \
--weights=examples/mnist/lenet_iter_10000.caffemodel -gpu=0
如果遇到权限问题,加上权限:
$ chmod +x ./examples/mnist/test_lenet.sh



























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值