BrainScript 基本概念
BrainScript--A Walk-Through
本節介紹 「BrainScript」 語言的基本概念。 新語言? 別擔心 & 閱讀,這是非常直接的。
在 CNTK 中,自定義網路是使用 BrainScriptNetworkBuilder
定義,並在 CNTK 網络描述語言 「BrainScript」 中描述。同樣地,網路描述稱為大腦腳本。
BrainScript 提供簡單的方式,以類似程式碼的方式定義網路,使用表示式、變數、基本和自我定義函式、巢狀區塊和其他瞭解良好的概念。 它看起來類似於語法中的腳本語言。
沒關係,讓我們以完整的 BrainScript 範例讓腳步變得滿了!
完整 BrainScript 範例網路定義
下列範例顯示簡單類神經網路的網路描述,其中包含一個隱藏層和一個分類層。 我們將在此範例中說明概念。 在繼續進行之前,可能需要幾分鐘的範例,並嘗試猜測它的意義。 您可能會發現,當您閱讀時,您猜到大部分正確。
BrainScriptNetworkBuilder = { # (we are inside the train section of the CNTK config file)
SDim = 28*28 # feature dimension
HDim = 256 # hidden dimension
LDim = 10 # number of classes
# define the model function. We choose to name it 'model()'.
model (features) = {
# model parameters
W0 = ParameterTensor {(HDim:SDim)} ; b0 = ParameterTensor {HDim}
W1 = ParameterTensor {(LDim:HDim)} ; b1 = ParameterTensor {LDim}
# model formula
r = RectifiedLinear (W0 * features + b0) # hidden layer
z = W1 * r + b1 # unnormalized softmax
}.z
# define inputs
features = Input {SDim}
labels = Input {LDim}
# apply model to features
z = model (features)
# define criteria and output(s)
ce = CrossEntropyWithSoftmax (labels, z) # criterion (loss)
errs = ErrorPrediction (labels, z) # additional metric
P = Softmax (z) # actual model usage uses this
# connect to the system. These five variables must be named exactly like this.
featureNodes = (features)
inputNodes = (labels)
criterionNodes = (ce)
evaluationNodes = (errs)
outputNodes = (P)
}
BrainScript 語法基本概念
在深入探討之前,先瞭解 BrainScript 語法的一些一般注意事項。
BrainScript 使用簡單的語法,其目標是允許以類似數學公式的方式來表達類神經網路。 因此,基本語法單位是指派,用於變數指派和函式定義。 例如:
Softplus (x) = Log (1 + Exp (x))
h = Softplus (W * v + b)
行、批注、包含
雖然指派通常是在單一行上撰寫,但表達式可以跨越多行。 不過,若要將多個指派放在單一行上,您必須以分號分隔它們。 例如:
SDim = 28*28 ; HDim = 256 ; LDim = 10 # feature, hidden, and label dimension
除了在沒有換行符的工作分派之間要求分號以外,BrainScript 不會區分空格符。
BrainScript 使用 Python 樣式 #
和 C++樣式 //
了解行尾批注。 內嵌批注使用 C 語法 (/* this is a comment*/
) ,但與 C 不同,這些語法可能不會跨越多行。
對於內嵌在 CNTK 配置檔中的 BrainScript (,而不是透過指示詞) 從個別檔案 include
讀取的 BrainScript,由於與組態剖析器互動, (有些奇怪) 額外的限制,任何括弧、大括號或括號都必須在 C/C++ 樣式批註和字元串常值內平衡。 因此,C/C++樣式批注中沒有笑臉!
include "PATH"
指示詞可以在任何位置使用,在語句的點插入檔案的內容。 在這裡, PATH
可以是絕對路徑或相對相對路徑, () 或沒有子目錄。 如果是相對路徑,則會依序搜尋下列位置:目前的工作目錄;目錄 (包含外部檔案的目錄) 如果有的話;directory (s) ,其中包含組態檔 (s) ;最後是包含 CNTK 可執行檔案的目錄。 所有內建 BrainScript 函式都會以這種方式包含在名為 CNTK.core.bs
的檔案中,該檔案位於 CNTK 可執行文件旁邊。
運算式
接下來,您必須瞭解 BrainScript 運算式,也就是描述您網路的公式。
BrainScript 表達式 是以類似熱門程式設計語言的語法撰寫數學。 最簡單的運算式是常值,例如數位和字串。 類似數學的範例是 W1 * r + b
,其中 *
會根據變數的類型來參考純量、矩陣或張量乘積。 另一種常見的運算式是函式呼叫,例如 RectifiedLinear (.)
。
BrainScript 是動態類型的語言。 重要的表達式類型是 記錄、使用 {...}
語法定義,以及透過點語法存取。 例如, r = { x = 13 ; y = 42 }
將具有兩個成員的記錄指派給 r
,其中第一個成員可以存取為 r.x
。
除了一般的數學運算符之外,BrainScript 還有條件表達式 (if c then t else f
) 、陣列運算式和簡單的 Lambda。 最後,為了與 CNTK C++ 程式代碼介面,BrainScript 可以直接具現化一組有限的預先定義 C++ 物件,主要是 ComputationNode
由該計算網路所組成。 如需詳細資訊,請參閱 表達式。
BrainScript 運算式會在第一次使用時進行評估。 BrainScript 的主要用途是描述網路,因此表達式的值通常不是最終值,而是計算圖表中的節點,以便延遲計算 (W1 * r + b
如同) 。 只有純量的 BrainScript 運算式 (例如 28*28
,) 在剖析 BrainScript 時會「計算」。 從未使用過的表達式 (例如,因為條件) 永遠不會評估。
注意:現在已淘汰 NDLNetworkBuilder
的版本僅支援函式調用語法;例如,一個必須寫入 Plus (Times (W1, r), b1)
。
變數
變數可以保存任何 BrainScript 表達式的值 (數位、字串、記錄、陣列、Lambda、CNTK C++ 物件) ,並在運算式中使用時取代。 變數不可變,也就是只指派一次。 例如,上述網路定義開頭為:
SDim = 28*28
HDim = 256
LDim = 10
這裡的 變數 會設定為後續表達式中做為參數的純量數值。 這些值是用於定型的數據範例、隱藏層和標籤度。 此特定範例設定適用於 MNIST 數據集,這是 -圖元影像的 [28 x 28]
集合。 每個影像都是手寫數位 (0-9) ,因此可以套用至每個影像的 10 個可能標籤。 隱藏的啟用維度 HDim
是用戶選擇。
大部分變數都是記錄成員, (外部 BrainScript 區塊是隱含的記錄) 。 此外,變數可以是函式自變數,也可以儲存為數位元素。
確定,準備好完成模型定義。
定義網路
網路主要是由如何從輸入計算網路輸出的公式來描述。 我們稱之為 模型函式,這通常定義為 BrainScript 中的實際函式。 在模型函式中,用戶必須宣告 模型參數。 最後,必須定義網路的 輸入和 準則/輸出。 所有這些都定義為變數。 輸入與準則/輸出變數必須接著與系統通訊。
網路的模型函式和模型參數
模型函式包含實際的網路公式和個別的模型參數。 我們的範例使用矩陣乘積和加法,而「基本」 (能源 RectifiedLinear()
函式的內建) 函式,因此網路函式的核心包含下列方程式:
r = RectifiedLinear (W0 * features + b0)
z = W1 * r + b1
模型參數 是矩陣、偏差向量,或任何其他在定型完成時構成學習模型的張量。 模型參數張量用於將輸入範例數據轉換成所需的輸出,並由學習程式更新。 上述範例網路包含下列矩陣參數:
W0 = ParameterTensor {(HDim:SDim)}
b0 = ParameterTensor {(HDim)}
在此情況下, W0
是權數矩陣,而且 b0
是偏差向量。 ParameterTensor{}
表示特殊的 CNTK 基本類型,它會具現化向量、矩陣或任意排名的 tensor,並將維度參數當作 BrainScript 陣列, (冒號 :
) 串連的數位。 向量的維度是單一數位,而矩陣維度應指定為 (numRows:numCols)
。 根據預設,參數會在直接具現化時使用統一隨機數初始化,而 heNormal
透過 圖層使用時,但其他選項 (請參閱這裡) 以取得完整清單。
不同於一般函式, ParameterTensor{}
它會以大括弧括住其自變數,而不是括弧。 大括弧是建立參數或物件的函式的 BrainScript 慣例,而不是函式。
然後,這全都會包裝成 BrainScript 函式。 BrainScript 函式是以 的形式 f(x) = an expression of x
宣告。 例如, Sqr (x) = x * x
是有效的 BrainScript 函式宣告。 無法更簡單且直接,正確嗎?
現在,上述範例的實際模型函式會比較複雜:
model (features) = {
# model parameters
W0 = ParameterTensor {(HDim:SDim)} ; b0 = ParameterTensor {HDim}
W1 = ParameterTensor {(LDim:HDim)} ; b1 = ParameterTensor {LDim}
# model formula
r = RectifiedLinear (W0 * features + b0) # hidden layer
z = W1 * r + b1 # unnormalized softmax
}.z
外部 { ... }
和最終 .z
需要一些說明。 外部標籤 { ... }
及其內容實際上會定義具有 6 個記錄成員的記錄, (W0
、 b0
、 W1
、、 b1
、 r
和 z
) 。 不過,模型函式的值只是 z
;所有其他函式都是內部的。 因此,我們使用 .z
來選取要傳回的記錄成員。 這隻是存取記錄成員的點語法。 如此一來,其他記錄成員就無法從外部存取。 但它們會繼續存在於表示式中,以計算 z
。
模式 { ... ; x = ... }.x
是使用局部變數的方式。
請注意,不需要記錄語法。 或者, model(features)
也可以透過記錄宣告,而不透過記錄宣告為單一表達式:
model (features) = ParameterTensor {(LDim:HDim)} * (RectifiedLinear (ParameterTensor {(HDim:SDim)}
* features + ParameterTensor {HDim})) + ParameterTensor {LDim}
這很難讀取,更重要的是,不允許在公式中的多個位置使用相同的參數。
輸入
網路輸入是由範例數據和與範例相關聯的標籤所定義:
features = Input {SDim}
labels = Input {LDim}
Input{}
是模型定義所需的第二個特殊 CNTK 基本類型, (第一個) Parameter{}
。 它會建立變數,以接收來自網路外部的輸入:從讀取器。 的 Input{}
自變數是數據維度。 在此範例中 features
,輸入會有範例數據的維度 (我們在變數 SDim
) 中定義,而 labels
輸入將會有卷標的維度。 輸入的變數名稱應該符合讀取器定義中的對應專案。
訓練準則和網路輸出
我們仍然需要宣告網路輸出如何與世界互動。 我們的模型函式會計算 (非正規化對數機率) 的對數值。 這些logit值可用來
- 定義定型準則,
- 量值精確度和
- 根據輸入計算輸出類別的機率,以根據 (分類決策,請注意,非正規化的記錄海報
z
通常可用於直接分類) 。
範例網路會使用類別標籤,以一個熱向量表示。 對於 MNIST 範例,這些範例會顯示為 10 個浮點值的陣列,除了 1.0 的適當卷標類別之外,所有值都是零。
類似我們的分類工作通常會使用 SoftMax()
函式來取得每個標籤的機率。 然後,網路會優化為將正確類別的對數機率最大化, (交叉 entropy) ,並將所有其他類別的對數機率降到最低。 這是我們的 訓練準則或 損失函式。 在 CNTK 中,這兩個動作通常會結合在一個函式中,以提升效率:
ce = CrossEntropyWithSoftmax (labels, z)
CrossEntropyWithSoftmax()
函式會接受輸入、計算 SoftMax()
函式、使用交叉 entropy 從實際值計算錯誤,並使用該錯誤訊號透過反向傳播來更新網路中的參數。 因此,在上述範例中,我們計算為P
的標準化Softmax()
值不會在定型期間使用。 不過,再次使用網路需要它 (請注意,在許多情況下,z
分類通常就已足夠;在此情況下,z
本身會是輸出) 。
CNTK 使用 隨機梯度下降 () 作為 學習演算法。 SGD 必須計算目標函式與所有模型參數相關的漸層。 重要的是,CNTK 不需要使用者指定這些漸層。 相反地,CNTK 中的每個內建函式也有衍生的對應函式,而且系統會自動執行網路參數的反向傳播更新。 使用者看不到此專案。 用戶永遠不需要擔心漸層。 Ever.
除了定型準則之外,預測的錯誤率通常會在定型階段進行計算,以驗證系統改善,因為訓練會進一步。 這會使用下列函式在 CNTK 中處理:
errs = ClassificationError (labels, z)
網路所產生的機率會與實際標籤進行比較,並計算錯誤率。 這通常是由系統顯示。 雖然這非常有用,但並非必須使用 ClassificationError()
。
將輸入、輸出和準則通訊至系統
既然已定義所有變數,我們必須告訴系統它應該視為輸入、輸出和準則的變數。 這是藉由定義 5 個必須有下列名稱的特殊變數來完成:
featureNodes = (features)
labelNodes = (labels)
criterionNodes = (ce)
evaluationNodes = (errs)
outputNodes = (z:P)
這些值是陣列,其中值應該以冒號分隔, (冒號 :
是 BrainScript 運算符,藉由串連兩個值或數位來形成數位) 。 這會顯示在 outputNodes
上,這會將 z
和 P
宣告為輸出。
(注意:已被取代 NDLNetworkBuilder
的陣列元素必須改為以逗號分隔。)
特殊名稱的摘要
如前所述,我們必須注意 7 個特殊名稱,其具有 「magic」 屬性:
ParameterTensor{}
:宣告並初始化可學習的參數。Input{}
:宣告從數據讀取器連線和饋送的變數。featureNodes
、labelNodes
、criterionNodes
、evaluationNodes
和outputNodes
:向系統宣告要作為輸入、輸出和準則的變數。
此外,CNTK 中有 3 個具有內建 “magic” 的特殊函式,會在其他地方討論:
Constant()
:宣告常數。PastValue()
和FutureValue()
:在不同的時間步驟中存取網路函式中的變數,以形成遞歸迴圈。
任何其他預先定義的名稱都是內建基本函式,例如 Sigmoid()
或 Convolution()
C++ 實作、在 BrainScript BS.RNNs.LSTMP()
中實現的預先定義連結庫函式,或做為連結庫函式命名空間的記錄 (,例如 BS.RNNs
) 。 如需完整清單,請參閱 BrainScript-Full-Function-Reference 。
下一步: BrainScript 表達式