BrainScript-Netzwerk-Generator
Benutzerdefinierte Netzwerke werden in der benutzerdefinierten Netzwerkbeschreibungssprache "BrainScript" von CNTK beschrieben. Um ein benutzerdefiniertes Netzwerk zu definieren, fügen Sie einen Abschnitt mit dem Namen BrainScriptNetworkBuilder
in Ihre Trainingskonfiguration ein. Eine ausführliche Beschreibung der Netzwerkbeschreibungssprache finden Sie auf der Seite Grundlegende Konzepte und den entsprechenden Unterseiten.
Es gibt zwei Formen der Verwendung des BrainScript-Netzwerk-Generators: eine mit Klammern (...)
und ein kurzhandformular mit geschweiften Klammern {...}
. Um Ihr Netzwerk in einer externen Datei zu beschreiben, geben Sie einen Block ähnlich dem folgenden an:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "yourNetwork.bs"
})
wobei yourNetwork.bs
das mit BrainScript beschriebene Netzwerk enthält. Die Datei yourNetwork.bs
wird zuerst im selben Verzeichnis wie die Konfigurationsdatei und, falls nicht gefunden, im Verzeichnis der ausführbaren CNTK-Datei gesucht. Hier werden sowohl absolute als auch relative Pfadnamen akzeptiert. Bedeutet z. B. eine Datei, bs/yourNetwork.bs
die sich in einem Verzeichnis bs
neben Ihrer Konfigurationsdatei befindet (oder alternativ ein Verzeichnis bs
im ausführbaren Verzeichnis CNTK).
Hinweis: Bis CNTK 1.6 verwendete BrainScript Klammern [...]
anstelle von geschweiften Klammern {...}
. Klammern sind weiterhin akzeptiert, aber veraltet.
Alternativ können Sie Ihr Netzwerk direkt in der Konfigurationsdatei inline definieren. Dies kann die Konfiguration vereinfachen, wenn Sie nicht planen, dasselbe Gehirnskript für mehrere Konfigurationen zu verwenden. Verwenden Sie dieses Formular:
BrainScriptNetworkBuilder = {
# insert network description here
}
Wie sieht also der BrainScript-Code aus, der in die Klammern geht? Um dies herauszufinden, springen Sie direkt zu BrainScript Basic Concepts.
Oder bleiben Sie auf dieser Seite und lesen Sie einige weniger häufig benötigte Details für Sie.
Die {...}
obige Form ist wirklich nur eine Kurze dafür:
BrainScriptNetworkBuilder = (new ComputationNetwork {
# insert network description here
})
Schließlich ist das (...)
Formular als erweiterte Verwendung nicht auf die Verwendung new
beschränkt. Vielmehr ist jeder BrainScript-Ausdruck, der zu einem Objekt von ComputationNetwork
auswertet, innerhalb der Klammern zulässig. Beispiel:
BrainScriptNetworkBuilder = ({
include "myNetworks.bs"
network = CreateMyNetworkOfType42()
}.network)
Dies ist eine erweiterte Verwendung, die manchmal auch im Kontext der Modellbearbeitung auftritt.
Weiter: Grundlegende Konzepte von BrainScript.
Hinterlassenschaft NDLNetworkBuilder
In älteren Versionen von CNTK hieß NDLNetworkBuilder
der Netzwerk-Generator . Die Definitionssprache ist eine Teilmenge von BrainScript. Der alte Parser war weniger fähig, aber auch verzeihend. Es gibt auch andere kleine Unterschiede.
NDLNetworkBuilder
ist jetzt veraltet, aber aufgrund der Ähnlichkeit ist es nicht schwierig, auf zu BrainScriptNetworkBuilder
aktualisieren. Im Folgenden finden Sie eine Anleitung zum Konvertieren von NDLNetworkBuilder
Netzwerkbeschreibungen in BrainScriptNetworkBuilder
's.
Aktualisieren von von auf NDLNetworkBuilder
BrainScriptNetworkBuilder
Das Konvertieren einer vorhandenen Netzwerkdefinition für den ist BrainScriptNetworkBuilder
in den NDLNetworkBuilder
meisten Fällen einfach. Die Standard Änderungen sind die umgebende Syntax. Die Kernnetzwerkbeschreibung selbst ist weitgehend nach oben kompatibel und wahrscheinlich identisch oder nahezu identisch, wenn Sie die neuen Sprachfeatures nicht nutzen.
Um Ihre Beschreibungen zu konvertieren, müssen Sie den Netzwerk-Generator wechseln, die äußere Syntax anpassen und möglicherweise kleinere Anpassungen an Ihren Netzwerkcode selbst vornehmen.
Schritt 1: Wechseln des Netzwerk-Generators. Ersetzen Sie durch NDLNetworkBuilder
den entsprechenden BrainScriptNetworkBuilder
Block in der CNTK-Konfigurationsdatei. Wenn sich Ihre Netzwerkbeschreibung in einer separaten Datei befindet:
# change from:
NDLNetworkBuilder = [
ndlMacros = "shared.ndl" # (if any)
networkDescription = "yourNetwork.ndl"
]
# ...to:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "shared.bs" # (if any)
include "yourNetwork.bs"
})
(Die Änderung der Dateinamenerweiterung ist nicht unbedingt erforderlich, aber empfohlen.)
Wenn sich Ihre Netzwerkbeschreibung in der .cntk
Konfigurationsdatei selbst befindet:
# 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")
}
Schritt 2: Entfernen und load
run
blockieren. Mit BrainScriptNetworkBuilder
werden Makro-/Funktionsdefinitionen und Standard Code kombiniert. Die load
Blöcke und run
müssen einfach entfernt werden. So wird beispielsweise
load = ndlMnistMacros
run = DNN
ndlMnistMacros = [
featDim = 784
...
labels = InputValue(labelDim)
]
DNN = [
hiddenDim = 200
...
outputNodes = (ol)
]
wird einfach:
featDim = 784
...
labels = InputValue(labelDim)
hiddenDim = 200
...
outputNodes = (ol)
Möglicherweise haben Sie die run
Variable verwendet, um eine von mehreren Konfigurationen mit einer externen Variablen auszuwählen, z. B.:
NDLNetworkBuilder = [
run = $whichModel$ # outside parameter selects model, must be either "model1" or "model2"
model1 = [ ... (MODEL 1 DEFINITION) ]
model2 = [ ... (MODEL 1 DEFINITION) ]
]
Dieses Muster war hauptsächlich erforderlich, da NDL keine bedingten Ausdrücke hatte. In BrainScript wird dies nun mit einem if
Ausdruck geschrieben:
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$'")
)
Häufig ähneln sich die ausgewählten Modelle jedoch sehr, sodass eine bessere Möglichkeit darin besteht, ihre Beschreibungen zusammenzuführen und stattdessen Nur dort Bedingungen zu verwenden, wo sie sich unterscheiden. Hier sehen Sie ein Beispiel, in dem ein Parameter verwendet wird, um zwischen einem unidirektionalen und einem bidirektionalen LSTM zu wählen:
encoderFunction =
if useBidirectionalEncoder
then BS.RNNs.RecurrentBirectionalLSTMPStack
else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)
Schritt 3: Anpassen der Netzwerkbeschreibung. In Bezug auf die Netzwerkbeschreibung (Formeln) selbst ist BrainScript weitgehend kompatibel mit NDL. Dies sind die Standard Unterschiede:
Der Rückgabewert von Makros (Funktionen) ist nicht mehr die letzte darin definierte Variable, sondern der gesamte Satz von Variablen. Sie müssen den Ausgabewert am Ende explizit auswählen. Beispiel:
# 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
Ohne diese Änderung wäre der Funktionsrückgabewert der gesamte Datensatz, und der typische Fehler, den Sie erhalten, ist, dass erwartet
ComputationNode
wurde, wo einComputationNetwork
gefunden wurde.BrainScript lässt keine Funktionen mit variabler Anzahl von Parametern zu. Dies ist in erster Linie für die
Parameter()
Funktion wichtig: Ein Vektorparameter kann nicht mehr alsParameter(N)
geschrieben werden, er muss nun explizit als TensorParameterTensor{N}
oder als 1-Spalten-MatrixParameter(N, 1)
geschrieben werden. Ohne diese Änderung erhalten Sie eine Fehlermeldung über die nicht übereinstimmende Anzahl von Positionsparametern. Diese Notation funktioniert auch mit NDL, sodass Sie diese Änderung zuerst vornehmen und vor der Konvertierung mit NDL testen können. Dies ist auch eine gute Gelegenheit, alle Verwendungen des LegacynamensLearnableParameter()
in umzubenennenParameterTensor{}
.Es ist auch für die
RowStack()
Funktion wichtig, die in BrainScript einen einzelnen Parameter akzeptiert, der ein Array von Eingaben ist. Die Eingaben müssen durch einen Doppelpunkt (:
) anstelle eines Kommas getrennt sein, z. B.RowStack (a:b:c)
anstelle vonRowStack (a, b, c)
.Einige Standardwerte wurden aktualisiert, vor allem der optionale
imageLayout
Parameter vonConvolution()
, die Poolvorgänge undImageInput()
. Für NDL sind diese standardmäßig auflegacy
festgelegt, während der Standardwert jetzt erforderlich istcudnn
, um mit den cuDNN-Convolution-Primitiven kompatibel zu sein. (Alle NDL-Codebeispiele geben diesen Parameter explizit an.cudnn
)Der BrainScript-Parser ist restriktiver:
Bei Bezeichnern wird jetzt die Groß-/Kleinschreibung beachtet. Integrierte Funktionen verwenden PascalCase (z. B.
RectifiedLinear()
), und integrierte Variablen und Parameternamen verwenden camelCase (z. B.modelPath
,criterionNodes
), sowie Optionszeichenfolgen (init="fixedValue"
,tag="criterion"
). Beachten Sie, dass bei Namen optionaler Parameter falsche Schreibweisen nicht immer als Fehler abgefangen werden. Stattdessen werden einige falsch geschriebene optionale Parameter einfach ignoriert. Ein Beispiel sind die Definitionen für spezielle Knoten. Ihre richtige Schreibweise für diese lautet jetzt:featureNodes = ... labelNodes = ... criterionNodes = ... evaluationNodes = ... outputNodes = ...
Abgekürzte alternative Namen sind nicht mehr zulässig, z
Const()
. BConstant()
. sollten ,tag="eval"
undtag="evaluation"
evalNodes
ist jetztevaluationNodes
.Einige falsch geschriebene Namen wurden korrigiert: ist jetzt
criterion
(ebenso ),criterionNodes
defaultHiddenActivity
ist jetztdefaultHiddenActivation
.criteria
Das
=
Zeichen ist für Funktionsdefinitionen nicht mehr optional.Es ist zwar zulässig, Klammern für Blöcke (
[ ... ]
) zu verwenden, ist jedoch veraltet. Verwenden Sie geschweifte Klammern ({ ... }
).Optionsbezeichnungen müssen als Zeichenfolgen angegeben werden, z. B.
init="uniform"
anstelle voninit=uniform
. Ohne die Anführungszeichen schlägt BrainScript mit einer Fehlermeldung fehl, die besagt, dass das Symboluniform
unbekannt ist.Die BrainScript-Grundtypen, die Parameter (
Input{}
undParameterTensor{}
) erstellen, sollten geschweifte Klammern für ihre Argumente verwenden (z. B.f = Input{42}
). Dies ist eine Konvention, die nicht erzwungen, aber für die Zukunft empfohlen wird.
Diese eingeschränktere Syntax wird weiterhin von
NDLNetworkBuilder
akzeptiert, daher wird empfohlen, zuerst diese syntaktischen Änderungen vorzunehmen und mit NDL zu testen, bevor Sie tatsächlich zu BrainScript wechseln.
Schritt 4. Entfernen Sie NDLNetworkBuilder
aus den Abschnitten "Schreiben" und "Testen". Überprüfen Sie die Abschnitte NDLNetworkBuilder
"Schreiben" und "Testen", und entfernen Sie sie. Einige unserer Bestands-NDL-Beispiele haben zusätzliche NDLNetworkBuilder
Abschnitte. Sie werden nicht verwendet und sollten nicht vorhanden sein. Wenn Ihre Konfiguration auf einem dieser Beispiele basiert, verfügen Sie möglicherweise auch über solche Abschnitte. Sie wurden früher ignoriert, aber mit dem BrainScript-Update hat das Definieren eines neuen Netzwerks in diesen Abschnitten jetzt eine Bedeutung (Modellbearbeitung), sodass sie nicht mehr ignoriert werden und daher entfernt werden sollten.
NDLNetworkBuilder
Referenz (veraltet)
Die Syntax des veralteten NDLNetworkBuilder
lautet:
NDLNetworkBuilder = [
networkDescription = "yourNetwork.ndl"
]
Der NDLNetworkBuilder
Block verfügt über die folgenden Parameter:
networkDescription
: der Dateipfad der Netzwerkbeschreibungsdatei. Mit dem veraltetenNDLNetworkBuilder
war es üblich, die Dateierweiterung.ndl
zu verwenden. Wenn keinnetworkDescription
Parameter angegeben ist, wird davon ausgegangen, dass die Netzwerkbeschreibung in denselbenNDLNetworkBuilder
Teilblock eingeteilt wird, der mit demrun
folgenden Parameter angegeben wird. Beachten Sie, dass nur ein Dateipfad über dennetworkDescription
Parameter angegeben werden kann. Verwenden Sie denndlMacros
Parameter, um mehrere Makrodateien zu laden.run
: der Block der ausgeführten NDL. Wenn über dennetworkDescription
Parameter eine externe NDL-Datei angegeben wird, identifiziert derrun
Parameter einen Block in dieser Datei. Dieser Parameter überschreibt allerun
Parameter, die möglicherweise bereits in der Datei vorhanden sind. Wenn keinenetworkDescription
Datei angegeben ist, identifiziert derrun
Parameter einen Block in der aktuellen Konfigurationsdatei.load
: die zu ladenden Blöcke von NDL-Skripts. Mehrere Blöcke können über eine durch ":" getrennte Liste angegeben werden. Die durch den Parameter angegebenen Blöcke enthalten in derload
Regel Makros zur Verwendung durch denrun
Block. Ähnlich wie derrun
Parameter identifiziert derload
Parameter Blöcke in einer externen NDL-Datei und überschreibt alleload
Parameter, die möglicherweise bereits in der Datei vorhanden sind, wenn eine Datei durch dennetworkDescription
-Parameter angegeben wird. Wenn keinenetworkDescription
Datei angegeben ist,load
identifiziert einen Block in der aktuellen Konfigurationsdatei.ndlMacros
: Der Dateipfad, in den NDL-Makros geladen werden können. Dieser Parameter wird normalerweise verwendet, um einen Standardsatz von NDL-Makros zu laden, die von allen NDL-Skripts verwendet werden können. Mehrere NDL-Dateien, die jeweils unterschiedliche Makrosätze angeben, können geladen werden, indem sie eine getrennte Liste von Dateipfaden mit "+" für diesenndlMacros
Parameter angeben. Um Makros mit anderen Befehlsblöcken wie den MEL-Blöcken (Model Editing Language) von NDL freizugeben, sollten Sie sie auf der Stammebene der Konfigurationsdatei definieren.randomSeedOffset
: Ein nicht negativer Zufälliger Startoffsetwert beim Initialisieren der lernbaren Parameter. Standardwert:0
. Dadurch können Benutzer Experimente mit unterschiedlicher zufälliger Initialisierung ausführen.