你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
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
非常简单。 main更改是周围的语法。 如果不利用新的语言功能,核心网络描述本身基本上向上兼容,并且可能完全相同或几乎相同。
若要转换说明,必须切换网络生成器,调整 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
,宏/函数定义和main代码组合在一起。 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 和双向 LSTM 之间进行选择:
encoderFunction =
if useBidirectionalEncoder
then BS.RNNs.RecurrentBirectionalLSTMPStack
else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)
步骤 3. 调整网络说明. 关于网络描述 (公式本身) ,BrainScript 在很大程度上与 NDL 向上兼容。 以下是main差异:
宏 (函数) 的返回值不再是其中定义的最后一个变量,而是整个变量集。 必须在末尾显式选择输出值。 例如:
# 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{}
的好机会。它对于
RowStack()
函数也很重要,该函数在 BrainScript 中采用单个参数,该参数是一个输入数组。 输入必须用冒号分隔 (:
) 而不是逗号,例如RowStack (a:b:c)
,而不是RowStack (a, b, c)
。某些默认值已更新,主要是 、 池操作 和
ImageInput()
的Convolution()
可选imageLayout
参数。 对于 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="eval"
应为tag="evaluation"
,现在evalNodes
evaluationNodes
为 。更正了一些拼写错误的名称:
criteria
现在criterion
(同样criterionNodes
) ,defaultHiddenActivity
现在是defaultHiddenActivation
。对于
=
函数定义,符号不再是可选的。虽然允许对块使用括号 (
[ ... ]
) ,但它已被弃用。 使用大括号 ({ ... }
) 。选项标签必须用字符串括起,例如
init="uniform"
,而不是init=uniform
。 如果没有引号,BrainScript 将失败,并显示一条错误消息,指出符号uniform
未知。创建参数的
Input{}
BrainScript 基元 (和ParameterTensor{}
) 应使用大括号作为参数 (,例如f = Input{42}
) 。 这是一个不强制执行但建议今后执行的约定。
此更受限的语法仍被
NDLNetworkBuilder
接受,因此我们建议先进行这些语法更改,并使用 NDL 对其进行测试,然后再实际更改为 BrainScript。
步骤 4. 从“写入”和“测试”部分删除 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
参数类似,load
参数标识外部 NDL 文件中的块,并覆盖文件中可能已存在的任何load
参数(如果 文件由networkDescription
参数指定)。 如果未networkDescription
指定文件,load
则 标识当前配置文件中的块。ndlMacros
:可以加载 NDL 宏的文件路径。 此参数通常用于加载可由所有 NDL 脚本使用的默认 NDL 宏集。 可以通过为此参数ndlMacros
指定“+”分隔的文件路径列表来加载多个 NDL 文件,每个文件指定不同的宏集。 若要与其他命令块(例如 NDL 的模型编辑语言 (MEL) 块)共享宏,应在配置文件的根级别定义它。randomSeedOffset
:初始化可学习参数时的非负随机种子偏移值。 默认值为0
。 这允许用户运行具有不同随机初始化的试验。