Caffe学习笔记2:LeNet拒绝官方脚本!从数据准备到训练再到预测

作为深度学习界的“hello world!”,学习起来真没那么容易。
接触深度学习,第一个接触的就是mnist。但是初次接触就只跑了三个脚本

get_mnist.sh
create_mnist.sh
train_lenet.sh

然后就结束了,对此我蒙逼了许久。因为对于caffe的整体框架不熟悉,对CNN不深入,因此感觉举步维艰。经过1个多月的沉淀终于能完整的走一遍MNIST。
对于初学者,深度学习分为三步:1.数据准备 2.训练 3.预测
一.数据准备
官方例程推荐的数据集为

t10k-images-idx3-ubyte
t10k-labels-idx1-ubyte
train-images-idx3-ubyte
train-labels-idx1-ubyte

相信许多人和我一样会问:这是什么啊,打开还是一推二进制数。确实,官方的数据集可视化不好,但是可以借助matlab或者python解析出来。但是,对于普通人拿到的数据往往都是图片格式,而且是很多。

Caffe学习笔记2:LeNet拒绝官方脚本!从数据准备到训练再到预测_第1张图片
Paste_Image.png

这该进行怎么加载训练呢。
先粗略的看下,官方的数据集。可以看出images对应一个labels,所以我们准备的数据包括图片和标签。
1)基础准备
在data文件夹下创建如下文件夹,准备训练集,验证集和测试集


Paste_Image.png

创建 train test文件夹和对应的txt将你的训练集放到train中,将验证集放到test中。(这里应该多建一个valid文件夹,里面存放的是验证集,而test中放测试集,这里偷工减料了)
接着要制作标签,如果量少可以考虑手敲,但是大数据就只能借助代码了。
创建make_list.py

#coding=utf-8
#caffe and opencv test mnist
#test by yuzefan
import os
from os.path import join, isdir

def gen_listfile(dir):
    cwd=os.getcwd() # 获取当前目录
    os.chdir(dir)   # 改变当前的目录
    sd=[d for d in os.listdir('.') if isdir(d)] # 列出当前目录下的所有文件和目录名,os.listdir可以列出文件和目录
    sd.sort()
    class_id=0
    with open(join(dir,'listfile.txt'),'w') as f :  #join():connect string,"with...as"is used for safety,without it,you must write by"file = open("/tmp/foo.txt") file.close()
        for d in sd :
            fs=[join(d,x) for x in os.listdir(d)]
            for img in fs:
                f.write(img + ' '+str(class_id)+'\n')
            class_id+=1
    os.chdir(cwd)

if __name__ == "__main__":
    root_dir = raw_input('image root dir: ')
    while not isdir(root_dir):
        raw_input('not exist, re-input please: ')
    gen_listfile(root_dir)

运行后可以得到标签,如下:

Caffe学习笔记2:LeNet拒绝官方脚本!从数据准备到训练再到预测_第2张图片
Paste_Image.png

list已经准备好了,接着要把数据转成lmdb。caffe之所以速度快,得益于lmdb数据格式。
创建creat_lmdb.sh脚本

#coding=utf-8
#!/usr/bin/env sh 
#指定脚本的解释程序
#by yuzefan
set -e #如果任何语句的执行结果不是true则应该退出
# CAFFEIMAGEPATH is the txt file path
# DATA is the txt file path

CAFFEDATAPATH=mytest/chinese/data
DATA=mytest/chinese/data/mnist
TOOLS=~/caffe-master/build/tools

# TRAIN_DATA_PATH & VAL_DATA_ROOT is root path of your images path, so your train.txt file must do not contain
# this line again!!
TRAIN_DATA_ROOT=/home/ubuntu/caffe-master/mytest/chinese/data/mnist/train/
VAL_DATA_ROOT=/home/ubuntu/caffe-master/mytest/chinese/data/mnist/test/
# Set RESIZE=true to resize the images to 28x28. Leave as false if images have
# already been resized using another tool.
RESIZE=true
if $RESIZE;then
    RESIZE_HEIGHT=28
    RESIZE_WIDTH=28
else
    RESIZE_HEIGHT=0
    RESIZE_WIDTH=0
fi
if [ ! -d "$TRAIN_DATA_ROOT" ]; then
  echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT"
  echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \
       "where the ImageNet training data is stored."
  exit 1
fi

if [ ! -d "$VAL_DATA_ROOT" ]; then
  echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT"
  echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path" \
       "where the ImageNet validation data is stored."
  exit 1
fi

echo "Creating train lmdb..."

GLOG_logtostderr=1 $TOOLS/convert_imageset \
    --resize_height=$RESIZE_HEIGHT \
    --resize_width=$RESIZE_WIDTH \
    --shuffle \
    --gray=true\
    $TRAIN_DATA_ROOT \
    $DATA/train.txt \
    $CAFFEDATAPATH/caffe_train_lmdb

echo "Creating val lmdb..."

GLOG_logtostderr=1 $TOOLS/convert_imageset \
    --resize_height=$RESIZE_HEIGHT \
    --resize_width=$RESIZE_WIDTH \
    --shuffle \
    --gray=true\
    $VAL_DATA_ROOT \
    $DATA/test.txt \
    $CAFFEDATAPATH/caffe_val_lmdb

echo "Done."

运行完后在data目录下出现

caffe_train_lmdb
caffe_val_lmdb

这里使用了caffe的tools中的convert_imageset。使用方法:

convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME 
其中 
参数:ROOTFOLDER 表示输入的文件夹 
参数:LISTFILE 表示输入文件列表,其每一行为:类似 subfolder1/file1.JPEG 7 
可选参数:[FLAGS] 可以指示是否使用shuffle,颜色空间,编码等。
--gray=true  \-------------------------------------------->如果灰度图的话加上即可
还调用了opencv,对输入图像进行尺寸变换,满足网络的要求。

注意:

TRAIN_DATA_PATH & VAL_DATA_ROOT is root path of your images path, so your train.txt file must do not contain

到此,数据准备就结束了。
二.训练
训练需要模型描述文件和模型求解文件。

lenet_train_test.prototxt
lenet_solver.prototxt

对于lenet_train_test.prototxt,需要改的地方只有数据层

name: "LeNet"
layer {
  name: "mnist"  #名字随便
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "mytest/chinese/data/caffe_train_lmdb"  #这里是上一步生成的lmdb
    batch_size: 64#一次压入网络的数量
    backend: LMDB
  }
}
layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "mytest/chinese/data/caffe_val_lmdb"
    batch_size: 100 
    backend: LMDB
  }
}

对于lenet_solver.prototxt

# The train/test net protocol buffer definition
net: "mytest/chinese/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 #test_iter * batch_size= 10000(test集的大小)
# 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: 20
# The maximum number of iterations
max_iter: 10000
# snapshot intermediate results
snapshot: 5000
snapshot_prefix: "mytest/chinese/lenet"
# solver mode: CPU or GPU
solver_mode: GPU

训练可以执行train_lenet.sh,实际上还是调用了tools

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

./build/tools/caffe train --solver=mytest/chinese/lenet_solver.prototxt $@

没有意外的话就能正常开始训练了。
三.预测
预测可以参考我之前写的

Caffe学习笔记1:用训练好的mnist模型进行预测(两种方法)
http://www.jianshu.com/p/6fcdefbacf5b

小笔记:均值计算
减均值预处理能提高训练和预测的速度,利用tools

二进制格式的均值计算
build/tools/compute_image_mean examples/mnist/mnist_train_lmdb examples/mnist/mean.binaryproto
带两个参数:
第一个参数:examples/mnist/mnist_train_lmdb, 表示需要计算均值的数据,格式为lmdb的训练数据。
第二个参数:examples/mnist/mean.binaryproto, 计算出来的结果保存文件。

接下来的计划:现在说白了是个10类的分类器,接下来增强网络使其能够训练并预测出0~9 and ‘a’~‘z’

你可能感兴趣的:(Caffe学习笔记2:LeNet拒绝官方脚本!从数据准备到训练再到预测)