最近准备要做毕业设计了,所以从头又配了一遍Caffe,学了一遍SSD,看了Caffe的源码,准备对SSD网络做一些改进。由于这已经是第n遍配置Caffe了,但是还是费了不少时间,所以意识到,总结还是很重要的,所以写下博客记录这一路如何走来,同时也希望可以给有需要的朋友一点点帮助。
配置环境win7+caffe+cudnn8.0+Anaconda2 GPU:1080ti
配置这几位博主总结的就很好了,照着配就没问题
https://blog.csdn.net/gxb0505/article/details/73702451
https://blog.csdn.net/Allyli0022/article/details/62215416
第二个网址里的网盘还没有失效,第一个网址里面给的网址的网盘失效了。
结合这几位博主参考的两篇博客,已经总够了。不过我还想补充一些个人经验,比如opencv2.4.10包的问题,可以看我另一篇博客。Windows下基于Caffe的SSD网络配置经验。
配置完成后,先编译libcaffe,生成需要的一些库文件,再编译caffe。其他的以后用到哪个编译哪个,注意,这里编译是在release模式下编译,因为我们是要在D:\Caffe_Project\caffe-ssd-microsoft\Build\x64\Release生成.exe文件,方便以后调用。在windows下调用它们的方法就是通过.bat文件。
接着就改准备自己的数据集了。就是要把图片文件和.xml文件整合在一起生成caffe可以识别的.lmdb文件。一下是步骤
1、由于我的数据集的图片和.xml文件是在一起放着,所以我先要把他们分开,把xml文件存入Annotations(注解的意思)文件夹里,把bmp图片存入BMPImages文件夹里。为什么要分开呢?因为想要用自带的一些工具必须这么做,随后会提到。但是我没用自带的工具,自己写了脚本所以不分开也可以。分开当然不能自己手动分,丢程序员的人,所以用python写了一个脚本,下面是代码和讲解。
import os,shutil
root = "D:/database/ssd/XingChe"
txtfilenames=[]
for dirpath, dirnames, filenames in os.walk(root):
filenames=filter(lambda filename:filename[-4:]=='.bmp',filenames)
filenames=map(lambda filename:os.path.join(dirpath,filename),filenames)
txtfilenames.extend(filenames)
for file in txtfilenames:#注意这里的txtfilenames是列表,不要加括号
print file
shutil.copy(file,r'D:/database/ssd/BMPImages')
txtfilenames是列表,不要加括号
print file
shutil.copy(file,r'D:/database/ssd/BMPImages')
别看这么短的代码,我写了快一上午,没办法,不知道该用哪个函数。导入了两个模块,os和shutil,他们两个的用法这里有
https://www.cnblogs.com/dkblog/archive/2011/03/25/1995537.html
https://www.cnblogs.com/WonderHow/p/4403727.html
关于os.walk(path)的用法就是遍历这个path下的所有文件,然后返回三元元组(dirpath,dirnames,filenames)
dirpath:根路径(字符串),dirnames:路径下的所有目录名(列表),filenames:路径下的所有非目录文件名(列表)其中目录名和文件名都是没有加上根路径的,所以需要完整路径时要将目录名和文件名与根路径连接起来。
示例:
import os
root = "C:\\dir"
for dirpath, dirnames, filenames in os.walk(root):
for filepath in filenames:
print os.path.join(dirpath, filepath)
接着filter就是一个过滤器,lamda的用法如下:
#lambda简化了函数定义的书写形式 func=lambda x:x+1就相当于
def func(x):
return(x+1)
1 from functools import reduce
2 foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
3
4 print (list(filter(lambda x: x % 3 == 0, foo)))
5 #[18, 9, 24, 12, 27]
6
7 print (list(map(lambda x: x * 2 + 10, foo)))
8 #[14, 46, 28, 54, 44, 58, 26, 34, 64]
接着是shutil.copy(),把file文件拷贝到,第二个文件夹里,用法可参考
https://blog.csdn.net/qq_25360769/article/details/80023656
我还要补充下append和extend的区别。这样就把图片和xml文件分开了。接下来就要用编译出来的create_annoset.exe,没有这个应用程序编译一下create_annoset工程就有了。但是在用它之前需要准备几样东西,我们一个一个来说。
labelmap_voc.prototxt文件,这个文件就是一个映射文件,根据自己标注的类别修改
item {
name: "none_of_the_above"
label: 0
display_name: "background"
}
item {
name: "car"
label: 1
display_name: "car"
}
item {
name: "person"
label: 2
display_name: "person"
}
接着就是trainval.txt文件格式是一个有路径的图片名空格它对应的有路径xml文件。它的生成方法,我用matlab写了一个脚本实现的,代码讲解如下:大致思想就是读出xml文件,然后生成同名的.bmp文件存入trainval.txt文件里。
clear;
trainval_dir = 'D:\database\ssd\Annotations';
test_dir = 'D:\database\test';
all_file_folder = fullfile(trainval_dir);%fullfile的用法就是产生一个地址
file_names = {dir(fullfile(all_file_folder,'*.xml'))}';%定义为一个cell数据
fid = fopen(fullfile(trainval_dir,'trainval.txt'),'w');
for i_file = 1: length(file_names{1,1})%即定义一个1*1的cell单元
xml_file_name = file_names{1,1}(i_file).name;
name_len = length(file_names{1,1}(i_file).name);
image_file_name = [file_names{1,1}(i_file).name(1:name_len - 4),'.bmp'];
fprintf(fid,'%s %s\n',[image_file_name],[trainval_dir,'\',file_names{1,1}(i_file).name]);
disp(sprintf('当前进度: %d / %d ...', i_file ,length(file_names{1,1})));
end
fclose(fid);
all_file_folder = fullfile(test_dir);
file_names = {dir(fullfile(all_file_folder,'*.xml'))}';
fid = fopen(fullfile(test_dir,'test.txt'),'w');
for i_file = 1: length(file_names{1,1})
xml_file_name = file_names{1,1}(i_file).name;
name_len = length(file_names{1,1}(i_file).name);
image_file_name = [file_names{1,1}(i_file).name(1:name_len - 4),'.bmp'];
fprintf(fid,'%s %s\n',[image_file_name],[test_dir,'\',file_names{1,1}(i_file).name]);
disp(sprintf('当前进度: %d / %d ...', i_file ,length(file_names{1,1})));
end
fclose(fid);
fullfile的用法
f = fullfile('dir1', 'dir2', ..., 'filename')
%fullfile构成地址字符串;
如:输入:f
= fullfile('C:','Applications','matlab','fun.m')
得到:f =C:\Applications\matlab\fun.m
%下例为读取train文件夹中的所有图片;
folder=‘train';
filepaths
= dir(fullfile(folder,'*.bmp'));%列出该文件夹下所有.bmp格式的文件(其中包括文件的名字、日期、像素等);
for
i = 1 : length(filepaths)
image = imread(fullfile(folder,filepaths(i).name));%读入第i个图片;
image = rgb2ycbcr(image);
image = im2double(image(:, :, 1));%获得图像的y通道;
im_label = modcrop(image, scale);%保证图像被scale整除;
[hei,wid] = size(im_label);
im_input = imresize(imresize(im_label,1/scale,'bicubic'),[hei,wid],'bicubic');%对图像用'bicubic'先下采样再上采样;
%提取数据;
for x = 1 : stride : hei-size_input+1
for y = 1 :stride : wid-size_input+1
subim_input = im_input(x : x+size_input-1, y : y+size_input-1);%子图像尺寸33*33;
subim_label = im_label(x+padding : x+padding+size_label-1, y+padding : y+padding+size_label-1);%子图像类别尺寸21*21;
%subim_input和subim_label的中心一致;
count=count+1;
data(:, :, 1, count) = subim_input;
label(:, :, 1, count) = subim_label;
end
end
end
这样就完成了trainval.txt , test.txt和labelmap_voc.prototxt的生成。
生成好了的trainval.txt , test.txt,labelmap_voc.prototxt文件是用来生成数据集train_lmdb和test_lmdb的,我们这里用convert_annoset.exe,是之前编译caffe工程生成的一个工具,不用作者给的python文件来生成数据集,是因为会报错。创建convert_annoset.bat文件,里面输入为
D:\caffe-ssd-microsoft\Build\x64\Release\convert_annoset.exe --anno_type=detection --label_map_file=D:\caffe-ssd-microsoft\models\MyXingChe\labelmap_xingche.prototxt --encode_type=bmp D:\caffe-ssd-microsoft\models\MyXingChe\out\ D:\caffe-ssd-microsoft\models\MyXingChe\trainval1.txt D:\caffe-ssd-microsoft\models\MyXingChe\trainval_lmdb
D:\caffe-ssd-microsoft\Build\x64\Release\convert_annoset.exe --anno_type=detection --label_map_file=D:\caffe-ssd-microsoft\models\MyXingChe\labelmap_xingche.prototxt --encode_type=bmp D:\caffe-ssd-microsoft\models\MyXingChe\out\ D:\caffe-ssd-microsoft\models\MyXingChe\trainval1.txt D:\caffe-ssd-microsoft\models\MyXingChe\test_lmdb
因为我这里生成的trainval.txt里面的文件只有名字,没有路径,所以在它前面要加上绝对路径即D:\caffe-ssd-microsoft\models\MyXingChe\out\。根据自己的路径进行修改,我这里偷了个懒训练数据和测试数据是一样的。