Freigeben über


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 newbeschrä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ß NDLNetworkBuilderder 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 BrainScriptNetworkBuilderaktualisieren. Im Folgenden finden Sie eine Anleitung zum Konvertieren von NDLNetworkBuilder Netzwerkbeschreibungen in BrainScriptNetworkBuilder's.

Aktualisieren von von auf NDLNetworkBuilderBrainScriptNetworkBuilder

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 loadrun blockieren. Mit BrainScriptNetworkBuilderwerden 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 ein ComputationNetwork 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 als Parameter(N)geschrieben werden, er muss nun explizit als Tensor ParameterTensor{N} oder als 1-Spalten-Matrix Parameter(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 Legacynamens LearnableParameter() in umzubenennen ParameterTensor{}.

    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 von RowStack (a, b, c).

  • Einige Standardwerte wurden aktualisiert, vor allem der optionale imageLayout Parameter von Convolution(), die Poolvorgänge und ImageInput(). Für NDL sind diese standardmäßig auf legacyfestgelegt, während der Standardwert jetzt erforderlich ist cudnn , 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, zConst(). BConstant(). sollten , tag="eval" und tag="evaluation"evalNodes ist jetzt evaluationNodes.

    • Einige falsch geschriebene Namen wurden korrigiert: ist jetzt criterion (ebenso ), criterionNodesdefaultHiddenActivity ist jetzt defaultHiddenActivation. 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 von init=uniform. Ohne die Anführungszeichen schlägt BrainScript mit einer Fehlermeldung fehl, die besagt, dass das Symbol uniform unbekannt ist.

    • Die BrainScript-Grundtypen, die Parameter (Input{} und ParameterTensor{}) 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 NDLNetworkBuilderakzeptiert, 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 veralteten NDLNetworkBuilderwar es üblich, die Dateierweiterung .ndlzu verwenden. Wenn kein networkDescription Parameter angegeben ist, wird davon ausgegangen, dass die Netzwerkbeschreibung in denselben NDLNetworkBuilder Teilblock eingeteilt wird, der mit dem run folgenden Parameter angegeben wird. Beachten Sie, dass nur ein Dateipfad über den networkDescription Parameter angegeben werden kann. Verwenden Sie den ndlMacros Parameter, um mehrere Makrodateien zu laden.

  • run: der Block der ausgeführten NDL. Wenn über den networkDescription Parameter eine externe NDL-Datei angegeben wird, identifiziert der run Parameter einen Block in dieser Datei. Dieser Parameter überschreibt alle run Parameter, die möglicherweise bereits in der Datei vorhanden sind. Wenn keine networkDescription Datei angegeben ist, identifiziert der run 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 der load Regel Makros zur Verwendung durch den run Block. Ähnlich wie der run Parameter identifiziert der load Parameter Blöcke in einer externen NDL-Datei und überschreibt alle load Parameter, die möglicherweise bereits in der Datei vorhanden sind, wenn eine Datei durch den networkDescription -Parameter angegeben wird. Wenn keine networkDescription 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 diesen ndlMacros 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.