因为要用Caffe做医学图像的分类,于是收集了各种医学图像进行训练测试。本次实验参考了逆水之天的博客,也将其中遇到的一些问题记录了下来,接下来是环境介绍及操作步骤。
- 训练环境介绍
- Windows下的数据准备
- 具体步骤
- 实验结果
- 遇到的问题及解决办法
训练环境介绍
本次实验是在Ubuntu 14.04系统中运行的,环境搭建参考《21天实战Caffe》一书的搭建方法。Caffe目录位于/home/yang/caffe。
Windows下的数据准备
注意!!如果已经有图片集了,则可以跳过数据准备阶段。直接看具体步骤!!
1、收集图片。
训练集:心脏图和非心脏图各100张。
测试集:心脏图和非心脏图各30张。
2、图片重命名。
图片重命名是有很多好处的,因为是在windows下收集的图片,于是在网上找了文件重命名的方法,在windows里一次性将文件名改成固定格式了。方法如下:
(1)在图片文件夹下创建两个脚本文件(图片文件夹下只有.jpg文件),first.bat和second.bat。
first.bat如下:
dir /a-d /b *.jpg>src.txt
echo 收集成功!
pause
second.bat如下:
@for /f %%s in (src.txt) do (
if exist %%s for /f %%d in (des.txt) do (rename %%s %%d)
)
echo 成功!
pause
(2)在图片文件夹下创建文本文件src.txt。(用于存放当前文件夹下的全部.jpg文件的文件名)
(3)打开cmd窗口,到图片文件夹下,输入first.bat
,运行first.bat脚本。此时src.txt文件中会包含所有当前文件夹下的.jpg文件名。
(4)制作目标文件名替换文件des.txt.
方法一:复制一份src.txt,改名为des.txt(用于存放目标文件名),用Notepad++或者是UltraEdit软件打开des.txt。利用替换功能将文件名改成目标文件名。例如原文件名为1.jpg,则将1.jpg替换为heart.jpg。此方法比较繁琐,最好采用方法二。
方法二:写个代码制作替换文件比较好。创建个.cpp文件,写入如下代码:
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
using namespace std;
int main()
{
string str;
char cstr[50];
ofstream fout;
fout.open("des.txt");//打开des.txt文件(文件要存在!)
for(int i=1; i<101; i++)//101是文件数量+1
{
str = "heart"; //因为要生成字符串"heart1.jpg"
//所以先准备好字符串"heart"
itoa(i,cstr,10);
strcat(cstr, ".jpg\n");
str += cstr;
fout << str;
}
fout.close();
return 0;
}
运行此代码可生成des.txt文件。
(5)生成的des.txt文件放入图片文件夹下,在刚刚打开的cmd窗口中输入second.bat
,即可将src.txt中的文件名全部改掉成des.txt中的文件名。
具体步骤
1、在caffe/data下新建文件夹myself,在myself文件夹下新建文件夹train,用于存放训练用的图片。在train文件夹下分别建立不同类别对应的文件夹,此处新建文件夹 heart,no_heart。将对应类型训练集图片放入对应文件夹。
2、在caffe/data/myself文件路径下,重复使用下面这几句话,最后将两类训练数据的文件名都复制到一起生成train.txt文件,其路径为caffe/data/myself/train.txt。(文件格式参考caffe/data/ilsvrc12下的train.txt和val.txt。)
find train/heart -name *.jpg | cut -d '/' -f2-3 >train.txt
sed "s/$/ 2/" ./train.txt>./train1.txt
生成几个trainX.txt文件,合并成train.txt文件,其内容应该如下:(每一类后面都带有一个表示该类的数字,如此处heart类图片后面都是1,no_heart类图片后都是2;注意路径不包含train)
3、同样的,在caffe/data/myself下新建文件夹 val,val文件夹下存放所有的测试集图片,heart类和no_heart类都有。
4、用生成train.txt的方法生成val.txt,路径为caffe/data/myself/val.txt。其内容为:(注意没有多余的文件夹)
test_heart1.jpg 1
test_heart2.jpg 1
...
test_no_heart.jpg 2
5、在与val.txt相同的路径下,将val.txt复制粘贴,重命名为test.txt文件,将其文件中最后的类别数字全部修改为0,用于验证测试。 其内容为:
test_heart1.jpg 0
test_heart2.jpg 0
...
test_no_heart.jpg 0
6、在路径caffe/examples下新建文件夹myself,将caffe/examples/imagenet的create_imagenet.sh复制到该文件夹下,将其名改为create_myimagenet.sh,修改文件中的训练和测试路径,最好是修改为绝对路径,因为旧版本的caffe只能再根目录下输入运行命令(我的是/home/yang/caffe/data/myself/train和/home/yang/caffe/data/myself/val)。同时要将目标数据库文件夹名称ilsvrc12_train_lmdb、ilsvrc12_val_lmdb对应改成myself_train_lmdb、myself_val_lmdb。
注意!!路径绝对绝对不要写错,不然后患无穷!!
7、运行该.sh文件。如果出现错误Not found之类的,麻烦看看是不是粗心大意路径写错了。运行结束后,在caffe/examples/myself下会生成两个文件夹:myself_train_lmdb和myself_val_lmdb。两个文件夹中都包含一个data.mdb和一个lock.mdb文件。
8、计算图像均值。减去图像均值会获得更好的分类效果。使用的是caffe/build/toolscompute_image_mean.cpp实现。同样,复制 caffe/examples/imagenet下的make_image_mean.sh 到 exampls/myself中,将其改名为make_myimagenet_mean.sh,将其中的路径和目标文件名对应修改如下。
9、运行make_myimagenet_mean.sh文件,会在data/myself下生成myimagenet_mean.binaryproto文件。
10、网络定义。把caffe/models/bvlc_reference_caffenet中所有文件复制到caffe/examples/myself文件夹下,修改train_val.prototxt文件,注意修改数据层的路径。(一共改四个地方)
11、适当修改solver.prototxt文件内容,如果是CPU模式的,要将GPU改成CPU。snapshot表示每迭代2000次就显示一次状态。
12、打开train_caffenet.sh,修改其路径信息,然后到caffe/下运行./examples/myself/train_caffenet.sh
,开始训练 。
实验结果
实验结果就是跑起来啦~~明明256x256的图片才100张跑得特别慢,也可能是跟网络毕竟复杂,或者是机器性能不好有关,总之跑了一晚上也没跑完……准确率在0.83左右不是很准确,一开始学习率设0.1太大了,loss猛增,于是将学习率改成0.0005还好了些。过程跟逆水之天的很像,大家也可以去参考一下。
遇到的问题及解决办法
在运行./create_myimagenet.sh的时候遇到如下报错:
F0324 19:48:32.291528 12180 db_lmdb.cpp:15] Check failed: mkdir(source.c_str(), 0744) == 0 (-1 vs. 0) mkdir /home/yang/caffe/examples/myself/ilsvrc12_val_lmdbfailed
* Check failure stack trace: *
@ 0x7f07c69c3daa (unknown)
@ 0x7f07c69c3ce4 (unknown)
@ 0x7f07c69c36e6 (unknown)
@ 0x7f07c69c6687 (unknown)
@ 0x7f07c6d1578e caffe::db::LMDB::Open()
@ 0x402c22 main
@ 0x7f07c5bd0f45 (unknown)
@ 0x40395c (unknown)
@ (nil) (unknown)
Aborted (core dumped)
Done.
解决办法:
这是因为当时没有改lmdb文件夹名字:ilsvrc12_val_lmdb,ilsvrc12_trian_lmdb这两个文件夹的名字在那个目录下冲突了,只要把ilsvrc12_xxx_lmdb换成自定义的名字,比如my_xxx_lmdb就好了。
来自博主的话:对于博客中的任何错误或不恰当的地方,欢迎各位批评指正!