程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++卷積神經網絡實例:tiny_cnn代碼詳解(11)——層結構容器layers類源碼分析

C++卷積神經網絡實例:tiny_cnn代碼詳解(11)——層結構容器layers類源碼分析

編輯:C++入門知識

C++卷積神經網絡實例:tiny_cnn代碼詳解(11)——層結構容器layers類源碼分析


  在這篇博文中我們對tiny_cnn卷積神經網絡模型中的最後一個網絡結構方面的類——layers做簡要分析。

  首先,layers通俗的講可以被稱為是層結構的vector,即層結構容器。由於卷積神經網絡是一個多層的網絡模型,因此有必要將網絡中各個層進行統一管理,這便引出了本篇博文中所要介紹的layers類。layers類是一個vector類型的變量,其中壓入的元素就是網絡中的各個層模型,這裡給出一個簡單的結構圖,一目了然:

\

  從上圖中可以清晰的看到layers的vector結構,說白了就是一個層結構類的容器,彼此之間通過prev_(指向後一層)和next_(指向前一層)兩個指針相聯系。接下來開始著重分析layers的內部代碼結構。首先給出layers的結構示意圖:

\

  同樣我們按照成員變量、成員函數的思路對這個類的結構和代碼進行解讀。

  一、成員變量

  layers有兩個成員變量,一個是vector容器變量,用來保存各個壓棧的層結構類;一個是input_layer類型變量,用來保存網絡模型中輸入層的結構信息:

\

  這個有兩個問題需要強調:

  (1)容器元素的類型。從上圖中可以看出,layers_容器中的基本元素類型是layer_base*類型,原因很明確,layer_base是卷積層、下采樣層、全連接層等層結構的公共基類,聲明成指針形式是為了方便使用前向指針和反向指針進行連接。

  (2)輸入層的獨特性。這裡之所以將輸入層單獨拿出來作為一個成員變量,主要是考慮到在任何卷積神經網絡的網絡模型(無論是單層模型還是多層模型)中,輸入層都是必不可少的,並且都處於網絡模型的最前端。對於這個存在性和位置都已經確定的層成員,這裡選擇將其放在layers中進行默認添加構造,使得用戶在指定層結構模型時無需再一成不變的添加輸入層。

  二、構造函數

  layers類內提供了兩種功能的構造函數:

\

  第一個構造函數用於構造單層網絡模型,即只有一個輸入層(first_是一個input_layer類型變量);第二個構造函數用於按照指定的層類型來構造多層網絡模型,構造函數的實現機制主要通過add()和construct()兩個函數,有關這兩個函數的具體功能稍後介紹。

  三、模型構造方法

  layers在對網絡模型執行構造的過程中,主要依賴於add()和construct()這兩個構造方法,這裡稍作分析。

  3.1 add()函數

  顧名思義,add()函數的作用是將指定的層類型類添加到當前的layers結構體中,類似於vector中的壓棧操作(實際上也確實借用了push_back):

\

  add()函數在執行過程中主要分為兩大部分,即建立連接關系和層結構壓棧。首先需要調用connect()函數來建立待加入層(new_tail)與已有模型之間的關系。connect()函數是定義在基類layer_base中的成員函數,目的就是建立網絡模型中前後兩層之間的指針聯系:

\

  在connect函數中,首先針對前後層之間的連接關系進行判斷,在連接匹配的情況下,通過“next_ = tail”語句將當前層的下一層指定為tail(新加入的層),再通過“tail->prev_ = this”將新加入的層的前一層指定為當前層。從這種意義上將,connect()的構造方式與指針隊列的構造方式很像。

  繼續分析add()函數。在通過connect函數建立新加入層與已有模型的最後一層之間的指針聯系之後,直接調用push_back將待加入的層結構類壓棧即可,完成新層的構造和存儲。

  3.2construct()函數

  construct()函數旨在完成多層模型的構造,包括建立連接和壓棧等等,其基本的工作原理就是循環調用add()函數:

\

  這裡同樣可以分為兩個過程。首先,向layers容器中加入輸入層first_,因為對於所有的模型,輸入層都是必不可少的,因此與其讓用戶在每次構建模型時都先在第一個位置寫上Input_layer,還不如將這一步放到構造函數內部來自動執行。接下來就循環調用add()函數,將需要添加的層逐個的建連接、壓棧、建連接、壓棧。

  四、權重操作

  由於layers屬於對層結構類的再封裝,因此需要提供與各個網絡層共有功能相對應的接口,比如說權重操作。這裡的權重操作主要包括權重的初始化、重置以及權重更新等操作。這些操作函數一般都是只提供一個接口,具體實現過程中主要還是調用各個類內部的對應的功能函數,比如說權重的初始化和重置:

\

  再比如說權重的更新update:

\

  五、屬性返回

  由於layers是用戶所能接觸到的最上層的層結構封裝,因此其有必要提供一些屬性返回的接口函數,供用戶查看網絡層的輸出以及權重核的具體情況等等,當然這裡的接口函數同樣作為一個橋梁式的存在,一方面連接用戶,一方面調用各個元素類的對應功能函數。除此之外還需要添加一些與整體層結構相關的屬性返回函數,來告訴用戶這個保存著layer_base的vector實際上有多少層,第一層是什麼,最後一層是什麼,怎麼訪問到指定層。

  首先是如何訪問第一層和最後一層,這裡提供了兩個函數head()和tail(),具體實現機制很簡單,相信大家一看就懂:

\

  至於如何訪問指定層,tiny_cnn提供兩個手段,一是定義at函數,並通過dynamic_cast進行類型轉換:

\

  另一種手段是重載“[]”運算發,類數組形式訪問

\

  以上兩種訪問方式都是通過索引(index)來完成,比較方便。

  OK,有關層結構容器layers類的源碼就先介紹到這裡,還有一些補丁式的小函數,也就一兩行代碼,功能明確,實現簡單,這裡就不再贅述了,還有三個月就研三了,要好好想想工作的事了,嘿嘿。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved