構造Classifier類
初始化net_并讀入網絡模型文件.prototxt
net_.reset(new Net<float>(model_file, TEST)); //model_file = models/bvlc_reference_caffenet/deploy.prototxt
net_->CopyTrainedLayersFrom(trained_file); //trained_file = models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel
通過net初始化來了解Net類
blob_names_ —— 讀取各層blob名字

image.png
blob_names_index —— map類存儲的網絡名稱和對應編號
image.png
blob_need_backward_ —— 是否需要反向傳播梯度
image.png
blobs —— 用于存儲數據和梯度std::vector<boost::shared_ptr<caffe::Blob<float>>>
image.png
bottom_id_vecs_ —— 存儲每一層bottom的vector
這里注意要配合
layer_names_來理解,[0]是data層,故其沒有bottom,[2]-relu1[3]-pool1由于[2]-relu1是in-place存儲,所以其bottom和[3]-pool1相同

image.png
bottom_vecs_ —— 存儲對應bottom的地址
image.png
layer_names_ —— 各層名稱

image.png
layer_names_index_ —— 各層順序
image.png
存儲每一層
top的vector
image.png
讀取輸入信息并設置輸出blob
num_input() num_output()函數分別返回net_input_blobs_.size() net_output_blobs_.size()
CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";
可以看到初始網絡輸入維度為10×3*227*227 輸出維度為10*1000(注意這里只是讀取model_file網絡的輸入輸出維度,網絡至少要有一個輸入和輸出)

image.png
設置一個指向輸入層的Blob
(10×3×227*227)指針
Blob<float>* input_layer = net_->input_blobs()[0]; //input_blobs()函數返回net_input_blobs_
num_channels_ = input_layer->channels(); //顯然,這里的num_channels_為輸入的channel數 = 3
input_geometry_ = cv::Size(input_layer->width(), input_layer->height()); //input_geometry_ = (227,227)
加載均值文件
SetMean(mean_file);
讀入類別及對應的編號
std::ifstream labels(label_file.c_str());

image.png
同樣的,設置一個指向輸出層的Blob(10×1000)指針用于讀取網絡運行結果
Blob<float>* output_layer = net_->output_blobs()[0]; //10*1000的blob
Classify函數
std::vector<float> output = Predict(img);
Predict函數
Predict(const cv::Mat& img)Blob<float>* input_layer = net_->input_blobs()[0]; //與上文中的input_layer相同 input_layer->Reshape(1, num_channels_, input_geometry_.height, input_geometry_.width); //10×3*227*227→1*3*227*227接下來對
net_進行reshape,結果就是所有blob的第一個維度由10變?yōu)?
image.pngnet_->Reshape(); WrapInputLayer(&input_channels);WrapInputLayer函數
Blob<float>* input_layer = net_->input_blobs()[0]; //同上問一樣,只是第一個維度為1 int width = input_layer->width(); //227 int height = input_layer->height(); //227 float* input_data = input_layer->mutable_cpu_data(); //input_data為指向數據的指針 for (int i = 0; i < input_layer->channels(); ++i) { cv::Mat channel(height, width, CV_32FC1, input_data); //32位浮點型單通道 //在input_data處創(chuàng)建一個Mat用于Preprocess函數中通道分離之后存儲數據 input_channels->push_back(channel); //注意是指針,channel就是在CPU中為輸入圖像預留的空間 input_data += width * height; }Preprocess(img, &input_channels);Preprocess函數
else sample = img; //(360×480) cv::Mat sample_resized; if (sample.size() != input_geometry_) //判斷輸入圖像尺寸是否和網絡輸入尺寸大小相同 cv::resize(sample, sample_resized, input_geometry_); //調整為網絡輸入尺寸大小(227*227) else sample_resized = sample; cv::Mat sample_float; if (num_channels_ == 3) sample_resized.convertTo(sample_float, CV_32FC3); //轉化為CV_32FC3 else sample_resized.convertTo(sample_float, CV_32FC1); cv::Mat sample_normalized; cv::subtract(sample_float, mean_, sample_normalized); //減去均值操作 /* 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); //見《OpenCV3》書籍P125、分成B、G、R三個單獨通道 //同時也將sample_normalized讀入了*input_channels,即讀入到input_layer->mutable_cpu_data();中執(zhí)行前向傳播
net_->Forward(); 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);image.png
輸出結果
為什么輸出5個結果詳見Classify構造函數設置了變量
N

image.png

