mini-caffe編譯,用BLVC caffe編譯的mnist模型進行測試

來源:互聯網
上載者:User

mini-caffe是最小化Caffe的運行版本,只用來forward,運算效率高、佔用小,因此其極其適合用於線上測試。但是,如果你自己實現了非官方caffe的Layer,同樣需要在mini-caffe中自己實現對應的計算代碼。

這篇文章用VS2015編譯mini-caffe項目,記載caffe訓練mnist資料產生的模型和deploy.prototxt,對測試圖片進行分類。 1、編譯準備

下載mini-caffe項目,https://github.com/luoyetx/mini-caffe,解壓到自己的存放目錄即可。

另外,mini-caffe編譯需要protobuf庫,同樣需要自己下載編譯,下載地址https://github.com/google/protobuf。(建議下載release下的)

在我這裡,mini-caffe存放地址如下;protobuf解壓存放在mini-caffe-master\3rdparty\src\protobuf下。

  2、編譯protobuf

開啟CMake工具,指定source目錄為E:/Program Files/Tools/mini-caffe-master/3rdparty/src/protobuf/cmake,

build目錄為E:/Program Files/Tools/mini-caffe-master/3rdparty/src/protobuf/cmake/build。

點擊Configure,選擇編譯器Visual Studio 14 2015 Win64,取消勾選protobuf_BUILD_TESTS和protobuf_MSVC_STATIC_RUNTIME,再次點擊Configure,再點擊Generate,就會產生protobuf.sln解決方案。

同樣也可以用cmake命令:

cd 3rdparty/src/protobuf/cmakemkdir buildcd buildcmake .. -Dprotobuf_BUILD_TESTS=OFF -Dprotobuf_MSVC_STATIC_RUNTIME=OFF -G "Visual Studio 14 2015 Win64"

開啟protobuf.sln,編譯產生Debug和Release版本,儲存在protobuf/CMake/build/Debug和protobuf/CMake/build/Release檔案夾下面。

有了這2個版本的庫檔案,就可以編譯mini-caffe了。 3、編譯mini-caffe

編譯mini-cafe之前,有2個準備步驟。

(1)先要複製依賴檔案到指定位置,大致過程為:

拷貝3rdparty\src\protobuf\src下的google檔案夾到mini-caffe-master\3rdparty\include\下 (其實只需要.h檔案);

拷貝protobuf\cmake\build\Debug\libprotobufd.lib 和 protobuf\cmake\build\Release\libprotobuf.lib到3rdparty\lib\下;

拷貝 protobuf\cmake\build\Release\protoc.exe 到 3rdparty\bin\下;

(2)產生caffe.pb.h和caffe.pb.cc

利用前面複製的操作,執行下面代碼即可

"./3rdparty/bin/protoc" -I="./src/proto" --cpp_out="./src/proto" "./src/proto/caffe.proto"

mini-caffe已經做好了上述兩個步驟步驟的指令碼,可以分別點擊mini-caffe-master目錄下的兩個批次檔執行,分別為copydeps.bat 和 generatepb.bat。

完成上述兩個準備步驟之後,就可以用CMake產生mini-caffe.sln了,命令列或者CMake的視窗工具都可以。(另外,還可以選擇是否使用GPU)

mkdir buildcd buildcmake .. -G "Visual Studio 14 2015 Win64"

同樣,編譯可以產生Debug和Release兩個版本的ceffe.lib和caffe.dll。後面就可以拿這個開始測試了。 4、測試mnist模型

在前面的部落格中有用官方的classification.exe實現對mnist手寫字元映像的識別(傳送門),儘管改寫後從篇幅上略有減小,但是整個網路中還有不少的東西可以去掉,例如網路反向計算的資料,在測試中不會用到的計算層等等。相較而言,mini-caffe只包含了forward計算,從網路Net上去掉了不需要的東西,並且在前向計算後清空了中間的所有層資料,極大的減小了空間的消耗,並且計算速度較快。

#include <caffe/caffe.hpp>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <chrono>/*! \brief Timer */class Timer {using Clock = std::chrono::high_resolution_clock;public:/*! \brief start or restart timer */inline void Tic() {start_ = Clock::now();}/*! \brief stop timer */inline void Toc() {end_ = Clock::now();}/*! \brief return time in ms */inline double Elasped() {auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_ - start_);return duration.count();}private:Clock::time_point start_, end_;};using namespace caffe;  // NOLINT(build/namespaces)using std::string;static bool PairCompare(const std::pair<float, int>& lhs,const std::pair<float, int>& rhs) {return lhs.first > rhs.first;}void main(){string model_file =   R"(E:\ProgramData\caffe-windows\data\mnist\windows\lenet.prototxt)";string trained_file = R"(E:\ProgramData\caffe-windows\data\mnist\windows\snapshot_lenet_mean\_iter_10000.caffemodel)";string mean_file =    R"(E:\ProgramData\caffe-windows\data\mnist\windows\mean.binaryproto)";string label_file =   R"(E:\ProgramData\caffe-windows\data\mnist\windows\synset_words.txt)";string file =         R"(E:\ProgramData\caffe-windows\data\mnist\windows\3.bmp)";//////////////////////////////////////////////////////////////////////////////  讀取網路Net, 指定資料類型是 float, 後面有關cv::Mat的type應該為 CV_32Fif (caffe::GPUAvailable()) caffe::SetMode(caffe::GPU, 0); // 若有GPU可用,設定為GPU模式shared_ptr<caffe::Net> net_( new caffe::Net(model_file));net_->CopyTrainedLayersFrom(trained_file);//////////////////////////////////////////////////////////////////////////// //  標籤資料(可不用)cv::Size input_geometry_;int num_channels_;cv::Mat mean_;std::vector<string> labels_ = { "zero","one","two","three","four","five","six","seven","Eight","Nine" };////////////////////////////////////////////////////////////////////////////// 輸入層,只能通過blob_by_name擷取,沒有input_blobs()函數//shared_ptr<caffe::Blob> input_layer = net_->blob_by_name("data");// 小寫,儘管lenet.prototxt輸入層name為"Data"input_geometry_ = cv::Size(input_layer->width(), input_layer->height());num_channels_ = input_layer->channels();std::cout << "input shape:    "<< input_layer->shape_string()<< std::endl;std::cout << "input size:     "<< input_geometry_<< std::endl; std::cout << "input channels: " << num_channels_<< std::endl;//////////////////////////////////////////////////////////////////////////////  從檔案中讀取均值映像資料shared_ptr<Blob> mean_blob = ReadBlobFromFile(mean_file); std::vector<cv::Mat> channels;float* data = mean_blob->mutable_cpu_data();//for (int i = 0; i < num_channels_; ++i) {//cv::Mat channel(mean_blob->height(), mean_blob->width(), CV_32FC1, data);//channels.push_back(channel);//data += mean_blob->height() * mean_blob->width();//}//cv::Mat mean;//cv::merge(channels, mean);// 代替上面代碼程式,這裡已經明確是 1*1*28*28 的Blob,  輸入Blob的shape一樣cv::Mat mean(mean_blob->height(), mean_blob->width(), CV_32FC1, data); cv::Scalar channel_mean = cv::mean(mean); // 均值映像, 每個像素為 均值映像的平均亮度值mean_ = cv::Mat(input_geometry_, mean.type(), channel_mean);//////////////////////////////////////////////////////////////////////////////  讀入映像,並將映像資料寫入到網路輸入層Blobcv::Mat img = cv::imread(file, -1);if (!img.data) {std::cout << "Unable to decode image.\nQuit." << std::endl;system("pause");return;}// 明確輸入是  單通道資料 1*1*28*28if (img.channels() == 3 && num_channels_ == 1)cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);else if (img.channels() == 4 && num_channels_ == 1)cv::cvtColor(img, img, cv::COLOR_BGRA2GRAY);//else if (img.channels() == 4 && num_channels_ == 3)cv::cvtColor(img, img, cv::COLOR_BGRA2BGR);//else if (img.channels() == 1 && num_channels_ == 3)cv::cvtColor(img, img, cv::COLOR_GRAY2BGR);if (img.size() != input_geometry_)cv::resize(img, img, input_geometry_);img.convertTo(img, CV_32FC1);//input_layer->Reshape({ 1,1,28,28 });  // 不需要執行,已經是確定的float *dataInput = input_layer->mutable_cpu_data();//img -= mean_;  // 去均值//img.copyTo(cv::Mat(input_geometry_, mean_.type(), dataInput));// 去均值後映像資料拷貝到 data blob,方法1//memcpy(dataInput, img.data, sizeof(float)*img.cols*img.rows);// 去均值後映像資料拷貝到 data blob,方法2// 注釋img -= mean_; 這兩句代替上面的拷貝 cv::Mat dataImg(input_geometry_, CV_32FC1, dataInput);// 去均值後映像資料拷貝到 data blob,方法3dataImg = img - mean_;//////////////////////////////////////////////////////////////////////////////進行forward之後,僅保留第一層和最後一層的Blob資料, 也就是blob_by_name參數只能為"data"和"prob"auto t1 = cv::getTickCount();net_->Forward();auto t2 = cv::getTickCount();std::cout << " Forward time: " << (t2 - t1) / cv::getTickFrequency() * 1000 << " ms" << std::endl;shared_ptr<caffe::Blob> output_layer = net_->blob_by_name("prob"); // InnerProduct 輸出std::cout <<" output layer shape: " << output_layer->shape_string() << std::endl;const float* begin = output_layer->cpu_data();const float* end = begin + /*output_layer->channels()*/output_layer->shape(1);   // 只有2維,shape為(1,10)std::vector<float> OutRes = std::vector<float>(begin, end);//  channels()同shape(1), 也即N*C*W*H 的C, 儘管沒有W和H//////////////////////////////////////////////////////////////////////////////  輸出層的結果進行排序,列印輸出//int N = 5;std::vector<std::pair<float, int> > pairs;for (size_t i = 0; i < OutRes.size(); ++i)pairs.push_back(std::make_pair(OutRes[i], static_cast<int>(i)));std::partial_sort(pairs.begin(), pairs.begin() + N, pairs.end(), PairCompare);std::vector<std::pair<std::string, float> > result;std::cout << "=========== Prediction ============" << std::endl;for (int i = 0; i < N; ++i){int idx = pairs[i].second;//result.push_back(std::make_pair(labels_[idx], OutRes[idx]));std::cout << std::fixed  <<  OutRes[idx] << "  " << labels_[idx]<< std::endl;}system("pause");}

在訓練產生模型時指定了均值檔案,因此最好在測試時減去均值,使測試結果更加準確。

測試圖片(放大後顯示),減去均值測試結果,不減均值測試結果,依次如下圖所示:

附件:VS2015編譯的64位mini-caffe庫下載地址http://download.csdn.net/download/wanggao_1990/10000792


5、可能遇到的錯誤

當使用cudnn版本不同,可能會遇到一些錯誤,例如使用cudnn6.0時,會提示"caffe cudnnSetConvolution2dDescriptor error: too few arguments in function call ...”的錯誤,查看cudnn發現需要dataType::type類型的參數。若用cudnn6,需要修改有關所有的調用地方的模板類型,包括標頭檔和源檔案。建議用cudnn5.1。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.