用caffe用LeNet来训练MNIST

本文介绍如何使用Caffe框架配合LeNet模型训练MNIST数据集,详细讲解了网络结构定义、数据输入配置、各层参数设定及训练流程。

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

caffeLeNet来训练MNIST

首先假定你的caffe安装在CAFFE_ROOT

1. 准备数据集

cd $CAFFE_ROOT

./data/mnist/get_mnist.sh

./examples/mnist/create_mnist.sh

get_mnist.sh从网上downmnist的数据集,create_mnist.sh

把数据放在工作目录下。运行完之后应该会产生两个数据集,分别叫mnist_train_lmdbmnist_test_lmdb

 

2. LeNet

在运行程序之前,先介绍下下面程序用的LeNet模型。下面用的方法和原始的LeNet有一点不同,就是将激活函数sigmoid换成了RectifiedLinear Unit (ReLU)

LeNet由两个紧跟pooling层的卷积层和两个全联接层构成。具体见$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt

 

3.定义MNIST网络

这一部分主要介绍lenet_train_test.prototxt,它定义了网络的结构。特别的,我们将会写一个caffe::NetParameter(or in python, caffe.proto.caffe_pb2.NetParameter)。首先,给这个网络一个名字。

 

name: "LeNet"

 

3.1 数据输入层

现在,我们将会从开始准备好的lmdb数据集中读取数据。这层的定义如下:

 

layer {

  name:"mnist"

  type:"Data"

 transform_param {

   scale: 0.00390625

  }

 data_param {

   source: "mnist_train_lmdb"

   backend: LMDB

   batch_size: 64

  }

  top:"data"

  top:"label"

}

 

特别的,这层的名字是mnist,类型是data,它从给定的mnist_train_lmdb中读取数据。采用batch的大小是64,并且scale输入的像素,使得它们落在[0,1)区间内。但是这里为什么要取0.00390625

呢?这个值是1/256得到的。最后,这一层产生了两个blobs,一个是data,另一个是label

 

3.2写一个卷积层

 

卷积层的定义如下:

 

layer {

  name:"conv1"

  type:"Convolution"

  param{ lr_mult: 1 }

  param{ lr_mult: 2 }

 convolution_param {

   num_output: 20

   kernel_size: 5

   stride: 1

   weight_filler {

     type: "xavier"

    }

   bias_filler {

     type: "constant"

    }

  }

 bottom: "data"

  top:"conv1"

}

 

这一层从data blob中读取数据,并且产生conv1层。它产生20channels输出,且kernel的大小是5stride1.

Fillers准许我们随意的初始化weightsbias的值。对于weightfilter,我们用xavier算法来基于输入和输出神经元树来自动的决定初始化的scale。对于biasfiller,我们仅仅初始化它为一个常数,缺省值为0.

lr_mult是该层的可学习参数的学习速率。在上面例子中,我们设置weight的学习速率和solver在运行时给的学习速率相同,bias是该速率的两倍(这样通常能更快的收敛)。

 

3.3 pooling

 

pooling层就很简单啦

 

layer {

  name:"pool1"

  type:"Pooling"

 pooling_param {

   kernel_size: 2

   stride: 2

   pool: MAX

  }

 bottom: "conv1"

  top:"pool1"

}

 

这个poolingkernel的大小是2stride2,用的是最大pooling

类似的,可以写第二个卷积和pooling层,这里就不赘述了,自己看$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt

 

3.4 写全连接层

 

全连接层也很简单:

 

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"

}

 

这个定义了一个有500个输出的全连接层(knownin Caffe as an InnerProduct layer

 

3.5 写一个ReLU

 

ReLU层也很简单:

 

layer {

  name:"relu1"

  type:"ReLU"

 bottom: "ip1"

  top:"ip1"

}

 

由于ReLU是一个element-wise操作,我们可以做in-place操作来减少内存开销。通过简单的给bottomtopblobs相同的名字就可以实现。当然在其他层不要让topbottom名字相同!

 

ReLU层之后,我们写另一个innerproduct层:

 

layer {

  name:"ip2"

  type:"InnerProduct"

  param{ lr_mult: 1 }

  param{ lr_mult: 2 }

 inner_product_param {

   num_output: 10

   weight_filler {

     type: "xavier"

    }

   bias_filler {

     type: "constant"

    }

  }

 bottom: "ip1"

  top:"ip2"

}

 

3.6 loss

 

layer {

  name:"loss"

  type:"SoftmaxWithLoss"

 bottom: "ip2"

 bottom: "label"

}

 

softmax_loss层实现了softmaxmultinomiallogistic loss(这节省了时间,并且提高了数据稳定性)。它有两个输入blob,第一个是预测值,另一个是label。它没有输出,它只需要在反向传播的时候report出比较结果,然后根据ip2来进行梯度下降。这也是反向传播开始的地方。

 

3.7 另外需要注意:写每一层的规则

 

layer定义可以包括它们进入网络的时间和位置,例如:

 

layer {

  //...layer definition...

 include: { phase: TRAIN }

}

 

这表示这层只有在训练的时候调用,如果是TEST,则只有在测试的时候调用。因此在lenet_train_test.prototxt中有两个DATA层(它们有不同的batch_size),其中一个训练时用,另一个测试时用。当然,在TEST时还有Accuracy层,来报告每100次迭代后的准确率,被定义在lenet_solver.prototxt中。

 

 

4.定义MNISTsolver

检查$CAFFE_ROOT/examples/mnist/lenet_solver.prototxt:

 

# The train/test net protocol bufferdefinition

net: "examples/mnist/lenet_train_test.prototxt"

# test_iter specifies how many forward passesthe test should carry out.

# In the case of MNIST, we have test batchsize 100 and 100 test iterations,

# covering the full 10,000 testing images.

test_iter: 100

# Carry out testing every 500 trainingiterations.

test_interval: 500

# The base learning rate, momentum and theweight 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

 

 

5.训练和测试模型

 

训练很简单,只需要runtrain_lenet.sh,或者用下面的命令:

 

cd $CAFFE_ROOT

./examples/mnist/train_lenet.sh

 

train_lenet.sh时一个简单的脚本,这里简单的介绍下:themain tool for training is caffe with action train and the solver protobuf textfile as its argument.

 

当运行代码的时候,你可以看到许多的message,像下面这样的:

 

I1203 net.cpp:66] Creating Layer conv1

I1203 net.cpp:76] conv1 <- data

I1203 net.cpp:101] conv1 -> conv1

I1203 net.cpp:116] Top shape: 20 24 24

I1203 net.cpp:127] conv1 needs backwardcomputation.

 

这些信息告诉你每一层的细节,它的连接关系和输出的shape。这些信息对于debug是很重要的。在initialization结束后,训练就会开始啦:

 

I1203 net.cpp:142] Network initializationdone.

I1203 solver.cpp:36] Solver scaffolding done.

I1203 solver.cpp:44] Solving LeNet

 

基于solver设置,会每100次迭代后打印出训练loss500次迭代后打印出测试loss。你会看到下面的信息:

 

I1203 solver.cpp:204] Iteration 100, lr =0.00992565

I1203 solver.cpp:66] Iteration 100, loss =0.26044

...

I1203 solver.cpp:84] Testing net

I1203 solver.cpp:111] Test score #0: 0.9785

I1203 solver.cpp:111] Test score #1: 0.0606671

 

对于每一次迭代,lr时学习速率,loss是训练方程。对于测试时的输出,score0是准确率,score 1是测试loss

 

几秒后,就完成了!

 

I1203 solver.cpp:84] Testing net

I1203 solver.cpp:111] Test score #0: 0.9897

I1203 solver.cpp:111] Test score #1: 0.0324599

I1203 solver.cpp:126] Snapshotting tolenet_iter_10000

I1203 solver.cpp:133] Snapshotting solverstate to lenet_iter_10000.solverstate

I1203 solver.cpp:78] Optimization Done.

 

最终的模型存在一个二进制protobuf文件中,它存在lenet_iter_10000

 

如何在GPU上运行?

其实刚刚的就是在GPU上运行,如果你想在CPU上运行,就把lenet_solver.prototxt中改成下面这样:

 

# solver mode: CPU or GPU

solver_mode: CPU

 

原文及代码链接:https://github.com/BVLC/caffe/tree/master/examples/mnist

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值