Sdílet prostřednictvím


Tvůrce sítě v jazyce BrainScript

Vlastní sítě jsou popsány v jazyce pro popis vlastní sítě cntk "BrainScript". Pokud chcete definovat vlastní síť, zahrňte do konfigurace trénování oddíl s názvem BrainScriptNetworkBuilder . Podrobný popis jazyka popisu sítě najdete na stránce Základní koncepty a na odpovídajících dílčích stránkách.

Existují dvě formy použití tvůrce sítě BrainScript, jedna pomocí závorek (...)a zkrácená forma používající složené závorky {...}. Pokud chcete síť popsat v externím souboru, zadejte blok podobný tomuto:

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

kde yourNetwork.bs obsahuje síť popsanou pomocí BrainScriptu. Soubor yourNetwork.bs se nejprve hledá ve stejném adresáři jako konfigurační soubor, a pokud není nalezen, v adresáři spustitelného souboru CNTK. Tady se přijímají absolutní i relativní názvy cest. Například se rozumí soubor umístěný bs/yourNetwork.bs v adresáři bs vedle konfiguračního souboru (nebo případně adresář bs uvnitř spustitelného adresáře CNTK).

Poznámka: Až do verze CNTK 1.6 používal BrainScript hranaté závorky [...] místo složených závorek {...}. Hranaté závorky jsou stále přijímány, ale jsou zastaralé.

Alternativně můžete definovat vloženou síť přímo v konfiguračním souboru. To může zjednodušit konfiguraci, pokud neplánujete sdílet stejný brain script napříč více konfiguracemi. Použijte tento formulář:

BrainScriptNetworkBuilder = {
    # insert network description here
}

Jak vypadá kód BrainScriptu, který jde do hranatých závorek? Pokud to chcete zjistit, přejděte rovnou k části BrainScript Basic Concepts (Základní koncepty brainscriptu).

Nebo zůstaňte na této stránce a přečtěte si o některých méně často potřebných podrobnostech.

Výše {...} uvedený formulář je ve skutečnosti jen zkratkou:

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

A konečně, jako rozšířené použití (...) není formulář omezen na použití new. Místo toho je každý výraz BrainScript, který se vyhodnotí jako objekt , ComputationNetwork povolen uvnitř závorek. Příklad:

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

Jedná se o rozšířené použití, ke kterému také někdy dochází v kontextu úprav modelu.

Další: Základní koncepty brainscriptu.

Starší NDLNetworkBuilder

Ve starších verzích CNTK se tvůrce sítě jmenoval NDLNetworkBuilder. Jazyk jeho definice je podmnožinou BrainScriptu. Starý analyzátor byl méně schopný, ale také více odpouštějící. Existují také další malé rozdíly.

NDLNetworkBuilder je nyní zastaralá, ale vzhledem k podobnosti není obtížné upgradovat na BrainScriptNetworkBuilder. Následuje průvodce převodem NDLNetworkBuilder popisů sítě na BrainScriptNetworkBuilderpopisy sítě.

Aktualizace z NDLNetworkBuilder na BrainScriptNetworkBuilder

Převod existující definice sítě pro NDLNetworkBuilder na BrainScriptNetworkBuilder je ve většině případů jednoduchý. Hlavní změny jsou syntaxe okolí. Samotný popis základní sítě je z velké části směrem nahoru kompatibilní a pravděpodobně identický nebo téměř identický, pokud nevyužíváte nové jazykové funkce.

Chcete-li převést popisy, musíte přepnout tvůrce sítě, přizpůsobit bez vnější syntaxe a případně provést menší úpravy samotného síťového kódu.

Krok 1. Přepnutí tvůrce sítě. NDLNetworkBuilder Nahraďte odpovídajícím BrainScriptNetworkBuilder blokem v konfiguračním souboru CNTK. Pokud je popis sítě v samostatném souboru:

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

(Změna přípony názvu souboru není nezbytně nutná, ale doporučuje se.)

Pokud je popis sítě v samotném konfiguračním .cntk souboru:

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

Krok 2. Odebrat load bloky a run V nástroji BrainScriptNetworkBuilderse kombinují definice maker a funkcí a hlavní kód. Bloky load a run je nutné jednoduše odebrat. Příklad:

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

jednoduše se stane:

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

Proměnnou jste mohli použít run k výběru jedné z více konfigurací s externí proměnnou, například:

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

Tento model byl většinou nezbytný, protože NDL nemělo podmíněné výrazy. V BrainScriptu by to teď bylo napsané pomocí výrazu 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$'")
)

Vybrané modely jsou si ale často velmi podobné, takže lepším způsobem by bylo sloučit jejich popisy a místo toho použít podmínky uvnitř pouze tam, kde se liší. Tady je příklad, kdy se parametr používá k výběru mezi jednosměrným a obousměrným LSTM:

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

Krok 3. Úprava popisu sítě. Pokud jde o samotný popis sítě (vzorce), je BrainScript s NDL kompatibilní z velké části směrem nahoru. Toto jsou hlavní rozdíly:

  • Návratová hodnota maker (funkcí) už není poslední proměnnou definovanou v nich, ale celou sadou proměnných. Výstupní hodnotu musíte explicitně vybrat na konci. Příklad:

      # 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
    

    Bez této změny by návratovou hodnotou funkce byl celý záznam a typickou chybou ComputationNode , která se zobrazí, je, že byl očekáváno, kde ComputationNetwork byl nalezen.

  • BrainScript nepovoluje funkce s proměnnými čísly parametrů. To je důležité především pro Parameter() funkci: Parametr vektoru již nelze zapsat jako Parameter(N), musí být nyní explicitně zapsán jako tenzor ParameterTensor{N} nebo matici Parameter(N, 1)o 1 sloupci . Bez této změny se zobrazí chyba týkající se neshody počtu pozičních parametrů. Tato notace funguje také s NDL, takže tuto změnu můžete nejprve provést a otestovat ji pomocí NDL před převodem. Toto je také dobrá příležitost přejmenovat jakékoli použití starší verze názvu LearnableParameter() na ParameterTensor{}.

    Záleží také na RowStack() funkci , která v BrainScriptu přebírá jediný parametr, což je pole vstupů. Vstupy musí být oddělené dvojtečky (:) místo čárky, například RowStack (a:b:c) místo RowStack (a, b, c).

  • Aktualizovali jsme některé výchozí hodnoty, především volitelný imageLayout parametr Convolution(), operace sdružování a ImageInput(). V případě NDL se jako výchozí hodnota použila legacy, zatímco výchozí hodnota je cudnn teď, která musí být kompatibilní s primitivy konvoluce cuDNN. (Všechny ukázky kódu NDL tento parametr explicitně specifikují jako cudnn již.)

  • Analyzátor BrainScriptu je více omezující:

    • V identifikátorech se teď rozlišují malá a velká písmena. Předdefinované funkce používají PascalCase (např. RectifiedLinear()) a předdefinované proměnné a názvy parametrů používají camelCase (např. modelPath, criterionNodes), stejně jako řetězce možností (init="fixedValue", tag="criterion"). Všimněte si, že u názvů volitelných parametrů není nesprávný pravopis vždy zachycen jako chyba. Místo toho se některé nesprávně napsané volitelné parametry prostě ignorují. Příkladem jsou definice speciálních uzlů. Jejich správná kontrola pravopisu je teď:

        featureNodes    = ...
        labelNodes      = ...
        criterionNodes  = ...
        evaluationNodes = ...
        outputNodes     = ...
      
    • Zkrácené alternativní názvy již nejsou povoleny, například Const() by měly být , tag="eval" měly by Constant()být tag="evaluation"a evalNodes jsou teď evaluationNodes.

    • Byla opravena některá špatně napsaná jména: criteria is now criterion (podobně), criterionNodesdefaultHiddenActivity je teď defaultHiddenActivation.

    • Znaménko = už není volitelné pro definice funkcí.

    • I když je povoleno používat hranaté závorky pro bloky ([ ... ]), je zastaralá. Používejte složené závorky ({ ... }).

    • Popisky možností musí být uvozovány jako řetězce, například init="uniform" místo init=uniform. Bez uvozovek BrainScript selže s chybovou zprávou, že symbol uniform je neznámý.

    • Primitiva BrainScriptu, která vytvářejí parametry (Input{} a ParameterTensor{}), by měla pro argumenty používat složené závorky (např. f = Input{42}). Jedná se o konvenci, která se nevynucuje, ale doporučuje se do budoucna.

    Tato omezenější syntaxe je stále přijímána NDLNetworkBuilder, proto doporučujeme nejprve provést tyto syntaktické změny a otestovat je pomocí NDL, než se skutečně změní na BrainScript.

Krok 4: Odeberte NDLNetworkBuilder z oddílů "write" a "test". Přečtěte si prosím oddíly "write" a "test" a NDLNetworkBuilder odeberte je. Některé z našich ukázkových příkladů NDL mají nadbytečné NDLNetworkBuilder oddíly. Nepoužívají se a neměly by tam být. Pokud je vaše konfigurace založená na jednom z těchto příkladů, můžete mít i takové oddíly. Dřív se ignorovaly, ale po aktualizaci BrainScriptu má teď definování nové sítě v těchto oddílech význam (úpravy modelu), takže se už nebudou ignorovat, a proto by se měly odebrat.

NDLNetworkBuilder reference (zastaralé)

Syntaxe zastaralého NDLNetworkBuilder objektu je:

NDLNetworkBuilder = [
    networkDescription = "yourNetwork.ndl"
]

Blok NDLNetworkBuilder má následující parametry:

  • networkDescription: cesta k souboru popisu sítě. U zastaralého NDLNetworkBuildersouboru bylo obvyklé používat příponu .ndlsouboru . Pokud není zadaný žádný networkDescription parametr, předpokládá se, že popis sítě je vložený ve stejném NDLNetworkBuilder dílčím bloku zadaném pomocí parametru run níže. Všimněte si, že prostřednictvím parametru networkDescription může být zadána pouze jedna cesta k souboru. Pokud chcete načíst více souborů maker, použijte ndlMacros parametr .

  • run: blok NDL, který se spustí. Pokud je externí soubor NDL zadán prostřednictvím parametru networkDescription , run parametr identifikuje blok v tomto souboru. Tento parametr přepíše všechny run parametry, které již mohou v souboru existovat. Pokud není zadán žádný networkDescription soubor, run parametr identifikuje blok v aktuálním konfiguračním souboru.

  • load: bloky skriptů NDL, které se mají načíst. Více bloků je možné zadat prostřednictvím odděleného seznamu ":". Bloky určené parametrem load obvykle obsahují makra pro použití v run bloku. run Podobně jako parametr load identifikuje bloky v externím souboru NDL a přepíše všechny load parametry, které už v souboru existují, pokud je soubor zadaný parametrem networkDescription . Pokud není zadán žádný networkDescription soubor, load identifikuje blok v aktuálním konfiguračním souboru.

  • ndlMacros: Cesta k souboru, kam se můžou načíst makra NDL. Tento parametr se obvykle používá k načtení výchozí sady maker NDL, které můžou používat všechny skripty NDL. Více souborů NDL, z nichž každý určuje různé sady maker, lze načíst zadáním seznamu "+" oddělených cest k souborům pro tento ndlMacros parametr. Chcete-li sdílet makra s jinými bloky příkazů, jako jsou bloky jazyka pro úpravy modelu (MEL) NDL, měli byste je definovat na kořenové úrovni konfiguračního souboru.

  • randomSeedOffset: nezáporná hodnota náhodného počátečního posunu při inicializaci učitelných parametrů. Výchozí hodnota je 0. To umožňuje uživatelům spouštět experimenty s různými náhodnými inicializacemi.