http://www.cnblogs.com/denny402/p/5684431.html
感谢博主徐其华随笔分类 - caffe系列教程,收获颇丰。在这里记录下自己学习训练和测试模型的过程,可以说相关知识是完全来自参考博文,只是记录一下自己实践中的问题和感悟。
一、数据准备
官网提供的mnist数据并不是图片,但我们以后做的实际项目多数可能是图片。因此有些人并不知道该怎么办。在此我将mnist数据进行了转化,变成了一张张的图片,我们练习就从图片开始。
linu下直接用wget下载 wget http://deeplearing.net/data/mnist/mnist.pkl.gz
mnist.pkl.gz其实是数据的训练集、验证集和测试集用pickle导出的文件被压缩为gzip格式,所以用python的gzip模块当成文件就可以读取。其中每个数据集是一个元组,第一个元素存储的是手写数字图片,表示每张图片是长度为28*28=784的一维浮点型numpy数组,这个数组就是单通道灰度图片按行展开得到,最大值为1(白),最小值为0(黑)。元组中的第二个元素是图片对应的标签,是一个一维的整型numpy数组,按照下标位置对应图片中的数字。然后运行 convert_mnist.py 将pickle格式的数据转换为图片。
import os | |
import pickle, gzip | |
from matplotlib import pyplot | |
# Load the dataset | |
print('Loading data from mnist.pkl.gz ...') | |
with gzip.open('mnist.pkl.gz', 'rb') as f: | |
train_set, valid_set, test_set = pickle.load(f) | |
imgs_dir = 'mnist' | |
os.system('mkdir -p {}'.format(imgs_dir)) | |
datasets = {'train': train_set, 'val': valid_set, 'test': test_set} | |
for dataname, dataset in datasets.items(): | |
print('Converting {} dataset ...'.format(dataname)) | |
data_dir = os.sep.join([imgs_dir, dataname]) | |
os.system('mkdir -p {}'.format(data_dir)) | |
for i, (img, label) in enumerate(zip(*dataset)): | |
filename = '{:0>6d}_{}.jpg'.format(i, label) | |
filepath = os.sep.join([data_dir, filename]) | |
img = img.reshape((28, 28)) | |
pyplot.imsave(filepath, img, cmap='gray') | |
if (i+1) % 10000 == 0: | |
print('{} images converted!'.format(i+1)) |
该脚本首先创建一个叫mnist的文件夹,然后在mnist下创建3个子文件夹train、val和test,分别用来保存对应3个数据集转换后产生的图片。每个文件的命名规则为第一个字段是序号,第二个字段是数字的值。
二、制作LMDB数据
LMDB差不多是CAFFE用来训练图片最常用的数据格式。caffe提供了专门为图像分类任务将图片转换为LMDB的官方工具,路径为caffe/build/tools/convert_imageset。要使用这个工具,第一步是生成一个图片文件路径的列表,每一行是文件路径和对应标签我,用space键或者制表符(tab)分开。运行gen_caffe_imglist.py,代码如下:
这样就生成了3个数据集的文件列表和对应标签。然后直接调用convert_imageset就可以制作lmdb了。
>>/build/tools/convert_imageset ./train.txt train_lmdb --gray --shuffle
>>/build/tools/convert_imageset ./val.txt val_lmdb --gray --shuffle
>>/build/tools/convert_imageset ./test.txt test_lmdb --gray --shuffle
--gray是单通道读取灰度图的选项;--shuffle是个常用的选项,作用是打乱文件列表顺序。
二、训练LeNet-5
网络结构和caffe官方例子的版本没有区别,只是输入的数据层变成了我们自己制作的LMDB。配置文件实际上就是一些txt文档,只是后缀名是prototxt,我们可以直接到编辑器里编写,也可以用代码生成。此处,我用python来生成。
三、生成参数文件solver
# The train/validate net protocol buffer definition | |
net: "lenet_train_val.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: 36000 | |
# snapshot intermediate results | |
snapshot: 5000 | |
snapshot_prefix: "mnist_lenet" | |
# solver mode: CPU or GPU | |
solver_mode: CPU |
四、开始训练模型
最后,调用下面命令就可以进行训练了。
也可以写成以下形式:
/build/tools/caffe train \
caffe提供了对输出log文件的解析工具parse_log.py
&CAFFE_ROOT/tools/extra/parse_log.py mnist_train.log ./
根据解析结果,即可绘制train-loss,test-loss和accuracy的变化曲线,参考博文:https://blog.youkuaiyun.com/zziahgf/article/details/79215862
五、可视化
caffe官方提供可视化log文件的工具,在caffe/tools/extra下有个plot_training_log.py.example,把这个文件复制一份命名为plot_training_log.py,就可以用来画图了。另外这个脚本要求log文件必须以.log结尾。用mv命令把log文件名改成mnist_train.log
>>python plot_training_log.py 0 test_acc_vs_iters.png mnist_train.log
>>python plot_training_log.py 2 test_loss_vs_iters.png mnist_train.log

有了训练好的模型,就可以识别手写数字了。测试用的是test数据集的图片和之前生成的列表,recognize_digit.py
需要安装opencv2。安装opencv后出现ImportError:No module named cv2的错误,找不到cv2的包。这时安装扩展包即可:pip install opencv-python
import sys | |
sys.path.append('/path/to/caffe/python') | |
import numpy as np | |
import cv2 | |
import caffe | |
MEAN = 128 | |
SCALE = 0.00390625 | |
imglist = sys.argv[1] | |
caffe.set_mode_gpu() | |
caffe.set_device(0) | |
net = caffe.Net('lenet.prototxt', 'mnist_lenet_iter_36000.caffemodel', caffe.TEST) | |
net.blobs['data'].reshape(1, 1, 28, 28) | |
with open(imglist, 'r') as f: | |
line = f.readline() | |
while line: | |
imgpath, label = line.split() | |
line = f.readline() | |
image = cv2.imread(imgpath, cv2.IMREAD_GRAYSCALE).astype(np.float) - MEAN | |
image *= SCALE | |
net.blobs['data'].data[...] = image | |
output = net.forward() | |
pred_label = np.argmax(output['prob'][0]) | |
print('Predicted digit for {} is {}'.format(imgpath, pred_label)) |