美文网首页
caffe window跑mnist

caffe window跑mnist

作者: 陈穗龙666 | 来源:发表于2018-03-03 06:58 被阅读0次

用Caffe在MNIST上训练LeNet

我们假设你已经成功编译了Caffe。如果没有,请参阅安装页面。在本教程中,我们将假设您的Caffe安装位于CAFFE_ROOT

准备数据集

您首先需要从MNIST网站下载并转换数据格式。为此,只需运行以下命令:

cd $CAFFE_ROOT
./data/mnist/get_mnist.sh
./examples/mnist/create_mnist.sh

如果它抱怨wget或未gunzip安装,则需要分别安装它们。运行脚本后,应该有两个数据集mnist_train_lmdb,和mnist_test_lmdb。

在window上这就是然并卵啊!!! 没事有招..

image.png

在windows下使用caffe时,如果先前没有啥经验,会考虑按照官方文档中的例子跑一跑。比如mnist手写数字识别。

然后就会遇到这个问题:windows下怎么执行/examples/mnist/create_mnist.sh呢?

当然,你需要先编译了convert_mnist_data子项目,以及下载了mnist数据集。

ok,要执行的脚本create_mnist.sh是shell语法,不妨转写为python

# create_mnist.py

import os
import shutil

EXAMPLE='F:\\py\\mnist'
DATA='F:\\py\\mnist'
BUILD='G:\\caffe\\bin'

BACKEND='lmdb'

print "Createing "+BACKEND+"..."

#rm -rf $EXAMPLE/mnist_train_${BACKEND}
#rm -rf $EXAMPLE/mnist_test_${BACKEND}

path1=EXAMPLE+"\\mnist_train_"+BACKEND
path2=EXAMPLE+"\\mnist_test_"+BACKEND

if os.path.exists(path1):
    shutil.rmtree(path1)
if os.path.exists(path2):
    shutil.rmtree(path2)

s1=BUILD+"\\convert_mnist_data.exe"
s2=DATA+"\\train-images.idx3-ubyte"
s3=DATA+"\\train-labels.idx1-ubyte"
s4=EXAMPLE+"\\mnist_train_"+BACKEND
s5="--backend="+BACKEND

cmd=s1+" "+s2+" "+s3+" "+s4+" "+s5
print cmd
os.system(cmd)

t1=BUILD+"\\convert_mnist_data.exe"
t2=DATA+"\\t10k-images.idx3-ubyte"
t3=DATA+"\\t10k-labels.idx1-ubyte"
t4=EXAMPLE+"\\mnist_test_"+BACKEND
t5="--backend="+BACKEND

cmd=t1+" "+t2+" "+t3+" "+t4+" "+t5
print "cmd2="+cmd
os.system(cmd)
PS G:\Projects\caffe\examples\mnist> py ./create_mnist.py
Createing lmdb...
G:\caffe\bin\convert_mnist_data.exe F:\py\mnist\train-images.idx3-ubyte F:\py\mnist\train-labels.idx1-ubyte F:\py\mnist\
mnist_train_lmdb --backend=lmdb
I0302 14:46:29.084498  7608 common.cpp:36] System entropy source not available, using fallback algorithm to generate see
d instead.
I0302 14:46:29.086498  7608 db_lmdb.cpp:40] Opened lmdb F:\py\mnist\mnist_train_lmdb
I0302 14:46:29.086498  7608 convert_mnist_data.cpp:93] A total of 60000 items.
I0302 14:46:29.087498  7608 convert_mnist_data.cpp:94] Rows: 28 Cols: 28
I0302 14:46:40.301141  7608 convert_mnist_data.cpp:113] Processed 60000 files.
cmd2=G:\caffe\bin\convert_mnist_data.exe F:\py\mnist\t10k-images.idx3-ubyte F:\py\mnist\t10k-labels.idx1-ubyte F:\py\mni
st\mnist_test_lmdb --backend=lmdb
I0302 14:46:40.795168 14096 common.cpp:36] System entropy source not available, using fallback algorithm to generate see
d instead.
I0302 14:46:40.798168 14096 db_lmdb.cpp:40] Opened lmdb F:\py\mnist\mnist_test_lmdb
I0302 14:46:40.798168 14096 convert_mnist_data.cpp:93] A total of 10000 items.
I0302 14:46:40.798168 14096 convert_mnist_data.cpp:94] Rows: 28 Cols: 28
I0302 14:46:41.637217 14096 convert_mnist_data.cpp:113] Processed 10000 files.
PS G:\Projects\caffe\examples\mnist>

生成好训练的数据了

LeNet:MNIST分类模型

在我们实际运行培训计划之前,让我们先解释一下会发生什么。我们将使用已知在数字分类任务中运作良好的LeNet网络。我们将使用与原始LeNet实施方案略有不同的版本,用神经元的整流线性单位(ReLU)激活代替S形激活。

LeNet的设计包含了CNN的本质,这些CNN仍然用于ImageNet等大型模型中。一般来说,它由一个卷积层,一个汇集层,另一个卷积层,然后是一个汇集层,然后是两个完全连接的层,类似于传统的多层感知器。我们已经定义了图层$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt

定义MNIST网络

本节介绍了lenet_train_test.prototxt指定MNIST手写数字分类的LeNet模型的模型定义。我们假设您熟悉Google Protobuf,并且假设您已经阅读了Caffe使用的protobuf定义,可以在这里找到它$CAFFE_ROOT/src/caffe/proto/caffe.proto

具体来说,我们将编写一个caffe::NetParameter(或python caffe.proto.caffe_pb2.NetParameter)protobuf。我们将首先给网络一个名字:

name: "LeNet"

编写数据层

目前,我们将从我们之前在演示中创建的lmdb中读取MNIST数据。这由数据层定义:

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,并从给定的lmdb源读取数据。我们将使用64的批处理大小,并缩放输入像素,使其位于[0,1)范围内。为什么0.00390625?它是1除以256.最后,这一层产生两个斑点,一个是data斑点,另一个是label斑点。

编写卷积层

我们来定义第一个卷积层:

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"
}

该图层采用dataBlob(由数据层提供)并生成conv1图层。它产生20个通道的输出,卷积核大小为5,执行步长为1。

填充符允许我们随机初始化权重和偏差的值。对于加权填充器,我们将使用xavier基于输入和输出神经元数自动确定初始化规模的算法。对于偏置填充器,我们将简单地将其初始化为常量,默认填充值为0。

lr_mults是图层可学习参数的学习速率调整。在这种情况下,我们将设置权重学习率与求解器在运行时给出的学习率相同,并且偏差学习率为此的两倍 - 这通常会导致更好的收敛率。

编写池图层

唷。合并图层实际上更容易定义:

layer {
  name: "pool1"
  type: "Pooling"
  pooling_param {
    kernel_size: 2
    stride: 2
    pool: MAX
  }
  bottom: "conv1"
  top: "pool1"
}

这就是说,我们将执行池大小为2的最大池和跨度为2(所以相邻池区之间不重叠)。

同样,你可以写出第二个卷积和合并图层。检查$CAFFE_ROOT/examples/mnist/lenet_train_test.prototxt细节。

编写完全连接的层

编写完全连接的图层也很简单:

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"
}

这定义了InnerProduct具有500个输出的完全连接的层(在Caffe中称为层)。所有其他线看起来很熟悉,对吧?

编写ReLU层

ReLU层也很简单:

layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}

由于ReLU是一种按元素操作,我们可以进行就地操作以节省一些内存。这是通过简单地给底部和顶部斑点赋予相同的名称来实现的。当然,不要为其他图层类型使用重复的斑点名称!

在ReLU层之后,我们将编写另一个内部产品层:

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"
}

编写损失层

最后,我们会写下损失!

layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
}

该softmax_loss层实现softmax和多项logistic损失(这节省了时间并提高了数值稳定性)。它需要两个blob,第一个是预测,第二个是label数据层提供的(记住它?)。它不会产生任何输出 - 它只是计算损失函数值,在反向传播开始时报告它,并针对其启动梯度ip2。这是所有魔法开始的地方。

其他注意事项:编写层规则
图层定义可以包含是否以及何时包含在网络定义中的规则,如下所示:

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

这是一个规则,它根据当前网络的状态控制网络中的层包含。您可以参考$CAFFE_ROOT/src/caffe/proto/caffe.proto关于图层规则和模型模式的更多信息。

在上面的例子中,这一层将只包含在TRAIN阶段中。如果我们改变TRAIN了TEST,那么这个图层将仅用于测试阶段。默认情况下,没有图层规则,图层始终包含在网络中。因此,lenet_train_test.prototxt有DATA两层定义(不同batch_size),一个用于训练阶段,另一个用于测试阶段。此外,还有一个Accuracy仅包含在TEST阶段中的层,用于每100次迭代报告模型精度,如定义lenet_solver.prototxt。

定义MNIST求解器

查看解释原型文件中每一行的注释$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

培训和测试模型

在编写网络定义protobuf和求解器protobuf文件后,训练模型很简单。train_lenet.sh直接运行,或直接执行以下命令:

cd $CAFFE_ROOT
./examples/mnist/train_lenet.sh

train_lenet.sh是一个简单的脚本,但这里是一个快速解释:训练的主要工具是caffe动作train和解算器protobuf文本文件作为其参数。

当你运行代码时,你会看到很多像这样飞行的消息:

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 backward computation.

这些消息告诉你关于每一层的细节,它的连接和它的输出形状,这可能对调试有帮助。初始化后,培训将开始:

I1203 net.cpp:142] Network initialization done.
I1203 solver.cpp:36] Solver scaffolding done.
I1203 solver.cpp:44] Solving LeNet

基于求解器设置,我们将每100次迭代打印一次训练损失函数,并且每500次迭代测试一次​​网络。你会看到这样的消息:

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是训练函数。对于测试阶段的输出,得分0是准确度,得分1是测试损失函数。

几分钟后,你就完成了!

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 to lenet_iter_10000
I1203 solver.cpp:133] Snapshotting solver state 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

并且您将使用CPU进行培训。这不容易吗?

MNIST是一个小型数据集,因此使用GPU进行培训并不会因通信开销而带来太多好处。在更复杂模型的大型数据集上,如ImageNet,计算速度差异将更为显着。

训练跑起来了

image.png

模型也训练好了

image.png

现在的文件目录结构

image.png

前面又是 sh.改成cmd.

train_lenet.cmd

G:\caffe\bin\caffe train --solver=lenet_solver.prototxt

lenet_solver.prototxt
lenet_train_test.prototxt
这两个文件从demo里面就有..自己复制一下.
需要打开文件,修改路径

image.png
image.png

然后就可以训练了。

预测

生成均值文件

compute_image_mean.cmd

G:\caffe\bin\compute_image_mean mnist_train_lmdb mean.binaryproto 
pause

跑一下就出来均值文件了

test_lenet-one.cmd

G:\caffe\bin\classification lenet.prototxt ./lenet/_iter_10000.caffemodel mean.binaryproto label.txt ./test/3.png
pause
image.png

python调用caffe模型

import sys
import caffe

classifier = caffe.Classifier(
    'lenet.prototxt',
    'lenet/_iter_10000.caffemodel',
    image_dims=(28, 28),
    mean=None,
    input_scale=None,
    raw_scale=255,
    channel_swap=None)

img = 'test/3.png'
inputs = [caffe.io.load_image(img, False)]  # rgb to gray
scores = classifier.predict(inputs, False).argmax()

scores

image.png

相关文章

网友评论

      本文标题:caffe window跑mnist

      本文链接:https://www.haomeiwen.com/subject/treaxftx.html