自制lenet:从获取数据到网络编写…

这两天自己从数据预处理一直到编写网络,做了一次完整的caffe编程,用的数据集是mnist,参考的网络是caffe上的lenet。

首先说几个对自己帮助比较大的博客:
【1】、http://www.cnblogs.com/NanShan2016/p/5487194.html
这个系列博客介绍了一种一般性的方法,如何从任意图像数据,得到能被caffe处理的lmdb数据。
【2】、http://www.68idc.cn/help/buildlang/erlang/20160517616848.html
这篇文章可以视为一个补充,主要帮助点在于,已有处理好的mnist图像数据(含train.txt和test.txt文件),要如何利用ImageNet的功能函数,得到能被数据层读取的lmdb文件。
【3】、http://www.2cto.com/kf/201607/527860.html(此文作为延伸阅读)
这篇博文详细介绍了Caffe自带的create_mnist.sh中,一个关键性的bin文件convert_mnist_data.bin,它的源码是怎么实现的,此文很深入地剖析了Caffe是如何生成lmdb文件的,以后有时间可以仔细研读。

下面开始正文
一、数据预处理
对于mnist手写数据库,有两种原始数据,一种是mnist官网下载的二进制文件,这个的数据处理方法可以参考上述博文【3】,这里主要介绍第二种,也就是自己下载到了原始图片数据,如
自制lenet:从获取数据到网络编写的全笔记(上)
要如何得到lmdb数据。

先说一下 Caffe 为什么采用 LMDB、LEVELDB,而不是直接读取原始数据?
原因是,一方面,数据类型多种多样,有二进制文件、文本文件、编码后的图像文件(如 JPEG、PNG、网络爬取的数据等),不可能用一套代码实现所有类型的输入数据读取,转换为统一格式可以简化数据读取层的实现;另一方面,使用 LMDB、LEVELDB 可以提高磁盘 IO 利用率。

下载的原始数据是分0-9共10个文件夹存放,每个文件夹存了许多对应数字的手写图片。首先要做的工作,就是把这些图片整合到同一个文件夹中,并用一个txt文档记录全部图片文件名。

首先是记录所有图片文件名,因为每个文件夹里面的图片,名字都是一样的,如下:
自制lenet:从获取数据到网络编写的全笔记(上)

自制lenet:从获取数据到网络编写的全笔记(上)
可以看到,0和1的手写文件名是一样的,所以就需要先分别记录0、1的文件名,再加上前缀,最后整合到同一个txt中。

这里参考博文2的方法,首先用dir /s /on /b > train.txt
把某个数字的所有文件名整合到train.txt中,形式如下:
D:\mnist\0\1.bmp
D:\mnist\0\10.bmp
D:\mnist\0\100.bmp
.........
再用替换功能,把前缀替换成0_,这样得到的就是:
0_1.bmp
0_10.bmp
........
然后再替换bmp为bmp 0,这样就加上了label得到:
0_1.bmp 0
0_10.bmp 0
.......

得到了文件名记录的txt文档,现在还要做的就是把所有图片集中到同一个文件夹,这就要解决相同文件名的问题。首先按照上面说的,把文件目录替换成下面形式:
rename 1.bmp
rename 10.bmp
.......
然后用下面的C++程序处理,主要功能就是读取上面的txt文件,生成一个bat文件,把每个文件名加上一个前缀,这里只给出主要代码,前面打开文件流之类的略过
while(!input.eof())
{
std::getline(input,line);
stringstream record(line);
string rename,filename,kind_num;
record>>rename>>filename;
kind_num=i+'0';
kind_num=kind_num+'_'+filename;
output<
}
处理过后,生成的.bat就变成下面的形式了:
rename 1.bmp 0_1.bmp
rename 10.bmp 0_10.bmp
.......
然后放到0号文件夹目录下,执行.bat,就把所有文件都加上label的前缀了。有了前缀,就可以把所有文件整合到同一个文件夹下。test数据可以类似处理,不过懒得麻烦了,就直接用官网的二进制文件好了。

二、原始数据转为输入数据
有了原始数据,下一步就是把这些数据转为能被Caffe识别的lmdb格式的数据,这个可以利用系统原有的转化程序,不过在此之前,需要 先安装lmdb的python包,不然会创建数据时会报错,输入下列指令即可:
pip install lmdb
然后,参考Caffe的源码开始编译自己的数据。首先需要指出的是,Caffe示例中的mnist数据对应的创建文件是examples/mnist/create_mnist.sh,它使用的是Caffe自带的bin文件,但这个文件只能处理mnist官网给出的二进制数据,没法处理原始的图片。
对于图片数据,Caffe提供了一个通用的处理文件,即是examples/imagenet/create_imagenet.sh。可以直接用此文件提供的命令,这里主要解释几个宏定义:

EXAMPLE:指明当数据处理完之后,lmdb数据存放在哪。
DATA:数据文件的地址,有别于下面的TRAIN_DATA_ROOT和VAL_DATA_ROOT,这个一般指数据根目录,里面就一个记录文件名列表的txt文档,至于训练和测试图片集,在这个目录的子目录
TOOLS:这个一般不用动,sh文件执行的命令就是调用tools目录下的工具文件
TRAIN/VAL_DATA_ROOT:训练/测试图片存放的路径,一般是在DATA目录下的子文件夹。
另外,RESIZE那一栏也需要改成28*28,这个才是mnist的输入规格。

配置路径完成之后,执行sh文件,就得到了lmdb数据。如果需要重新生成,就需要把之前的lmdb先删除,不然重新生成时会报错。
接下来先用Caffe自带的mnist网络,测试本数据集是否能用
好吧,网络报错Check failed Cannot share param 0 weights from layer......,大致意思就是,数据层的输入和conv1的源param不符合,一个是20*1*5*5,一个是20*3*5*5,师兄说第二个参数是channel,说明是通道不匹配,可能因为一个是彩色的(RGB三色对应三通道),一个是黑白的(单色,即单通道)。不过仔细想了想,这种可能性应该不大,更大的可能是因为,我训练数据是自己生成的,测试数据用的是官网二进制文件生成的,因此把自己 用训练数据相同的办法,重新做了一个测试集,果然就OK了。

至此,数据处理已经OK,数据已能被数据层读取,实验结果准确率也有99%,说明是可行的。接下来的任务就是尝试自己来编写一个lenet网络了。

你可能感兴趣的:(机器学习与图像识别)