Generatore di reti BrainScript
Le reti personalizzate sono descritte nel linguaggio di descrizione della rete personalizzato di CNTK "BrainScript". Per definire una rete personalizzata, includere una sezione denominata BrainScriptNetworkBuilder
nella configurazione di training. La descrizione dettagliata del linguaggio di descrizione di rete è disponibile nella pagina Concetti di base e nelle pagine secondarie corrispondenti.
Esistono due forme di utilizzo del generatore di rete BrainScript, una che usa parentesi (...)
e una forma a mano breve usando parentesi {...}
graffe. Per descrivere la rete in un file esterno, specificare un blocco simile al seguente:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "yourNetwork.bs"
})
dove yourNetwork.bs
contiene la rete descritta usando BrainScript. Il file yourNetwork.bs
viene cercato per primo nella stessa directory del file di configurazione e, se non viene trovato, nella directory dell'eseguibile CNTK. I nomi dei percorsi assoluti e relativi sono accettati qui. Ad esempio, bs/yourNetwork.bs
significa un file che si trova in una directory bs
accanto al file di configurazione (o in alternativa una directory bs
all'interno della directory eseguibile CNTK).
Nota: fino a CNTK 1.6, BrainScript usa parentesi [...]
quadre anziché parentesi graffe {...}
. Le parentesi quadre sono ancora accettate ma deprecate.
In alternativa, è possibile definire la rete inline, direttamente all'interno del file di configurazione. In questo modo è possibile semplificare la configurazione se non si prevede di condividere lo stesso script cerebrale tra più configurazioni. Usare questo modulo:
BrainScriptNetworkBuilder = {
# insert network description here
}
Quindi, cosa sembra che il codice BrainScript si inserisca tra parentesi quadre? Per scoprire, passare direttamente a BrainScript Basic Concepts (Concetti di base di BrainScript).
Oppure resta in questa pagina e leggi alcuni dettagli meno frequentemente necessari per te.
Il {...}
modulo precedente è in realtà solo una breve mano per questo:
BrainScriptNetworkBuilder = (new ComputationNetwork {
# insert network description here
})
Infine, come uso avanzato, il (...)
modulo non è limitato all'uso new
di . Invece, qualsiasi espressione BrainScript che restituisce un oggetto di ComputationNetwork
è consentita all'interno delle parentesi. Ad esempio:
BrainScriptNetworkBuilder = ({
include "myNetworks.bs"
network = CreateMyNetworkOfType42()
}.network)
Si tratta di un uso avanzato che talvolta si verifica anche nel contesto della modifica del modello.
Avanti: Concetti di base di BrainScript.
Eredità NDLNetworkBuilder
Nelle versioni precedenti di CNTK, il generatore di rete è stato chiamato NDLNetworkBuilder
. Il linguaggio di definizione è un subset di BrainScript. Il vecchio parser era meno capace, ma anche più forgiving. Ci sono anche altre piccole differenze.
NDLNetworkBuilder
è ora deprecato, ma a causa della somiglianza, non è difficile eseguire l'aggiornamento a BrainScriptNetworkBuilder
. Di seguito è riportata una guida su come convertire NDLNetworkBuilder
le descrizioni di rete in BrainScriptNetworkBuilder
's.
Aggiornamento da NDLNetworkBuilder
a BrainScriptNetworkBuilder
La conversione di una definizione di rete esistente per in NDLNetworkBuilder
BrainScriptNetworkBuilder
è semplice nella maggior parte dei casi. Le modifiche principali sono la sintassi circostante. La descrizione della rete principale è in gran parte compatibile verso l'alto e probabilmente identica o quasi identica se non si sfruttano le nuove funzionalità del linguaggio.
Per convertire le descrizioni, è necessario cambiare il generatore di rete, adattare la sintassi esterna w.r.t ed eventualmente apportare adattamenti secondari al codice di rete stesso.
Passaggio 1. Cambio del generatore di rete. Sostituire con NDLNetworkBuilder
il blocco corrispondente BrainScriptNetworkBuilder
nel file di configurazione CNTK. Se la descrizione di rete si trova in un file separato:
# change from:
NDLNetworkBuilder = [
ndlMacros = "shared.ndl" # (if any)
networkDescription = "yourNetwork.ndl"
]
# ...to:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "shared.bs" # (if any)
include "yourNetwork.bs"
})
La modifica dell'estensione del nome file non è strettamente necessaria, ma consigliata.
Se la descrizione di rete si trova nel .cntk
file di configurazione stesso:
# 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")
}
Passaggio 2. Rimuovere load
e run
bloccare. Con BrainScriptNetworkBuilder
, le definizioni di macro/funzione e il codice principale vengono combinati. I load
blocchi e run
devono essere semplicemente rimossi. Ad esempio:
load = ndlMnistMacros
run = DNN
ndlMnistMacros = [
featDim = 784
...
labels = InputValue(labelDim)
]
DNN = [
hiddenDim = 200
...
outputNodes = (ol)
]
diventa semplicemente:
featDim = 784
...
labels = InputValue(labelDim)
hiddenDim = 200
...
outputNodes = (ol)
È possibile che sia stata usata la run
variabile per selezionare una delle più configurazioni con una variabile esterna, ad esempio:
NDLNetworkBuilder = [
run = $whichModel$ # outside parameter selects model, must be either "model1" or "model2"
model1 = [ ... (MODEL 1 DEFINITION) ]
model2 = [ ... (MODEL 1 DEFINITION) ]
]
Questo modello era per lo più necessario perché NDL non disponeva di espressioni condizionali. In BrainScript, questo sarebbe stato scritto con un'espressione 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$'")
)
Tuttavia, spesso, i modelli selezionati sono molto simili, quindi un modo migliore sarebbe unire le relative descrizioni e usare invece le condizionali all'interno solo per dove differiscono. Ecco un esempio in cui viene usato un parametro per scegliere tra un LSTM unidirezionale e un LSTM bidirezionale:
encoderFunction =
if useBidirectionalEncoder
then BS.RNNs.RecurrentBirectionalLSTMPStack
else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)
Passaggio 3. Modificare la descrizione della rete. Per quanto riguarda la descrizione di rete (formule), BrainScript è in gran parte compatibile con NDL. Ecco le principali differenze:
Il valore restituito delle macro (funzioni) non è più l'ultima variabile definita, ma l'intero set di variabili. È necessario selezionare in modo esplicito il valore di output alla fine. Ad esempio:
# 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
Senza questa modifica, il valore restituito dalla funzione sarà l'intero record e l'errore tipico che si otterrà è che è stato previsto dove
ComputationNode
è stato trovato un oggettoComputationNetwork
.BrainScript non consente funzioni con numeri variabili di parametri. Questo aspetto è importante principalmente per la
Parameter()
funzione: un parametro vector non può più essere scritto comeParameter(N)
, ora deve essere scritto in modo esplicito come tensoreParameterTensor{N}
o una matriceParameter(N, 1)
a 1 colonna . Senza questa modifica, verrà visualizzato un errore relativo alla mancata corrispondenza del numero di parametri posizionali. Questa notazione funziona anche con NDL, quindi è possibile apportare questa modifica per prima e testarla con NDL prima della conversione. Si tratta anche di una buona opportunità per rinominare qualsiasi uso del nomeLearnableParameter()
legacy inParameterTensor{}
.È importante anche per la
RowStack()
funzione , che in BrainScript accetta un singolo parametro che è una matrice di input. Gli input devono essere separati da due punti (:
) anziché da una virgola, ad esempioRowStack (a:b:c)
anzichéRowStack (a, b, c)
da .Alcune impostazioni predefinite sono state aggiornate, principalmente il parametro facoltativo
imageLayout
diConvolution()
, le operazioni di pooling eImageInput()
. Per NDL, queste impostazioni predefinite sono , mentre ora è necessario che l'impostazione predefinitalegacy
cudnn
sia compatibile con le primitive di convoluzione cuDNN. Tutti gli esempi di codice NDL specificano in modo esplicito questo parametro comecudnn
già.Il parser di BrainScript è più restrittivo:
Gli identificatori fanno ora distinzione tra maiuscole e minuscole. Le funzioni predefinite usano PascalCase (ad esempio
RectifiedLinear()
) e le variabili predefinite e i nomi dei parametri usano camelCase (ad esempiomodelPath
,criterionNodes
), come le stringhe di opzione (init="fixedValue"
,tag="criterion"
). Si noti che per i nomi dei parametri facoltativi, le ortografie non corrette non vengono sempre rilevate come errore. Alcuni parametri facoltativi digitati in modo non corretto vengono invece ignorati. Un esempio sono le definizioni "nodi speciali". L'ortografia corretta per quelle è ora:featureNodes = ... labelNodes = ... criterionNodes = ... evaluationNodes = ... outputNodes = ...
I nomi alternativi abbreviati non sono più consentiti, ad esempio
Const()
dovrebbe esseretag="evaluation"
Constant()
,tag="eval"
eevalNodes
oraevaluationNodes
è .Alcuni nomi digitati in modo non corretto sono stati corretti:
criteria
è oracriterion
(analogamentecriterionNodes
),defaultHiddenActivity
è oradefaultHiddenActivation
.Il
=
segno non è più facoltativo per le definizioni di funzione.Anche se è consentito usare parentesi quadre per i blocchi (
[ ... ]
), è deprecato. Usare parentesi graffe ({ ... }
).Le etichette di opzione devono essere racchiuse tra virgolette come stringhe, ad esempio
init="uniform"
anzichéinit=uniform
. Senza le virgolette, BrainScript avrà esito negativo con un messaggio di errore che indica che il simbolouniform
è sconosciuto.Le primitive BrainScript che creano parametri (
Input{}
eParameterTensor{}
) devono usare le parentesi graffe per i relativi argomenti ( ad esempiof = Input{42}
). Si tratta di una convenzione che non viene applicata ma consigliata in futuro.
Questa sintassi più limitata è ancora accettata da
NDLNetworkBuilder
, quindi è consigliabile prima apportare queste modifiche sintattiche e testarle con NDL, prima di passare effettivamente a BrainScript.
Passaggio 4. Rimuovere NDLNetworkBuilder
da sezioni "write" e "test". Esaminare le sezioni "write" e "test" per NDLNetworkBuilder
le sezioni e rimuoverle. Alcuni dei nostri esempi NDL azionari hanno sezioni estranee NDLNetworkBuilder
. Non vengono usati e non devono essere presenti. Se la configurazione è basata su uno di questi esempi, potrebbero essere presenti anche sezioni di questo tipo. Essi erano stati ignorati, ma con l'aggiornamento BrainScript, definendo una nuova rete in queste sezioni ora ha un significato (modifica del modello), quindi non vengono più ignorati e pertanto devono essere rimossi.
NDLNetworkBuilder
riferimento (deprecato)
La sintassi dell'oggetto deprecato NDLNetworkBuilder
è:
NDLNetworkBuilder = [
networkDescription = "yourNetwork.ndl"
]
Il NDLNetworkBuilder
blocco ha i parametri seguenti:
networkDescription
: percorso del file di descrizione di rete. Con l'oggetto deprecatoNDLNetworkBuilder
, è stato consuetudine usare l'estensione.ndl
di file . Se nonnetworkDescription
è specificato alcun parametro, si presuppone che la descrizione della rete venga inlinedata nello stessoNDLNetworkBuilder
blocco secondario, specificata con ilrun
parametro seguente. Si noti che è possibile specificare un solo percorso file tramite ilnetworkDescription
parametro . Per caricare più file di macro, usare ilndlMacros
parametro .run
: blocco del file NDL che verrà eseguito. Se viene specificato un file NDL esterno tramite ilnetworkDescription
parametro, ilrun
parametro identifica un blocco nel file. Questo parametro esegue l'override di tuttirun
i parametri che potrebbero già esistere nel file. Se non viene specificato alcunnetworkDescription
file, ilrun
parametro identifica un blocco nel file di configurazione corrente.load
: blocchi di script NDL da caricare. È possibile specificare più blocchi tramite un elenco separato ":". I blocchi specificati dalload
parametro in genere contengono macro da usare dalrun
blocco. Analogamente alrun
parametro, ilload
parametro identifica i blocchi in un file NDL esterno ed esegue l'overridenetworkDescription
di tuttiload
i parametri che potrebbero già esistere nel file, se un file viene specificato dal parametro . Se nonnetworkDescription
viene specificato alcun file,load
identifica un blocco nel file di configurazione corrente.ndlMacros
: percorso del file in cui possono essere caricate le macro NDL. Questo parametro viene in genere usato per caricare un set predefinito di macro NDL che possono essere usate da tutti gli script NDL. È possibile caricare più file NDL, ognuno dei quali specifica diversi set di macro, specificando un elenco separato "+" di percorsi file per questondlMacros
parametro. Per condividere macro con altri blocchi di comando, ad esempio i blocchi MEL (Model Editing Language) di NDL, è necessario definirlo a livello radice del file di configurazione.randomSeedOffset
: valore di offset di inizializzazione casuale non negativo per inizializzare i parametri appresi. Il valore predefinito è0
. Ciò consente agli utenti di eseguire esperimenti con inizializzazione casuale diversa.