Czytnik formatu tekstu CNTK BrainScript
Ta strona dokumentuje element CNTKTextFormatReader z punktu widzenia języka BrainScript, ale użytkownicy języka Python mogą się uczyć, czytając ten dokument, a także — pojęcia, parametry i wzorce są takie same.
Klasa CNTKTextFormatReader (później po prostu czytnik CTF) została zaprojektowana tak, aby używać danych tekstowych wejściowych sformatowanych zgodnie ze specyfikacją poniżej. Obsługuje ona następujące główne funkcje:
- Wiele strumieni wejściowych (danych wejściowych) na plik
- Zarówno rozrzedne, jak i gęste dane wejściowe
- Sekwencje o zmiennej długości
format tekstu CNTK (CTF)
Każdy wiersz w pliku wejściowym zawiera jedną próbkę dla co najmniej jednego wejścia. Ponieważ (jawnie lub niejawnie) każdy wiersz jest również dołączany do sekwencji, definiuje co najmniej jedną <sekwencję, dane wejściowe, relacje przykładowe> . Każdy wiersz wejściowy musi być sformatowany w następujący sposób:
[Sequence_Id](Sample or Comment)+
gdzie
Sample=|Input_Name (Value )*
Comment=|# some content
- Każdy wiersz rozpoczyna się od identyfikatora sekwencji i zawiera co najmniej jedną próbkę (innymi słowy każdy wiersz jest nieurządkowaną kolekcją przykładów).
- Identyfikator sekwencji jest liczbą. Można go pominąć, w tym przypadku numer wiersza będzie używany jako identyfikator sekwencji.
- Każda próbka jest w rzeczywistości parą klucz-wartość składającą się z nazwy wejściowej i odpowiedniego wektora wartości (mapowanie wyższych wymiarów odbywa się w ramach samej sieci).
- Każda próbka rozpoczyna się od symbolu kreski kreskowej (
|
), a następnie nazwy wejściowej (bez spacji), a następnie ogranicznika odstępów, a następnie listy wartości. - Każda wartość jest liczbą lub liczbą z prefiksem indeksu dla rzadkich danych wejściowych.
- Zarówno karty, jak i spacje mogą być używane zamiennie jako ograniczniki.
- Komentarz zaczyna się od potoku bezpośrednio po symbolu skrótu:
|#
, a następnie faktycznie zawartości (treści) komentarza. Treść może zawierać dowolne znaki, jednak symbol potoku wewnątrz treści musi zostać unikowany przez dołączenie do niego symbolu skrótu (zobacz poniższy przykład). Treść komentarza będzie kontynuowana do końca wiersza lub następnego nieokreślonego potoku, w zależności od tego, co nastąpi wcześniej.
Prosty przykład
Ten przykład jest oparty na minimalnym zestawie parametrów i opcji formatowania.
Aby użyć czytnika CTF ustaw wartość readerType
na CNTKTextFormatReader
w sekcji czytelnika konfiguracji CNTK:
...
reader = [
readerType = "CNTKTextFormatReader"
file = "c:\mydata\SampleInput.txt" # See the second example for Linux path example
# IMPORTANT!
# All inputs are grouped within "input" sub-section.
input = [
A = [
dim = 5
format = "dense"
]
B = [
dim = 1000000
format = "sparse"
]
C = [
dim = 1
format = "dense"
]
]
]
# the rest of the cntk config ...
(Ten fragment, a także inne przykłady NDL w tym dokumencie zawiera tylko reader
sekcję, pomijając pozostałą część konfiguracji CNTK; zobacz koniec tej strony dla wskaźników do zestawu kompletnych przykładowych sieci i odpowiednich zestawów danych)
Czytnik CTF wymaga następującego zestawu parametrów:
file
— ścieżka do pliku z zestawem danych.input
— podsekcji definiujące dane wejściowe identyfikowane przez nazwy danych wejściowych (A
B
iC
w powyższym przykładzie). W każdym wejściu należy określić następujące wymagane parametry:format
- określa typ danych wejściowych. Musi byćdense
lubsparse
dim
- określa wymiar wektora wartości wejściowej (dla gęstych danych wejściowych odpowiada to bezpośrednio liczbie wartości w każdej próbce, dla rozrzednionych reprezentuje górną granicę zakresu możliwych wartości indeksu).
Dane wejściowe odpowiadające powyższej konfiguracji czytnika powinny wyglądać mniej więcej tak:
|B 100:3 123:4 |C 8 |A 0 1 2 3 4 |# a CTF comment
|# another comment |A 0 1.1 22 0.3 54 |C 123917 |B 1134:1.911 13331:0.014
|C -0.001 |# a comment with an escaped pipe: '|#' |A 3.9 1.11 121.2 99.13 0.04 |B 999:0.001 918918:-9.19
Zwróć uwagę na następujący format danych wejściowych:
|Input_Name
identyfikuje początek każdego przykładu wejściowego. Ten element jest obowiązkowy i następuje wektor wartości korespondenta.- Gęsty wektor to tylko lista wartości zmiennoprzecinkowych; wektor rozrzedny jest listą
index:value
krotki. - Zarówno karty, jak i spacje są dozwolone jako ograniczniki wartości (w wektorach wejściowych), a także ograniczniki danych wejściowych (między wejściami).
- Każda oddzielna linia stanowi "sekwencję" długości 1 ("Sekwencje o zmiennej długości rzeczywistej" objaśniono w poniższym przykładzie rozszerzonym).
- Każdy identyfikator wejściowy może pojawić się tylko raz w jednym wierszu (co przekłada się na jedną próbkę na dane wejściowe na wymaganie wiersza).
- Kolejność przykładów wejściowych w wierszu nie jest ważna (koncepcyjnie każdy wiersz jest nieurządkowaną kolekcją par klucz-wartość)
- Każda dobrze sformułowana linia musi kończyć się symbolami "Line Feed"
\n
lub "Carriage Return, Line Feed".\r\n
Przykład rozszerzony
Ten przykład zawiera wszystkie możliwe parametry konfiguracji i pokazuje różne opcje formatu wejściowego. Zapoznaj się z poniższymi tabelami, aby uzyskać pełny opis parametrów konfiguracji używanych w tym przykładzie.
...
precision="double"
reader = [
readerType = "CNTKTextFormatReader"
file = "/home/mydata/SampleInput.txt" # See the first example for Windows style path example
randomize = true
randomizationWindow = 30
skipSequenceIds = false
maxErrors = 100
traceLevel = 2
chunkSizeInBytes = 1024
keepDataInMemory = true
frameMode = false
input = [
Some_very_long_input_name = [
alias = "a"
dim = 3
format = "dense"
]
Some_other_also_very_long_input_name = [
alias = "b"
dim = 2
format = "dense"
]
]
]
# the rest of the cntk config ...
Czytnik złożony wygląda następująco:
reader = {
verbosity = 0 ;
randomize = true;
randomizationWindow=30
deserializers = ({
type = "CNTKTextFormatDeserializer" ; module = "CNTKTextFormatReader"
file = "/home/mydata/SampleInput.txt" # See the first example for Windows style path example
maxErrors = 100
skipSequenceIds = false
traceLevel = 2
input = {
qu1fea = {alias = "qui"; dim = 95589; format = "sparse"}
qu2fea = {alias = "quj"; dim = 95589; format = "sparse"}
pairweight = {alias = "wij"; dim = 1; format = "dense"}
}
})
}
Odpowiedni plik wejściowy może następnie wyglądać w przybliżeniu w następujący sposób:
100 |a 1 2 3 |b 100 200
100 |a 4 5 6 |b 101 201
100 |b 102983 14532 |a 7 8 9
100 |a 7 8 9
200 |b 300 400 |a 10 20 30
333 |b 500 100
333 |b 600 -900
400 |a 1 2 3 |b 100 200
|a 4 5 6 |b 101 201
|a 4 5 6 |b 101 201
500 |a 1 2 3 |b 100 200
Wszystkie opcje omówione w powyższym przykładzie nadal mają zastosowanie tutaj. Oprócz tego wprowadziliśmy dwie dodatkowe funkcje:
Aliasy nazw wejściowych
Nazwy danych wejściowych mogą być dowolnie długie i dlatego powtarzanie ich w całym pliku wejściowym może nie być wydajne. Aby temu zapobiec, zestaw danych może używać aliasów zamiast pełnych nazw wejściowych. Następnie należy określić aliasy w każdej podsekcji wejściowej. W naszym przykładzie zestaw danych używa aliasów a
i b
, które są mapowane na odpowiednio "Some_very_long_input_name" i "Some_other_also_very_long_input_name" w sekcji konfiguracji czytnika.
Identyfikatory sekwencji
Jak już wspomniano, każdy oddzielny wiersz w pliku wejściowym reprezentuje sekwencję zawierającą jedną próbkę dla każdego danych wejściowych. Jeśli jednak wiersz jest poprzedzony liczbą nieujemną, numer jest używany jako odpowiadający mu identyfikator sekwencji. Wszystkie kolejne wiersze współużytkujące ten sam identyfikator sekwencji są scalane razem, aby stać się częścią tej samej sekwencji. W związku z tym powtarzanie tego samego prefiksu liczbowego dla wierszy N pozwala utworzyć sekwencję z wieloma próbkami, z każdymi danymi wejściowymi zawierającymi od 1 do N próbek. Pominięcie prefiksu sekwencji na drugim i następujące wiersze ma taki sam efekt. W związku z tym powyższy przykładowy zestaw danych definiuje pięć sekwencji z identyfikatorami 100
, 200
, 333
400
i 500
.
Ustawienie skipSequenceIds
parametru w sekcji czytelnika na true
, wymusza, aby czytelnik ignorował wszystkie jawne identyfikatory sekwencji w zestawie danych i traktować oddzielne wiersze jako poszczególne sekwencje. Ponadto pominięcie identyfikatora sekwencji w pierwszym wierszu w zestawie danych ma taki sam efekt — wszystkie kolejne identyfikatory sekwencji są ignorowane, wiersze traktowane jako poszczególne sekwencje, jak w tym przykładzie:
|a 1 2 3 |b 100 200
100 |a 4 5 6 |b 101 201
200 |b 102983 14532 |a 7 8 9
Kilka ostatnich kwestii, które należy wziąć pod uwagę podczas korzystania z sekwencji:
- Identyfikatory sekwencji muszą być unikatowe.
- Prefiksy identyfikatorów można powtarzać tylko dla kolejnych wierszy.
- Długość sekwencji w wierszach (czyli liczba wierszy współużytkujących ten sam prefiks identyfikatora) nie może przekraczać maksymalnej długości wejściowej w próbkach (liczba próbek w danych wejściowych) w tej sekwencji.
Na przykład następujące zestawy danych są nieprawidłowe:
100 |a 1 2 3 |b 100 200
200 |a 4 5 6 |b 101 201
100 |b 102983 14532 |a 7 8 9
123 |a 1 2 3 |b 100 200
456 |a 4 5 6
456 |b 101 201
Kilka przykładów Real-World
- Klasyfikacja: każdy wiersz zawiera przykład, składający się z etykiety i funkcji. Nie jest potrzebny identyfikator sekwencji, ponieważ każdy wiersz jest własną "sekwencją" o długości 1.
|class 23:1 |features 2 3 4 5 6
|class 13:1 |features 1 2 0 2 3
...
- DSSM: każdy wiersz zawiera parę dokumentów typu source-target wyrażoną za pomocą worka słów zakodowanych jako rozrzedane wektory.
|src 12:1 23:1 345:2 45001:1 |tgt 233:1 766:2 234:1
|src 123:1 56:1 10324:1 18001:3 |tgt 233:1 2344:2 8889:1 2234:1 253434:1
- Tagowanie części mowy: sekwencje mapowania każdego elementu na odpowiednią etykietę. Sekwencje są wyrównane w pionie (jeden wyraz + tag na wiersz).
0 |word 234:1 |tag 12:1
0 |word 123:1 |tag 10:1
0 |word 123:1 |tag 13:1
1 |word 234:1 |tag 12:1
1 |word 123:1 |tag 10:1
...
- Klasyfikacja sekwencji: sekwencje mapowane na pojedynczą etykietę. Sekwencje są wyrównane w pionie; Etykieta "class" może wystąpić w dowolnym wierszu, który ma ten sam identyfikator sequenceId.
Uwaga
W tej chwili liczba wierszy nie może przekraczać długości najdłuższej sekwencji. Oznacza to, że etykieta nie może pojawiać się samodzielnie w wierszu. Jest to szczegół implementacji, który zostanie zniesiony w przyszłości.
0 |word 234:1 |class 3:1
0 |word 123:1
0 |word 890:1
1 |word 11:1 |class 2:1
1 |word 344:1
- Sekwencja do sekwencji: mapuj sekwencję źródłową na sekwencję docelową. Dwie sekwencje są wyrównane w pionie i, w najprostszym przypadku, po prostu wydrukowane po drugim. Są one przyłączone przez posiadanie tego samego ogólnego "identyfikatora sekwencji" (który następnie staje się "identyfikatorem jednostki roboczej" w tym przypadku).
Uwaga
W tej chwili liczba wierszy nie może przekraczać długości najdłuższej sekwencji. Oznacza to, że sekwencje muszą być wyrównane w poziomie. Jest to szczegół implementacji, który zostanie zniesiony w przyszłości.
0 |sourceWord 234:1 |targetWord 344:1
0 |sourceWord 123:1 |targetWord 456:1
0 |sourceWord 123:1 |targetWord 2222:1
0 |sourceWord 11:1
1 |sourceWord 123:1
...
- Edukacja do rangi: "sekwencja" reprezentuje zapytanie, każdy przykładowy dokument z ręcznie oznaczoną oceną. W tym przypadku "sekwencja" jest po prostu wielozbiorem, który (w kontekście funkcji utraty typu "uczenie do rangi") nie ma kolejności.
0 |rating 4 |features 23 35 0 0 0 21 2345 0 0 0 0 0
0 |rating 2 |features 0 123 0 22 44 44 290 22 22 22 33 0
0 |rating 1 |features 0 0 0 0 0 0 1 0 0 0 0 0
1 |rating 1 |features 34 56 0 0 0 45 1312 0 0 0 0 0
1 |rating 0 |features 45 45 0 0 0 12 335 0 0 0 0 0
2 |rating 0 |features 0 0 0 0 0 0 22 0 0 0 0 0
...
Parametry konfiguracji
Parametr | Opis |
---|---|
precision |
Określa precyzję zmiennoprzecinkową (double lub float ) wartości wejściowych. Opcjonalnie wartość domyślna to float . |
reader
Sekcji
Parametr | Opis |
---|---|
readerType |
Określa jeden z obsługiwanych CNTK czytników do załadowania (np. CNTKTextFormatReader ). Wymagane. |
file |
Ścieżka do pliku zawierającego wejściowy zestaw danych (Windows lub styl systemu Linux). Wymagane. |
randomize |
Określa, czy dane wejściowe powinny być losowe (true , false ). Opcjonalnie wartość domyślna to true . |
randomizationSeed |
Początkowa wartość inicjacji losowej (zwiększana jest każda zamiatanie, gdy dane wejściowe są ponownie losowe). Opcjonalnie wartość domyślna to 0 . |
randomizationWindow |
Określa rozmiar (dodatnią liczbę całkowitą) okna losowania (tj. zakres losowania). Ten parametr wpływa na to, ile zestawu danych musi znajdować się w pamięci jednocześnie. Opcjonalnie, w zależności od sampleBasedRandomizationWindow wartości, domyślnie rozmiar całego zestawu danych w próbkach (tj. dane wejściowe są losowe w całym zestawie danych) lub 4 GB miejsca na dysku o wartości fragmentów (tj. 128 gdy rozmiar fragmentu jest równy 32 MB). Ten parametr jest ignorowany, gdy randomize jest to false . |
sampleBasedRandomizationWindow |
Jeśli true rozmiar okna losowania jest interpretowany jako pewna liczba próbek, w przeciwnym razie — jako liczba fragmentów. Opcjonalnie wartość domyślna to false . Podobnie jak randomizationWindow , ten parametr jest ignorowany, gdy randomize jest false . |
skipSequenceIds |
Jeśli true czytnik zignoruje identyfikatory sekwencji w pliku wejściowym, interpretując każdy oddzielny wiersz jako niezależną sekwencję rozmiaru 1 (zobacz sekcję w identyfikatorach sekwencji). Opcjonalnie wartość domyślna to false . |
maxErrors |
Liczba błędów wejściowych, po których należy zgłaszać wyjątek. Opcjonalnie wartość domyślna 0 to , co oznacza, że pierwsza źle sformułowana wartość spowoduje wyzwolenie wyjątku. |
traceLevel |
Poziom szczegółowości danych wyjściowych. 0 - pokaż tylko błędy; 1 - pokaż błędy i ostrzeżenia; 2 — pokaż wszystkie dane wyjściowe. Opcjonalnie wartość domyślna to 1 . |
chunkSizeInBytes |
Liczba kolejnych bajtów do odczytu z dysku w jednej operacji odczytu. Opcjonalne wartości domyślne to 33554432 (32 MB). |
keepDataInMemory |
Jeśli true cały zestaw danych będzie buforowany w pamięci. Opcjonalnie wartość domyślna to false . |
frameMode |
true sygnalizuje czytelnikowi użycie metody pakowania zoptymalizowanej pod kątem ramek (sekwencje zawierające tylko jedną próbkę). Opcjonalnie wartość domyślna to false . |
cacheIndex |
Określa, czy metadane utworzone podczas etapu przetwarzania wstępnego powinny być zapisywane na dysku i ładowane z dysku, jeśli są dostępne (true , false ). Opcjonalnie wartość domyślna to false . Aby uzyskać więcej informacji, zobacz sekcję poniżej. Nowość w wersji CNTK 2.1. |
Buforowanie indeksów
Uwaga
Nowość w wersji CNTK 2.1.
Buforowanie indeksów pozwala znacząco (przez współczynnik 2–3x) skrócić czas uruchamiania, zwłaszcza podczas pracy z dużymi plikami wejściowymi. Ustawienie flagi cacheIndex
true
, aby zasygnalizować czytelnikowi zapisanie indeksujących metadanych na dysku (ten sam katalog co plik wejściowy), jeśli plik pamięci podręcznej jest niedostępny lub jest nieaktualny (starszy niż plik wejściowy). Pisanie jest najlepsze i jest wykonywane na osobnym wątku, aby nie wpływać na wydajność czytnika. Jeśli plik pamięci podręcznej jest obecny i jest aktualny, czytnik nie będzie już skąski pliku wejściowego do skompilowania indeksu, zamiast tego załaduje indeks z pliku pamięci podręcznej. Należy pamiętać, że niektóre parametry konfiguracji czytnika mają bezpośredni wpływ na indeksowanie (na przykład różne wartości mogą frameMode
spowodować indeksy o różnej liczbie sekwencji). Z tego powodu plik pamięci podręcznej może zostać zignorowany przez czytelnika z konfiguracją inną niż ta, która wyprodukowała pamięć podręczną. Aby zobaczyć pełną korzyść z buforowania, konfiguracja nie powinna być modyfikowana podczas kolejnych ponownych uruchomień.
input
podsekcji
input
Łączy wiele pojedynczych danych wejściowych, z których każda ma odpowiednio oznaczona etykietą podsekcji konfiguracji. Wszystkie parametry opisane poniżej są specyficzne dla podsekcji Nazwa danych wejściowych skojarzonych z określonymi danymi wejściowymi.
Parametr | Opis |
---|---|
alias |
Alternatywna nazwa skrótu (ciąg) używana do identyfikowania danych wejściowych w zestawie danych. Opcjonalne |
format |
Określa typ danych wejściowych (dense , sparse ). Wymagane. |
dim |
Wymiar (dodatnia liczba całkowita) wartości wejściowej (tj. liczba wartości wejściowych w próbce dla gęstych danych wejściowych, górna granica zakresu indeksów dla danych wejściowych rozrzednionych ). Wymagane. |
definesMBSize |
Flaga (wartość domyślna false) wskazująca, czy rozmiar minibatch powinien być liczone w próbkach z tego konkretnego strumienia Opcjonalne. |
Pełne definicje sieci i odpowiednie przykłady zestawu danych znajdziesz w repozytorium CNTK. W tym miejscu znajdziesz również test end-to-end , który używa czytnika CNTKTextFormat.