自己動手實現深度學習框架-1 架構設計


前言

        隨着tensorflow2的發布, 構建一個復雜的深度學習模型變得簡單很多。與此同時,更多的原理及細節被隱藏起來,很容易讓人知其然而不知其所以然。如果要了解那些隱藏在簡單表象下的原理和細節,首先想到的是閱讀它的代碼。然而這並不是一件容易的事,核心原理相關代碼淹沒在大量工程優化代碼中,讓人很難抓住要點。例如tensorflow使用了GPU技術用來加速模型的訓練和預測,然而GPU技術屬於工程上的優化技術,雖然在實際應用中不可或缺(想象一下你點擊一個鏈接幾分鍾頁面才跳出來吧),但並不涉及深度學習的相關算法和原理。
        本人被這個問題困擾許久之后,決定自己寫一個輕量級的深度學習框架,通過在小規模數據集上和tensorflow對比,來加深相關原理的理解。
        接下來首先給出這個框架的架構設計,然后一步一步實現一個小而美的框架。

核心概念

  • 模型: 表示一個執行特定任務的神經網絡,是神經網絡層的集合。
  • 神經網絡層: 完成特定任務的神經元集合, 如卷積層用於捕捉數據的空間特征,循環層用於捕捉數據的序列特征。
  • 損失函數: 訓練模型的算法,它的作用是在訓練時量化模型輸出和任務目標之間的差距。
  • 向前傳播: 數據經過從模型的輸入層進入,模型的每一層都使用上一層的輸出作為輸入計算出一個輸出,直到最后一層(模型的輸出層)輸出結果,預測階段向前傳播過程到此結束。如果是訓練階段,最后還要把結果送入損失函數計算誤差.
  • (誤差梯度)反向傳播: 在模型的訓練階段, 損失函數計算誤差之后, 即開始誤差梯度的反向傳播過程: 把梯度從模型的輸出層送入,層層傳遞,直到模型的輸入層.
  • 學習率優化算法: 深度學習模型一般使用隨機梯度的方法進行訓練,這涉及到學習率的問題,學習率優化算法在模型訓練的不同階段給出合適的學習率,從而加快模型訓練速度,提升模型最終的性能。
  • 正則化: 修改學習算法的算法,可以在不影響模型訓練誤差的情況下降低泛化誤差,從而提升模型性能。其本質是懲罰與任務目標相悖的行。

整體架構

主要功能

        作為一個主要用來學習原理的框架,會不涉及GPU加速和分布式並行運算,這樣整個框架的架構就會變得比較簡單。框架的主要功能有:

  1. 定義層的接口, 使層在模型中具有統一的抽象行為.
  2. 定義層參數的數據結構和命名規范, 使任意層的參數可以被靈活地訪問和修改.
  3. 定義激活函數的接口.
  4. 定義模型工作做方式, 模型可以以序列的方式把層組裝在一起, 實現向前傳播和向后傳播.
  5. 定義損失函數的接口.
  6. 定義優化器接口.
  7. 維護訓練上下文環境,實現模型的訓練: 向前傳播, 反向傳播, 參數更新, 訓練過程記錄, 上下文環境的保存和加載.

核心類

        框架主要包含以下幾個抽象類:

  • Layer: 神經網絡中的層,所有層的實現都是它的子類。
  • LayerParam: Layer的參數.
  • Activation: 激活函數,所有激活函數實現都是它的子類。
  • Model: 模型, 一個或多個層的集合。
  • Optimizer: 優化器,定義了優化器的接口. 所有優化器實現都是它的子類。
  • Loss: 損失函數, 定義的損失函數的接口。
  • Session: 會話,集成了模型及訓練模型所需要的所有對象,用於訓練,保存,恢復模型和訓練狀態。

架構圖

在這里插入圖片描述
        上圖描述了訓練模型的過程, 樣本數據提交給Session, Session把data送入模型執行向前傳播過程, 收到模型的輸出后,把輸出數據及label送入損失函數計算誤差梯度, 然后把梯度反向送入模型執行反向傳播過程。待反向傳播過程完成,調用優化器執行更新模型的參數。上圖中GenOptimizer是廣義優化器, Optimizer是學習率專用優化器, 廣義優化器指其他所有用來更新參數的算法如: L2正則化優化算法優化.

設計約束

LayerParam

屬性:

名稱 讀/寫 類型 說明
name r string 參數名稱,必須全局唯一
value rw darray 參數值
gradient rw darray 參數值的梯度
udt rw int 記錄參數被跟新的次數

另外, 優化器可以根據需要添加屬性。

name格式: /layerName/layerName/.../paramName. 參數名使用樹形結構, layerName是參數所屬層的名字, 因此只要保證layerName全局唯一, paramName只需要保證層范圍內唯一就能滿足要求。

Layer

屬性

名稱 讀/寫 類型 說明
layer_id r int 層的全局唯一id
name r string 層的名字, 全局唯一
params r list 層的參數列表
inshape r tuple 向前傳播時輸入數據的形狀
outshape r tuple 向前傳播時輸出數據的形狀
activation r Activation 激活函數對象

方法

__ init __(self, *outshape, **kargs)

outshape: 指定輸出形狀, 可以是tuple或in.
kargs: 可選參數

  • activation: 激活函數的名字。
  • inshape: 輸入形狀。除了第一個層外, 其他層都不用在這個方法傳入inshape。

join(self, pre_layer, *inshape=None)

把當前層和前一個層連接在一起. 使用前一個層的outshape作為當前層的inshape, 如果設置了inshape參數, 則使用inshape參數作為當前層的inshape。如果是第一個層這個方法不會被調用。

  • pre_layer: 前一個層。
  • inshape: 指定當前層的輸入形狀。

init_params(self)

初始化參數,由子類實現。當Layer發現inshape和outshape都已經設置了, 才會調用這個方法。

forward(self, in_batch, training=False)

向前傳播的方法。由子類實現。

  • in_batch: 輸入數據.
  • training: 是否處於訓練狀態.

backward(self, gradient)

反向傳播方法。由子類實現。

  • gradient: 反向傳回來的梯度。

reset(self)

重置當前層的狀態。由子類實現。

Model

方法

__init __(self, layers=None)

  • layers: Layer對象list.

add(self, layer)

向模型中添加一個層.

get_layer(self, index)

使用索引從model中得到一個Layer對象。Model中需要維護一個layer list, index是layer在這個list中的索引。

layer_iterator(self)

得到層的迭代器.

assemble(self)

組裝層。檢查輸入層的inshape參數是否設置。然后調用layer的join方法把layer連接在一起。

predict(self, in_batch, training=False)

向前傳播輸出模型的預測值。參數的含義和Layer的forward相同。

backward(self, gradient)

反向傳播。參數的含義和Layer的forward相同。

reset(self)

重置模型狀態。

Activation

方法

__call __(self, in_batch)

激活函數的調用方法,由子類實現。

  • in_batch: 向前傳播時輸入的數據。

grad(self, gradient)

反向傳播時計算並返回激活函數的梯度。

Loss

屬性

名稱 讀/寫 類型 說明
gradient r darray 損失函數的梯度值

方法

__call __(self, y_true, y_pred)

損失函數調用方法。

  • y_true: 數據的標簽值。
  • y_pred: 由模型輸出的數據的預測值。

Optimizer

方法

__ call__(self, model)

優化器函數的調用方法.

  • model: Model對象.

Session

屬性

名稱 讀/寫 類型 說明
model r Model 訓練的目標模型
loss r Loss 訓練模型使用的損失函數
history r dict 訓練歷史記錄數據

方法

__init __(self, model, loss, optimizer, genoptimizer=None)

  • model: Model對象。
  • loss: Loss對象。
  • optimizer: optimizer對象。
  • genoptimizer: 廣義優化器。

batch_train(self, data, label)

分批訓練。返回損失值。

  • data: 輸入數據, darray。
  • label: 數據標簽, darray。

save(self, fpath)

把模型和訓練上下文保存到fpath指定的位置。

load(cls, fpath)

這是一個類方法。從fpath指定位置加載模型和訓練上下文,返回已經准備就緒的Session對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM