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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

深度学习(七)caffe源码c++学习笔记

發(fā)布時(shí)間:2025/3/21 c/c++ 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度学习(七)caffe源码c++学习笔记 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

caffe源碼c++學(xué)習(xí)筆記

原文地址:http://blog.csdn.net/hjimce/article/details/48933845

作者:hjimce

一、預(yù)測(cè)分類

最近幾天為了希望深入理解caffe,于是便開始學(xué)起了caffe函數(shù)的c++調(diào)用,caffe的函數(shù)調(diào)用例子網(wǎng)上很少,需要自己慢慢的摸索,即便是找到了例子,有的時(shí)候caffe版本不一樣,也會(huì)出現(xiàn)錯(cuò)誤。對(duì)于預(yù)測(cè)分類的函數(shù)調(diào)用,caffe為我們提供了一個(gè)例子,一開始我懶得解讀這個(gè)例子,網(wǎng)上找了一些分類預(yù)測(cè)的例子,總是會(huì)出現(xiàn)各種各樣的錯(cuò)誤,于是沒辦法最后只能老老實(shí)實(shí)的學(xué)官方給的例子比較實(shí)在,因此最后自己把代碼解讀了一下,然后自己整理成自己的類,這個(gè)類主要用于訓(xùn)練好模型后,我們要進(jìn)行調(diào)用預(yù)測(cè)一張新輸入圖片的類別。

頭文件:

[cpp]?view plaincopy
  • /*?
  • ?*?Classifier.h?
  • ?*?
  • ?*??Created?on:?Oct?6,?2015?
  • ?*??????Author:?hjimce?
  • ?*/??
  • ??
  • #ifndef?CLASSIFIER_H_??
  • #define?CLASSIFIER_H_??
  • ??
  • ??
  • #include?<caffe/caffe.hpp>??
  • ??
  • #include?<opencv2/core/core.hpp>??
  • #include?<opencv2/highgui/highgui.hpp>??
  • #include?<opencv2/imgproc/imgproc.hpp>??
  • ??
  • #include?<algorithm>??
  • #include?<iosfwd>??
  • #include?<memory>??
  • #include?<string>??
  • #include?<utility>??
  • #include?<vector>??
  • ??
  • ??
  • using?namespace?caffe;??
  • using?std::string;??
  • ??
  • /*?std::pair?(標(biāo)簽,?屬于該標(biāo)簽的概率)*/??
  • typedef?std::pair<string,?float>?Prediction;??
  • ??
  • class?Classifier??
  • {??
  • ?public:??
  • ????Classifier(const?string&?model_file,?const?string&?trained_file,const?string&?mean_file);??
  • ????std::vector<Prediction>?Classify(const?cv::Mat&?img,?int?N?=?1);//N的默認(rèn)值,我選擇1,因?yàn)槲业捻?xiàng)目判斷的圖片,一般圖片里面就只有一個(gè)種類??
  • ????void?SetLabelString(std::vector<string>strlabel);//用于設(shè)置label的名字,有n個(gè)類,那么就有n個(gè)string的名字??
  • private:??
  • ??
  • ????void?SetMean(const?string&?mean_file);??
  • ??
  • ???std::vector<float>?Predict(const?cv::Mat&?img);??
  • ??
  • ???void?WrapInputLayer(std::vector<cv::Mat>*?input_channels);??
  • ??
  • ???void?Preprocess(const?cv::Mat&?img,??
  • ??????????????????std::vector<cv::Mat>*?input_channels);??
  • ??
  • private:??
  • ???shared_ptr<Net<float>?>?net_;//網(wǎng)絡(luò)??
  • ???cv::Size?input_geometry_;//網(wǎng)絡(luò)輸入圖片的大小cv::Size(height,width)??
  • ???int?num_channels_;//網(wǎng)絡(luò)輸入圖片的通道數(shù)??
  • ???cv::Mat?mean_;//均值圖片??
  • ???std::vector<string>?labels_;??
  • };??
  • ??
  • ??
  • #endif?/*?CLASSIFIER_H_?*/??

  • 源文件:

    [cpp]?view plaincopy
  • /*?
  • ?*?Classifier.cpp?
  • ?*?
  • ?*??Created?on:?Oct?6,?2015?
  • ?*??????Author:?hjimce?
  • ?*/??
  • ??
  • #include?"Classifier.h"??
  • using?namespace?caffe;??
  • Classifier::Classifier(const?string&?model_file,const?string&?trained_file,const?string&?mean_file)??
  • {??
  • ????//設(shè)置計(jì)算模式為CPU??
  • ??Caffe::set_mode(Caffe::CPU);??
  • ??
  • ??
  • ?//加載網(wǎng)絡(luò)模型,??
  • ??net_.reset(new?Net<float>(model_file,?TEST));??
  • ??//加載已經(jīng)訓(xùn)練好的參數(shù)??
  • ??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<float>*?input_layer?=?net_->input_blobs()[0];??
  • ??num_channels_?=?input_layer->channels();??
  • ??//輸入層一般是彩色圖像、或灰度圖像,因此需要進(jìn)行判斷,對(duì)于Alexnet為三通道彩色圖像??
  • ??CHECK(num_channels_?==?3?||?num_channels_?==?1)<<?"Input?layer?should?have?1?or?3?channels.";??
  • ??//網(wǎng)絡(luò)輸入層的圖片的大小,對(duì)于Alexnet大小為227*227??
  • ??input_geometry_?=?cv::Size(input_layer->width(),?input_layer->height());??
  • ??
  • ?//設(shè)置均值??
  • ??SetMean(mean_file);??
  • ??
  • }??
  • ??
  • static?bool?PairCompare(const?std::pair<float,?int>&?lhs,??
  • ????????????????????????const?std::pair<float,?int>&?rhs)?{??
  • ??return?lhs.first?>?rhs.first;??
  • }??
  • ??
  • //函數(shù)用于返回向量v的前N個(gè)最大值的索引,也就是返回概率最大的五種物體的標(biāo)簽??
  • //如果你是二分類問題,那么這個(gè)N直接選擇1??
  • static?std::vector<int>?Argmax(const?std::vector<float>&?v,?int?N)??
  • {??
  • ????//根據(jù)v的大小進(jìn)行排序,因?yàn)橐祷厮饕?#xff0c;所以需要借助于pair??
  • ??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;??
  • }??
  • ??
  • //預(yù)測(cè)函數(shù),輸入一張圖片img,希望預(yù)測(cè)的前N種概率最大的,我們一般取N等于1??
  • //輸入預(yù)測(cè)結(jié)果為std::make_pair,每個(gè)對(duì)包含這個(gè)物體的名字,及其相對(duì)于的概率??
  • std::vector<Prediction>?Classifier::Classify(const?cv::Mat&?img,?int?N)?{??
  • ??std::vector<float>?output?=?Predict(img);??
  • ??
  • ??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]));??
  • ??}??
  • ??
  • ??return?predictions;??
  • }??
  • void?Classifier::SetLabelString(std::vector<string>strlabel)??
  • {??
  • ????labels_=strlabel;??
  • }??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • ??
  • //加載均值文件??
  • void?Classifier::SetMean(const?string&?mean_file)??
  • {??
  • ??BlobProto?blob_proto;??
  • ??ReadProtoFromBinaryFileOrDie(mean_file.c_str(),?&blob_proto);??
  • ??
  • ??/*把BlobProto?轉(zhuǎn)換為?Blob<float>類型?*/??
  • ??Blob<float>?mean_blob;??
  • ??mean_blob.FromProto(blob_proto);??
  • ??//驗(yàn)證均值圖片的通道個(gè)數(shù)是否與網(wǎng)絡(luò)的輸入圖片的通道個(gè)數(shù)相同??
  • ??CHECK_EQ(mean_blob.channels(),?num_channels_)<<?"Number?of?channels?of?mean?file?doesn't?match?input?layer.";??
  • ??
  • ?//把三通道的圖片分開存儲(chǔ),三張圖片按順序保存到channels中??
  • ??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);??
  • ??
  • //計(jì)算每個(gè)通道的均值,得到一個(gè)三維的向量channel_mean,然后把三維的向量擴(kuò)展成一張新的均值圖片??
  • ??//這種圖片的每個(gè)通道的像素值是相等的,這張均值圖片的大小將和網(wǎng)絡(luò)的輸入要求一樣??
  • ??cv::Scalar?channel_mean?=?cv::mean(mean);??
  • ??mean_?=?cv::Mat(input_geometry_,?mean.type(),?channel_mean);??
  • }??
  • //預(yù)測(cè)函數(shù),輸入一張圖片??
  • std::vector<float>?Classifier::Predict(const?cv::Mat&?img)??
  • {??
  • ????//???
  • ????Blob<float>*?input_layer?=?net_->input_blobs()[0];??
  • ????input_layer->Reshape(1,?num_channels_,?input_geometry_.height,?input_geometry_.width);??
  • ????net_->Reshape();??
  • ???//輸入帶預(yù)測(cè)的圖片數(shù)據(jù),然后進(jìn)行預(yù)處理,包括歸一化、縮放等操作??
  • ????std::vector<cv::Mat>?input_channels;??
  • ????WrapInputLayer(&input_channels);??
  • ??
  • ????Preprocess(img,?&input_channels);??
  • ???//前向傳導(dǎo)??
  • ????net_->ForwardPrefilled();??
  • ??
  • ??//把最后一層輸出值,保存到vector中,結(jié)果就是返回每個(gè)類的概率??
  • ??Blob<float>*?output_layer?=?net_->output_blobs()[0];??
  • ??const?float*?begin?=?output_layer->cpu_data();??
  • ??const?float*?end?=?begin?+?output_layer->channels();??
  • ??return?std::vector<float>(begin,?end);??
  • }??
  • ??
  • /*?這個(gè)其實(shí)是為了獲得net_網(wǎng)絡(luò)的輸入層數(shù)據(jù)的指針,然后后面我們直接把輸入圖片數(shù)據(jù)拷貝到這個(gè)指針里面*/??
  • void?Classifier::WrapInputLayer(std::vector<cv::Mat>*?input_channels)??
  • {??
  • ??Blob<float>*?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;??
  • ??}??
  • }??
  • //圖片預(yù)處理函數(shù),包括圖片縮放、歸一化、3通道圖片分開存儲(chǔ)??
  • //對(duì)于三通道輸入CNN,經(jīng)過該函數(shù)返回的是std::vector<cv::Mat>因?yàn)槭侨ǖ罃?shù)據(jù),索引用了vector??
  • void?Classifier::Preprocess(const?cv::Mat&?img,std::vector<cv::Mat>*?input_channels)??
  • {??
  • /*1、通道處理,因?yàn)槲覀內(nèi)绻茿lexnet網(wǎng)絡(luò),那么就應(yīng)該是三通道輸入*/??
  • ??cv::Mat?sample;??
  • ??//如果輸入圖片是一張彩色圖片,但是CNN的輸入是一張灰度圖像,那么我們需要把彩色圖片轉(zhuǎn)換成灰度圖片??
  • ??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);??
  • ??//如果輸入圖片是灰度圖片,或者是4通道圖片,而CNN的輸入要求是彩色圖片,因此我們也需要把它轉(zhuǎn)化成三通道彩色圖片??
  • ??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;??
  • /*2、縮放處理,因?yàn)槲覀冚斎氲囊粡垐D片如果是任意大小的圖片,那么我們就應(yīng)該把它縮放到227×227*/??
  • ??cv::Mat?sample_resized;??
  • ??if?(sample.size()?!=?input_geometry_)??
  • ????cv::resize(sample,?sample_resized,?input_geometry_);??
  • ??else??
  • ????sample_resized?=?sample;??
  • /*3、數(shù)據(jù)類型處理,因?yàn)槲覀兊膱D片是uchar類型,我們需要把數(shù)據(jù)轉(zhuǎn)換成float類型*/??
  • ??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);??
  • ??
  • ??/*?3通道數(shù)據(jù)分開存儲(chǔ)?*/??
  • ??cv::split(sample_normalized,?*input_channels);??
  • ??
  • ??CHECK(reinterpret_cast<float*>(input_channels->at(0).data)?==?net_->input_blobs()[0]->cpu_data())?<<?"Input?channels?are?not?wrapping?the?input?layer?of?the?network.";??
  • }??

  • 調(diào)用實(shí)例,下面這個(gè)實(shí)例是要用于性別預(yù)測(cè)的例子:

    [cpp]?view plaincopy
  • //============================================================================??
  • //?Name????????:?caffepredict.cpp??
  • //?Author??????:???
  • //?Version?????:??
  • //?Copyright???:?Your?copyright?notice??
  • //?Description?:?Hello?World?in?C++,?Ansi-style??
  • //============================================================================??
  • ??
  • #include?<string>??
  • #include?<vector>??
  • #include?<fstream>??
  • #include?"caffe/caffe.hpp"??
  • #include?<opencv2/opencv.hpp>??
  • #include"Classifier.h"??
  • ??
  • int?main()??
  • {??
  • ?????caffe::Caffe::set_mode(caffe::Caffe::CPU);??
  • ????cv::Mat?src1;??
  • ????src1?=?cv::imread("4.jpg");??
  • ????Classifier?cl("deploy.prototxt",?"gender_net.caffemodel","imagenet_mean.binaryproto");??
  • ????std::vector<string>label;??
  • ????label.push_back("male");??
  • ????label.push_back("female");??
  • ????cl.SetLabelString(label);??
  • ????std::vector<Prediction>pre=cl.Classify(src1);??
  • ????cv::imshow("1.jpg",src1);??
  • ??
  • ????std::cout?<<pre[0].first<<?std::endl;??
  • ????return?0;??
  • }??

  • 二、文件數(shù)據(jù)

    [cpp]?view plaincopy
  • /函數(shù)的作用是讀取一張圖片,并保存到到datum中??
  • //第一個(gè)參數(shù):filename圖片文件路徑名??
  • //第二個(gè)參數(shù):label圖片的分類標(biāo)簽??
  • //第三、四個(gè)參數(shù):圖片resize新的寬高??
  • //調(diào)用方法:??
  • /*Datum?datum?
  • ???ReadImageToDatum(“1.jpg”,?10,?256,?256,?true,&datum)*/??
  • //把圖片1.jpg,其標(biāo)簽為10的圖片縮放到256*256,并保存為彩色圖片,最后保存到datum當(dāng)中??
  • bool?ReadImageToDatum(const?string&?filename,?const?int?label,??
  • ????const?int?height,?const?int?width,?const?bool?is_color,??
  • ????const?std::string?&?encoding,?Datum*?datum)?{??
  • ??cv::Mat?cv_img?=?ReadImageToCVMat(filename,?height,?width,?is_color);//讀取圖片到cv::Mat??
  • ??if?(cv_img.data)?{??
  • ????if?(encoding.size())?{??
  • ??????if?(?(cv_img.channels()?==?3)?==?is_color?&&?!height?&&?!width?&&??
  • ??????????matchExt(filename,?encoding)?)??
  • ????????return?ReadFileToDatum(filename,?label,?datum);??
  • ??????std::vector<uchar>?buf;??
  • ??????cv::imencode("."+encoding,?cv_img,?buf);??
  • ??????datum->set_data(std::string(reinterpret_cast<char*>(&buf[0]),??
  • ??????????????????????buf.size()));??
  • ??????datum->set_label(label);??
  • ??????datum->set_encoded(true);??
  • ??????return?true;??
  • ????}??
  • ????CVMatToDatum(cv_img,?datum);//把圖片由cv::Mat轉(zhuǎn)換成Datum??
  • ????datum->set_label(label);//設(shè)置圖片的標(biāo)簽??
  • ????return?true;??
  • ??}?else?{??
  • ????return?false;??
  • ??}??
  • }??
  • **********************作者:hjimce ? 時(shí)間:2015.10.1 ? 地址:http://blog.csdn.net/hjimce?轉(zhuǎn)載請(qǐng)保留本行信息********************

    總結(jié)

    以上是生活随笔為你收集整理的深度学习(七)caffe源码c++学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。