共用方式為


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 個記錄成員的記錄, (W0b0W1、、 b1rz) 。 不過,模型函式的值只是 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上,這會將 zP 宣告為輸出。

(注意:已被取代 NDLNetworkBuilder 的陣列元素必須改為以逗號分隔。)

特殊名稱的摘要

如前所述,我們必須注意 7 個特殊名稱,其具有 「magic」 屬性:

  • ParameterTensor{}:宣告並初始化可學習的參數。
  • Input{}:宣告從數據讀取器連線和饋送的變數。
  • featureNodeslabelNodescriterionNodesevaluationNodesoutputNodes:向系統宣告要作為輸入、輸出和準則的變數。

此外,CNTK 中有 3 個具有內建 “magic” 的特殊函式,會在其他地方討論:

  • Constant():宣告常數。
  • PastValue()FutureValue():在不同的時間步驟中存取網路函式中的變數,以形成遞歸迴圈。

任何其他預先定義的名稱都是內建基本函式,例如 Sigmoid()Convolution() C++ 實作、在 BrainScript BS.RNNs.LSTMP()中實現的預先定義連結庫函式,或做為連結庫函式命名空間的記錄 (,例如 BS.RNNs) 。 如需完整清單,請參閱 BrainScript-Full-Function-Reference

下一步: BrainScript 表達式