BrainScript Network Builder
Sieci niestandardowe są opisane w niestandardowym języku opisu sieci CNTK "BrainScript". Aby zdefiniować sieć niestandardową, dołącz sekcję o nazwie BrainScriptNetworkBuilder
w konfiguracji trenowania. Szczegółowy opis języka opisu sieci można znaleźć na stronie Podstawowe pojęcia i odpowiednie podstrony.
Istnieją dwie formy korzystania z konstruktora sieci BrainScript, jeden z nawiasami (...)
i krótką formę przy użyciu nawiasów klamrowych {...}
. Aby opisać sieć w pliku zewnętrznym, określ blok podobny do następującego:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "yourNetwork.bs"
})
gdzie yourNetwork.bs
zawiera sieć opisaną przy użyciu języka BrainScript. Plik yourNetwork.bs
jest szukany jako pierwszy w tym samym katalogu co plik konfiguracji, a jeśli nie zostanie znaleziony, w katalogu pliku wykonywalnego CNTK. Nazwy ścieżek bezwzględnych i względnych są akceptowane tutaj. Np. bs/yourNetwork.bs
oznacza plik znajdujący się w katalogu bs
obok pliku konfiguracji (lub alternatywnie katalog wewnątrz katalogu bs
wykonywalnego CNTK).
Uwaga: do wersji CNTK 1.6 język BrainScript używał nawiasów klamrowych zamiast nawiasów [...]
klamrowych {...}
. Nawiasy są nadal akceptowane, ale przestarzałe.
Alternatywnie możesz zdefiniować sieć w tekście bezpośrednio w pliku konfiguracji. Może to uprościć konfigurację, jeśli nie planujesz współużytkowania tego samego skryptu mózgu w wielu konfiguracjach. Użyj tego formularza:
BrainScriptNetworkBuilder = {
# insert network description here
}
Więc jak wygląda kod BrainScript, który przechodzi do nawiasów? Aby dowiedzieć się, przejdź bezpośrednio do podstaw brainscript podstawowych pojęć.
Możesz też pozostać na tej stronie i przeczytać na temat niektórych rzadziej potrzebnych szczegółów.
Powyższy {...}
formularz jest naprawdę tylko krótką ręką dla tego:
BrainScriptNetworkBuilder = (new ComputationNetwork {
# insert network description here
})
Na koniec, jako zaawansowane użycie, (...)
formularz nie jest ograniczony do użycia new
. Zamiast tego każde wyrażenie BrainScript, które oblicza obiekt, ComputationNetwork
jest dozwolone wewnątrz nawiasów. Na przykład:
BrainScriptNetworkBuilder = ({
include "myNetworks.bs"
network = CreateMyNetworkOfType42()
}.network)
Jest to zaawansowane użycie, które czasami występuje również w kontekście edycji modelu.
Dalej: Podstawowe pojęcia dotyczące języka BrainScript.
Starszych NDLNetworkBuilder
W starszych wersjach CNTK konstruktor sieci został nazwany NDLNetworkBuilder
. Jego język definicji jest podzbiorem BrainScript. Stary analizator był mniej zdolny, ale również bardziej forgiving. Istnieją również inne małe różnice.
NDLNetworkBuilder
jest teraz przestarzały, ale ze względu na podobieństwo nie jest trudno uaktualnić do BrainScriptNetworkBuilder
klasy . Poniżej przedstawiono przewodnik dotyczący konwertowania NDLNetworkBuilder
opisów sieci na BrainScriptNetworkBuilder
's).
Aktualizowanie z NDLNetworkBuilder
do BrainScriptNetworkBuilder
Konwertowanie istniejącej definicji sieci dla elementu NDLNetworkBuilder
to BrainScriptNetworkBuilder
jest proste w większości przypadków. Główne zmiany to otaczająca składnia. Sam opis sieci podstawowej jest w dużej mierze zgodny w górę i prawdopodobnie identyczny lub niemal identyczny, jeśli nie korzystasz z nowych funkcji językowych.
Aby przekonwertować opisy, należy przełączyć konstruktora sieci, dostosować składnię zewnętrzną w.r.t. i ewentualnie wprowadzić drobne dostosowania do samego kodu sieciowego.
Krok 1. Przełączanie konstruktora sieci. NDLNetworkBuilder
Zastąp element odpowiednim BrainScriptNetworkBuilder
blokiem w pliku konfiguracji CNTK. Jeśli opis sieci znajduje się w osobnym pliku:
# change from:
NDLNetworkBuilder = [
ndlMacros = "shared.ndl" # (if any)
networkDescription = "yourNetwork.ndl"
]
# ...to:
BrainScriptNetworkBuilder = (new ComputationNetwork {
include "shared.bs" # (if any)
include "yourNetwork.bs"
})
(Zmiana rozszerzenia nazwy pliku nie jest ściśle konieczna, ale zalecana).
Jeśli opis sieci znajduje się w .cntk
samym pliku konfiguracji:
# 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. Usuń load
i run
bloki. W programie BrainScriptNetworkBuilder
są łączone definicje makr/funkcji i kod główny. Bloki load
i run
muszą zostać po prostu usunięte. Na przykład:
load = ndlMnistMacros
run = DNN
ndlMnistMacros = [
featDim = 784
...
labels = InputValue(labelDim)
]
DNN = [
hiddenDim = 200
...
outputNodes = (ol)
]
po prostu staje się:
featDim = 784
...
labels = InputValue(labelDim)
hiddenDim = 200
...
outputNodes = (ol)
Być może użyto zmiennej run
do wybrania jednej z wielu konfiguracji ze zmienną zewnętrzną, np.:
NDLNetworkBuilder = [
run = $whichModel$ # outside parameter selects model, must be either "model1" or "model2"
model1 = [ ... (MODEL 1 DEFINITION) ]
model2 = [ ... (MODEL 1 DEFINITION) ]
]
Ten wzorzec był głównie niezbędny, ponieważ NDL nie ma wyrażeń warunkowych. W języku BrainScript zostanie to teraz napisane za if
pomocą wyrażenia:
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$'")
)
Jednak często wybrane modele są bardzo podobne, więc lepszym sposobem byłoby scalenie ich opisów i zamiast tego użycie warunkowych w obrębie tylko tam, gdzie się różnią. Oto przykład, w którym parametr jest używany do wyboru między jednokierunkowym i dwukierunkowym LSTM:
encoderFunction =
if useBidirectionalEncoder
then BS.RNNs.RecurrentBirectionalLSTMPStack
else BS.RNNs.RecurrentLSTMPStack
encoder = encoderFunction (encoderDims, inputEmbedded, inputDim=inputEmbeddingDim)
Krok 3. Dostosowywanie opisu sieci. Jeśli chodzi o sam opis sieci (formuły), BrainScript jest w dużej mierze w górę zgodny z NDL. Są to główne różnice:
Zwracana wartość makr (funkcji) nie jest już ostatnią zmienną zdefiniowaną w nich, ale cały zestaw zmiennych. Musisz jawnie wybrać wartość wyjściową na końcu. Na przykład:
# 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 tej zmiany zwracana wartość funkcji będzie całym rekordem, a typowy błąd, który zostanie wyświetlony, jest to, że
ComputationNode
oczekiwano miejsca znalezienia elementuComputationNetwork
.Język BrainScript nie zezwala na funkcje ze zmiennymi liczbami parametrów. Ma to znaczenie przede wszystkim dla
Parameter()
funkcji: Parametr wektora nie może być już zapisywany jakoParameter(N)
, teraz musi być jawnie zapisany jako tensorParameterTensor{N}
lub macierzParameter(N, 1)
1-kolumnowa . Bez tej zmiany zostanie wyświetlony błąd dotyczący niezgodności liczby parametrów pozycyjnych. Ta notacja działa również z językiem NDL, aby można było najpierw wprowadzić tę zmianę i przetestować ją przy użyciu języka NDL przed przekonwertowaniem. Jest to również dobra okazja do zmiany nazwy wszystkich zastosowań starszej nazwyLearnableParameter()
naParameterTensor{}
.Ma to również znaczenie dla
RowStack()
funkcji, która w języku BrainScript przyjmuje pojedynczy parametr, który jest tablicą danych wejściowych. Dane wejściowe muszą być rozdzielone dwukropkiem (:
) zamiast przecinka, np.RowStack (a:b:c)
zamiastRowStack (a, b, c)
.Niektóre wartości domyślne zostały zaktualizowane, przede wszystkim opcjonalny
imageLayout
parametrConvolution()
operacji puli iImageInput()
. W przypadku języka NDL te domyślne wartościlegacy
to , natomiast teraz wartość domyślna jestcudnn
wymagana do zgodności z elementami pierwotnymi cuDNN. (Wszystkie przykłady kodu NDL jawnie określają ten parametr jakocudnn
już).Analizator BrainScript jest bardziej restrykcyjny:
Identyfikatory są teraz uwzględniane wielkość liter. Wbudowane funkcje używają funkcji PascalCase (np.
RectifiedLinear()
), a wbudowane zmienne i nazwy parametrów używają camelCase (np.modelPath
,criterionNodes
), jak do ciągów opcji (init="fixedValue"
,tag="criterion"
). Należy pamiętać, że w przypadku nazw parametrów opcjonalnych nieprawidłowe pisownie nie zawsze są przechwytywane jako błąd. Zamiast tego niektóre niepoprawnie napisane parametry opcjonalne są po prostu ignorowane. Przykładem są definicje "węzłów specjalnych". Ich poprawne pisownia dla tych jest teraz:featureNodes = ... labelNodes = ... criterionNodes = ... evaluationNodes = ... outputNodes = ...
Skrócone nazwy alternatywne nie są już dozwolone, takie jak
Const()
powinna być , powinna byćtag="evaluation"
Constant()
,tag="eval"
ievalNodes
jest terazevaluationNodes
.Poprawiono niektóre nieprawidłowe nazwy:
criteria
jest terazcriterion
(podobniecriterionNodes
),defaultHiddenActivity
jest terazdefaultHiddenActivation
.Znak
=
nie jest już opcjonalny dla definicji funkcji.Chociaż może używać nawiasów dla bloków (
[ ... ]
), jest przestarzały. Użyj nawiasów klamrowych ({ ... }
).Etykiety opcji muszą być cytowane jako ciągi, np.
init="uniform"
zamiastinit=uniform
. Bez cudzysłowów kod BrainScript zakończy się niepowodzeniem z komunikatem o błędzie informującym, że symboluniform
jest nieznany.Typy pierwotne BrainScript, które tworzą parametry (
Input{}
iParameterTensor{}
), powinny używać nawiasów klamrowych dla argumentów (np.f = Input{42}
). Jest to konwencja, która nie jest wymuszana, ale zalecana w przyszłości.
Ta bardziej ograniczona składnia jest nadal akceptowana przez
NDLNetworkBuilder
program , dlatego zalecamy najpierw wprowadzenie tych zmian syntatycznych i przetestowanie ich za pomocą języka NDL, zanim rzeczywiście zmieni się na BrainScript.
Krok 4. Usuń NDLNetworkBuilder
z sekcji "write" i "test". Przejrzyj sekcje "write" i "test" w NDLNetworkBuilder
sekcjach i usuń je. Niektóre z naszych stockowych przykładów NDL mają dodatkowe NDLNetworkBuilder
sekcje. Nie są używane i nie powinny być tam. Jeśli konfiguracja jest oparta na jednym z tych przykładów, możesz również mieć takie sekcje. Kiedyś były ignorowane, ale w przypadku aktualizacji BrainScript zdefiniowanie nowej sieci w tych sekcjach ma teraz znaczenie (edytowanie modelu), więc nie są już ignorowane i dlatego należy je usunąć.
NDLNetworkBuilder
reference (przestarzałe)
Składnia przestarzałego NDLNetworkBuilder
elementu to:
NDLNetworkBuilder = [
networkDescription = "yourNetwork.ndl"
]
Blok NDLNetworkBuilder
ma następujące parametry:
networkDescription
: ścieżka pliku opisu sieci. W przypadku przestarzałejNDLNetworkBuilder
wersji niestandardowej było użycie rozszerzenia.ndl
pliku . Jeśli nienetworkDescription
określono parametru, zakłada się, że opis sieci zostanie podkreślony w tym samymNDLNetworkBuilder
podbloku, określony za pomocą poniższego parametrurun
. Należy pamiętać, że za pomocą parametru można określić tylko jedną ścieżkęnetworkDescription
pliku. Aby załadować wiele plików makr, użyj parametrundlMacros
.run
: blok NDL, który zostanie wykonany. Jeśli zewnętrzny plik NDL jest określony za pośrednictwem parametrunetworkDescription
,run
parametr identyfikuje blok w tym pliku. Ten parametr zastępuje wszystkierun
parametry, które mogą już istnieć w pliku. Jeśli nienetworkDescription
określono pliku,run
parametr identyfikuje blok w bieżącym pliku konfiguracji.load
: bloki skryptów NDL do załadowania. Wiele bloków można określić za pośrednictwem listy rozdzielonej ciągiem ":". Bloki określone przezload
parametr zwykle zawierają makra do użycia przezrun
blok. Podobnie jak w przypadku parametrurun
,load
parametr identyfikuje bloki w zewnętrznym pliku NDL i zastępuje wszystkieload
parametry, które mogą już istnieć w pliku, jeśli plik jest określony przeznetworkDescription
parametr . Jeśli nienetworkDescription
określono pliku,load
identyfikuje blok w bieżącym pliku konfiguracji.ndlMacros
: ścieżka pliku, w której można załadować makra NDL. Ten parametr jest zwykle używany do ładowania domyślnego zestawu makr NDL, które mogą być używane przez wszystkie skrypty NDL. Wiele plików NDL, z których każdy określa różne zestawy makr, można załadować, określając rozdzielaną listę ścieżek plików "+" dla tegondlMacros
parametru. Aby udostępnić makra innym blokom poleceń, takim jak bloki języka edycji modelu NDL (MEL), należy zdefiniować je na poziomie głównym pliku konfiguracji.randomSeedOffset
: wartość przesunięcia inicjującego losowe inicjowanie parametrów możliwych do nauki. Wartość domyślna to0
. Dzięki temu użytkownicy mogą uruchamiać eksperymenty z inną losową inicjacją.