作为深度学习界的“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解析出来。但是,对于普通人拿到的数据往往都是图片格式,而且是很多。
这该进行怎么加载训练呢。
先粗略的看下,官方的数据集。可以看出images对应一个labels,所以我们准备的数据包括图片和标签。
1)基础准备
在data文件夹下创建如下文件夹,准备训练集,验证集和测试集
创建 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)
运行后可以得到标签,如下:
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’