日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

caffe学习:通过研读classification.cpp了解如何使用caffe模型

發布時間:2024/9/21 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 caffe学习:通过研读classification.cpp了解如何使用caffe模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在學習caffe的過程中,安裝caffe訓練和測試手寫字體識別例子成功時以為caffe不過如此;再用編譯好的classification.bin分類小貓的圖片時,發現自己能做的又非常的少。每次分類我都要提供這些文件?我能隨便給一張圖片嗎?我能更加隨心所欲的用這個模型嗎?模型的輸出應該怎么看?這些問題都可以通過研讀classification.cpp得到一定的啟發。所以我決定參照classification.cpp改一個自己寫的程序。

一、工程建立

如我的一篇博客Caffe + ROS + OpenCV + Qt creator所說,我利用Cmake管理工程,利用qt creator編寫程序。目錄結構如下:

  • classify文件夾?
    • src文件夾?
      • classify.cpp
    • CmakeLists.txt

CmakeLists.txt內容如下:

cmake_minimum_required(VERSION 2.8.3) project(classify)#設置caffe的根目錄,需改成你的路徑 set(Caffe_DIR /home/gph/Desktop/caffe_cmake/caffe-master) #設置OpenCV的根目錄,需改成你的路徑 set(OpenCV_DIR /home/gph/opencv/opencv-2.4.11/build)find_package(Caffe) include_directories(${Caffe_INCLUDE_DIRS}) find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS})include_directories(include ${OpenCV_INCLUDE_DIRS}${Caffe_INCLUDE_DIRS} )set(CPP_SOURCES src/classify.cpp)add_executable(classify ${CPP_SOURCES}) target_link_libraries(classify ${OpenCV_LIBS}${Caffe_LIBRARIES} )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

打開qt creator,在Welcome頁點擊Open Project打開相應的CmakeList.txt,再點擊Run cmake即可。

二、改寫程序

1.原程序解析

在classification.cpp中包含一個Classifier類,該類中包含:

Classifier函數:根據模型的配置文件.prototxt,訓練好的模型文件.caffemodel,建立模型,得到net_;處理均值文件,得到mean_;讀入labels文件,得到labels_。

classify函數:調用Predict函數對圖像img進行分類,返回std::pair< std::string, float >形式的預測結果。

私有函數:僅供classifier函數和classify函數使用,包括

  • setmean函數:將均值文件讀入,轉化為一張均值圖像mean_。
  • Predict函數:調用Process函數將圖像輸入到網絡中,使用net_->Forward()函數進行預測;將輸出層的輸出保存到vector容器中返回。
  • Process函數:這里寫代碼片對圖像的通道數、大小、數據形式進行改變,減去均值mean_,再寫入到net_的輸入層中。

私有變量:

  • net_:模型變量;
  • input_geometry_:輸入層的圖像的大小;
  • num_channels_:輸入層的通道數;
  • mean_:均值文件處理得到的均值圖像;
  • labels_:標簽文件,輸出的結果表示的含義;

2.改寫程序

改寫后的程序如下:

#include "caffe/caffe.hpp" #include <string> #include <opencv2/opencv.hpp>using namespace std; using namespace cv; using namespace caffe;//用于表存輸出結果的,string保存的預測結果對應的字符,如cat;float表示概率 typedef pair<string, float> Prediction;// 函數Argmax()需要用到的子函數 static bool PairCompare(const std::pair<float, int>& lhs,const std::pair<float, int>& rhs) {return lhs.first > rhs.first; }// 返回預測結果中概率從大到小的前N個預測結果的索引 static std::vector<int> Argmax(const std::vector<float>& v, int N) {std::vector<std::pair<float, int> > 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<int> result;for (int i = 0; i < N; ++i)result.push_back(pairs[i].second);return result; }int main(int argc, char** argv) {// 定義模型配置文件,模型文件,均值文件,標簽文件以及帶分類的圖像string model_file = "/home/gph/Desktop/caffe_cmake/caffe-master/models/bvlc_reference_caffenet/deploy.prototxt";string trained_file = "/home/gph/Desktop/caffe_cmake/caffe-master/models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel";string label_file = "/home/gph/Desktop/caffe_cmake/caffe-master/data/ilsvrc12/synset_words.txt";string img_file = "/home/gph/Desktop/caffe_cmake/caffe-master/examples/images/cat.jpg";string mean_file = "/home/gph/Desktop/caffe_cmake/caffe-master/data/ilsvrc12/imagenet_mean.binaryproto";Mat img = imread(img_file);// 定義變量shared_ptr<Net<float> > net_;// 保存模型Size input_geometry_; // 模型輸入圖像的尺寸int num_channels_; // 圖像的通道數Mat mean_; // 根據均值文件計算得到的均值圖像vector<string> labels_; // 標簽向量Caffe::set_mode(Caffe::GPU); // 是否使用GPUnet_.reset(new Net<float>(model_file, TEST)); // 加載配置文件,設定模式為分類net_->CopyTrainedLayersFrom(trained_file); // 根據訓練好的模型修改模型參數Blob<float>* input_layer = net_->input_blobs()[0]; // 定義輸入層變量num_channels_ = input_layer->channels(); // 得到輸入層的通道數LOG(INFO) << "num_channels_:" << num_channels_; // 輸出通道數input_geometry_ = Size(input_layer->width(), input_layer->height()); // 得到輸入層的圖像大小// 處理均值文件,得到均值圖像BlobProto blob_proto;ReadProtoFromBinaryFileOrDie(mean_file.c_str(), &blob_proto); // mean_file.c_str()將string類型轉化為字符型Blob<float> mean_blob;mean_blob.FromProto(blob_proto);vector<Mat> channels;float* data = mean_blob.mutable_cpu_data();// data指針for (int i = 0; i < num_channels_; i++){Mat channel(mean_blob.height(), mean_blob.width(), CV_32FC1, data);//將一副單通道圖像的數據記錄再channel中channels.push_back(channel);data += mean_blob.height() * mean_blob.width();// data指向下一個通道的開始}Mat mean;merge(channels, mean); //分離的通道融合,查看cv::merge的作用Scalar channel_mean = cv::mean(mean);mean_ = Mat(input_geometry_, mean.type(), channel_mean);//得到均值圖像// 得到標簽ifstream labels(label_file.c_str());string line;while (getline(labels, line))labels_.push_back(string(line));//判斷標簽的類數和模型輸出的類數是否相同Blob<float>* output_layer = net_->output_blobs()[0];LOG(INFO) << "output_layer dimension: " << output_layer->channels()<< "; labels number: " << labels_.size();// 預測圖像input_layer->Reshape(1, num_channels_, input_geometry_.height, input_geometry_.width);net_->Reshape(); 調整模型//將input_channels指向模型的輸入層相關位置(大概是這樣的)vector<Mat> input_channels;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++){Mat channel(height, width, CV_32FC1, input_data);input_channels.push_back(channel);input_data += width * height;}//改變圖像的大小等Mat sample;if (img.channels() == 3 && num_channels_ == 1)cv::cvtColor(img, sample, cv::COLOR_BGR2GRAY);else if (img.channels() == 4 && num_channels_ == 1)cv::cvtColor(img, sample, cv::COLOR_BGRA2GRAY);else if (img.channels() == 4 && num_channels_ == 3)cv::cvtColor(img, sample, cv::COLOR_BGRA2BGR);else if (img.channels() == 1 && num_channels_ == 3)cv::cvtColor(img, sample, cv::COLOR_GRAY2BGR);elsesample = img;// change img sizecv::Mat sample_resized;if (sample.size() != input_geometry_)cv::resize(sample, sample_resized, input_geometry_);elsesample_resized = sample;// change img to floatcv::Mat sample_float;if (num_channels_ == 3)sample_resized.convertTo(sample_float, CV_32FC3);elsesample_resized.convertTo(sample_float, CV_32FC1);// img normalizecv::Mat sample_normalized;cv::subtract(sample_float, mean_, sample_normalized);//將圖像通過input_channels變量傳遞給模型/* 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);// 調用模型進行預測net_->Forward();// 得到輸出const float* begin = output_layer->cpu_data();const float* end = begin + output_layer->channels();//將輸出給vector容器vector<float> output = vector<float>(begin, end);//顯示概率前N大的結果int N = 10;N = std::min<int>(labels_.size(), N);std::vector<int> maxN = Argmax(output, N);std::vector<Prediction> predictions;for (int i = 0; i < N; ++i) {int idx = maxN[i];predictions.push_back(std::make_pair(labels_[idx], output[idx]));}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;}return 0; }// end for main
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160

3.編譯并運行

在classify文件夾路徑下輸入以下命令:

mkdir build cd build cmake .. make
  • 1
  • 2
  • 3
  • 4

編譯成功后運行程序:

./classify
  • 1

結果:

I1028 21:36:29.941694 13761 classify.cpp:53] num_channels_:3 I1028 21:36:29.944052 13761 classify.cpp:80] output_layer dimension: 1000; labels number: 1000 0.3134 - "n02123045 tabby, tabby cat" 0.2380 - "n02123159 tiger cat" 0.1235 - "n02124075 Egyptian cat" 0.1003 - "n02119022 red fox, Vulpes vulpes" 0.0715 - "n02127052 lynx, catamount" 0.0539 - "n02119789 kit fox, Vulpes macrotis" 0.0144 - "n02123394 Persian cat" 0.0113 - "n04493381 tub, vat" 0.0063 - "n02120505 grey fox, gray fox, Urocyon cinereoargenteus" 0.0062 - "n02112018 Pomeranian"

總結

以上是生活随笔為你收集整理的caffe学习:通过研读classification.cpp了解如何使用caffe模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。