Построитель сетей BrainScript
Пользовательские сети описаны в пользовательском языке описания сети CNTK "BrainScript". Чтобы определить пользовательскую сеть, включите раздел с именем BrainScriptNetworkBuilder
в конфигурацию обучения. Подробное описание на языке описания сети можно найти на странице Основные понятия и на соответствующих подстраницах.
Существует две формы использования построителя сетей BrainScript: одна из которых использует круглые скобки (...)
и короткая форма с фигурными скобками {...}
. Чтобы описать сеть во внешнем файле, укажите блок, аналогичный следующему:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "yourNetwork.bs"
})
где yourNetwork.bs
содержит сеть, описанную с помощью BrainScript. Сначала файл yourNetwork.bs
ищется в том же каталоге, что и файл конфигурации, а если он не найден, в каталоге исполняемого файла CNTK. Здесь принимаются как абсолютные, так и относительные имена путей. Например, означает файл, bs/yourNetwork.bs
расположенный в каталоге bs
рядом с файлом конфигурации (или каталог bs
в исполняемом каталоге CNTK).
Примечание. До CNTK 1.6 в BrainScript использовались квадратные скобки [...]
вместо фигурных скобок {...}
. Квадратные скобки по-прежнему принимаются, но не рекомендуются.
Кроме того, можно определить встроенную сеть непосредственно в файле конфигурации. Это может упростить настройку, если вы не планируете совместно использовать один и тот же сценарий мозга в нескольких конфигурациях. Используйте эту форму:
BrainScriptNetworkBuilder = {
# insert network description here
}
Так как выглядит код BrainScript, который входит в квадратные скобки? Чтобы узнать это, перейдите к разделу Основные понятия BrainScript.
Или оставайтесь на этой странице и читайте о некоторых менее часто необходимых сведениях для вас.
В приведенной {...}
выше форме на самом деле просто короткие руки для этого:
BrainScriptNetworkBuilder = (new ComputationNetwork {
# insert network description here
})
Наконец, в качестве расширенного (...)
использования форма не ограничивается использованием new
. Вместо этого в круглых скобках допускается любое выражение BrainScript, результатом которого ComputationNetwork
является объект . Пример:
BrainScriptNetworkBuilder = ({
include "myNetworks.bs"
network = CreateMyNetworkOfType42()
}.network)
Это расширенное использование, которое также иногда встречается в контексте редактирования модели.
Далее: Основные понятия BrainScript.
Наследие NDLNetworkBuilder
В более ранних версиях CNTK построитель сети назывался NDLNetworkBuilder
. Его язык определения является подмножеством BrainScript. Старый синтаксический анализатор был менее способным, но и более прощающим. Существуют и другие небольшие различия.
NDLNetworkBuilder
В настоящее время является устаревшим, но из-за сходства не трудно выполнить обновление до BrainScriptNetworkBuilder
. Ниже приведено руководство по преобразованию NDLNetworkBuilder
описаний сети в BrainScriptNetworkBuilder
.
Обновление с NDLNetworkBuilder
до BrainScriptNetworkBuilder
Преобразование существующего определения сети для NDLNetworkBuilder
BrainScriptNetworkBuilder
в в большинстве случаев просто. Изменения main — это окружающий синтаксис. Само описание основной сети в значительной степени совместимо и, вероятно, идентично или почти идентично, если вы не используете преимущества новых функций языка.
Чтобы преобразовать описания, необходимо переключить построитель сети, адаптировать внешний синтаксис w.r.t. и, возможно, внести незначительные изменения в сам сетевой код.
Шаг 1. Переключение построителя сетей. Замените NDLNetworkBuilder
соответствующим BrainScriptNetworkBuilder
блоком в файле конфигурации CNTK. Если описание сети находится в отдельном файле:
# 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:
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}
или матрицыParameter(N, 1)
из 1 столбца . Без этого изменения вы получите ошибку о несоответствии количества позиционных параметров. Эта нотация также работает с NDL, поэтому вы можете сначала внести это изменение и протестировать его с помощью NDL перед преобразованием. Это также хорошая возможность переименовать любое использование устаревшего имениLearnableParameter()
вParameterTensor{}
.Это также важно для
RowStack()
функции, которая в BrainScript принимает один параметр, который является массивом входных данных. Входные данные должны быть разделены двоеточием (:
) вместо запятой, напримерRowStack (a:b:c)
вместоRowStack (a, b, c)
.Были обновлены некоторые значения по умолчанию, в первую очередь необязательный
imageLayout
параметрConvolution()
, операции пула иImageInput()
. Для NDL по умолчанию используетсяlegacy
значение , в то время как теперь используетсяcudnn
значение по умолчанию, которое требуется для совместимости с примитивами свертки cuDNN. (Все примеры кода NDL явно указывают этот параметр какcudnn
уже.)Средство синтаксического анализа 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
неизвестен.Примитивы BrainScript, создающие параметры (
Input{}
иParameterTensor{}
), должны использовать фигурные скобки для аргументов (например,f = Input{42}
). Это соглашение, которое не применяется, но рекомендуется в дальнейшем.
Этот более ограниченный синтаксис по-прежнему принимается
NDLNetworkBuilder
, поэтому мы рекомендуем сначала внести эти синтаксические изменения и протестировать их с помощью NDL, прежде чем переходить на BrainScript.
Шаг 4. Удалите NDLNetworkBuilder
из разделов write и test. Просмотрите разделы "запись" и "тестирование" для NDLNetworkBuilder
разделов и удалите их. Некоторые из наших стандартных примеров NDL содержат лишние NDLNetworkBuilder
разделы. Они не используются и не должны быть там. Если конфигурация основана на одном из этих примеров, могут быть и такие разделы. Раньше они пропускались, но с обновлением BrainScript определение новой сети в этих разделах теперь имеет смысл (редактирование модели), поэтому они больше не игнорируются и, следовательно, должны быть удалены.
NDLNetworkBuilder
reference (не рекомендуется)
Синтаксис нерекомендуемого NDLNetworkBuilder
объекта:
NDLNetworkBuilder = [
networkDescription = "yourNetwork.ndl"
]
Блок NDLNetworkBuilder
имеет следующие параметры:
networkDescription
: путь к файлу описания сети. В устаревшейNDLNetworkBuilder
версии было принято использовать расширение.ndl
файла . Если параметр неnetworkDescription
указан, предполагается, что описание сети встраиваются в тот жеNDLNetworkBuilder
подблок, указанныйrun
с помощью параметра ниже. Обратите внимание, что с помощью параметра можно указать только один путь к файлуnetworkDescription
. Чтобы загрузить несколько файлов макросов, используйтеndlMacros
параметр .run
: блок NDL, который будет выполнен. Если внешний NDL-файл указан с помощьюnetworkDescription
параметра ,run
параметр определяет блок в этом файле. Этот параметр переопределяет всеrun
параметры, которые уже могут существовать в файле. Если файл неnetworkDescription
указан,run
параметр определяет блок в текущем файле конфигурации.load
: блоки скриптов NDL для загрузки. С помощью разделенного списка ":" можно указать несколько блоков. Блоки, заданные параметромload
, обычно содержат макросы для использования блокомrun
. Аналогично параметруrun
,load
параметр определяет блоки во внешнем NDL-файле и переопределяет всеload
параметры, которые уже могут существовать в файле, если файл указан параметромnetworkDescription
. Если файл неnetworkDescription
указан,load
определяет блок в текущем файле конфигурации.ndlMacros
: путь к файлу, по которому могут быть загружены макросы NDL. Этот параметр обычно используется для загрузки набора макросов NDL по умолчанию, которые могут использоваться всеми скриптами NDL. Несколько NDL-файлов, каждый из которых задает разные наборы макросов, можно загрузить, указав разделенный "+" список путей к файлам для этогоndlMacros
параметра. Для совместного использования макросов с другими командными блоками, такими как блоки языка редактирования моделей (MEL) NDL, необходимо определить их на корневом уровне файла конфигурации.randomSeedOffset
: неотрицательное значение случайного смещения начального значения при инициализации изучаемых параметров. Значение по умолчанию —0
. Это позволяет пользователям выполнять эксперименты с разными случайными инициализациями.