BrainScript 網路產生器
自訂網路會在 CNTK 的自訂網路描述語言 「BrainScript」 中描述。若要定義自訂網路,請在訓練組態中包含名為 的 BrainScriptNetworkBuilder
區段。 您可以在 [ 基本概念 ] 頁面和對應的子頁面上找到網路描述語言的詳細描述。
使用 BrainScript 網路建立器有兩種形式,一種使用括弧 (...)
,另一種是使用大括弧的 {...}
簡短表單。 若要在外部檔案中描述您的網路,請指定類似以下的區塊:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "yourNetwork.bs"
})
其中 yourNetwork.bs
包含使用 BrainScript 描述的網路。 yourNetwork.bs
檔案會先在與組態檔相同的目錄中尋找,如果找不到,則位於 CNTK 可執行檔的目錄中。 這裡接受絕對和相對路徑名稱。 例如, bs/yourNetwork.bs
表示位於組態檔旁的檔案 bs
(或 CNTK 可執行檔目錄內的目錄 bs
) 。
注意:在 CNTK 1.6 之前,BrainScript 使用括弧 [...]
,而不是大括弧 {...}
。 仍接受方括弧,但已被取代。
或者,您可以直接在組態檔內定義網路內嵌。 如果您不打算跨多個組態共用相同的大腦腳本,這可以簡化設定。 使用此表單:
BrainScriptNetworkBuilder = {
# insert network description here
}
所以 BrainScript 程式碼看起來會像這樣進入括弧? 若要瞭解,請直接跳到 BrainScript 基本概念。
或者,請留在此頁面,並閱讀您一些較不常需要的詳細資料。
上述 {...}
表單實際上只是一個簡短的程式碼:
BrainScriptNetworkBuilder = (new ComputationNetwork {
# insert network description here
})
最後,作為進階用途,表單 (...)
不限於使用 new
。 相反地,在括弧內允許評估為 物件的 ComputationNetwork
BrainScript 運算式。 例如:
BrainScriptNetworkBuilder = ({
include "myNetworks.bs"
network = CreateMyNetworkOfType42()
}.network)
這是進階用法,有時也會發生在模型編輯的內容中。
下一步: BrainScript 基本概念。
遺產 NDLNetworkBuilder
在舊版的 CNTK 中,網路產生器稱為 NDLNetworkBuilder
。 其定義語言是 BrainScript 的子集。 舊的剖析器較不具功能,但更適合使用。 還有其他小差異。
NDLNetworkBuilder
現在已被取代,但由於相似性,因此不難升級至 BrainScriptNetworkBuilder
。 以下是如何將網路描述 BrainScriptNetworkBuilder
轉換成 NDLNetworkBuilder
的指南。
從 NDLNetworkBuilder
更新至 BrainScriptNetworkBuilder
在大部分情況下,將 的現有網路定義 NDLNetworkBuilder
BrainScriptNetworkBuilder
轉換成 很簡單。 主要變更是周圍的語法。 如果您未利用新的語言功能,核心網路描述本身主要是向上相容且可能完全相同或幾乎完全相同。
若要轉換您的描述,您必須切換網路產生器、調整 w.r.t. 外部語法,並可能稍微調整網路程式碼本身。
步驟 1: 切換網路建立器. NDLNetworkBuilder
將 取代為 CNTK 組態檔中對應的 BrainScriptNetworkBuilder
區塊。 如果您的網路描述位於個別的檔案中:
# change from:
NDLNetworkBuilder = [
ndlMacros = "shared.ndl" # (if any)
networkDescription = "yourNetwork.ndl"
]
# ...to:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "shared.bs" # (if any)
include "yourNetwork.bs"
})
(副檔名的變更並非絕對必要,而是建議使用。)
如果您的網路描述位於 .cntk
組態檔本身:
# change from:
NDLNetworkBuilder = [
# macros
load = [
SigmoidNetwork (x, W, b) = Sigmoid (Plus (Times (W, x), b))
]
# network description
run = [
feat = Input (13)
...
ce = CrossEntropyWithSoftmax (labels, z, tag="criterion")
]
]
# ...to:
BrainScriptNetworkBuilder = {
# macros are just defined inline
SigmoidNetwork (x, W, b) = Sigmoid (Plus (Times (W, x), b)) # or: Sigmoid (W * x + b)
# network description
feat = Input {13}
...
ce = CrossEntropyWithSoftmax (labels, z, tag="criterion")
}
步驟 2: 移除 load
和 run
區塊。 使用 BrainScriptNetworkBuilder
時,會合並宏/函式定義和主要程式碼。 load
和 run
區塊必須直接移除。 例如下列程式碼:
load = ndlMnistMacros
run = DNN
ndlMnistMacros = [
featDim = 784
...
labels = InputValue(labelDim)
]
DNN = [
hiddenDim = 200
...
outputNodes = (ol)
]
只會變成:
featDim = 784
...
labels = InputValue(labelDim)
hiddenDim = 200
...
outputNodes = (ol)
您可能已使用 run
變數來選取其中一個具有外部變數的多個組態,例如:
NDLNetworkBuilder = [
run = $whichModel$ # outside parameter selects model, must be either "model1" or "model2"
model1 = [ ... (MODEL 1 DEFINITION) ]
model2 = [ ... (MODEL 1 DEFINITION) ]
]
此模式大部分是必要的,因為 NDL 沒有條件運算式。 在 BrainScript 中,現在會使用 if
運算式來撰寫:
BrainScriptNetworkBuilder = (new ComputationNetwork
if "$whichModel$" == "model1" then { ... (MODEL 1 DEFINITION) }
else if "$whichModel$" == "model2" then { ... (MODEL 2 DEFINITION) }
else Fail ("Invalid model selector value '$whichModel$'")
)
不過,選取的模型通常非常類似,因此最好是合併其描述,而改為只針對其不同之處使用內部的條件。 以下是用來在單向與雙向 LSTM 之間選擇參數的範例:
encoderFunction =
if useBidirectionalEncoder
then BS.RNNs.RecurrentBirectionalLSTMPStack
else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)
步驟 3: 調整您的網路描述. 關於網路描述 (公式本身) ,BrainScript 大致上與 NDL 相容。 以下是主要差異:
宏 (函式的傳回值) 不再是其中定義的最後一個變數,而是整個變數集。 您必須在結尾明確選取輸出值。 例如:
# NDL: f(x) = [ x2 = Times (x, x) y = Plus (x2, Constant (1)) ] # <-- return value defaults to last entry, i.e. y # BrainScript: f(x) = { x2 = x*x y = x2 + 1 }.y # <-- return value y must be explicitly dereferenced
如果沒有這項變更,函式傳回值會是整個記錄,而您得到的一般錯誤是
ComputationNode
,預期找到 的位置ComputationNetwork
。BrainScript 不允許具有可變參數數目的函式。 這主要對函
Parameter()
式很重要:向量參數無法再撰寫為Parameter(N)
,現在必須明確寫入為張量ParameterTensor{N}
或 1 欄矩陣Parameter(N, 1)
。 如果沒有這項變更,您會收到與位置參數數目不符的錯誤。 此標記法也適用于 NDL,因此您可以先進行這項變更,並在轉換之前先使用 NDL 進行測試。 這也是將舊版名稱LearnableParameter()
的任何用法重新命名為ParameterTensor{}
的好機會。在 BrainScript 中,函式也很重要
RowStack()
,其會採用單一參數作為輸入陣列。 輸入必須以冒號分隔 (:
) 而不是逗號,例如RowStack (a:b:c)
,而不是RowStack (a, b, c)
。某些預設值已更新,主要是 的選擇性
imageLayout
參數Convolution()
、共用作業和ImageInput()
。 針對 NDL,這些預設legacy
為 ,而現在預設值是cudnn
與 cuDNN 卷積基本類型相容的預設值。 (所有 NDL 程式碼範例都會明確指定此參數為cudnn
already.)BrainScript 的剖析器更嚴格:
識別碼現在會區分大小寫。 內建函式會使用 PascalCase (,例如
RectifiedLinear()
) ,而內建變數和參數名稱則使用 camelCase (,例如modelPath
、criterionNodes
) ,如同選項字串 (init="fixedValue"
,tag="criterion"
) 。 請注意,對於選擇性參數的名稱,不一定會攔截不正確的拼字錯誤。 相反地,只會忽略一些拼字錯誤的選擇性參數。 例如「特殊節點」定義。 它們的正確拼字現在如下:featureNodes = ... labelNodes = ... criterionNodes = ... evaluationNodes = ... outputNodes = ...
不再允許縮寫的替代名稱,例如
Const()
應該是Constant()
,應該是tag="evaluation"
,tag="eval"
而且evalNodes
現在是evaluationNodes
。修正了一些拼字錯誤的名稱:
criteria
現在criterion
(同樣criterionNodes
) ,defaultHiddenActivity
現在是defaultHiddenActivation
。函
=
式定義不再是選擇性的符號。雖然允許對區塊使用方括弧 (
[ ... ]
) ,但它已被取代。 使用大括弧 ({ ... }
) 。選項標籤必須以字串括住,例如
init="uniform"
,而不是init=uniform
。 如果沒有引號,BrainScript 將會失敗,並顯示錯誤訊息,指出符號uniform
未知。(和
ParameterTensor{}
) 建立參數Input{}
的 BrainScript 基本類型應該針對其引數使用大括弧 (,例如f = Input{42}
) 。 這是不會強制執行但建議繼續進行的慣例。
仍然接受
NDLNetworkBuilder
這個更受限的語法,因此建議您先進行這些語法變更,並使用 NDL進行測試,然後再實際變更為 BrainScript。
步驟 4: 從 「write」 和 「test」 區段中移除 NDLNetworkBuilder
。 請檢閱節的「寫入」和「測試」區段 NDLNetworkBuilder
,並加以移除。 我們的一些股票 NDL 範例有無關 NDLNetworkBuilder
的區段。 它們不會使用,而且不應該存在。 如果您的設定是以下列其中一個範例為基礎,您可能也會有這類區段。 它們過去會被忽略,但透過 BrainScript 更新,在這些區段中定義新的網路現在具有意義 (模型編輯) ,因此應該不再忽略它們,因此應該移除。
NDLNetworkBuilder
參考 (已被取代)
已被取代 NDLNetworkBuilder
的語法為:
NDLNetworkBuilder = [
networkDescription = "yourNetwork.ndl"
]
區塊 NDLNetworkBuilder
具有下列參數:
networkDescription
:網路描述檔案的檔案路徑。 在已被NDLNetworkBuilder
取代之後,使用副檔名.ndl
是自訂的 。networkDescription
如果沒有指定參數,則會假設網路描述會內嵌在相同的NDLNetworkBuilder
子區塊中,並使用run
下列參數指定。 請注意,只能透過networkDescription
參數指定一個檔案路徑。 若要載入多個宏檔案,請使用ndlMacros
參數。run
:將執行的 NDL 區塊。 如果透過networkDescription
參數指定外部 NDL 檔案,參數run
會識別該檔案中的區塊。 此參數會覆寫檔案中可能已經存在的任何run
參數。networkDescription
如果未指定任何檔案,run
參數會識別目前組態檔中的區塊。load
:要載入的 NDL 腳本區塊。 您可以透過 「:」 分隔清單來指定多個區塊。 參數指定的load
區塊通常會包含宏以供 區塊使用run
。 與 參數類似run
,如果參數指定networkDescription
檔案,參數load
會識別外部 NDL 檔案中的區塊,並覆寫檔案中可能已經存在的任何load
參數。networkDescription
如果未指定任何檔案,load
則識別目前組態檔中的 區塊。ndlMacros
:可載入 NDL 宏的檔案路徑。 此參數通常用來載入所有 NDL 腳本可以使用的預設 NDL 宏集。 您可以藉由指定此參數ndlMacros
的檔案路徑 「+」 分隔清單,來載入多個 NDL 檔案,每個檔案都指定不同的宏集。 若要與其他命令區塊共用宏,例如 NDL 的模型編輯語言 (MEL) 區塊,您應該在組態檔的根層級定義它。randomSeedOffset
:初始化可學習參數時的非負隨機種子位移值。 預設值是0
。 這可讓使用者使用不同的隨機初始化來執行實驗。