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"
})
où 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 new
de . 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 NDLNetworkBuilder
BrainScriptNetworkBuilder
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ù unComputationNetwork
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 queParameter(N)
, il doit maintenant être écrit explicitement comme un tenseurParameterTensor{N}
ou une matriceParameter(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 nomLearnableParameter()
hérité enParameterTensor{}
.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 exempleRowStack (a:b:c)
, au lieu deRowStack (a, b, c)
.Certaines valeurs par défaut ont été mises à jour, principalement le paramètre facultatif
imageLayout
deConvolution()
, les opérations de regroupement etImageInput()
. Pour NDL, celles-ci ont lalegacy
valeur par défaut , tandis que la valeur par défaut estcudnn
désormais requise pour être compatible avec les primitives de convolution cuDNN. (Tous les exemples de code NDL spécifient explicitement ce paramètre commecudnn
é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 (parmodelPath
exemple, ,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 êtreConstant()
,tag="eval"
doit êtretag="evaluation"
etevalNodes
est maintenantevaluationNodes
.Certains noms mal orthographiés ont été corrigés :
criteria
est maintenantcriterion
(de mêmecriterionNodes
),defaultHiddenActivity
est maintenantdefaultHiddenActivation
.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 deinit=uniform
. Sans les guillemets, BrainScript échoue avec un message d’erreur indiquant que le symboleuniform
est inconnu.Les primitives BrainScript qui créent des paramètres (
Input{}
etParameterTensor{}
) doivent utiliser des accolades pour leurs arguments (par exemplef = 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.ndl
de fichier . Si aucun paramètre n’estnetworkDescription
spécifié, la description du réseau est supposée être insérée dans le mêmeNDLNetworkBuilder
sous-bloc, spécifié avec lerun
paramètre ci-dessous. Notez qu’un seul chemin d’accès de fichier peut être spécifié via lenetworkDescription
paramètre . Pour charger plusieurs fichiers de macros, utilisez lendlMacros
paramètre .run
: bloc du NDL qui sera exécuté. Si un fichier NDL externe est spécifié via lenetworkDescription
paramètre , lerun
paramètre identifie un bloc dans ce fichier. Ce paramètre remplace tousrun
les paramètres qui peuvent déjà exister dans le fichier. Si aucun fichier n’estnetworkDescription
spécifié, lerun
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 leload
paramètre contiennent généralement des macros à utiliser par lerun
bloc. Comme pour lerun
paramètre , leload
paramètre identifie les blocs dans un fichier NDL externe et remplace tousload
les paramètres qui peuvent déjà exister dans le fichier, si un fichier est spécifié par lenetworkDescription
paramètre . Si aucun fichier n’estnetworkDescription
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 cendlMacros
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 est0
. Cela permet aux utilisateurs d’exécuter des expériences avec différentes initialisations aléatoires.