BrainScript Network Builder
Anpassade nätverk beskrivs i CNTK:s anpassade nätverksbeskrivningsspråk "BrainScript". Om du vill definiera ett anpassat nätverk inkluderar du ett avsnitt med namnet BrainScriptNetworkBuilder
i din träningskonfiguration. Detaljerad beskrivning av nätverksbeskrivningsspråket finns på sidan Grundläggande begrepp och motsvarande undersidor.
Det finns två former av att använda BrainScript-nätverksverktyget, en med parenteser (...)
och ett kortformulär med klammerparenteser {...}
. Om du vill beskriva nätverket i en extern fil anger du ett block som liknar detta:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "yourNetwork.bs"
})
där yourNetwork.bs
innehåller nätverket som beskrivs med Hjälp av BrainScript. Filen yourNetwork.bs
letar först efter i samma katalog som konfigurationsfilen, och om den inte hittas, i katalogen för den körbara CNTK-filen. Både absoluta och relativa sökvägar accepteras här. T.ex. bs/yourNetwork.bs
innebär en fil som finns i en katalog bs
bredvid din konfigurationsfil (eller alternativt en katalog bs
i den körbara CNTK-katalogen).
Obs! Fram till CNTK 1.6 använde BrainScript hakparenteser [...]
i stället för klammerparenteser {...}
. Hakparenteser accepteras fortfarande men är inaktuella.
Du kan också definiera nätverket infogat direkt i konfigurationsfilen. Detta kan förenkla konfigurationen om du inte planerar att dela samma hjärnskript i flera konfigurationer. Använd det här formuläret:
BrainScriptNetworkBuilder = {
# insert network description here
}
Så hur ser BrainScript-koden ut så där inom hakparenteserna? Du kan ta reda på det genom att gå direkt till Grundläggande begrepp i BrainScript.
Eller stanna kvar på den här sidan och läs vidare om några mindre ofta nödvändiga detaljer för dig.
Formuläret {...}
ovan är egentligen bara en kort hand för detta:
BrainScriptNetworkBuilder = (new ComputationNetwork {
# insert network description here
})
Slutligen, som en avancerad användning, (...)
är formuläret inte begränsat till att använda new
. I stället tillåts alla BrainScript-uttryck som utvärderas till ett objekt i ComputationNetwork
inom parenteserna. Ett exempel:
BrainScriptNetworkBuilder = ({
include "myNetworks.bs"
network = CreateMyNetworkOfType42()
}.network)
Detta är en avancerad användning som ibland även sker i samband med modellredigering.
Nästa: Grundläggande begrepp i BrainScript.
Legacy NDLNetworkBuilder
I äldre versioner av CNTK kallades NDLNetworkBuilder
nätverksverktyget . Dess definitionsspråk är en delmängd av BrainScript. Den gamla parsern var mindre kapabel, men också mer förlåtande. Det finns också andra små skillnader.
NDLNetworkBuilder
är nu inaktuell, men på grund av likheten är det inte svårt att uppgradera till BrainScriptNetworkBuilder
. Följande är en guide om hur du konverterar NDLNetworkBuilder
nätverksbeskrivningar till BrainScriptNetworkBuilder
's.
Uppdatera från NDLNetworkBuilder
till BrainScriptNetworkBuilder
Det är i de flesta fall enkelt att konvertera en befintlig nätverksdefinition för NDLNetworkBuilder
till BrainScriptNetworkBuilder
. De viktigaste ändringarna är den omgivande syntaxen. Själva beskrivningen av kärnnätverket är i stort sett uppåtkompatibel och sannolikt identisk eller nästan identisk om du inte drar nytta av de nya språkfunktionerna.
Om du vill konvertera dina beskrivningar måste du växla nätverksbyggaren, anpassa den yttre syntaxen för w.r.t. och eventuellt göra mindre anpassningar av själva nätverkskoden.
Steg 1. Växla nätverksverktyget. NDLNetworkBuilder
Ersätt med motsvarande BrainScriptNetworkBuilder
block i CNTK-konfigurationsfilen. Om nätverksbeskrivningen finns i en separat fil:
# change from:
NDLNetworkBuilder = [
ndlMacros = "shared.ndl" # (if any)
networkDescription = "yourNetwork.ndl"
]
# ...to:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "shared.bs" # (if any)
include "yourNetwork.bs"
})
(Ändringen av filnamnstillägget är inte absolut nödvändigt men rekommenderas.)
Om nätverksbeskrivningen finns i själva konfigurationsfilen .cntk
:
# 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")
}
Steg 2. Ta bort load
och run
block. Med BrainScriptNetworkBuilder
kombineras makro-/funktionsdefinitioner och huvudkod. Blocken load
och run
måste helt enkelt tas bort. Det här kan till exempel vara:
load = ndlMnistMacros
run = DNN
ndlMnistMacros = [
featDim = 784
...
labels = InputValue(labelDim)
]
DNN = [
hiddenDim = 200
...
outputNodes = (ol)
]
blir helt enkelt:
featDim = 784
...
labels = InputValue(labelDim)
hiddenDim = 200
...
outputNodes = (ol)
Du kan ha använt variabeln run
för att välja en av flera konfigurationer med en extern variabel, t.ex.
NDLNetworkBuilder = [
run = $whichModel$ # outside parameter selects model, must be either "model1" or "model2"
model1 = [ ... (MODEL 1 DEFINITION) ]
model2 = [ ... (MODEL 1 DEFINITION) ]
]
Det här mönstret var mest nödvändigt eftersom NDL inte hade villkorsuttryck. I BrainScript skulle detta nu skrivas med ett if
uttryck:
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$'")
)
Men ofta är de valda modellerna mycket lika, så ett bättre sätt är att sammanfoga deras beskrivningar och i stället använda villkor inuti endast för var de skiljer sig åt. Här är ett exempel där en parameter används för att välja mellan en enkelriktad och dubbelriktad LSTM:
encoderFunction =
if useBidirectionalEncoder
then BS.RNNs.RecurrentBirectionalLSTMPStack
else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)
Steg 3. Justera nätverksbeskrivningen. När det gäller själva nätverksbeskrivningen (formler) är BrainScript i stort sett uppåt kompatibelt med NDL. Det här är de största skillnaderna:
Returvärdet för makron (funktioner) är inte längre den sista variabeln som definierats i dem, utan hela uppsättningen variabler. Du måste uttryckligen välja utdatavärdet i slutet. Ett exempel:
# 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
Utan den här ändringen skulle funktionens returvärde vara hela posten, och det vanliga felet du får är att en
ComputationNode
förväntades där enComputationNetwork
hittades.BrainScript tillåter inte funktioner med variabelt antal parametrar. Detta gäller främst för
Parameter()
funktionen: En vektorparameter kan inte längre skrivas somParameter(N)
, den måste nu uttryckligen skrivas som en tensorParameterTensor{N}
eller en matris med 1 kolumnerParameter(N, 1)
. Utan den här ändringen får du ett felmeddelande om att antalet positionsparametrar inte matchar. Den här notationen fungerar också med NDL, så du kan göra den här ändringen först och testa den med NDL innan du konverterar. Det här är också ett bra tillfälle att byta namn på alla användningsområden för det äldre namnetLearnableParameter()
tillParameterTensor{}
.Det är också viktigt för
RowStack()
funktionen, som i BrainScript tar en enda parameter som är en matris med indata. Indata måste avgränsas med ett kolon (:
) i stället för ett kommatecken, t.ex.RowStack (a:b:c)
i stället förRowStack (a, b, c)
.Vissa standardvärden har uppdaterats, främst den valfria
imageLayout
parameternConvolution()
för , poolåtgärderna ochImageInput()
. För NDL har dessa standardvärdetlegacy
, medan nu ärcudnn
standardvärdet som måste vara kompatibelt med cuDNN-faltningsprimitiver. (Alla NDL-kodexempel anger uttryckligen den här parametern somcudnn
redan.)BrainScript-parsern är mer restriktiv:
Identifierare är nu skiftlägeskänsliga. Inbyggda funktioner använder PascalCase (t.ex.
RectifiedLinear()
) och inbyggda variabler och parameternamn använder camelCase (t.ex.modelPath
,criterionNodes
), liksom alternativsträngar (init="fixedValue"
,tag="criterion"
). Observera att felaktiga stavningar inte alltid fångas upp som ett fel för namn på valfria parametrar. I stället ignoreras vissa felaktigt stavade valfria parametrar. Ett exempel är definitionerna "särskilda noder". Deras rätta stavning för dessa är nu:featureNodes = ... labelNodes = ... criterionNodes = ... evaluationNodes = ... outputNodes = ...
Förkortade alternativa namn är inte längre tillåtna, till exempel
Const()
ska varaConstant()
,tag="eval"
ska varatag="evaluation"
ochevalNodes
är nuevaluationNodes
.Några felstavade namn korrigerades: är nu
criterion
(på samma sättcriterionNodes
),defaultHiddenActivity
är nudefaultHiddenActivation
.criteria
Tecknet
=
är inte längre valfritt för funktionsdefinitioner.Även om det är tillåtet att använda hakparenteser för block (
[ ... ]
), är det inaktuellt. Använd klammerparenteser ({ ... }
).Alternativetiketter måste anges som strängar, t.ex.
init="uniform"
i ställetinit=uniform
för . Utan citattecken misslyckas BrainScript med ett felmeddelande om att symbolenuniform
är okänd.BrainScript-primitiverna som skapar parametrarna (
Input{}
ochParameterTensor{}
) bör använda klammerparenteser för sina argument (t.ex.f = Input{42}
). Detta är en konvention som inte tillämpas men som rekommenderas framöver.
Den här mer begränsade syntaxen accepteras fortfarande av
NDLNetworkBuilder
, så vi rekommenderar att du först gör dessa syntaktiska ändringar och testar dem med NDL innan du faktiskt ändrar till BrainScript.
Steg 4. Ta bort NDLNetworkBuilder
från avsnitten "write" och "test". Läs avsnitten "skriva" och "testa" för NDLNetworkBuilder
avsnitt och ta bort dem. Några av våra NDL-exempel för lager har överflödiga NDLNetworkBuilder
avsnitt. De används inte och bör inte finnas där. Om konfigurationen baseras på något av dessa exempel kan du även ha sådana avsnitt. De brukade ignoreras, men med BrainScript-uppdateringen har definitionen av ett nytt nätverk i dessa avsnitt nu en betydelse (modellredigering), så de ignoreras inte längre och bör därför tas bort.
NDLNetworkBuilder
referens (inaktuell)
Syntaxen för den inaktuella NDLNetworkBuilder
är:
NDLNetworkBuilder = [
networkDescription = "yourNetwork.ndl"
]
Blocket NDLNetworkBuilder
har följande parametrar:
networkDescription
: sökvägen till nätverksbeskrivningsfilen. Med det inaktuellaNDLNetworkBuilder
var det vanligt att använda filnamnstillägget.ndl
. Om det inte finns någonnetworkDescription
angiven parameter antas nätverksbeskrivningen vara inlindad i sammaNDLNetworkBuilder
underblock, som anges med parameternrun
nedan. Observera att endast en filsökväg kan anges via parameternnetworkDescription
. Om du vill läsa in flera filer med makron använder du parameternndlMacros
.run
: blocket för den NDL som ska köras. Om en extern NDL-fil anges via parameternnetworkDescription
identifierar parameternrun
ett block i filen. Den här parametern åsidosätter allarun
parametrar som redan finns i filen. Om ingennetworkDescription
fil anges identifierar parameternrun
ett block i den aktuella konfigurationsfilen.load
: blocken i NDL-skript som ska läsas in. Flera block kan anges via en ":" avgränsad lista. De block som anges av parameternload
innehåller vanligtvis makron som ska användas avrun
blocket. Precis som parameternrun
identifierar parameternload
block i en extern NDL-fil och åsidosätter allaload
parametrar som redan finns i filen, om en fil anges av parameternnetworkDescription
. Om ingennetworkDescription
fil angesload
identifierar du ett block i den aktuella konfigurationsfilen.ndlMacros
: filsökvägen där NDL-makron kan läsas in. Den här parametern används vanligtvis för att läsa in en standarduppsättning NDL-makron som kan användas av alla NDL-skript. Flera NDL-filer, som var och en anger olika uppsättningar makron, kan läsas in genom att ange en "+" avgränsad lista över filsökvägar för den härndlMacros
parametern. Om du vill dela makron med andra kommandoblock, till exempel NDL:s MEL-block (Model Editing Language), bör du definiera det på rotnivå i konfigurationsfilen.randomSeedOffset
: ett icke-negativt förskjutningsvärde för slumpmässigt startvärde vid initiering av de inlärbara parametrarna. Standardvärdet är0
. På så sätt kan användare köra experiment med olika slumpmässig initiering.