Partager via


Générateur de réseau BrainScript

Les réseaux personnalisés sont décrits dans le langage de description de réseau personnalisé de CNTK « BrainScript ». Pour définir un réseau personnalisé, incluez une section nommée BrainScriptNetworkBuilder dans votre configuration d’entraînement. Vous trouverez une description détaillée du langage de description réseau dans la page Concepts de base et les sous-pages correspondantes.

Il existe deux formes d’utilisation du générateur de réseau BrainScript, l’une utilisant des (...)parenthèses et un formulaire à main courte utilisant des {...}accolades . Pour décrire votre réseau dans un fichier externe, spécifiez un bloc semblable à ceci :

BrainScriptNetworkBuilder = (new ComputationNetwork {
    include "yourNetwork.bs"
})

yourNetwork.bs contient le réseau décrit à l’aide de BrainScript. Le fichier yourNetwork.bs est d’abord à rechercher dans le même répertoire que le fichier de configuration et, s’il est introuvable, dans le répertoire de l’exécutable CNTK. Les noms de chemin absolus et relatifs sont acceptés ici. Par exemple, bs/yourNetwork.bs désigne un fichier situé dans un répertoire bs en regard de votre fichier de configuration (ou un répertoire bs à l’intérieur du répertoire exécutable CNTK).

Remarque : Jusqu’à CNTK 1.6, BrainScript utilisait des crochets [...] plutôt que des accolades {...}. Les crochets sont toujours acceptés, mais déconseillés.

Vous pouvez également définir votre réseau en ligne, directement à l’intérieur du fichier de configuration. Cela peut simplifier la configuration si vous ne prévoyez pas de partager le même script de cerveau entre plusieurs configurations. Utilisez ce formulaire :

BrainScriptNetworkBuilder = {
    # insert network description here
}

Alors à quoi ressemble le code BrainScript qui passe entre crochets ? Pour le savoir, passez directement à Concepts de base de BrainScript.

Ou restez sur cette page et lisez sur certains détails moins fréquemment nécessaires pour vous.

Le {...} formulaire ci-dessus n’est vraiment qu’une courte main pour ceci :

BrainScriptNetworkBuilder = (new ComputationNetwork {
    # insert network description here
})

Enfin, en tant qu’utilisation avancée, le (...) formulaire n’est pas limité à l’utilisation newde . Au lieu de cela, toute expression BrainScript qui prend la valeur d’un objet de ComputationNetwork est autorisée à l’intérieur des parenthèses. Par exemple :

BrainScriptNetworkBuilder = ({
    include "myNetworks.bs"
    network = CreateMyNetworkOfType42()
}.network)

Il s’agit d’une utilisation avancée qui se produit parfois dans le contexte de la modification de modèle.

Suivant : Concepts de base de BrainScript.

Héritage NDLNetworkBuilder

Dans les versions antérieures de CNTK, le générateur de réseau était appelé NDLNetworkBuilder. Son langage de définition est un sous-ensemble de BrainScript. L’ancien analyseur était moins capable, mais aussi plus indulgent. Il existe également d’autres petites différences.

NDLNetworkBuilder est maintenant déconseillé, mais en raison de la similarité, il n’est pas difficile de mettre à niveau vers BrainScriptNetworkBuilder. Vous trouverez ci-dessous un guide sur la conversion NDLNetworkBuilder des descriptions réseau en BrainScriptNetworkBuilder« s ».

Mise à jour de vers NDLNetworkBuilderBrainScriptNetworkBuilder

La conversion d’une définition réseau existante pour le à BrainScriptNetworkBuilder est simple dans la NDLNetworkBuilder plupart des cas. Les modifications main sont la syntaxe environnante. La description du réseau principal elle-même est en grande partie compatible vers le haut et probablement identique ou presque si vous ne tirez pas parti des nouvelles fonctionnalités de langage.

Pour convertir vos descriptions, vous devez basculer le générateur de réseau, adapter la syntaxe externe w.r.t. et éventuellement apporter des adaptations mineures à votre code réseau lui-même.

Étape 1. Basculement du générateur de réseau. Remplacez par NDLNetworkBuilder le bloc correspondant BrainScriptNetworkBuilder dans le fichier de configuration CNTK. Si la description de votre réseau se trouve dans un fichier distinct :

# change from:
NDLNetworkBuilder = [
    ndlMacros = "shared.ndl"   # (if any)
    networkDescription = "yourNetwork.ndl"
]
# ...to:
BrainScriptNetworkBuilder = (new ComputationNetwork {
    include "shared.bs"        # (if any)
    include "yourNetwork.bs"
})

(Le changement de l’extension de nom de fichier n’est pas strictement nécessaire, mais recommandé.)

Si la description de votre réseau se trouve dans le .cntk fichier de configuration lui-même :

# 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")
}

Étape 2. Supprimez load et run bloquez. Avec BrainScriptNetworkBuilder, les définitions macro/fonction et main code sont combinés. Les load blocs et run doivent simplement être supprimés. Par exemple, ceci :

load = ndlMnistMacros
run = DNN
ndlMnistMacros = [
    featDim = 784
    ...
    labels = InputValue(labelDim)
]
DNN = [
    hiddenDim = 200
    ...
    outputNodes = (ol)
]

devient simplement :

featDim = 784
...
labels = InputValue(labelDim)
hiddenDim = 200
...
outputNodes = (ol)

Vous avez peut-être utilisé la run variable pour sélectionner l’une des plusieurs configurations avec une variable externe, par exemple :

NDLNetworkBuilder = [
    run = $whichModel$   # outside parameter selects model, must be either "model1" or "model2"
    model1 = [ ... (MODEL 1 DEFINITION) ]
    model2 = [ ... (MODEL 1 DEFINITION) ]
]

Ce modèle était principalement nécessaire, car NDL n’avait pas d’expressions conditionnelles. Dans BrainScript, cela est désormais écrit avec une if expression :

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$'")
)

Toutefois, souvent, les modèles sélectionnés étant très similaires, une meilleure façon serait de fusionner leurs descriptions et d’utiliser des conditions à l’intérieur uniquement pour les différences. Voici un exemple où un paramètre est utilisé pour choisir entre un LSTM unidirectionnel et un LSTM bidirectionnel :

encoderFunction =
    if useBidirectionalEncoder
    then BS.RNNs.RecurrentBirectionalLSTMPStack
    else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)

Étape 3. Ajuster la description de votre réseau. En ce qui concerne la description réseau (formules) elle-même, BrainScript est largement compatible avec NDL. Voici les différences main :

  • La valeur de retour des macros (fonctions) n’est plus la dernière variable définie dans celles-ci, mais l’ensemble entier de variables. Vous devez sélectionner explicitement la valeur de sortie à la fin. Par exemple :

      # 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
    

    Sans cette modification, la valeur de retour de la fonction correspondrait à l’enregistrement entier, et l’erreur classique que vous obtiendrez est qu’un ComputationNode était attendu à l’endroit où un ComputationNetwork a été trouvé.

  • BrainScript n’autorise pas les fonctions avec des nombres variables de paramètres. Cela est principalement important pour la Parameter() fonction : un paramètre vectoriel ne peut plus être écrit en tant que Parameter(N), il doit maintenant être écrit explicitement comme un tenseur ParameterTensor{N} ou une matrice Parameter(N, 1)à 1 colonne . Sans cette modification, vous obtiendrez une erreur concernant le nombre de paramètres positionnels incompatibles. Cette notation fonctionne également avec NDL. Vous pouvez donc d’abord effectuer cette modification et la tester avec NDL avant la conversion. Il s’agit également d’une bonne occasion de renommer toutes les utilisations du nom LearnableParameter() hérité en ParameterTensor{}.

    Il est également important pour la RowStack() fonction, qui dans BrainScript prend un seul paramètre qui est un tableau d’entrées. Les entrées doivent être séparées par un signe deux-points (:) au lieu d’une virgule, par exemple RowStack (a:b:c) , au lieu de RowStack (a, b, c).

  • Certaines valeurs par défaut ont été mises à jour, principalement le paramètre facultatif imageLayout de Convolution(), les opérations de regroupement et ImageInput(). Pour NDL, celles-ci ont la legacyvaleur par défaut , tandis que la valeur par défaut est cudnn désormais requise pour être compatible avec les primitives de convolution cuDNN. (Tous les exemples de code NDL spécifient explicitement ce paramètre comme cudnn étant déjà spécifié.)

  • L’analyseur de BrainScript est plus restrictif :

    • Les identificateurs respectent désormais la casse. Les fonctions intégrées utilisent PascalCase (par RectifiedLinear()exemple), et les variables intégrées et les noms de paramètres utilisent camelCase (par modelPathexemple, , criterionNodes), comme le font les chaînes d’options (init="fixedValue", tag="criterion"). Notez que pour les noms de paramètres facultatifs, les orthographes incorrectes ne sont pas toujours interceptées comme une erreur. Au lieu de cela, certains paramètres facultatifs mal orthographiés sont simplement ignorés. Par exemple, les définitions « nœuds spéciaux ». Leur orthographe correcte pour ceux-ci est maintenant :

        featureNodes    = ...
        labelNodes      = ...
        criterionNodes  = ...
        evaluationNodes = ...
        outputNodes     = ...
      
    • Les autres noms abrégés ne sont plus autorisés, par Const() exemple, doit être Constant(), tag="eval" doit être tag="evaluation"et evalNodes est maintenant evaluationNodes.

    • Certains noms mal orthographiés ont été corrigés : criteria est maintenant criterion (de même criterionNodes), defaultHiddenActivity est maintenant defaultHiddenActivation.

    • Le = signe n’est plus facultatif pour les définitions de fonction.

    • Bien qu’il soit autorisé à utiliser des crochets pour les blocs ([ ... ]), il est déconseillé. Utilisez des accolades ({ ... }).

    • Les étiquettes d’options doivent être citées en tant que chaînes, par exemple, init="uniform" au lieu de init=uniform. Sans les guillemets, BrainScript échoue avec un message d’erreur indiquant que le symbole uniform est inconnu.

    • Les primitives BrainScript qui créent des paramètres (Input{} et ParameterTensor{}) doivent utiliser des accolades pour leurs arguments (par exemple f = Input{42}). Il s’agit d’une convention qui n’est pas appliquée, mais recommandée à l’avenir.

    Cette syntaxe plus restreinte étant toujours acceptée par NDLNetworkBuilder, nous vous recommandons d’effectuer d’abord ces modifications syntaxiques et de les tester avec NDL, avant de passer à BrainScript.

Étape 4. Supprimez NDLNetworkBuilder les sections « écriture » et « test ». Passez en revue vos sections « écriture » et « test » pour NDLNetworkBuilder les sections, puis supprimez-les. Certains de nos exemples de NDL d’actions ont des sections superflues NDLNetworkBuilder . Ils ne sont pas utilisés et ne devraient pas être là. Si votre configuration est basée sur l’un de ces exemples, vous pouvez également avoir ces sections. Elles ont été ignorées auparavant, mais avec la mise à jour de BrainScript, la définition d’un nouveau réseau dans ces sections a désormais une signification (modification de modèle), de sorte qu’elles ne sont plus ignorées et doivent donc être supprimées.

NDLNetworkBuilder référence (déconseillé)

La syntaxe du déprécié NDLNetworkBuilder est :

NDLNetworkBuilder = [
    networkDescription = "yourNetwork.ndl"
]

Le NDLNetworkBuilder bloc a les paramètres suivants :

  • networkDescription: chemin d’accès du fichier de description réseau. Avec le déprécié NDLNetworkBuilder, il était d’usage d’utiliser l’extension .ndlde fichier . Si aucun paramètre n’est networkDescription spécifié, la description du réseau est supposée être insérée dans le même NDLNetworkBuilder sous-bloc, spécifié avec le run paramètre ci-dessous. Notez qu’un seul chemin d’accès de fichier peut être spécifié via le networkDescription paramètre . Pour charger plusieurs fichiers de macros, utilisez le ndlMacros paramètre .

  • run: bloc du NDL qui sera exécuté. Si un fichier NDL externe est spécifié via le networkDescription paramètre , le run paramètre identifie un bloc dans ce fichier. Ce paramètre remplace tous run les paramètres qui peuvent déjà exister dans le fichier. Si aucun fichier n’est networkDescription spécifié, le run paramètre identifie un bloc dans le fichier de configuration actuel.

  • load: blocs de scripts NDL à charger. Plusieurs blocs peuvent être spécifiés via une liste séparée « : ». Les blocs spécifiés par le load paramètre contiennent généralement des macros à utiliser par le run bloc. Comme pour le run paramètre , le load paramètre identifie les blocs dans un fichier NDL externe et remplace tous load les paramètres qui peuvent déjà exister dans le fichier, si un fichier est spécifié par le networkDescription paramètre . Si aucun fichier n’est networkDescription spécifié, load identifie un bloc dans le fichier de configuration actuel.

  • ndlMacros: chemin d’accès au fichier où les macros NDL peuvent être chargées. Ce paramètre est généralement utilisé pour charger un ensemble par défaut de macros NDL qui peuvent être utilisées par tous les scripts NDL. Plusieurs fichiers NDL, chacun spécifiant différents ensembles de macros, peuvent être chargés en spécifiant une liste séparée « + » de chemins d’accès aux fichiers pour ce ndlMacros paramètre. Pour partager des macros avec d’autres blocs de commande, tels que les blocs MEL (Model Editing Language) de NDL, vous devez les définir au niveau racine du fichier de configuration.

  • randomSeedOffset: valeur de décalage de départ aléatoire non négative lors de l’initialisation des paramètres appris. La valeur par défaut est 0. Cela permet aux utilisateurs d’exécuter des expériences avec différentes initialisations aléatoires.