Repository: imistyrain/OpenDL Branch: master Commit: 2f4d0ace52b5 Files: 31 Total size: 155.4 KB Directory structure: gitextract__lt7gl0y/ ├── .gitignore ├── CMakeLists.txt ├── README.md ├── classification.bat ├── cpp/ │ ├── LenetClassifier.cpp │ ├── LenetClassifier.h │ ├── evaluation.cpp │ └── evaluationcpp.vcxproj ├── cpp4caffe/ │ ├── cnnpredictor.h │ ├── cpp4caffe.vcxproj │ └── evaluation.cpp ├── models/ │ ├── deploy.prototxt │ ├── labels.txt │ ├── mean.binaryproto │ ├── mean.npy │ ├── plate_fromimg.prototxt │ ├── plate_lenet.prototxt │ └── solver.prototxt ├── train.bat ├── train.py ├── train.sh └── util/ ├── deploy.prototxt ├── evaluation.py ├── meanfilebinartynpy.py ├── plotaccuracy.py ├── preprocess.py ├── solver.prototxt ├── test.prototxt ├── train.prototxt ├── train.txt └── val.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ build data output error error.txt *.solverstate *.caffemodel *lmdb ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required(VERSION 2.8) set(ProjName caffe-onclick) project(${ProjName}) set(CMAKE_CXX_STANDARD 11) find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) find_package(Caffe REQUIRED) include_directories(${Caffe_INCLUDE_DIRS}) add_executable(evaluation cpp/evaluation.cpp cpp/LenetClassifier.cpp) target_link_libraries(evaluation ${OpenCV_LIBS} ${Caffe_LIBRARIES}) add_executable(cpp4caffe cpp4caffe/evaluation.cpp) target_link_libraries(cpp4caffe ${OpenCV_LIBS} ${Caffe_LIBRARIES}) ================================================ FILE: README.md ================================================ caffe一键式训练评估集成开发环境 ==================================== **Last Update 2020.07.08** ## 概述 本项目提供一个集成式开发环境,在配好caffe环境的前提下,只需将准备好的图片放入data目录下,便可以一键生成lmdb数据文件、均值文件、标注文件和测试评估模型、找出错误样本、部署模型等所有的操作,更难能可贵的是它是跨平台的,可以无缝的在Windos和Linux间切换。 使用深度学习完成一个特定的任务比如说字符识别、人脸识别等大致可以分为数据准备、定义模型、训练模型、评估模型和部署模型等几个步骤。 ### 配置caffe 现在配置caffe十分方便,仅需几行命令即可搞定,确保安装了所需的依赖,这里仅摘录最关键的部分,其余的详细内容可参见参考链接. **Windows** ::为了减少日后不必要的麻烦,建议VS2015,Cuda8.0,cudnn5.1及以上,python2.7 git clone https://github.com/BVLC/caffe cd caffe git checkout windows scripts\build_win.cmd **Linux** git clone https://github.com/BVLC/caffe cd caffe mkdir build cd build cmake .. make -j8 ### 1.数据准备 首先收集要任务相关的数据,这里准备了一个车牌字符数据(仅包含0-9共10个数字),直接解压[data.zip](https://github.com/imistyrain/caffe-oneclick/releases/download/1.0/data.zip)到当前文件夹即可,格式如下图所示,每类图片对应一个文件夹,放到一个data文件夹下,注意格式一致型(都为.jpg或.png文件),仔细筛查,不要含有其他的非图片文件在里面,你也可以用自己的数据替换这些车牌字符数据。 ![structures](https://i.imgur.com/JQmNGYN.png) caffe使用了lmdb内存数据库等来加快训练时读取数据的速度,为此,caffe自带的tools里提供了一个工具(可由convert_imageset.cpp编译生成),它的输入是图片路径和标签对组成的文件,每次都手动生成这个文件不胜其烦。 我们希望是自动化的从文件夹读取的功能,因此,本项目通过preprocess/preprocess.py来获取如下图所示的文件夹下所有的文件路径以及对应的文件标签的功能,它输出训练和验证集preprocess/train.txt和preprocess/val.txt以及标签映射文件modef/labels.txt 你也可以直接下载已经转换好的[lmdb.tar.gz](https://github.com/imistyrain/caffe-oneclick/releases/download/1.0/lmdb.tar.gz)文件直接使用 ### 2.定义模型 训练定义文件位于models下的plate_train_test.prototxt,部署文件在deploy.prototxt,你可以通过[网络结构可视化](http://ethereon.github.io/netscope/#/editor)对这些网络进行可视化,以便更清晰的理解他们的含义 ### 3.训练模型 ``` ./train.sh ``` ### 4.评估模型 [evaluation.py](util/evaluation.py)用来对data文件下下的数据进行评估,它会得出迭代次数为10000时模型的错误率,并且打印出误识别图片对应的真值和预测值,并把相应数据保存在error文件夹下,命名格式为字符文件夹/图片在文件夹内的序号_真值类别_预测类别(以0/190_0_4.jpg为例,代表0/190.jpg被误识为4),这些错误识别的样本需要仔细分析,不断调试参数,以获得期望的结果。 本项目提供了一个训练好的[模型文件](https://github.com/imistyrain/caffe-oneclick/releases/download/1.0/plate999.caffemodel),其错误率低于0.1%,这就意味着其达到了99.9%以上的准确率。 ### 5.部署模型 由于速度原因,实际中多使用C++而不是python进行部署,因此本项目在cpp文件夹下提供了evaluationcpp工程,它使用单例模式来防止每次预测都加载模型,只需使用如下代码即可在你的项目中一行代码使用CNN,此外,该项目也提供了对模型进行评估的功能。 ``` cv::Mat img=cv::imread("imagepath.jpg"); string result=CnnPredictor::getInstance()->predict(img); ``` 当然,你也可以运行calssification.bat来调用caffe自身进行分类识别 ``` "../build/examples/cpp_classification/classification" "modeldef/deploy.prototxt" "trainedmodels/platerecognition_iter_1000.caffemodel" "modeldef/mean.binaryproto" "modeldef/labels.txt" "data/0/4-3.jpg" ```

其返回了最高的5个类别的相似度,不难看出训练的网络对于data/0/0.jpg有高达93%的概率认为其属于0这个字符,结果还是非常理想的 ## 参考 * [Caffe 配置与示例运行](http://blog.csdn.net/guoyk1990/article/details/52909864) * [图文并解caffe源码](http://blog.csdn.net/mounty_fsc/article/category/6136645) * [caffe源码解析](http://blog.csdn.net/qq_16055159) * [从零开始山寨Caffe caffe为什么这么设计?](http://www.cnblogs.com/neopenx/) * [Caffe代码导读 21天实战caffe作者博客](http://blog.csdn.net/kkk584520/article/category/2620891/2) * [CNN卷积神经网络推导和实现](http://blog.csdn.net/zouxy09/article/details/9993371) * [caffe卷积层代码阅读笔记](http://blog.csdn.net/tangwei2014/article/details/47730797) * [caffe添加新层教程](http://blog.csdn.net/shuzfan/article/details/51322976) * [caffe中各语言预处理对应方式](http://blog.csdn.net/minstyrain/article/details/78373914) * [mxnet 训练自己的数据](https://github.com/imistyrain/mxnet-mr) * [MatconvNet 训练自己的数据](https://github.com/imistyrain/MatConvNet-mr) ================================================ FILE: classification.bat ================================================ @echo off set CAFFE_DIR=.. set eval_iter=10000 set imagepath=data/0/0.jpg set trainedmodel=snapshot/plate_iter_%eval_iter%.caffemodel ::set trainedmodel=platere996.caffemodel echo %imagepath% %eval_iter% "%CAFFE_DIR%/build/examples/cpp_classification/classification" "models/deploy.prototxt" "%trainedmodel%" "models/mean.binaryproto" "models/labels.txt" "%imagepath%" pause ================================================ FILE: cpp/LenetClassifier.cpp ================================================ #include "LenetClassifier.h" std::pairCLenetClassifier::predict(const cv::Mat &img) { std::pairp; if (!bloaded) { load(); } else { cv::Mat input; cv::resize(img, input, cv::Size(20, 20)); cv::Mat inputBlob = blobFromImage(input);// , 255.0f, cv::Size(20, 20), _mean, false); cv::Mat prob; _net.setInput(inputBlob, "data"); prob = _net.forward("prob"); cv::Mat probMat = prob.reshape(1, 1); cv::Point classNumber; cv::minMaxLoc(probMat, NULL, &p.second, NULL, &classNumber); p.first = classNumber.x; } return p; } bool CLenetClassifier::load(cv::String modelTxt, cv::String modelBin) { _net = cv::dnn::readNetFromCaffe(modelTxt, modelBin); // _mean = cv::Scalar(66, 66, 66); bloaded = !_net.empty(); return bloaded; } ================================================ FILE: cpp/LenetClassifier.h ================================================ #pragma once #include "string" #include "opencv2/opencv.hpp" #include using namespace cv::dnn; using namespace std; const string caffeplatedir = "../"; const string model_file = caffeplatedir + "/models/deploy.prototxt"; const string trained_file = caffeplatedir + "/models/plate999.caffemodel"; const string mean_file = caffeplatedir + "/models/mean.binaryproto"; class CLenetClassifier { public: static CLenetClassifier*getInstance() { static CLenetClassifier instance; return &instance; } std::pairpredict(const cv::Mat &img); bool load(cv::String modelTxt = model_file, cv::String modelBin = trained_file); private: bool bloaded = false; Net _net; cv::Scalar _mean; CLenetClassifier() { } }; ================================================ FILE: cpp/evaluation.cpp ================================================ #include "mrdir.h" #include "mrutil.h" #include "mropencv.h" #include "LenetClassifier.h" using namespace std; const string errordir = caffeplatedir + "/error"; const string platedatadir = caffeplatedir + "data"; void cleardir(const string dir) { vectorfiles=getAllFilesinDir(dir); for (int i = 0; i < files.size(); i++) { string filepath = dir + "/" + files[i]; remove(filepath.c_str()); } } void clearerror(const string dir) { cout << "clearing" << dir << endl; vectorsubdirs=getAllSubdirs(dir); for (int i = 0; i < subdirs.size(); i++) { string subdir = dir + "/" + subdirs[i]; cout << subdirs[i]<subdirs=getAllSubdirs(platedatadir); for (auto sub : subdirs) { string subdir = platedatadir + "/" + sub; vectorfiles=getAllFilesinDir(subdir); for (auto file : files) { string fileapth = subdir + "/" + file; cv::Mat img = cv::imread(fileapth); auto ret=CLenetClassifier::getInstance()->predict(img).first; if (ret == string2int(sub)) rightcount++; else { cout << sub + "/" + file.substr(0, file.size() - 4) + ":" + int2string(ret) << endl; errorcount++; string errorlabeldir = errordir; errorlabeldir = errorlabeldir + "/" + sub; if (!EXISTS(errorlabeldir.c_str())) { MKDIR(errorlabeldir.c_str()); } string errorfilepath = errorlabeldir + "/" + file.substr(0,file.size()-4) + "_" + sub + "_" + int2string(ret) + ".png"; //imshow("error", img); imwrite(errorfilepath, img); //cv::waitKey(1); } total++; } } cout << "acc:" << rightcount << "/" << total << endl; cout << rightcount*1.0 / total << endl; return 0; } int testimg(const std::string imgpath = "data/0/0.jpg") { cv::Mat img = imread(imgpath); TickMeter tm; tm.start(); auto p = CLenetClassifier::getInstance()->predict(img); tm.stop(); std::cout << p.first << std::endl;// " " << p.second << endl; std::cout << tm.getTimeMilli() << "ms" << std::endl; return 0; } int testdir(const std::string dir = "img") { auto files = getAllFilesinDir(dir); for (int i = 0; i < files.size(); i++) { std::string imgpath = dir + "/" + files[i]; std::cout << files[i] << ":"; testimg(imgpath); } return 0; } int main(int argc,char*argv[]) { if (argc==1) evaluation(); else { testimg(); testdir(); } return 0; } ================================================ FILE: cpp/evaluationcpp.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {0A2F0DB8-57C5-4380-93D9-E45110DE3719} Win32Proj charsrecog 8.1 Application true v140 Unicode Application true v140 Unicode Application false v140 true Unicode Application false v140 true Unicode true true D:\opencv33\build\include;$(IncludePath) D:\opencv33\build\x64\vc14\lib;$(LibraryPath) false false D:\opencv33\build\include;$(IncludePath) D:\opencv33\build\x64\vc14\lib;$(LibraryPath) Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true Console true Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true $(SolutionDir)include;%(AdditionalIncludeDirectories) /D_CRT_SECURE_NO_WARNINGS %(AdditionalOptions) Console true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;cudart.lib;cublas.lib;curand.lib;libprotobufd.lib;hdf5_tools.lib;hdf5_hl_fortran.lib;hdf5_fortran.lib;hdf5_hl_f90cstub.lib;hdf5_f90cstub.lib;hdf5_cpp.lib;hdf5_hl_cpp.lib;hdf5_hl.lib;hdf5.lib;zlib.lib;szip.lib;caffelibd.lib;opencv_world300d.lib;shlwapi.lib;leveldbd.lib;cuda.lib;libglog.lib;lmdb.lib;cudnn.lib;libopenblas.dll.a;libgflags.lib;cublas_device.lib;%(AdditionalDependencies) compute_20,sm_20;compute_30,sm_30;compute_35,sm_35;compute_50,sm_50; Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true Console true true true Level3 Disabled true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true $(SolutionDir)include;%(AdditionalIncludeDirectories) true /D_CRT_SECURE_NO_WARNINGS %(AdditionalOptions) Console true true true kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;%(AdditionalDependencies) Shared 64 compute_20,sm_20;compute_30,sm_30;compute_35,sm_35;compute_50,sm_50; ================================================ FILE: cpp4caffe/cnnpredictor.h ================================================ #pragma once #include #include "mrdir.h" #include "opencv2/opencv.hpp" #include #include #include #include #include #include using namespace std; const string caffeplatedir = "../"; const string model_file = caffeplatedir + "models/deploy.prototxt"; const string trained_file = caffeplatedir + "models/plate999.caffemodel"; const string mean_file = caffeplatedir + "models/mean.binaryproto"; const string label_file = caffeplatedir + "models/labels.txt"; using namespace caffe; // NOLINT(build/namespaces) using std::string; /* Pair (label, confidence) representing a prediction. */ typedef std::pair Prediction; class Classifier { public: Classifier(const string& model_file, const string& trained_file, const string& mean_file, const string& label_file); std::vector Classify(const cv::Mat& img, int N = 5); private: void SetMean(const string& mean_file); std::vector Predict(const cv::Mat& img); void WrapInputLayer(std::vector* input_channels); void Preprocess(const cv::Mat& img, std::vector* input_channels); private: std::shared_ptr > net_; cv::Size input_geometry_; int num_channels_; cv::Mat mean_; std::vector labels_; }; Classifier::Classifier(const string& model_file, const string& trained_file, const string& mean_file, const string& label_file) { #ifdef CPU_ONLY Caffe::set_mode(Caffe::CPU); #else Caffe::set_mode(Caffe::GPU); #endif /* Load the network. */ net_.reset(new Net(model_file, TEST)); net_->CopyTrainedLayersFrom(trained_file); CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input."; CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output."; Blob* input_layer = net_->input_blobs()[0]; num_channels_ = input_layer->channels(); CHECK(num_channels_ == 3 || num_channels_ == 1) << "Input layer should have 1 or 3 channels."; input_geometry_ = cv::Size(input_layer->width(), input_layer->height()); /* Load the binaryproto mean file. */ SetMean(mean_file); /* Load labels. */ std::ifstream labels(label_file.c_str()); CHECK(labels) << "Unable to open labels file " << label_file; string line; while (std::getline(labels, line)) labels_.push_back(string(line)); Blob* output_layer = net_->output_blobs()[0]; CHECK_EQ(labels_.size(), output_layer->channels()) << "Number of labels is different from the output layer dimension."; } static bool PairCompare(const std::pair& lhs, const std::pair& rhs) { return lhs.first > rhs.first; } /* Return the indices of the top N values of vector v. */ static std::vector Argmax(const std::vector& v, int N) { std::vector > pairs; for (size_t i = 0; i < v.size(); ++i) pairs.push_back(std::make_pair(v[i], i)); std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare); std::vector result; for (int i = 0; i < N; ++i) result.push_back(pairs[i].second); return result; } /* Return the top N predictions. */ std::vector Classifier::Classify(const cv::Mat& img, int N) { std::vector output = Predict(img); N = std::min(labels_.size(), N); std::vector maxN = Argmax(output, N); std::vector predictions; for (int i = 0; i < N; ++i) { int idx = maxN[i]; predictions.push_back(std::make_pair(labels_[idx], output[idx])); } return predictions; } /* Load the mean file in binaryproto format. */ void Classifier::SetMean(const string& mean_file) { BlobProto blob_proto; ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto); /* Convert from BlobProto to Blob */ Blob mean_blob; mean_blob.FromProto(blob_proto); CHECK_EQ(mean_blob.channels(), num_channels_) << "Number of channels of mean file doesn't match input layer."; /* The format of the mean file is planar 32-bit float BGR or grayscale. */ std::vector channels; float* data = mean_blob.mutable_cpu_data(); for (int i = 0; i < num_channels_; ++i) { /* Extract an individual channel. */ cv::Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data); channels.push_back(channel); data += mean_blob.height() * mean_blob.width(); } /* Merge the separate channels into a single image. */ cv::Mat mean; cv::merge(channels, mean); /* Compute the global mean pixel value and create a mean image * filled with this value. */ cv::Scalar channel_mean = cv::mean(mean); mean_ = cv::Mat(input_geometry_, mean.type(), channel_mean); } std::vector Classifier::Predict(const cv::Mat& img) { Blob* input_layer = net_->input_blobs()[0]; input_layer->Reshape(1, num_channels_, input_geometry_.height, input_geometry_.width); /* Forward dimension change to all layers. */ net_->Reshape(); std::vector input_channels; WrapInputLayer(&input_channels); Preprocess(img, &input_channels); net_->Forward(); /* Copy the output layer to a std::vector */ Blob* output_layer = net_->output_blobs()[0]; const float* begin = output_layer->cpu_data(); const float* end = begin + output_layer->channels(); return std::vector(begin, end); } /* Wrap the input layer of the network in separate cv::Mat objects * (one per channel). This way we save one memcpy operation and we * don't need to rely on cudaMemcpy2D. The last preprocessing * operation will write the separate channels directly to the input * layer. */ void Classifier::WrapInputLayer(std::vector* input_channels) { Blob* input_layer = net_->input_blobs()[0]; int width = input_layer->width(); int height = input_layer->height(); float* input_data = input_layer->mutable_cpu_data(); for (int i = 0; i < input_layer->channels(); ++i) { cv::Mat channel(height, width, CV_32FC1, input_data); input_channels->push_back(channel); input_data += width * height; } } void Classifier::Preprocess(const cv::Mat& img, std::vector* input_channels) { /* Convert the input image to the input image format of the network. */ cv::Mat sample; if (img.channels() == 3 && num_channels_ == 1) cv::cvtColor(img, sample, CV_BGR2GRAY); else if (img.channels() == 4 && num_channels_ == 1) cv::cvtColor(img, sample, CV_BGRA2GRAY); else if (img.channels() == 4 && num_channels_ == 3) cv::cvtColor(img, sample, CV_BGRA2BGR); else if (img.channels() == 1 && num_channels_ == 3) cv::cvtColor(img, sample, CV_GRAY2BGR); else sample = img; cv::Mat sample_resized; if (sample.size() != input_geometry_) cv::resize(sample, sample_resized, input_geometry_); else sample_resized = sample; cv::Mat sample_float; if (num_channels_ == 3) sample_resized.convertTo(sample_float, CV_32FC3); else sample_resized.convertTo(sample_float, CV_32FC1); cv::Mat sample_normalized; // cv::subtract(sample_float, mean_, sample_normalized); sample_normalized = sample_float; /* This operation will write the separate BGR planes directly to the * input layer of the network because it is wrapped by the cv::Mat * objects in input_channels. */ cv::split(sample_normalized, *input_channels); CHECK(reinterpret_cast(input_channels->at(0).data) == net_->input_blobs()[0]->cpu_data()) << "Input channels are not wrapping the input layer of the network."; } class CnnPredictor { public: static CnnPredictor*getInstance() { static CnnPredictor instance; return &instance; } const string predict(cv::Mat &img) { std::vector predictions = pclassifier->Classify(img); return predictions[0].first; } private: CnnPredictor() { pclassifier = new Classifier(model_file, trained_file, mean_file, label_file); }; ~CnnPredictor() { if (pclassifier) delete pclassifier; }; Classifier *pclassifier; }; ================================================ FILE: cpp4caffe/cpp4caffe.vcxproj ================================================  Debug x64 Release x64 {D9C1D98F-F412-44F6-A819-D1AFB27D31E7} Win32Proj x64 cpp4caffe NoUpgrade 8.1 Application false MultiByte v140 Application false MultiByte v140 <_ProjectFileVersion>10.0.20506.1 Debug\ Debug\ $(ProjectName)-d .exe true true ..\bin\ Release\ $(ProjectName) .exe false true Debug/ EnableFastChecks CompileAsCpp ProgramDatabase Sync Disabled MaxSpeed NotUsing MultiThreadedDebugDLL true Level3 WIN32;_WINDOWS;CAFFE_VERSION=1.0.0;BOOST_ALL_NO_LIB;USE_LMDB;USE_LEVELDB;USE_CUDNN;USE_OPENCV;CMAKE_WINDOWS_BUILD;GLOG_NO_ABBREVIATED_SEVERITIES;GOOGLE_GLOG_DLL_DECL=__declspec(dllimport);GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS=__declspec(dllimport);H5_BUILT_AS_DYNAMIC_LIB=1;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) $(IntDir) WIN32;_DEBUG;_WINDOWS;CAFFE_VERSION=1.0.0;BOOST_ALL_NO_LIB;USE_LMDB;USE_LEVELDB;USE_CUDNN;USE_OPENCV;CMAKE_WINDOWS_BUILD;GLOG_NO_ABBREVIATED_SEVERITIES;GOOGLE_GLOG_DLL_DECL=__declspec(dllimport);GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS=__declspec(dllimport);H5_BUILT_AS_DYNAMIC_LIB=1;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:x64 kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;caffe-d.lib;caffeproto-d.lib;boost_system-vc140-mt-gd-1_61.lib;boost_thread-vc140-mt-gd-1_61.lib;boost_filesystem-vc140-mt-gd-1_61.lib;boost_chrono-vc140-mt-gd-1_61.lib;boost_date_time-vc140-mt-gd-1_61.lib;boost_atomic-vc140-mt-gd-1_61.lib;glogd.lib;gflagsd.lib;shlwapi.lib;libprotobufd.lib;caffehdf5_hl_D.lib;caffehdf5_D.lib;caffezlibd.lib;lmdbd.lib;ntdll.lib;leveldbd.lib;snappy_staticd.lib;caffezlibd.lib;cudart.lib;curand.lib;cublas.lib;cublas_device.lib;cudnn.lib;opencv_highgui310d.lib;opencv_videoio310d.lib;opencv_imgcodecs310d.lib;opencv_imgproc310d.lib;opencv_core310d.lib;libopenblas.dll.a;python27.lib;boost_python-vc140-mt-gd-1_61.lib %(AdditionalLibraryDirectories) Debug %(IgnoreSpecificDefaultLibraries) MTCNN-d.pdb Console false %(AdditionalIncludeDirectories) Release/ CompileAsCpp Sync AnySuitable MaxSpeed NotUsing MultiThreadedDLL true Level3 WIN32;_WINDOWS;NDEBUG;CAFFE_VERSION=1.0.0;BOOST_ALL_NO_LIB;USE_LMDB;USE_LEVELDB;USE_CUDNN;USE_OPENCV;CMAKE_WINDOWS_BUILD;GLOG_NO_ABBREVIATED_SEVERITIES;GOOGLE_GLOG_DLL_DECL=__declspec(dllimport);GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS=__declspec(dllimport);H5_BUILT_AS_DYNAMIC_LIB=1;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) $(IntDir) ProgramDatabase WIN32;_WINDOWS;NDEBUG;CAFFE_VERSION=1.0.0;BOOST_ALL_NO_LIB;USE_LMDB;USE_LEVELDB;USE_CUDNN;USE_OPENCV;CMAKE_WINDOWS_BUILD;GLOG_NO_ABBREVIATED_SEVERITIES;GOOGLE_GLOG_DLL_DECL=__declspec(dllimport);GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS=__declspec(dllimport);H5_BUILT_AS_DYNAMIC_LIB=1;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) $(ProjectDir)/$(IntDir) %(Filename).h %(Filename).tlb %(Filename)_i.c %(Filename)_p.c %(AdditionalOptions) /machine:x64 kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;boost_system-vc140-mt-1_61.lib;boost_thread-vc140-mt-1_61.lib;boost_filesystem-vc140-mt-1_61.lib;boost_chrono-vc140-mt-1_61.lib;boost_date_time-vc140-mt-1_61.lib;boost_atomic-vc140-mt-1_61.lib;glog.lib;gflags.lib;shlwapi.lib;libprotobuf.lib;caffehdf5_hl.lib;caffehdf5.lib;caffezlib.lib;lmdb.lib;ntdll.lib;leveldb.lib;snappy_static.lib;caffe.lib;caffeproto.lib;cudart.lib;curand.lib;cublas.lib;cublas_device.lib;cudnn.lib;opencv_highgui310.lib;opencv_imgcodecs310.lib;opencv_imgproc310.lib;opencv_core310.lib;libopenblas.dll.a;python27.lib;boost_python-vc140-mt-1_61.lib %(AdditionalLibraryDirectories) true %(IgnoreSpecificDefaultLibraries) MTCNN.pdb Console false ================================================ FILE: cpp4caffe/evaluation.cpp ================================================ #define REG_USE_CNN 1 #pragma warning(disable:4996) #include "mrdir.h" #include "mrutil.h" #include "cnnpredictor.h" const string errordir = caffeplatedir + "error"; const string platedatadir = caffeplatedir+"data"; void cleardir(const string dir) { vectorfiles=getAllFilesinDir(dir); for (int i = 0; i < files.size(); i++) { string filepath = dir + "/" + files[i]; remove(filepath.c_str()); } } void clearerror(const string dir) { vectorsubdirs=getAllSubdirs(dir); for (int i = 0; i < subdirs.size(); i++) { string subdir = dir + "/" + subdirs[i]; cleardir(subdir); } } int evaluation() { string line; string label; int rightcount = 0, errorcount = 0, total = 0; if (!EXISTS(errordir.c_str())) { cout << "Error dir not exist" << endl; MKDIR(errordir.c_str()); } clearerror(errordir); vectorsubdirs=getAllSubdirs(platedatadir); for (auto sub : subdirs) { string subdir = platedatadir + "/" + sub; vectorfiles=getAllFilesinDir(subdir); for (auto file : files) { string fileapth = subdir + "/" + file; cv::Mat img = cv::imread(fileapth); auto ret = split(CnnPredictor::getInstance()->predict(img), " ")[1]; if (ret == sub) rightcount++; else { errorcount++; string errorlabeldir = errordir; errorlabeldir = errorlabeldir + "/" + sub; if (!EXISTS(errorlabeldir.c_str())) { MKDIR(errorlabeldir.c_str()); } string errorfilepath = errorlabeldir + "/" + file.substr(0,file.size()-4) + "_" + sub + "_" + ret + ".png"; cout << sub + "/" + file.substr(0, file.size() - 4) + ":" + ret << endl; //imshow("error", img); imwrite(errorfilepath, img); //cv::waitKey(1); } total++; } } cout << "acc:" << rightcount << "/" << total << endl; cout << rightcount*1.0 / total << endl; return 0; } int main(int argc,char*argv[]) { if (argc==1) evaluation(); else { cv::Mat img = cv::imread(argv[1]); cout << CnnPredictor::getInstance()->predict(img) << endl; } return 0; } ================================================ FILE: models/deploy.prototxt ================================================ name: "LeNet" layer{ name:"data" type:"Input" top: "data" input_param { shape: {dim:1 dim:3 dim:20 dim:20 } } } layer { name: "conv1" type: "Convolution" bottom: "data" top: "conv1" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 20 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 50 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool2" type: "Pooling" bottom: "conv2" top: "pool2" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "fc1" type: "InnerProduct" bottom: "pool2" top: "fc1" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 500 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "relu1" type: "ReLU" bottom: "fc1" top: "fc1" } layer { name: "fc2" type: "InnerProduct" bottom: "fc1" top: "fc2" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 10 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "prob" type: "Softmax" bottom: "fc2" top: "prob" } ================================================ FILE: models/labels.txt ================================================ 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 ================================================ FILE: models/plate_fromimg.prototxt ================================================ name: "LeNet" layer { name: "mnist" type: "ImageData" top: "data" top: "label" image_data_param { source: "util/train.txt" root_folder: "data/" new_height: 20 new_width: 20 batch_size: 64 shuffle: true } include: { phase: TRAIN } } layer { name: "mnist" type: "ImageData" top: "data" top: "label" image_data_param { source: "util/val.txt" root_folder: "data/" new_height: 20 new_width: 20 batch_size: 64 } include: { phase: TEST } } layer { name: "conv1" type: "Convolution" bottom: "data" top: "conv1" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 20 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 50 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool2" type: "Pooling" bottom: "conv2" top: "pool2" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "fc1" type: "InnerProduct" bottom: "pool2" top: "fc1" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 500 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "relu1" type: "ReLU" bottom: "fc1" top: "fc1" } layer { name: "fc2" type: "InnerProduct" bottom: "fc1" top: "fc2" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 10 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "accuracy" type: "Accuracy" bottom: "fc2" bottom: "label" top: "accuracy" include { phase: TEST } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "fc2" bottom: "label" top: "loss" } ================================================ FILE: models/plate_lenet.prototxt ================================================ name: "Lenet" layer { name: "Lenet" type: "Data" top: "data" top: "label" transform_param { scale: 0.00390625 } data_param { source: "lmdb/train_lmdb" backend: LMDB batch_size: 64 } include: { phase: TRAIN } } layer { name: "Lenet" type: "Data" top: "data" top: "label" transform_param { scale: 0.00390625 } data_param { source: "lmdb/val_lmdb" backend: LMDB batch_size: 64 } include: { phase: TEST } } layer { name: "conv1" type: "Convolution" bottom: "data" top: "conv1" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 20 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 50 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "pool2" type: "Pooling" bottom: "conv2" top: "pool2" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "fc1" type: "InnerProduct" bottom: "pool2" top: "fc1" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 500 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "relu1" type: "ReLU" bottom: "fc1" top: "fc1" } layer { name: "fc2" type: "InnerProduct" bottom: "fc1" top: "fc2" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 10 weight_filler { type: "xavier" } bias_filler { type: "constant" } } } layer { name: "accuracy" type: "Accuracy" bottom: "fc2" bottom: "label" top: "accuracy" include { phase: TEST } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "fc2" bottom: "label" top: "loss" } ================================================ FILE: models/solver.prototxt ================================================ # The train/test net protocol buffer definition net: "models/plate_lenet.prototxt" #net: "models/plate_fromimg.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: 24 # Carry out testing every 500 training iterations. test_interval: 1000 # The base learning rate, momentum and the weight decay of the network. base_lr: 0.01 momentum: 0.9 #solver_type: ADAGRAD weight_decay: 0.0005 #weight_decay: 0.0005 # The learning rate policy lr_policy: "inv" gamma: 0.0001 power: 0.75 # Display every 100 iterations display: 1000 # The maximum number of iterations max_iter: 10000 # snapshot intermediate results snapshot: 5000 snapshot_prefix: "output/plate" # solver mode: CPU or GPU solver_mode: GPU ================================================ FILE: train.bat ================================================ @echo off set CAFFE_DIR=.. set DATA=data set REISZE_DIM=20 set converttool=%CAFFE_DIR%/build/tools/convert_imageset set finetunemodel=models/plate999.caffemodel if exist "lmdb/train_lmdb" (set regenlmdb=0) else (set regenlmdb=1) ::set regenlmdb=1 if %regenlmdb% equ 1 goto regeneratelmdb goto train :regeneratelmdb echo "Creating train lmdb..." del "lmdb/train_lmdb\*.*" /f /s /q del "lmdb/val_lmdb\*.*" /f /s /q rd /s /q "lmdb/train_lmdb" rd /s /q "lmdb/val_lmdb" rd /s /q lmdb mkdir lmdb "%converttool%" --resize_height=%REISZE_DIM% --resize_width=%REISZE_DIM% --shuffle "%DATA%/" "util/train.txt" "lmdb/train_lmdb" echo "Creating val lmdb..." "%converttool%" --resize_height=%REISZE_DIM% --resize_width=%REISZE_DIM% --shuffle "%DATA%/" "util/val.txt" "lmdb/val_lmdb" echo "Computing mean:" "%CAFFE_DIR%/build/tools/compute_image_mean" "lmdb/train_lmdb" "models/mean.binaryproto" :train rem if exist %finetunemodel% (set extra_cmd="--weights=%finetunemodel%") rem "%CAFFE_DIR%/build/tools/caffe" train --solver=models/solver.prototxt %extra_cmd% python3 train.py :evaluation python util/evaluation.py echo "Done" pause ================================================ FILE: train.py ================================================ import os import sys sys.path.insert(0, '../python') import caffe from caffe import layers as L, params as P from caffe.proto import caffe_pb2 import lmdb from tqdm import tqdm import logging import cv2 import numpy as np root_folder="data/" batch_size = 64 test_batch_size = 100 input_size = [20,20] G4 = 4*1024*1024*1024 def remove_if_exists(db): if os.path.exists(db): logger.info('remove %s'%db) shutil.rmtree(db) def get_test_num(valpath = "util/val.txt"): with open(valpath) as f: lines = f.readlines() return len(lines) def make_datum(img,label): return caffe_pb2.Datum(channels=3,width=input_size[0],height=input_size[1],label=label, data=np.rollaxis(img,2).tobytes()) def gen_data_layer(phase="train",uselmdb=True): if uselmdb: source = "lmdb/"+phase+"_lmdb" if not os.path.exists(source): print("creating "+source) os.makedirs(source) db = lmdb.open(source, map_size=G4) txn = db.begin(write=True) txtfile="util/"+phase+".txt" with open(txtfile) as f: lines = f.readlines() for i,line in tqdm(enumerate(lines)): items = line.split() imgpath = root_folder+"/"+items[0] img = cv2.imread(imgpath) if img is None: logging.info("cannot read"+imgpath) key = "%08d_data"%(i) label=int(items[1]) txn.put(key,make_datum(img,label).SerializeToString()) if i %1000 == 0: txn.commit() txn = db.begin(write=True) db.close() data, label = L.Data(batch_size=batch_size, backend=P.Data.LMDB,source=source,transform_param=dict(scale=1./255), ntop=2) else: txtfile="util/"+phase+".txt" data, label = L.ImageData(image_data_param=dict(source=txtfile,root_folder=root_folder,batch_size=batch_size,shuffle=phase=="train",new_width=20,new_height=20),ntop=2,transform_param=dict(scale=1./255)) return data,label def lenet(phase="train",batch_size=64): n = caffe.NetSpec() n.data, n.label = gen_data_layer(phase) n.conv1 = L.Convolution(n.data, kernel_size=5, num_output=20, weight_filler=dict(type='xavier')) n.pool1 = L.Pooling(n.conv1, kernel_size=2, stride=2, pool=P.Pooling.MAX) n.conv2 = L.Convolution(n.pool1, kernel_size=5, num_output=50, weight_filler=dict(type='xavier')) n.pool2 = L.Pooling(n.conv2, kernel_size=2, stride=2, pool=P.Pooling.MAX) n.fc1 = L.InnerProduct(n.pool2, num_output=500, weight_filler=dict(type='xavier')) n.relu1 = L.ReLU(n.fc1, in_place=True) n.fc2 = L.InnerProduct(n.relu1, num_output=10, weight_filler=dict(type='xavier')) n.acc = L.Accuracy(n.fc2, n.label) n.loss = L.SoftmaxWithLoss(n.fc2, n.label) return n def lenet_deploy(net,deploy_net_file="util/deploy.prototxt"): deploy_net = net with open(deploy_net_file, 'w') as f: net_param = deploy_net.to_proto() del net_param.layer[0] del net_param.layer[-1] del net_param.layer[-1] net_param.name = 'lenet' net_param.input.extend(['data']) net_param.input_shape.extend([ caffe_pb2.BlobShape(dim=[1, 3, input_size[0], input_size[1]])]) f.write(str(net_param)) def gen_solver_txt(train_net_path, test_net_path): s = caffe_pb2.SolverParameter() s.train_net = train_net_path s.test_net.append(test_net_path) s.test_interval = 500 s.test_iter.append(int(get_test_num()/test_batch_size)) s.max_iter = 10000 s.base_lr = 0.01 s.lr_policy = 'step' s.gamma = 0.1 s.power = 0.75 s.stepsize = 5000 s.momentum = 0.9 s.weight_decay = 5e-4 s.display = 1000 s.snapshot = 5000 s.snapshot_prefix = 'output/plate' s.solver_mode = caffe_pb2.SolverParameter.GPU return s def main(): train_net_path = 'util/train.prototxt' net = lenet('train',batch_size) with open(train_net_path, 'w') as f: f.write(str(net.to_proto())) test_net_path = 'util/test.prototxt' net = lenet('val',test_batch_size) with open(test_net_path, 'w') as f: f.write(str(net.to_proto())) lenet_deploy(net) solver_path = 'util/solver.prototxt' with open(solver_path, 'w') as f: f.write(str(gen_solver_txt(train_net_path, test_net_path))) caffe.set_mode_gpu() solver = caffe.get_solver(solver_path) solver.solve() if __name__=="__main__": main() ================================================ FILE: train.sh ================================================ #!/usr/bin/env sh set -e DATA=data TOOLS=../build/tools regeneratelmdb=0 convert_lmdb(){ RESIZE_HEIGHT=20 RESIZE_WIDTH=20 echo "Creating train lmdb..." GLOG_logtostderr=1 $TOOLS/convert_imageset \ --resize_height=$RESIZE_HEIGHT \ --resize_width=$RESIZE_WIDTH \ --shuffle $DATA/ \ util/train.txt \ lmdb/train_lmdb echo "Creating val lmdb..." GLOG_logtostderr=1 $TOOLS/convert_imageset \ --resize_height=$RESIZE_HEIGHT \ --resize_width=$RESIZE_WIDTH \ --shuffle $DATA/ \ util/val.txt \ lmdb/val_lmdb } create_lmdb(){ if [ -d lmdb ] ; then if [ $regeneratelmdb -eq 1 ] ; then rm lmdb -rf mkdir lmdb convert_lmdb fi else mkdir lmdb convert_lmdb fi } train(){ if [ ! -d output ]; then mkdir output fi latest=$(ls -t models/*.caffemodel | head -n 1) if [ -f ${latest} ]; then echo "Resume training from ${latest}" $TOOLS/caffe train --solver=models/solver.prototxt --weights=$latest else echo "Start Training" $TOOLS/caffe train --solver=models/solver.prototxt fi echo "Done" } # python evaluate evaluate(){ latest=$(ls -t output/*.caffemodel | head -n 1) echo "Evaluating "${latest} python util/evaluation.py --weights=${latest} cd .. } # c++ evaluate run(){ if [ not -d build ]; then mkdir build fi cd build cmake .. make -j8 ./evaluation #./cpp4caffe } # generate util/train.txt and val.txt for training # python3 util/preprocess.py #create_lmdb # train python train.py evaluate #run ================================================ FILE: util/deploy.prototxt ================================================ name: "lenet" input: "data" input_shape { dim: 1 dim: 3 dim: 20 dim: 20 } layer { name: "conv1" type: "Convolution" bottom: "data" top: "conv1" convolution_param { num_output: 20 kernel_size: 5 weight_filler { type: "xavier" } } } layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "conv2" type: "Convolution" bottom: "pool1" top: "conv2" convolution_param { num_output: 50 kernel_size: 5 weight_filler { type: "xavier" } } } layer { name: "pool2" type: "Pooling" bottom: "conv2" top: "pool2" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "fc1" type: "InnerProduct" bottom: "pool2" top: "fc1" inner_product_param { num_output: 500 weight_filler { type: "xavier" } } } layer { name: "relu1" type: "ReLU" bottom: "fc1" top: "fc1" } layer { name: "fc2" type: "InnerProduct" bottom: "fc1" top: "fc2" inner_product_param { num_output: 10 weight_filler { type: "xavier" } } } ================================================ FILE: util/evaluation.py ================================================ import os,argparse,sys,time,shutil import numpy as np import sys sys.path.append('../python') import caffe import logging from tqdm import tqdm def create_logger(logdir="output"): time_str = time.strftime('%Y%m%d-%H%M%S') log_file = '{}/{}.log'.format(logdir, time_str) head = '%(asctime)-15s %(message)s' logging.basicConfig(filename=str(log_file),format=head) logger = logging.getLogger() logger.setLevel(logging.INFO) console = logging.StreamHandler() logging.getLogger('').addHandler(console) def clearlasterrors(args): if os.path.exists("error"): subdirs=os.listdir(args.errordir) for subdir in subdirs: files=os.listdir(args.errordir+"/"+subdir) for file in files: os.remove(args.errordir+"/"+subdir+"/"+file) os.rmdir(args.errordir+"/"+subdir) def loadmean(meanprotopath): blob = caffe.proto.caffe_pb2.BlobProto() blob.ParseFromString(open(meanprotopath, 'rb').read()) return np.array(caffe.io.blobproto_to_array(blob))[0] def getclassifier(args): classifier = caffe.Classifier(args.modeldef, args.weights,image_dims=args.image_dims ) ##mean=loadmean(args.meanfile).mean(1).mean(1),#raw_scale=255,channel_swap=[2,1,0] caffe.set_mode_gpu() return classifier class EvalStatic: total = 0 error = 0 def __str__(self): return str(self.error)+","+str(self.total)+","+str(self.error*1.0/self.total) def evaluationonebyone(args): labels=[w.split()[1] for w in open(args.labelfile).readlines()] classifier = getclassifier(args) start = time.time() if not os.path.exists(args.errordir): os.mkdir(args.errordir) subdirs=os.listdir(args.datadir) evalstatics=[] for subdir in subdirs: print(subdir+":") evalstatic=EvalStatic() files=os.listdir(args.datadir+'/'+subdir) evalstatic.total=len(files) for file in tqdm(files): imgpath=args.datadir+'/'+subdir+'/'+file inputs = [caffe.io.load_image(imgpath)] try: predictions = classifier.predict(inputs,oversample=False) except Exception as e: print(e) p=predictions[0,:].argmax() label=labels[p] if subdir!=label: logging.info(subdir+" "+file+":"+str(label)) evalstatic.error=evalstatic.error+1 if not os.path.exists(args.errordir+'/'+subdir): os.mkdir(args.errordir+'/'+subdir) errorfilepath=args.errordir+'/'+subdir+'/'+file[:-4]+"_"+subdir+'_'+label+'.jpg' shutil.copy(imgpath,errorfilepath) evalstatics.append(evalstatic) logging.info("Done in %.2f s." % (time.time() - start)) totalcount=0 error=0 for i,evalstatic in enumerate(evalstatics): error=error+evalstatic.error totalcount=totalcount+evalstatic.total logging.info(subdirs[i]+":"+str(evalstatic)) logging.info("Toal error") logging.info(str(error)+" "+str(totalcount)+" "+str(error*1.0/totalcount)) def evaluation_batch(args): labels=[w.split()[1] for w in open(args.labelfile).readlines()] classifier=getclassifier(args) start = time.time() if not os.path.exists(args.errordir): os.mkdir(args.errordir) subdirs=os.listdir(args.datadir) evalstatics=[] for subdir in subdirs: print(subdir) evalstatic=EvalStatic() files=os.listdir(args.datadir+'/'+subdir) evalstatic.total=len(files) inputs=[caffe.io.load_image(args.datadir+'/'+subdir+'/'+file) for file in files] try: predictions = classifier.predict(inputs,oversample=False) except Exception as e: print(e) for i in tqdm(range(len(files))): p=predictions[i,:].argmax() label=labels[p] if subdir!=label: logging.info(subdir+" "+files[i]+":"+str(label)) evalstatic.error=evalstatic.error+1 if not os.path.exists(args.errordir+'/'+subdir): os.mkdir(args.errordir+'/'+subdir) imgpath=args.datadir+"/"+subdir+"/"+files[i] errorfilepath=args.errordir+'/'+subdir+'/'+files[i][:-4]+"_"+subdir+'_'+label+'.jpg' shutil.copy(imgpath,errorfilepath) evalstatics.append(evalstatic) logging.info("Done in %.2f s." % (time.time() - start)) totalcount=0 error=0 for i,evalstatic in enumerate(evalstatics): error=error+evalstatic.error totalcount=totalcount+evalstatic.total logging.info(subdirs[i]+":"+str(evalstatic)) logging.info("Toal error") logging.info(str(error)+" "+str(totalcount)+" "+str(error*1.0/totalcount)) def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--iter",default=10000,help="caffemodel iter to evaluation") parser.add_argument("--datadir",default="data",help="datadir") parser.add_argument("--image_dims",default=[20,20],help="image_dims") parser.add_argument("--modeldef",default="util/deploy.prototxt",help="deploy file") parser.add_argument("--weights",default="models/plate999.caffemodel",help="caffemodel") parser.add_argument("--labelfile",default="models/labels.txt",help="label file") parser.add_argument("--meanfile",default="models/mean.binaryproto",help="meanfile") parser.add_argument("--errordir",default="error",help="errordir") parser.add_argument("--logfile",default="error.txt",help="log txt") parser.add_argument("--evaluationonebyone",default=True,help="log txt") parser.add_argument("--imgpath",default="data/0/0.jpg",help="image path") args = parser.parse_args() return args def classification(): args = get_args() args = parser.parse_args() labels=[w.split()[1] for w in open(args.labelfile).readlines()] classifier=getclassifier(args) inputs=[caffe.io.load_image(args.imgpath)] predictions = classifier.predict(inputs,oversample=False) p=predictions[0,:].argmax() label=labels[p] print(label,predictions[0,p]) top_inds = predictions[0,:].argsort()[::-1][:5] def evaluation(): args = get_args() clearlasterrors(args) create_logger() if args.evaluationonebyone: evaluationonebyone(args) else: evaluation_batch(args) if __name__=='__main__': evaluation() #classification() ================================================ FILE: util/meanfilebinartynpy.py ================================================ import os import sys sys.path.append('../../python') MEAN_BIN = "../models/mean.binaryproto" MEAN_NPY = "../models/mean.npy" from caffe.proto import caffe_pb2 from caffe.io import blobproto_to_array print('generating mean file...') mean_blob = caffe_pb2.BlobProto() mean_blob.ParseFromString(open(MEAN_BIN, 'rb').read()) import numpy as np mean_npy = blobproto_to_array(mean_blob) mean_npy_shape = mean_npy.shape mean_npy = mean_npy.reshape(mean_npy_shape[1], mean_npy_shape[2], mean_npy_shape[3]) np.save(open(MEAN_NPY, 'wb'), mean_npy) print('done...') ================================================ FILE: util/plotaccuracy.py ================================================ #coding =utf-8 #迷若烟雨@Baidu import re import matplotlib.pyplot as plt import os import sys import datetime def getlastesttraininfofilefromdir(logdir): logfiles=os.listdir(logdir) infologfiles=filter(lambda s:s.startswith('INFO'),logfiles) infologfiles=filter(lambda s:s.endswith('.txt'),infologfiles) if infologfiles: lastestfile=infologfiles[0] maxtm=0 for logf in infologfiles: path = os.path.join(logdir, logf) timestamp = os.path.getmtime(path) date = datetime.datetime.fromtimestamp(timestamp) if timestamp>maxtm: lastestfile=path return lastestfile else: return None def plotaccuarcy(): logdir='log' infologfile=getlastesttraininfofilefromdir(logdir) print(infologfile) if infologfile: # infologfile='../log/INFO2015-11-19T19-45-15.txt' f=open(infologfile) lines=f.read() #print lines iterations=re.findall('Iteration \d*',lines) accuracysstrings=re.findall('accuracy = \d*.\d*',lines) trainlosstrings=re.findall('Train net output #0: loss = \d*.\d*',lines) testlossstrings=re.findall('Test net output #1: loss = \d*.\d*',lines) f.close() accuracys=[ac[11:] for ac in accuracysstrings] trainlosses=[loss[27:-1]for loss in trainlosstrings] testlosses=[loss[27:-1]for loss in testlossstrings] #for ac in accuracys: # print ac plt.plot(range(len(accuracys)),accuracys) #plt.plot(range(len(trainlosses)),trainlosses) #plt.plot(range(len(testlosses)),testlosses) plt.show() if __name__=="__main__": plotaccuarcy() ================================================ FILE: util/preprocess.py ================================================ import os,argparse,random,shutil def main(args): datadir=args.rootdir+"/"+args.dataname print("loading data from "+datadir+":") trainfile=open("util/train.txt","w") valfile=open("util/val.txt","w") categoryfile=open("models/labels.txt",'w') paths=os.listdir(datadir) classindex=0 trainpaths=[] valpaths=[] categorys=[] for subdir in paths: if(os.path.isdir(datadir+"/"+subdir)): categorys.append(str(classindex)+" "+subdir+"\n") files=os.listdir(datadir+"/"+subdir) files=[file for file in files] random.shuffle(files) print(subdir,len(files)) num2train=len(files)*args.trainrtaio for fileindex,file in enumerate(files): if fileindex