Udostępnij przez


Odwołanie do warstw za pomocą języka BrainScript

CNTK wstępnie zdefiniowano szereg typowych "warstw", co sprawia, że bardzo łatwo jest pisać proste sieci składające się ze standardowych warstw warstwowych na siebie. Warstwy są obiektami funkcji, które mogą być używane jak zwykłe funkcje BrainScript, ale przechowują parametry do nauki i mają dodatkową parę {} do przekazywania parametrów konstrukcji lub atrybutów.

Na przykład jest to opis sieci dla prostego modelu warstwy ukrytej 1 przy użyciu warstwy DenseLayer{} :

h = DenseLayer {1024, activation=ReLU} (features)
p = DenseLayer {9000, activation=Softmax} (h)

które następnie mogą być używane do trenowania względem kryterium entropii krzyżowej:

ce = CrossEntropy (labels, p)

Jeśli sieć jest prostą łączeniem operacji (wiele z nich to), możesz użyć alternatywy Sequential() Notacji:

myModel = Sequential (
    DenseLayer {1024, activation=ReLU} :
    DenseLayer {9000, activation=Softmax}
)

i wywołaj go w następujący sposób:

p = myModel (features)

Przykładowe modele

Poniżej przedstawiono sztylet gniazda, który osadza sekwencję wyrazów, przetwarza ją za pomocą cyklicznego LSTM, a następnie klasyfikuje każde słowo:

taggingModel = Sequential (
    EmbeddingLayer {150} :      # embed into a 150-dimensional vector
    RecurrentLSTMLayer {300} :  # forward LSTM
    DenseLayer {labelDim}       # word-wise classification
)

Poniżej przedstawiono prostą sieć splotową do rozpoznawania obrazów:

convNet = Sequential (
    # 3 layers of convolution and dimension reduction by pooling
    ConvolutionalLayer {32, (5:5), pad=true, activation=ReLU} :
    MaxPoolingLayer {(3:3), stride=(2:2)} :
    ConvolutionalLayer {32, (5:5), pad=true, activation=ReLU} :
    MaxPoolingLayer {(3:3), stride=(2:2)} :
    ConvolutionalLayer {64, (5:5), pad=true, activation=ReLU} :
    MaxPoolingLayer {(3:3), stride=(2:2)} :
    # 2 dense layers for classification
    DenseLayer {64, activation=ReLU} :
    LinearLayer {10}
)

Udostępnianie parametrów

Jeśli przypiszesz warstwę do zmiennej i użyjesz jej w wielu miejscach, parametry zostaną udostępnione. Jeśli mówisz

lay = DenseLayer {1024, activation=Sigmoid}
h1 = lay (x)
h2 = lay (h1)  # same weights as `h1`

h1 i h2 będzie współdzielić te same parametry, co lay() jest tą samą funkcją w obu przypadkach. W powyższym przypadku prawdopodobnie nie jest to, co było pożądane, więc należy pamiętać. Jeśli oba wywołania powyższych lay() mają mieć różne parametry, pamiętaj, aby zdefiniować dwa oddzielne wystąpienia, na przykład lay1 = DenseLayer{...} i lay2 = DenseLayer{...}.

Dlaczego więc to zachowanie? Warstwy umożliwiają udostępnianie parametrów między sekcjami modelu. Rozważmy model DSSM, który przetwarza dwa obrazy wejściowe, powiedzmy doc i query identycznie z tym samym łańcuchem przetwarzania, i porównuje wynikowe ukryte wektory:

imageToVec = Sequential (
    ConvolutionalLayer {32, (5:5), pad = true, activation = ReLU} :
    MaxPoolingLayer {(3:3), stride = (2:2)} :
    ConvolutionalLayer {64, (5:5), pad = true, activation = ReLU} :
    MaxPoolingLayer {(3:3), stride = (2:2)} :
    DenseLayer {64, activation = ReLU} :
    LinearLayer {10}
)
zDoc   = imageToVec (doc)
zQuery = imageToVec (query)  # same model as for zDoc
sim = CosDistance (zdoc, zQuery)

gdzie imageToVec jest częścią modelu, który konwertuje obrazy na wektor płaski. imageToVec to obiekt funkcji, który z kolei zawiera kilka obiektów funkcji (np. trzy wystąpienia ConvolutionalLayer{}obiektu ). imageToVec wystąpienie jest tworzone raz, a to wystąpienie zawiera możliwe do poznania parametry wszystkich uwzględnionych obiektów funkcji. Oba wywołania model() obiektu będą współdzielić te parametry w aplikacji, a ich gradienty będą sumą obu wywołań.

Wreszcie należy pamiętać, że jeśli w powyższym przykładzie query i doc musi mieć te same wymiary, ponieważ są one przetwarzane za pośrednictwem tego samego obiektu funkcji, a pierwsza warstwa obiektu funkcji ma swój wymiar wejściowy wywnioskowany tak, aby był zgodny z wartościami i querydoc. Jeśli ich wymiary różnią się, ta sieć jest źle sformułowana, a wnioskowanie/walidacja wymiarów zakończy się niepowodzeniem z komunikatem o błędzie.

Uwaga dotycząca implementacji

Wiele warstw to otoki podstawowych CNTK pierwotnych wraz z odpowiednimi wymaganymi parametrami do nauki. Na przykład ConvolutionalLayer{} opakowuje Convolution() element pierwotny. Zalety korzystania z warstw to:

  • warstwy zawierają czytelne parametry prawidłowego wymiaru
  • warstwy są komponowalne (cf. Sequential())

DenseLayer{}, LinearLayer{}

Funkcja Factory umożliwiająca utworzenie w pełni połączonej warstwy. DenseLayer{} przyjmuje z opcjonalną nieliniowością.

DenseLayer {outDim, activation=Identity, init='glorotUniform', initValueScale=1, bias=true}
LinearLayer {outDim, init='glorotUniform', initValueScale=1, bias=true}

Parametry

  • outDim: wymiar wyjściowy tej warstwy
  • activation (DenseLayer{} tylko): przekaż tutaj funkcję, która ma być używana jako funkcja aktywacji, na przykład activation=ReLU
  • init ('heNormal'|'glorotUniform'|...): typ inicjowania wag. Zobacz tutaj , aby uzyskać pełną listę opcji inicjowania.
  • initValueScale: wariancja losowa inicjalizacja jest mnożona za pomocą tej funkcji
  • bias: jeśli wartość false, nie dołączaj parametru odchyleń

Wartość zwracana

Funkcja, która implementuje żądaną w pełni połączoną warstwę. Patrz opis.

Opis

Użyj tych funkcji fabryki, aby utworzyć w pełni połączoną warstwę. Użyj polecenia DenseLayer{} , jeśli chcesz dołączyć funkcję aktywacji, w przeciwnym razie LinearLayer{}.

Każda z tych funkcji fabryki tworzy obiekt funkcji, który zawiera macierz wagi do nauki i, chyba bias=falseże , można nauczyć się stronniczy. Obiekt funkcji może służyć jako funkcja, która implementuje jedną z następujących formuł:

DenseLayer{...} (v) = activation (W * v + b)
LinearLayer{...} (v) = W * v + b

gdzie W jest macierzą wagi wymiaru [outDim x (dimension of v)], b jest stronniczość wymiaru [outdim], a wynikowa wartość ma wymiar (lub wymiary tensor) podane przez outDim.

Obsługa platformy Tensor

Jeśli zwrócona funkcja zostanie zastosowana do danych wejściowych wartości tensor rangi > 1, np. obrazu 2D, W będzie miał wymiar [outDim x (first dimension of input) x (second dimension of input) x ...].

Z drugiej strony outDim może być wektorem określającym wymiary tensorowe, na przykład (10:10). W takim przypadku W będzie miał wymiar [outDim[0] x outDim[1] x ... x (dimension of input)]i b będzie miał wymiary tensorowe [outDim[0] x outDim[1] x ...].

CNTK produkt macierzy zinterpretuje te dodatkowe wymiary wyjściowe lub wejściowe tak, jakby zostały spłaszczone w długi wektor. Aby uzyskać więcej informacji na ten temat, zobacz dokumentację Times()

Przykład:

h = DenseLayer {1024, activation=Sigmoid) (v)

lub alternatywnie:

Layer = DenseLayer {1024, activation=Sigmoid)
h = Layer (v)

Konwolucyjnalayer{}

Tworzy warstwę konwolucji z opcjonalną nieliniowością.

ConvolutionalLayer {numOutputChannels, filterShape,
                    activation = Identity,
                    init = 'glorotUniform', initValueScale = 1,
                    stride = 1, pad = false, lowerPad = 0, upperPad = 0,
                    bias = true}

Parametry

  • numOutputChannels: liczba kanałów wyjściowych (liczba filtrów)
  • filterShape: zakres przestrzenny filtru, np. (5:5) dla filtru 2D. Wymiar kanału wejściowego nie należy tutaj uwzględniać.
  • activation: opcjonalna nieliniowość, np. activation=ReLU
  • init ('heNormal'|'glorotUniform'|...): typ inicjowania losowego dla wag. Zobacz tutaj , aby uzyskać pełną listę opcji inicjowania losowego.
  • initValueScale: wariancja losowa inicjalizacja jest mnożona za pomocą tej funkcji
  • stride: zwiększa się podczas przesuwania filtru przez dane wejściowe. Na przykład (2:2) w celu zmniejszenia wymiarów o 2
  • pad: jeśli nie zostanie ustawiona (wartość domyślna), filtr zostanie przesunięty na obszar "prawidłowy" danych wejściowych, czyli bez wartości poza obszarem. Jeśli pad z drugiej strony zostanie ustawiony filtr, zostanie zastosowany do wszystkich pozycji wejściowych, a wartości poza prawidłowym regionem zostaną uznane za zero.
  • lowerPad, upperPad: jawnie określ różne marginesy do wypełnienia. Filtry zostaną przesunięte na prawidłowy region, który jest (praktycznie) rozszerzony o zery. Na przykład lowerPad=(1:2) dołączy kolumnę zer i dwa wiersze zer. Wymiar danych wyjściowych jest odpowiednio rozszerzony.
  • bias: jeśli wartość false, nie dołączaj parametru odchyleń

Wartość zwracana

Funkcja, która implementuje żądaną w pełni połączoną warstwę. Patrz opis.

Opis

Użyj tych funkcji fabryki, aby utworzyć warstwę konwolucji.

Wynikowa warstwa stosuje operację konwolucji na tensor N-wymiarowym. Obiekt wywołujący określa rozszerzenie przestrzenne filtru. Zestaw filtrów danego zakresu przestrzennego (np. (5:5)) jest skorelowany z każdą lokalizacją danych wejściowych (np. z obrazem [640 x 480]o rozmiarze). Przy założeniu, że dopełnienie jest włączone (pad), a kroki to 1, spowoduje to wygenerowanie regionu wyjściowego tego samego wymiaru ([640 x 480]).

Zazwyczaj wiele filtrów jest stosowanych w tym samym czasie. numOutputChannels określa liczbę, więc dla każdej lokalizacji wejściowej numOutputChannels jest generowany cały wektor. W powyższym przykładzie ustawienie numOutputChannels wartości 64 będzie miało wartość w tensor o rozmiarze [640 x 480 x 64]-size. Ta ostatnia oś jest nazywana wymiarem kanału.

Po zastosowaniu konwolucji do danych wejściowych z wymiarem kanału każdy filtr będzie również składać się z wektorów wymiaru kanału wejściowego. Na przykład w przypadku zastosowania konwolucji z określonym zakresem [640 x 480 x 3]filtru (5:5) przestrzennego do obrazu koloru o rozmiarze każdy filtr będzie tensorem[5 x 5 x 3].

Wszystkie numOutputChannels filtry ułożone razem są nazywane jądrem. W naszym przykładzie kształt jądra będzie mieć wartość [5 x 5 x 3 x 64].

Poniżej przedstawiono podsumowanie relacji między różnymi wymiarami i kształtami:

input shape    : [ (spatial dims)  x  (#input channels)                        ]
spatial extent : [ (filterShape)                                               ]
output shape   : [ (spatial dims)  x                     x  numOutputChannels  ]
kernel shape   : [ (filterShape)   x  (#input channels)  x  numOutputChannels  ]

które w naszym przykładzie to:

input shape    : [ 640 x 480   x   3                          ]
spatial extent : [   5 x 5                                    ]
output shape   : [ 640 x 480   x       x   numOutputChannels  ]
kernel shape   : [   5 x 5     x   3   x   numOutputChannels  ]

Dopełnienie

Jeśli dopełnienie nie jest włączone, region wyjściowy zostanie zredukowany przez lokalizacje granic, do których nie można zastosować pełnego zakresu filtru. Na przykład zastosowanie filtru (5:5)-extent do obrazu bez dopełnienia, najbardziej zewnętrzne 2 wiersze i kolumny pikseli spowodowałoby zastosowanie filtru poza granicami. ConvolutionalLayer{} W związku z tym odpowiednio zmniejszy wymiary.

[640 x 480] Obraz z filtrem (5:5) bez wypełnienia pozostawi [636 x 476]region wyjściowy o rozmiarze .

Postępy

Parametry stride określają przyrost filtrów. Wartości większe niż jeden prowadzą do próbkowania podrzędnego regionu danych wyjściowych. Na przykład filtrowanie obrazu z krokiem (2:2) spowoduje [320 x 240]wypełnienie [640 x 480] w regionie o rozmiarze i [318 x 238] bez dopełnienia.

Uwagi

Ta warstwa jest otoką wokół pierwotnego Convolution() .

Nazwa parametrów jądra filtru, jak pokazano w sekcji walidacji dziennika, zakończy się ciągiem .W. Wymiar nie będzie obecnie wyświetlany zgodnie [ (filterShape) x (#input channels) x numOutputChannels ] z powyższym opisem, ale zamiast tego [numOutputChannels x (produkt w kształcie filtru) * (kanały #input)) ]".

Przykład:

c = ConvolutionalLayer {64, (3:3), pad = true, stride = (1:1), bias=false} (x)

DeconvLayer{}

Tworzy warstwę dekonwolucji.

DeconvLayer {numOutputChannels,
             filterShape, numInputChannels,
             bias = true,
             activation = (x=>x),
             init = 'glorotUniform',
             initValueScale = 0.001,
             initBias = 0,
             stride = 1, autoPadding = false,
             lowerPad = 0, upperPad = 0,
             maxTempMemSizeInSamples = 0}

Parametry

  • numOutputChannels: liczba kanałów wyjściowych (liczba filtrów)
  • filterShape: zakres przestrzenny filtru, np. (5:5) dla filtru 2D. Wymiar kanału wejściowego nie należy tutaj uwzględniać.
  • numInputChannels: liczba kanałów wejściowych (liczba filtrów woluminu wejściowego)
  • bias: jeśli wartość false, nie dołączaj parametru odchyleń
  • activation: opcjonalna nieliniowość, np. activation=ReLU
  • init ('heNormal'|'glorotUniform'|...): typ inicjowania losowego dla wag. Zobacz tutaj , aby uzyskać pełną listę opcji inicjowania losowego.
  • initValueScale: wariancja losowa inicjalizacja jest mnożona za pomocą tej funkcji
  • initBias: początkowa wartość stronnicza
  • stride: zwiększa się podczas przesuwania filtru przez dane wejściowe. Na przykład (2:2) w celu zmniejszenia wymiarów o 2
  • autoPadding: jeśli nie zostanie ustawiona (wartość domyślna), filtr zostanie przesunięty na obszar "prawidłowy" danych wejściowych, czyli bez wartości poza obszarem. Jeśli autoPadding z drugiej strony zostanie ustawiony filtr, zostanie zastosowany do wszystkich pozycji wejściowych, a wartości poza prawidłowym regionem zostaną uznane za zero.
  • lowerPad, upperPad: jawnie określ różne marginesy do wypełnienia dla woluminu wyjściowego, tj. te, które zostały użyte dla danych wejściowych w odpowiedniej warstwie splotowej. Ważne jest, aby ustawić je w korespondencji z warstwą splotową, aby osiągnąć te same wymiary tensora.

Wartość zwracana

Funkcja, która implementuje żądaną w pełni połączoną warstwę. Patrz opis.

Opis

Użyj tych funkcji fabryki, aby utworzyć warstwę dekonwolucji.

Wynikowa warstwa stosuje operację dekonwolucji na tensor N-wymiarowym. Ta warstwa jest otoką wokół pierwotnego za Convolution() pomocą polecenia deconv=true.

Jedną z popularnych przypadków użycia do dekonwolucji jest odtworzenie obrazu (zobacz na przykład tutaj). Gdy konwolucja przyjmuje wejściowy region pola 2D i oblicza korelację z filtrem 2D, dekonwolucja przyjmuje piksel i rozkłada go w regionie 2D.

Rozważmy obraz p(.,.), lokalizację pikseli (x,y) i wyśrodkowany filtr [3 x 3] z następującą zawartością (na razie nie ma wymiaru głębokości mapy funkcji, tj. jednego kanału):

[ . . c
  a b .
  . . . ]

W tym przypadku wartości b i c są wagami filtru "". Odpowiada zerowej wadze. Funkcja Convolution() oblicza wynikowy piksel q(x, y) w lokalizacji (x, y) jako:

q(x,y) = b * p(x,y) + a * p(x-1,y) + c * p(x+1,y-1)

Dekonwolucja przyjmuje piksele q(x,y) i rozkłada je w regionie wokół (x,y). Jeśli użyliśmy tego samego filtru, wprowadzilibyśmy następujący wkład do danych wyjściowych r(x,y):

r(x,y)     += b * q(x,y)
r(x-1,y)   += a * q(x,y)
r(x+1,y-1) += c * q(x,y) 

Wiedząc, że to samo dotyczy wszystkich x i y na płaszczyźnie, możemy to wyrazić dla r(x,y):

r(x,y)     += b * q(x,y)
r(x,y)     += a * q(x+1,y)
r(x,y)     += c * q(x-1,y+1) 

lub łącznie,

r(x,y) = b * q(x,y) + a * q(x+1,y) + c * q(x-1,y+1) 

Ma on taką samą formę jak powyższy konwolucja, z tą różnicą, że filtr jest dublowany wzdłuż obu osi.

Teraz wprowadzamy mapy funkcji do mieszanki. Jest to łatwe: Zamiast przechodzić od głębokości wejściowej do głębokości danych wyjściowych, idziemy w innym kierunku.

Podsumowując, Convolution (W, x) == Deconvolution (W', x), gdzie

W : [W x H x C x K]

oraz

W’ = W z wartościami zmienionymi jako: [(W mirrored) x (H mirrored) x K x C]

Tj. co deconvolution() robi niejawnie:

  • wymiana dwóch wymiarów głębokości (transponuj)
  • wymiary przestrzenne (odwraca kolejność danych)
  • Convolution() z tymi

Przykład:

deconv_A = DeconvLayer {inputDim, (5:5), cMap1, lowerPad=(2:2:0), upperPad=(2:2:0)}(unpool_A)

Aby zapoznać się ze szczegółowym przykładem, zobacz Autoenkoder obrazów korzystający z funkcji Deconvolution i Unpooling .

MaxPoolingLayer{}, AveragePoolingLayer{}

Funkcje fabryki w celu utworzenia warstwy maksymalnej lub średniej puli.

MaxPoolingLayer {poolShape, stride = 1, pad = false, lowerPad = 0, upperPad = 0}
AveragePoolingLayer {poolShape, stride = 1, pad = false, lowerPad = 0, upperPad = 0} =

Parametry

  • poolShape: kształt regionu do puli, np. (2:2)
  • stride: inkrementacja podczas przesuwania puli przez dane wejściowe. Na przykład (2:2) w celu zmniejszenia wymiarów o 2
  • pad: jeśli nie zostanie ustawiona (wartość domyślna), pula zostanie przesunięta na "prawidłowy" obszar danych wejściowych, czyli nie zostanie użyta żadna wartość poza obszarem. Jeśli pad z drugiej strony zostanie ustawiona, pula zostanie zastosowana do wszystkich pozycji wejściowych, a wartości poza prawidłowym regionem zostaną uznane za zero. W przypadku średniego buforowania liczba dla średniej nie obejmuje wypełnionych wartości.
  • lowerPad, upperPad: jawnie określ różne marginesy do wypełnienia. Filtry zostaną przesunięte na prawidłowy region, który jest (praktycznie) rozszerzony o zery. Na przykład lowerPad=(1:2) dołączy kolumnę zer i dwa wiersze zer. Wymiar danych wyjściowych jest odpowiednio rozszerzony.

Wartość zwracana

Funkcja, która implementuje żądaną warstwę buforowania. Patrz opis.

Opis

Użyj tej funkcji fabryki, aby utworzyć operację buforowania. Użyj polecenia MaxPoolingLayer{} , aby obliczyć maksymalną wartość dla wartości w obszarze puli i AveragePoolingLayer{} obliczyć ich średnią.

Operacja buforowania przesuwa "okno puli" w lokalizacjach regionu wejściowego i oblicza maksymalną lub średnią wartości w odpowiednim regionie puli.

Ta operacja jest strukturalnie bardzo podobna do splotu, z tą różnicą, że operacja zastosowana do okna przesuwnego ma inny charakter.

Wszystkie zagadnienia dotyczące wymiarów wejściowych, wypełnienia i kroków mają takie same zastosowanie, więc zobacz ConvolutionalLayer{} , aby uzyskać więcej szczegółów.

Przykład:

p = MaxPoolingLayer {(3:3), stride=(2:2)} (c)

MaxUnpoolingLayer{}

Tworzy warstwę maksymalnego rozłączania.

MaxUnpoolingLayer {poolShape,
                   stride = 1, pad = false,
                   lowerPad = 0, upperPad = 0} 

Parametry

  • poolShape: kształt regionu do pulowania (rozmiar regionu wyjściowego ), np. (2:2)
  • stride: przyrost podczas przesuwania puli przez dane wyjściowe. Np. (2:2) zwiększenie wymiarów o 2
  • pad: jeśli nie zostanie ustawiona (wartość domyślna), pula zostanie przesunięta na "prawidłowy" obszar danych wyjściowych, czyli nie jest używana żadna wartość poza obszarem.
  • lowerPad, upperPad: jawnie określ różne marginesy do wypełnienia. Filtry zakładają prawidłowy region wyjściowy, który jest (praktycznie) rozszerzony.

Wartość zwracana

Funkcja, która implementuje żądaną warstwę pul. Patrz opis.

Opis

Użyj tej funkcji fabryki, aby utworzyć operację pulowania.

Operacja pulowania jest odwrotnością operacji buforowania. Wymaga dwóch danych wejściowych: danych wyjściowych odpowiedniej warstwy buforowania, powiedzmy p1 , i danych wejściowych odpowiedniej warstwy buforowania, np r1. , również. Przesuwa on "odwrotne okno puli" na lokalizacje jego danych wejściowych p1i projektuje wartość do tej pozycji regionu wyjściowego, która miała wartość maksymalną w odpowiedniej operacji buforowania, tj. w r1. Drugie dane wejściowe r1 są wymagane w CNTK w celu określenia celu operacji unpooling, ponieważ CNTK nie przechowuje tak nazywanych zmiennych przełącznika (zobacz tutaj, aby uzyskać szczegółowe informacje).

Przykład:

unpool_A = MaxUnpoolingLayer {(2:2), stride=(2:2)}(deconv_B, relu_A)

Zobacz Autokoder obrazu przy użyciu deconvolution i Unpooling , aby zapoznać się ze szczegółowym przykładem i zapoznać się z przewodnikiem.

Osadzanielayer{}

EmbeddingLayer {outDim,
                init='glorotUniform', initValueScale=1,
                embeddingPath = '', transpose = false}

Parametry

  • outDim: wymiar żądanego wektora osadzania
  • init ('heNormal'|'glorotUniform'|...): typ inicjowania wagi. Zobacz tutaj , aby uzyskać pełną listę opcji inicjowania.
  • initValueScale: inicjacja losowa wariancji jest mnożona za pomocą tej funkcji
  • embeddingPath: jeśli podane, osadzanie nie są wyuczone, ale ładowane z pliku i nie są aktualizowane dalej podczas trenowania
  • transpose: umożliwia ładowanie osadzania przechowywanych w transponowanym formularzu

Wartość zwracana

Funkcja, która implementuje warstwę osadzania. Patrz opis.

Opis

"Osadzanie" odnosi się do reprezentowania wyrazów lub innych dyskretnych elementów przez gęste wektory ciągłe. W tej warstwie przyjęto założenie, że dane wejściowe są w postaci gorąca. Na przykład w przypadku rozmiaru słownictwa 10 000 każdy wektor wejściowy ma mieć wymiar 10 000 i składa się z zer z wyjątkiem jednej pozycji zawierającej 1. Indeks tej lokalizacji jest indeksem wyrazu lub elementu, który reprezentuje.

W CNTK odpowiednie wektory osadzania są przechowywane jako kolumny macierzy. W związku z tym mapowanie wyrazu wejściowego na jego osadzanie jest implementowane jako produkt macierzy. Aby było to bardzo wydajne, ważne jest, aby wektory wejściowe przechowywane w formacie rozrzedzyłym.

Fakt zabawy: Gradient macierzy osadzania ma formę wektorów gradientu, które są tylko niezerowe dla słów widocznych w minibatch. Ponieważ w przypadku realistycznych słownictwa dziesiątek lub setek tysięcy zdecydowana większość kolumn byłaby zerowa, CNTK implementacje mają konkretną optymalizację reprezentującą gradient w postaci "rozrzednionej kolumny".

Znany problem: Wyżej wymieniony formularz gradientu rozrzedzonych kolumn nie jest obecnie obsługiwany przez naszą 1-bitową technikę równoległej SGD. Zamiast tego użyj techniki block-momentum .

Przykład

Poznane osadzanie reprezentujące wyrazy ze słownictwa 87636 jako wektor 300-wymiarowy:

input = Input{87636, sparse=true}    # word sequence, as one-hot vector, sparse format
embEn = EmbeddingLayer{300} (input)  # embed word as a 300-dimensional continuous vector

Oprócz sparse=trueprogramu należy również zadeklarować dane wejściowe jako rozrzedłe w reader bloku konfiguracji. Oto przykład odczytywania rozrzednych danych wejściowych tekstu za pomocą elementu CNTKTextFormatReader:

reader = {
    readerType = "CNTKTextFormatReader"
    file = "en2fr.txt"
    randomize = true
    input = {
        input  = { alias = "E" ; dim = 87636 ;  format = "sparse" }
        labels = { alias = "F" ; dim = 98624 ;  format = "sparse" }
    }
}

Jeśli zamiast tego istnieją już wektory osadzania i powinny być ładowane z pliku, wyglądałoby to następująco:

input = Input{87636, sparse=true}     # word sequence, as one-hot vector, sparse format
embEn = EmbeddingLayer{300, embeddingPath="embedding-en.txt", transpose=true} (w) # embedding from disk

gdzie oczekuje się, że plik "embedding-en.txt" będzie składać się z 87 636 wierszy tekstowych, z których każda składa się z 300 liczb rozdzielanych spacjami. Ponieważ ten plik zapisuje osadzanie jako wiersze, a nie kolumny, transpose=true transponuje macierz na bieżąco.

RecurrentLSTMLayer{}, RecurrentLSTMLayerStack{}

Funkcje fabryki w celu utworzenia cyklicznej maszyny LSTM w warstwie jednowarstwowej lub wielowarstwowej.

RecurrentLSTMLayer {outDim, cellShape = None,
                    goBackwards = false,
                    usePeepholes = false,
                    init = 'glorotUniform', initValueScale = 1,
                    enableSelfStabilization = false,
                    allowOptimizedEngine = false}
RecurrentLSTMLayerStack {layerDims,
                         cellShapes = None,
                         usePeepholes = false,
                         init = 'glorotUniform', initValueScale = 1,
                         enableSelfStabilization = false,
                         allowOptimizedEngine = false}

Parametry

  • outDim (RecurrentLSTMLayer{}): wymiar danych wyjściowych sieci. Aby oznaczyć tensor>rangi 1, może to być wektor, np. (40:2)
  • layerDims (RecurrentLSTMLayerStack{}): tablica wymiarów warstw wewnętrznych i danych wyjściowych sieci
  • cellShape ( (RecurrentLSTMLayer{}, opcjonalnie): wymiar komórki LSTM. Zwykle jest to identyczne z outDim. Jeśli zostanie podana inna wartość, zostanie wstawiona dodatkowa projekcja liniowa w celu przekonwertowania z wymiaru komórki na dane wyjściowe.
  • cellShapes ( (RecurrentLSTMLayerStack{}, opcjonalnie): tablica wartości, takich jak cellShape dla, RecurrentLSTMLayer() aby oznaczyć projekcję
  • goBackwards (opcjonalnie): jeśli prawda, cykl jest uruchamiany wstecz
  • usePeepholes (opcjonalnie): jeśli prawda, użyj połączeń peephole w LSTM
  • init ('heNormal'|'glorotUniform'|...): typ inicjowania wagi. Zobacz tutaj , aby uzyskać pełną listę opcji inicjowania.
  • initValueScale: inicjacja losowa wariancji jest mnożona za pomocą tej funkcji
  • enableSelfStabilization (opcjonalnie): jeśli prawda, wstaw operację "stabilizatora" podobną do StabilizerLayer{}
  • allowOptimizedEngine (opcjonalnie, wartość false domyślna): jeśli to prawda, użyj zoptymalizowanego aparatu RNN cuDNN, jeśli to możliwe

Wartość zwracana

Funkcja, która implementuje żądane warstwy, które mają zastosowanie/stosują cyklicznego LSTM do jego sekwencji wejściowej. Ta warstwa (stos) mapuje sekwencję wejściową na sekwencję ukrytych stanów o tej samej długości.

Opis

Implementuje to rekursję LSTM, która ma być stosowana do sekwencji danych wejściowych, w dwóch wariantach: pojedynczej warstwy i stosu wielowarstwowego. Ta operacja automatycznie obsługuje dane wejściowe o zmiennej długości. Początkowa wartość ukrytego stanu i komórki to 0.

Zastosowanie tej warstwy do sekwencji wejściowej spowoduje zwrócenie sekwencji ukrytych stanów rekursu (top-of-stack) cyklicznego LSTM (wartość komórki pamięci LSTM nie jest zwracana). Zwrócona sekwencja ma taką samą długość jak dane wejściowe. Jeśli żądany jest tylko ostatni stan, podobnie jak w scenariuszach klasyfikacji sekwencji lub sekwencji, użyj polecenia BS.Sequences.Last() , aby wyodrębnić tylko ukryty stan ostatniego elementu. (W cyklu wstecznym należy użyć elementu BS.Sequences.First().)

Aby utworzyć model dwukierunkowy z elementem RecurrentLSTMLayer(), użyj dwóch warstw, jeden z elementami goBackwards=truei Splice() dwa dane wyjściowe razem. RecurrentLSTMLayerStack() obecnie nie obsługuje modeli dwukierunkowych, należy ją ręcznie skonstruować przy użyciu wielu RecurrentLSTMLayer()/Splice() kombi.

Korzystanie z aparatu CuDNN5 RNN

Ta funkcja automatycznie użyje zoptymalizowanego aparatu RNN5 cuDNN5, jeśli jest to możliwe, to znaczy, jeśli

  • określony model jest jednym, który można zaimplementować przez funkcję CuDNN5
    • brak projekcji (brak cellShape parametru)
    • brak połączeń peep-hole
    • brak samozwańkowego stabilizacji
    • nie idzie do tyłu
    • dla RecurrentLSTMLayerStack{}programu wszystkie wymiary warstwy mają tę samą wartość
  • allowOptimizedEngine=true

W szczególności CNTK wymaga włączenia funkcji allowOptimizedEngine=true. Wynika to z faktu, że sieci RNN CuDNN5 są implementowane jako CNTK operacji pierwotnej, która wymaga procesora GPU. Jednak wiele rzeczywistych systemów używa procesorów GPU do trenowania, ale serwerów tylko procesora CPU we wdrożeniu. CuDNN5 RNN nie nadaje się tutaj. (Teoretycznie można użyć sieci RNN CuDNN5 do trenowania i zastąpić ją do wdrożenia operacją edycji z równoważną jawną implementacją LSTM w języku BrainScript).

Uwagi

Jeśli allowOptimizedEngine=true wtedy te dwa warianty warstwowe są otoki wokół pierwotnego OptimizedRNNStack() .

Przykład

Prosty klasyfikator tekstu, który uruchamia sekwencję wyrazów przez cykl, a następnie przekazuje ostatni ukryty stan LSTM do klasyfikatora softmax, może mieć następujący formularz:

w = Input{...}                   # word sequence (one-hot vectors)
e = EmbeddingLayer {150} (w)     # embed as a 150-dimensional dense vector
h = RecurrentLSTMLayer {300} (e) # left-to-right LSTM with hidden and cell dim 300
t = BS.Sequences.Last (h)        # extract last hidden state
z = DenseLayer {10000, activation=Softmax} (t)  # softmax classifier

Aby zmienić powyższy przykład na stos 3-warstwowy używający aparatu CuDNN5 RNN, zmień następujący wiersz:

h = RecurrentLSTMLayerStack {(300:300:300), allowOptimizedEngine=true} (e)

Aby utworzyć dwukierunkową jednowarstwową maszynę LSTM (np. przy użyciu połowy ukrytego wymiaru w porównaniu z powyższym), użyj następującego polecenia:

hFwd = RecurrentLSTMLayer {150} (e)
hBwd = RecurrentLSTMLayer {150, goBackwards=true} (e)
h = Splice (hFwd:hBwd)

DelayLayer{}

Funkcja Factory, aby utworzyć warstwę, która opóźnia dane wejściowe.

DelayLayer {T=1, defaultHiddenActivation=0}

Parametry

  • T: liczba kroków czasu, które mają być opóźnione. Aby uzyskać dostęp do przyszłych wartości, użyj wartości ujemnej
  • defaultHiddenActivation: wartość do użycia dla opóźnionych ramek na granicach

Wartość zwracana

Funkcja, która implementuje żądaną operację opóźnienia.

Opis

Ta operacja opóźnia sekwencję wejściową według T kroków (domyślnie 1). Jest to przydatne, na przykład, aby przekształcić sekwencję wyrazów w sekwencję nakładających się wyrazów potrójnie.

Należy wziąć pod uwagę sekwencję wejściową "b c b", która jest zakodowana jako sekwencja wektorów jedno-gorących w następujący sposób:

1 0 0 0
0 1 0 1
0 0 1 0

W tym miejscu każda kolumna jest jedną gorącą wektorem i odpowiada słowu. Zastosowanie do tych danych wejściowych spowoduje wygenerowanie DelayLayer{T=1} tej sekwencji:

0 1 0 0
0 0 1 0
0 0 0 1

Wszystkie tokeny są opóźnione o jeden, a pierwsze położenie zostaje wypełnione jako wektor 0. Podobnie użycie DelayLayer{T=-1} (ujemne opóźnienie) zapewni dostęp do przyszłych wartości i wybiegnie z prawej strony z zerem:

0 0 0 0
1 0 1 0
0 1 0 0

Uwagi

Ta warstwa jest otoką wokół PastValue() elementów pierwotnych i.FutureValue()

Przykład

Poniżej przedstawiono sposób stosu trzech wyrazów sąsiada do wektora trygramu:

x  = ...                   # input value, e.g. a N-dimensional one-hot vector
xp = DelayLayer{} (x)      # previous value
xn = DelayLayer{T-1} (x)   # next value (negative delay)
tg = Splice (xp : x : xn)  # concatenate all into a 3N-dimensional three-hot vector

BatchNormalizationLayer{}, LayerNormalizationLayer{}, StabilizerLayer{}

Funkcje fabryki służące do tworzenia warstw normalizacji wsadowej, normalizacji warstw i samozwańkowego stabilizacji.

BatchNormalizationLayer {spatialRank = 0,
                         normalizationTimeConstant = 5000,
                         initialScale = 1, epsilon = 0.00001, useCntkEngine = true}
LayerNormalizationLayer {initialScale = 1, initialBias = 0}
StabilizerLayer{}

Parametry

BatchNormalizationLayer:

  • spatialRank: parametry normalizacji są w puli w ramach pierwszych spatialRank wymiarów. Obecnie dozwolone wartości to 0 (bez puli) i 2 (łączenie wszystkich pozycji pikseli obrazu)
  • normalizationTimeConstant (wartość domyślna 5000): stała czasu w próbkach filtru o niskim przepustce pierwszej kolejności, który jest używany do obliczania statystyk średniej/wariancji na potrzeby wnioskowania
  • initialScale: początkowa wartość parametru skalowania
  • epsilon: mała wartość, która jest dodawana do oszacowania wariancji podczas przetwarzania odwrotnego
  • useCntkEngine: jeśli prawda, użyj implementacji natywnej CNTK. Jeśli wartość false, użyj implementacji cuDNN (tylko procesor GPU).

LayerNormalizationLayer:

  • initialScale: początkowa wartość parametru skalowania
  • initialBias: początkowa wartość parametru stronniczości

Wartość zwracana

Funkcja, która implementuje warstwę, która wykonuje operację normalizacji.

Opis

BatchNormalizationLayer{} implementuje technikę opisaną w artykule Batch Normalization: Przyspieszanie głębokiego trenowania sieci poprzez zmniejszenie wewnętrznej zmiany wariancji (Sergey Ioffe, Christian Szegedy). Normalizuje swoje dane wejściowe dla każdej minibatch przez średnią/wariancję minibatch i anuluje normalizację przy użyciu poznanego współczynnika skalowania i stronniczości.

W wnioskowaniu zamiast używać średniej/wariancji minibatch, normalizacja wsadowa używa długoterminowego oszacowania średniej/var. To oszacowanie jest obliczane podczas trenowania przez statystyki minibatch filtrowania niskiego poziomu. Stała czasowa filtru o niskim przepustce normalizationTimeConstant może zostać zmodyfikowana przez parametr . Zalecamy rozpoczęcie od wartości domyślnej (5000), ale eksperymentujemy z innymi wartościami, zazwyczaj w kolejności od kilku tysięcy do dziesiątek tysięcy.

LayerNormalizationLayer{} implementuje normalizację warstw (Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton). Normalizuje każdą próbkę wejściową, odejmując średnią we wszystkich elementach próbki, a następnie dzieląc ją przez odchylenie standardowe dla wszystkich elementów próbki.

StabilizerLayer{} implementuje samozwańcze stabilizator na samozwańczej głębokiej sieci neuronowej (P. Ghahremani, J. Droppo). Ta prosta, ale efektywna technika mnoży swoje dane wejściowe przy użyciu uczenia się skalarnego (ale w przeciwieństwie do normalizacji warstwy, nie najpierw normalizuje danych wejściowych ani nie odejmuje średniej). Zwróć uwagę, że w porównaniu z oryginalnym papierem, który proponuje liniowy skalar beta lub wykładniczy Exp (beta), okazało się, że korzystne jest użycie wyostrzonej operacji softplus na sugestię drugiego autora, która pozwala uniknąć zarówno wartości ujemnych, jak i niestabilności z wykładniczego.

Uwagi

BatchNormalizationLayer{} jest otoką wokół pierwotnego BatchNormalization() . LayerNormalizationLayer{} i StabilizerLayer{} są wyrażane bezpośrednio w języku BrainScript.

Przykład

Typowa warstwa w sieci konwolucyjnej z normalizacją wsadową:

MyLayer (x, depth, initValueScale) =
{
    c = ConvolutionalLayer {depth, (5:5), pad=true, initValueScale=initValueScale} (x)
    b = BatchNormalizationLayer {spatialRank = 2} (c)    #####
    r = ReLU (b)
    p = MaxPoolingLayer {(3:3), stride = (2:2)} (r)
}.p

FeatureMVNLayer{}

Funkcja factory, aby utworzyć warstwę, która normalizuje dane wejściowe funkcji według średniej i odchylenia standardowego.

FeatureMVNLayer{}

Parametry

Pusta lista argumentów {}.

Wartość zwracana

Funkcja, która implementuje warstwę, która wykonuje operację normalizacji.

Opis

Ta warstwa normalizuje dane wejściowe w sieci neuronowej przez jej odchylenie i wariancję. Te wartości są szacowane z góry przez wykonanie pełnego przekazywania danych treningowych, a następnie zapisanie i zamrożenie. Nastąpi to automatycznie.

Ponieważ parametry tej warstwy są wstępnie skompilowane w osobnym przekazaniu przed głównym trenowaniem, można go zastosować tylko do zmiennych zadeklarowanych jako Input{}.

Przykład

Jest to typowy początek sieci neuronowej do modelowania akustycznego mowy:

features = Input{40}      # e.g. speech features
featNorm = FeatureMVNLayer{} (features)
h = DenseLayer{2048} (featNorm)
...