1. 程式人生 > >Caffe 的 C++介面學習(一)

Caffe 的 C++介面學習(一)

Segnet-Caffe C++

學習筆記

從之前的Segnet-Slam程式碼中設定斷點進行除錯:

// OpenCV
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/core/eigen.hpp>
#include "opencv2/imgproc/imgproc.hpp"
//...............此處省略若干程式碼
// Semantic now
cv::Mat new_frame; cv::resize(frame->rgb, new_frame, cv::Size(480,360)); cv::resize(frame->rgb,frame->rgb,cv::Size(480,360)); std::vector<Prediction> predictions = classifier.Classify(new_frame); cv::Mat segnet(new_frame.size(), CV_8UC3, cv::Scalar(0,0,0));
/* Return the top N predictions. */
//預測函式,輸入一張圖片img,希望預測的前N種概率最大的,我們一般取N等於1 //輸入預測結果為std::make_pair,每個對包含這個物體的名字,及其相對於的概率 class Classifier { public: Classifier(); std::vector<Prediction> Classify(const cv::Mat& img, int N = 1); //..............省略 };//在.h檔案中N已經定義為1 std::vector<Prediction> Classifier::Classify(const
cv::Mat& img, int N) { std::vector<float> output = Predict(img);//將圖片給Predict函式 //【1】Predict函式進行網路的前向傳輸,得到輸入屬於每一類的概率,儲存在output中 std::vector<int> maxN = Argmax(output, N); std::vector<Prediction> predictions; predictions.reserve(input_geometry_.height * input_geometry_.width); for (int i = 0; i < input_geometry_.height * input_geometry_.width; ++i) { int idx = maxN[i]; predictions.push_back(std::make_pair(labels_[idx], idx)); } return predictions; }
斷點除錯時GDB視窗所示影象資料:
img = {const cv::Mat &} {
 flags = {int} 1124024336
 dims = {int} 2 //dims:Mat所代表的矩陣的維度,如3*4的矩陣為2維,3*4*5的為3維
 rows = {int} 360
 cols = {int} 480
 data = {uchar * | 0x7fffafa8e020} "\363\265\203\355\262\........
 //data:Mat物件中的一個指標,指向記憶體中存放矩陣資料的一塊記憶體 (uchar* data)
 refcount = {int * | 0x7fffafb0c920} 0x7fffafb0c920 //引用計數器
 datastart = {uchar * | 0x7fffafa8e020} "\363\265\203\355\262\.....
 dataend = {uchar * | 0x7fffafb0c920} "\001"
 datalimit = {uchar * | 0x7fffafb0c920} "\001"
 allocator = {cv::MatAllocator * | 0x0} NULL
 size = {cv::Mat::MSize} 
 step = {cv::Mat::MStep} 
 }

Predict()函式

net類資料結構除錯 【net類的一些說明
Net類

//通過合成和自動微分,網路同時定義了一個函式和其對應的梯度。通過合成各層的輸出來計算這個函式,來執行給定的任務,
//並通過合成各層的向後傳播過程來計算來自損失函式的梯度,從而學習任務。Caffe模型是端到端的機器學習引擎。
//Net是由一系列層組成的有向五環(DAG)計算圖,Caffe保留了計算圖中所有的中間值以確保前向和反向迭代的準確性。
//一個典型的Net開始於data layer--從磁碟中載入資料,終止於loss layer--計算分類和重構這些任務的目標函式。
//Net由一系列層和它們之間的相互連線構成,用的是一種文字建模語言(protobuf)。
//Net是通過protobuf檔案來描述整個Net是怎麼由layer組成的。
//Caffe中網路的構建與裝置無關。網路構建完之後,通過設定Caffe::mode()函式中的Caffe::set_mode()即可
//實現在CPU或GPU上的執行。CPU與GPU無縫切換並且獨立於模型定義。
//前傳(forward)過程為給定的待推斷的輸入計算輸出。在前傳過程中,Caffe組合每一層的計算以得到整個模型的計算”函式”。
//本過程自底向上進行。
//反傳(backward)過程根據損失來計算梯度從而進行學習。在反傳過程中,Caffe通過自動求導並反向組合每一層的梯度
//來計算整個網路的梯度。這就是反傳過程的本質。本過程自頂向下進行。
//反傳過程以損失開始,然後根據輸出計算梯度。根據鏈式準則,逐層計算出模型其餘部分的梯度。
//有引數的層,會在反傳過程中根據引數計算梯度。
//只要定義好了模型,Caffe中前傳和反傳的計算就可以立即進行,Caffe已經準備好了前傳和反傳的實現方法。
////實現方法:
//(1)、Net::Forward()和Net::Backward()方法實現網路的前傳和反傳,而Layer::Forward()和Layer::Backward()計算每一層的前傳和後傳。
//(2)、每一層都有forward_{cpu,gpu}()和backward_{cpu,gpu}方法來適應不同的計算模式。由於條件限制
//或者為了使用便利,一個層可能僅實現了CPU或者GPU模式。
//與大多數的機器學習模型一樣,在Caffe中,學習是由一個損失函式驅動的(通常也被稱為誤差、代價或者目標函式)。
//因此,學習的目的是找到一個網路權重的集合,使得損失函式最小。
//在Caffe中,損失是通過網路的前向計算得到的。每一層由一系列的輸入blobs(bottom),
//典型的一對多分類任務的損失函式是softMaxWithLoss函式。
//Loss weights:對於含有多個損失層的網路(例如,一個網路使用一個softMaxWithLoss輸入分類
//並使用EuclideanLoss層進行重構),損失權值可以被用來指定它們之間的相對重要性。
//按照慣例,有著Loss字尾的Caffe層對損失函式有貢獻,其它層被假定僅僅用於中間計算。
//對於帶字尾Loss的層來說,其對於該層的第一個top blob含有一個隱式的loss_weight:1;其它層對應於所有top blob有一個隱式的loss_weight: 0。
//然而,任何可以反向傳播的層,可允許給予一個非0的loss_weight,例如,如果需要,
//對網路的某些中間層所產生的啟用進行正則化。對於具有相關非0損失的非單輸出,損失函式可以通過對所有blob求和來進行簡單地計算。
//那麼,在Caffe中最終的損失函式可以通過對整個網路中所有的權值損失進行求和計算獲得。
//為了建立一個Caffe模型,需要在一個protobuf(.prototxt)檔案中定義模型的結構。
//在Caffe中,層和相應的引數都定義在caffe.proto檔案裡。

深度網路是組成模型,自然地表示為在大量資料上工作的互連層集合。 Caffe在其自己的模型模式中定義了一個網路層。 網路將整個模型從輸入資料自下而上地定義為損失。 隨著資料和派生物在前向和後向流經網路,Caffe儲存,傳達和操縱資訊為blobblobCaffe框架的標準陣列和統一記憶體介面。 該層次是模型和計算的基礎。 網路作為圖層的收集和連線。 blob的詳細資訊描述了資訊在層和網路中如何儲存和傳輸。

Blob儲存和通訊

Blob是Caffe處理和傳遞的實際資料的封裝,並且還提供CPU和GPU之間的同步功能。 在數學上,Blob是以C語言風格的連續方式儲存的N維陣列。
Caffe使用Blob儲存和傳輸資料。 Blob提供了儲存資料的統一的儲存器介面; 例如批量的影象,模型引數以及用於優化的衍生物。
Blob通過根據需要從CPU主機同步到GPU裝置來隱藏混合CPU / GPU操作的計算和心理開銷。 主機和裝置上的記憶體按需(懶散地)分配以提高記憶體使用率。
批量影象資料的常規Blob尺寸是

數量N×通道K×高度H×寬度W

Blob在佈局中主要以行進行儲存,所以最後/最右維度變化最快。 例如,在4D blob中,index(n,k,h,w)處的值在物理上位於索引

((n * K + k)* H + h)* W + w

數量N是資料的批量大小。 批處理為通訊和裝置處理實現更好的吞吐量。 對於256個影象的N = 256的ImageNet訓練批次。
通道K是特徵維度,例如對於RGB影象K = 3

Layer(層)計算和通訊

Layer是模型的本質和計算的基本單位。

net_ = {boost::shared_ptr<caffe::Net>}  //net類:一個Net由多個Layer組成。一個典型的網路
                                       //從data layer(從磁碟中載入資料)出發到loss layer結束。
  name_ = {std::string} "VGG_ILSVRC_16_layer"//網路的名稱,從.prototxt檔案中載入
  phase_ = {caffe::Phase} caffe::TEST
  layer_names_ =  //layer是Caffe的基本計算單元
   [0] = {std::basic_string<char, std::char_traits, std::allocator>} "input"   
   [1] =  "conv1_1"
   [2] =  "conv1_1_bn"
//..................省略
   [86] = "conv1_1_D"
   [87] = "argmax"
//網路中大部分功能都是以Layer的形式去展開的,如convolute,pooling,loss等等。
//在建立一個Caffe模型的時候,也是以Layer為基礎進行的,需按照src/caffe/proto/caffe.proto中定義的網路及引數格式定義網路的.prototxt檔案
  blobs_ = {std::vector<boost::shared_ptr, std::allocator>} 
   [0] = {boost::shared_ptr<caffe::Blob>} 
    px = {boost::shared_ptr<caffe::Blob>::element_type * | 0x8d4fb80} 0x8d4fb80
     data_ = {boost::shared_ptr<caffe::SyncedMemory>} 
     diff_ = {boost::shared_ptr<caffe::SyncedMemory>} 
     shape_data_ = {boost::shared_ptr<caffe::SyncedMemory>} 
     shape_ = {std::vector<int, std::allocator>} 
     count_ = {int} 518400
     capacity_ = {int} 518400
    pn = {boost::detail::shared_count} 
     pi_ = {boost::detail::sp_counted_base * | 0x8d4fbe0} 0x8d4fbe0
   [1] = {boost::shared_ptr<caffe::Blob>} 
  blob_names_ = {std::vector<std::basic_string, std::allocator>} 
   [0] = {std::basic_string<char, std::char_traits, std::allocator>} "data"
   [1] = {std::basic_string<char, std::char_traits, std::allocator>} "conv1_1"
   [2] = {std::basic_string<char, std::char_traits, std::allocator>} "conv1_2"
   [42] = {std::basic_string<char, std::char_traits, std::allocator>} "argmax"
   [41] = {std::basic_string<char, std::char_traits, std::allocator>} "conv1_1_D"
  net_input_blobs_ = {std::vector<caffe::Blob*, std::allocator>} 
   [0] = {caffe::Blob<float> * | 0x8d4fb80} 0x8d4fb80
    data_ = {boost::shared_ptr<caffe::SyncedMemory>} 
     px = {boost::shared_ptr<caffe::SyncedMemory>::element_type * | 0x9230300} 0x9230300
      cpu_ptr_ = {void * | 0x0} NULL
      gpu_ptr_ = {void * | 0x0} NULL
      size_ = {size_t} 2073600
      head_ = {caffe::SyncedMemory::SyncedHead} caffe::SyncedMemory::UNINITIALIZED
      own_cpu_data_ = {bool} false
      cpu_malloc_use_cuda_ = {bool} false
      own_gpu_data_ = {bool} false
      gpu_device_ = {int} -1
     pn = {boost::detail::shared_count} 
      pi_ = {boost::detail::sp_counted_base * | 0x922f950} 0x922f950
       use_count_ = {int} 1
       weak_count_ = {int} 1
    diff_ = {boost::shared_ptr<caffe::SyncedMemory>} 
     px = {boost::shared_ptr<caffe::SyncedMemory>::element_type * | 0x9230240} 0x9230240
      cpu_ptr_ = {void * | 0x0} NULL
      gpu_ptr_ = {void * | 0x0} NULL
      size_ = {size_t} 2073600
      head_ = {caffe::SyncedMemory::SyncedHead} caffe::SyncedMemory::UNINITIALIZED
      own_cpu_data_ = {bool} false
      cpu_malloc_use_cuda_ = {bool} false
      own_gpu_data_ = {bool} false
      gpu_device_ = {int} -1
     pn = {boost::detail::shared_count} 
      pi_ = {boost::detail::sp_counted_base * | 0x8d5c240} 0x8d5c240
       use_count_ = {int} 1
       weak_count_ = {int} 1
    shape_data_ = {boost::shared_ptr<caffe::SyncedMemory>} 
     pn = {boost::detail::shared_count} 
    shape_ = {std::vector<int, std::allocator>} 
     [0] = {int} 1
     [1] = {int} 3
     [2] = {int} 360
     [3] = {int} 480
    count_ = {int} 518400
    capacity_ = {int} 518400
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);
    /* Forward dimension change to all layers. */
    net_->Reshape();

    std::vector<cv::Mat> input_channels;
    WrapInputLayer(&input_channels);

    Preprocess(img, &input_channels);

    net_->ForwardPrefilled();

    /* Copy the output layer to a std::vector */
    Blob<float>* output_layer = net_->output_blobs()[0];

    const float* begin = output_layer->cpu_data();
    const float* end = begin + output_layer->height() * output_layer->width() * output_layer->channels();

    return std::vector<float>(begin, end);
}

相關推薦

CaffeC++介面學習

Segnet-Caffe C++ 學習筆記 從之前的Segnet-Slam程式碼中設定斷點進行除錯: // OpenCV #include <opencv2/core/core.hpp> #include <opencv2

C++語言學習——C++簡介

產品 泛型 alt 科學計算 內容 實現 .com 運算符 ces C++語言學習(一)——C++簡介 一、C++簡介 C 語言作是結構化和模塊化的語言,適合處理較小規模的程序。對於復雜的問題,規模較大的程序,需要高度的抽象和建模時,C語言並不合適。為了解決軟件危機, 20

C語言學習

C語言的順序結構,迴圈結構,選擇結構等,都是重要的的結構。今天編寫了判斷年份的程式以及花工資的程式,還有一個判斷素數的程式現在還沒有結果,還需要仔細研究 判某一年是否閏年。 輸入:年(year) 計算:判是否閏年 輸出:閏年或非閏年(leap) 閏年條件: 能被4整除,但不

C++ 快速學習

總感覺學計算機不該只關注計算機技術,結合計算機技術做一些跨領域 的事情會更有意義。計算機視覺是一個不錯的方向,鑑於影象處理一般用C++的場景比較多,決定先從C++入手。 預備知識 熟悉C、Java、Python任意一門語言,瞭解程式語言的通

GUN C中的socket學習

ipp 區分 如果 raw 文件表 一起 通訊 res 概念   socket是用於通信的工具。   套接字其實是一個廣義上的進程間通信的信道。就像pipe一樣,在GUN環境下socket也被用一個文件表示。不同的socket文件可以用於不同的進程間通信,甚至可以用來在網絡

設計模式學習筆記 C#代碼

內容 編程 繼承 color 模式 c# 派生類 ive spa 《深入淺出設計模式》學習筆記第一章 原始需求和設計 事情是這樣開始的,公司需要做一套程序,鴨子,設計如下: 一個鴨子父類,多個派生類,三個可override的方法。 第一次需求變更 我們要會飛的鴨子!!!!

C# 異步編程學習

apm 結果 mic public b- num row worker inf 異步 編程 可在 等待 某個 任務 完成時, 避免 線程 的 占用, 但要 想 正確地 實現 編程, 仍然 十分 傷腦筋。 . NET Framework 中, 有三種 不同 的 模型 來 簡化

lua原始碼學習lua的c api外圍實現

工作後,整個人已經比較鬆懈了。儘管一直在看lua的原始碼。可是一直是比較零碎的時間,沒有系統的整理,所以還是收穫不多。由於近期工作也不是非常忙了,就想整理下lua的原始碼學習的筆記。加深下印象,並分享給大家。 先說下這系列bolg我會每週更新2-3篇,沒有順序的 這些文章

lua源代碼學習lua的c api外圍實現

在操作 時間 struct ack cti 壓棧 c api field stat 工作後,整個人已經比較松懈了。盡管一直在看lua的源代碼。可是一直是比較零碎的時間,沒有系統的整理

深度學習——deepNN模型實現攝像頭實時識別人臉表情C++和python3.6混合程式設計

一、背景介紹 最近需要做人臉識別方向的東西,就被分配了新的任務,利用攝像頭實時檢測人臉表情,並製作成一個小軟體,這裡當然要用C++實現,並用C++做成一個介面。 由於博主之前用python做過類似的小程式,因此這裡的模型實現主要採用了python,為了用C++實現介面,這裡採用C++呼叫py

侯捷C++學習

//c++學習//標準庫非常重要//要規範自己的程式碼complex c1(2,1);complex c2;complex* pc = new complex(0,1);string s1("Hello");string s2("world");string* ps #include<iostream

caffe的python介面學習6:用訓練好的模型caffemodel來分類新的圖片

#coding=utf-8import caffeimport numpy as nproot='/home/xxx/' #根目錄deploy=root + 'mnist/deploy.prototxt' #deploy檔案caffe_model=root + 'mnist/lenet_iter

介面自動化之requests學習--get方法獲取常用返回資料

#!usr/bin/env python #-*- coding:utf-8 -*- """ @author:Administrator @file: request.py @time: 2018/10/13 """ import requests # 請求百度網頁 res

c++學習

//判斷是否是迴文數 #include"pch.h"#include<iostream>using namespace std;bool systm(unsigned n){ unsigned i = n; unsigned m = 0; while (i>0) { m = m * 10

Write a Shell in C 學習

自己的C很差很差,所以趁著這一次寫一個shell的作業來提高一下自己C的程式設計水平。 希望此筆記可以使初學者毫無阻礙的寫成一個shell,並對每一個句子知其所以然。 由於我本人亦是初學者,內容難免謬誤多多,望大神指導海涵。 要寫一個shell出來,同時作為一個

C#反射的學習--獲得成員資訊

using UnityEngine; using System.Collections; using System; using System.Reflection; public class Reflection_Test : MonoBehaviour { // Use this for ini

C++】C++類的學習——初識類

前言       C++在C語言的基礎上做了一些改進,使得C++具有了面向物件程式設計(Object Oriented Programming,OOP)的特性。其中最重要的改進就是提供了類的概念。可以說學習了C++卻不會使用類的話,那麼就沒有學習到C++的精髓。       

基於c++的網路開發庫boost.Asio學習 Ubuntu安裝boost以及問題解決

執行環境:Ubuntu 12.04   版本: boost 1.68 下載網址:http://sourceforge.net/projects/boost/files/boost/1.58.0/boost_1_58_0.tar.bz2/download

深度學習——被Intel caffe支配的恐懼

一、Intel caffe在Ubuntu上的安裝配置 1. 安裝配置MKL-DNN 我用的是CPU版本的caffe,安裝配置MKL-DNN可以提高caffe訓練的速度。英特爾MKL-DNN專為在英特爾架構上加快深度學習框架的速度而設計,包含高度向量化和執

Windows下基於Caffe的SSD網路學習配置加生成自己的資料集

    最近準備要做畢業設計了,所以從頭又配了一遍Caffe,學了一遍SSD,看了Caffe的原始碼,準備對SSD網路做一些改進。由於這已經是第n遍配置Caffe了,但是還是費了不少時間,所以意識到,總結還是很重要的,所以寫下部落格記錄這一路如何走來,同時也希望可以給有需