本人是深度学习小白,最近在做windows下的caffe图像分类,虽然网上也有许多相关的资料,但是对于小白来说,仍然遇到了许多波折,费了很大功夫终于调通,简直开心到飞起。所以在这里总结回顾这两三周的工作,记录一下详细过程和遇到的问题,同时也为了可以让和我一样的小白少走一些弯路。废话不说了,下面开始正题。
主要参考链接:
http://blog.csdn.net/shakevincent/article/details/52995253
1.下载caffe-windows安装包
微软提供了windows下的caffe开发包,链接地址为:https://github.com/happynear/caffe-windows
此版本需要在VS2013下编译,所以没有VS2013的需要先安装软件,安装过程和安装包网上有很多,都可以参考。不过,在windows环境下装VS2013容易出现安装失败,可能是电脑配置的原因,本人在台式机上装了两天没有成功,换了笔记本却一次成功(两个都是win7 X64系统)。
其他的库文件暂时都不用安装,因为后面编译过程中会自动生成第三方库文件。
2.编译过程
2.1 修改配置文件
将caffe-master\windows\下的CommonSettings.props.example文件复制一份,改名为CommonSettings.props。打开该文件,按照自己的需求进行修改。主要有两个部分,是否需要(true/false),若为true,修改下面的对应路径。
因为我用的是笔记本,所以选择不支持GPU,那么CpuOnly就要选择true,是否支持Python和matlab可以根据个人需求选择,我这里选择了true,但是后面并没有用到。若选择true,就要在计算机上安装这两个软件。
2.2编译生成第三方库文件
修改完配置文件,保存CommonSettings.props。用Visual Studio 2013打开caffe-master\windows\Caffe.sln,会看到有很多子工程。右击libcaffe,选择->重新生成,会出现一个进度条,第三库就自动下载了,这个过程大概需要持续等待十几分钟。
在生成第三方库文件的过程中,会出现许多问题,不过大都可以在网上找到解决方案,相关参考链接如下:
http://blog.csdn.net/wishchin/article/details/45339753
http://www.mamicode.com/info-detail-1524110.html
总结一下自己编译过程中大概遇到的错误:
1>.common.cpp中的getpid()报错
解决办法:在common.cpp中加头文件
#include
然后将getpid()改成_getpid()即可。
2>.unit.cpp中的open()/close()报错
解决办法:在unit.cpp头文件的位置加
#if defined(_MSC_VER)
#include
#endif
3>.db_lmdb.cpp中的mkdir()报错
解决办法:加判断语句
#ifdef _MSC_VER
CHECK_EQ(mkdir(source.c_str(), 0744), 0) << "mkdir " << source << " failed";
#endif
4>.signal_handler.cpp出现SA_RESTART不是属性等问题
解决办法:重新下载caffe-windows-master中的signal_handler.cpp文件,进行复制替换就可以了。
5>.xx.cpp没有生成“object”文件
解决办法: VS->项目->属性->配置属性->C/C++->常规->将警告视为错误->改为“否”,然后点击cpp文件,在VS2013里面重新保存即可。
生成的第三方库文件如下所示:
2.3编译caffe
右击子工程caffe,选择->重新生成,编译生成相关的dll文件,最好是debug和release版本的都编译一下,后面都可能会用到。
编译过程中可能会出现以下问题:
1>.无法打开python27.lib,是因为前面配置环境的时候我的Python选择为true,在项目属性->配置属性->VC++目录->中添加Python27的包含目录和库目录。
2>.出现错误 error LNK2019: 无法解析的外部符号 “_declspec(dllimport) void __cdecl google::InstallFailureSignalHandler(void)” (__imp?InstallFailureSignalHandler@google@@YAXXZ),该符号在函数 “void __cdecl caffe::GlobalInit(int ,char * *)” (?GlobalInit@caffe@@YAXPEAHPEAPEAPEAD@Z) 中被引用 D:\caffe-master\caffe\caffe\common.obj caffe
解决办法:网上看了好多资料,本人觉得有两个比较靠谱。出现这个问题的原因是caffe-windows下的golg库中没有InstallFailureSignalHandler()这个函数。所以一种是直接屏蔽初始化common.cpp中的这个函数,如下图:
第二种是添加判断语句
#if !defined(_MSC_VER)
::google::InstallFailureSignalHandler();
#endif
两种办法都试了一下,第一个方法简单粗暴,成功解决问题;第二个并没有解决bug。
2.4编译classification
2.4.1 这一步有很多人是自己新建工程,然后把caffe-master\examples\cpp_classification中的classification.cpp拷贝到自己的工程中进行编译,这要配置之前生成的第三方库文件路径和相关的caffe的lib库文件,具体可参考链接
http://blog.csdn.net/xjz18298268521/article/details/61921357
在编译前可以先参考链接
http://blog.csdn.net/auto1993/article/details/70198435
测试一下自己的caffe环境是否配置好了,确定可用。
在这一过程中可能遇到的问题:
1>Release环境下编译,出现#include
等C的头文件无法识别的问题
解决办法:将配置属性中的“C++目录”和“链接器->输入”里底下的“从父级或者项目默认设置”选项打勾。
2>运行程序,出现“CL.exe”已退出问题
解决办法:可能是杀毒软件造成的。将电脑里面安装的百度杀毒,360杀毒等卸载就可以了。我的是将360安全卫士卸载后好了。
3>检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项,值“0”不匹配
解决办法:原因是在链接器中输入库文件时,在Debug下使用了Release的库文件或者在Release下使用了Debug的库文件,仔细检查核对,大多数Debug下的lib库文件后面都是有d的,而Release版本没有,例如opencv的lib库。
2.4.2 第二种就是我在最开始给的主要参考链接中的方法,直接在caffe-windows工程中编译classification子工程。首先编译生成,过程中可能出现以下问题:
1>无法打开文件“libcaffe.lib”
解决办法:重新编译生成libcaffe子工程
2>无法打开”libflags-debug.dll”
解决办法:重新编译生成caffe子工程
2.4.3 调用已经训练好的caffemodel
int main(int argc, char** argv) {
string model_file("../model/deploy.prototxt");
string trained_file("../model/type.caffemodel");
string mean_file("../model/type_mean.binaryproto");
string label_file("../model/labels.txt");
string picture_path("../model/type");
Classifier classifier(model_file, trained_file, mean_file, label_file);
vector<string> files;
getFiles(picture_path, files);
for (int i = 0; i < files.size(); i++)
{
clock_t start, finish;
double duration;
start = clock();
cv::Mat img = cv::imread(files[i], -1);
cv::Mat img2;
std::vector predictions = classifier.Classify(img);
//Prediction p = predictions[i];
IplImage* show;
CvSize sz;
sz.width = img.cols;
sz.height = img.rows;
float scal = 0;
scal = sz.width > sz.height ? (300.0 / (float)sz.height) : (300.0 / (float)sz.width);
sz.width *= scal;
sz.height *= scal;
resize(img, img2, sz, 0, 0, CV_INTER_LINEAR);
show = cvCreateImage(sz, IPL_DEPTH_8U, 3);
cvCopy(&(IplImage)img2, show);
CvFont font;
cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX, 0.5, 0.5, 0, 1, 8); //初始化字体
//cvPutText(show, text.c_str(), cvPoint(10, 30), &font, cvScalar(0, 0, 255, NULL));
string name_text;
name_text = files[i].substr(files[i].find_last_of("\\") + 1);
name_text = "Test picture ID::"+ name_text;
cvPutText(show, name_text.c_str(), cvPoint(10, 130), &font, cvScalar(0, 0, 255, NULL));
for (size_t i = 0; i < predictions.size(); ++i)
{
Prediction p = predictions[i];
std::cout << std::fixed << std::setprecision(4) << p.second << " - \""
<< p.first << "\"" << std::endl;
string text = p.first;
char buff[20];
_gcvt(p.second, 4, buff);
text = text + ":" + buff;
/***************************输出英文标签*****************************************/
//CvFont font;
//cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX, 0.5, 0.5, 0, 1, 8); //初始化字体
//cvPutText(show, text.c_str(), cvPoint(10, 30), &font, cvScalar(0, 0, 255, NULL));
//string name_text;
cvPutText(show, text.c_str(), cvPoint(10, 30 + i * 20), &font, cvScalar(0, 0, 255, NULL));
/**********************************************************************************/
cvNamedWindow("结果");
cvShowImage("结果", show);
cvWaitKey(1);
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Time to do is ::");
printf("%f seconds\n", duration);
int c = cvWaitKey();
cvDestroyWindow("结果");
cvReleaseImage(&show);
std::cout << "///" << std::endl;
if (c == 27)
{
return 0;
}
}
return 0;
}
主要参数介绍:
1>string model_file(“../model/deploy.prototxt”): 是网络结构文件,一定要用测试文件,用训练文件会报错,说没有入参。
2>string trained_file(“../model/type.caffemodel”):训练好的模型权值文件,这个我用的是自己在linux下训练好的模型文件。
3>string mean_file(“../model/type_mean.binaryproto”):均值文件,这个真的是困惑了我一段时间,因为我的linux程序里均值是直接给定的三个定值,并没有这个文件,是在不知道它是个什么东西,后来查了很多,程序里是有自己生成的cpp的,接下来会将如何生成均值文件。
4>string label_file(“../model/labels.txt”):标签文件,标签数目要和你网络里设置的最终输出的类别数一直,否则会出错。
5>string picture_path(“../model/type”):测试图片的路径,没什么好讲的。
这几个文件在最开始提到的主要参考链接里面有云盘下载地址,可以先下载下来,跑一跑,试试自己的环境是否正确。
在这个过程中,加载均值文件SetMean(),一直报错,困扰了我两天。函数第一句
ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto);
一直报错Check failed,但是我的均值文件没有任何问题,不管是自己生成的,还是别人提供的,都报错,应该是均值文件没有加载进来,但是路径又是对的,郁闷,后来一句一句对代码,发现是io.cpp中的ReadProtoFromBinaryFile()这个函数的一个参数设置不太一样,具体修改如下:
源文件中open的第二个参数O_RDONLY,改为O_RDONLY|O_BINARY就好了,顺利运行出结果。
到这里整个过程基本就结束了,接下篇说说自己生成均值文件的过程。