BrainScript i Python: interpretacja i rozszerzanie czytelników
Począwszy od wersji 1.5, CNTK odchodzi od projektu czytnika monolitycznego w kierunku bardziej złożonego modelu, który umożliwia określanie i redagowanie danych wejściowych różnych formatów.
Wcześniej każdy czytelnik był odpowiedzialny za różne aspekty odczytywania danych, w tym między innymi:
- Deserializacja danych z magazynu zewnętrznego do reprezentacji w pamięci
- Randomizacja całego korpusu
- Różne przekształcenia sekwencji wejściowych/przykładów (np. przycinanie lub skalowanie obrazów)
- Tworzenie minibatches dla różnych trybów (tj. ramka, sekwencja lub obcięta BPTT) z układem, który może być używany przez procesor GPU
- Pobieranie wstępne na poziomie minibatches i fragmentów we/wy
W wersji 1.5 główne elementy powyższej funkcjonalności zostały wyliczone i przeniesione do podstawowego zestawu CNTK, aby były udostępniane między różnymi czytnikami. W tej wersji wprowadzono również dwie główne abstrakcje, które można rozszerzyć w celu obsługi nowych formatów danych:
- deserializacji — jest odpowiedzialny za deserializacji danych wejściowych z magazynu zewnętrznego do sekwencji w pamięci
- przekształcenia — przekształca sekwencję wejściową w sekwencję wyjściową
W następnych sekcjach bardziej szczegółowo omówiono te abstrakcji.
Konfigurowanie czytnika (minibatch source) w języku Python
Ta sekcja zawiera kilka przykładów konfigurowania czytnika złożonego (np. MinibatchSource) w języku Python.
Poniższy przykład został dostosowany z AlexNet_ImageNet_Distributed.py, przedstawia odpowiednik języka Python czytnika AlexNet z sekcji Transforms.
import cntk.io
mean_file = ...
map_file = ...
# model dimensions
image_height = 227
image_width = 227
num_channels = 3 # RGB
num_classes = 1000
transforms = [
ImageDeserializer.crop(crop_type='randomside',
side_ratio=0.88671875,
jitter_type='uniratio'),
ImageDeserializer.scale(width=image_width,
height=image_height,
channels=num_channels,
interpolations='linear'),
ImageDeserializer.mean(mean_file)
]
reader = MinibatchSource(
ImageDeserializer(map_file, StreamDefs(
# first column in map file is referred to as 'image'
features = StreamDef(field='image', transforms=transforms),
# and second as 'label'
labels = StreamDef(field='label', shape=num_classes))))
W poniższym przykładzie (dostosowanym z A2_RunCntk_py3.py) pokazano, jak można połączyć ze sobą kilka deserializacji.
n_rois = 100
n_classes = 17
rois_dim = 4 * n_rois
label_dim = n_classes * n_rois
map_file = ...
roi_file = ...
label_file = ...
# read images
scale = ImageDeserializer.scale(width=1000,
height=1000,
channels=3,
scale_mode="pad",
pad_value=114,
interpolations='linear')
image_source = ImageDeserializer(map_file)
image_source.ignore_labels()
image_source.map_features('features', [scale])
# read rois and labels
roi_source = CTFDeserializer(roi_file)
roi_source.map_input('rois', dim=rois_dim, format="dense")
label_source = CTFDeserializer(label_file)
label_source.map_input('roiLabels', dim=label_dim, format="dense")
# define a composite reader
reader = MinibatchSource([image_source, roi_source, label_source])
...
# define mapping from reader streams to network inputs
input_map = {
image_input: reader.streams.features,
roi_input: reader.streams.rois,
label_input: reader.streams.roiLabels
}
BrainScript
Deserializatory
Przyjrzyjmy się następującemu fragmentowi konfiguracji HTKMLFReader z kompleksowego LSTM/FullUtterance (pełna konfiguracja tutaj):
...
# Old reader config. For illustration only.
reader = [
readerType = "HTKMLFReader"
readMethod = "blockRandomize"
nbruttsineachrecurrentiter = 32
randomize = "auto"
verbosity = 0
features = [
dim = 363
type = "real"
scpFile = "$DataDir$/glob_0000.scp"
]
labels = [
mlfFile = "$DataDir$/glob_0000.mlf"
labelMappingFile = "$DataDir$/state.list"
labelDim = 132
labelType = "category"
]
]
Ten fragment konfiguracji deklaruje czytelnika, który tworzy dwa strumienie danych o nazwach "features"
i "labels"
. Przyjmuje on jako dane wejściowe dwa typy plików:
- lista plików funkcji znanych w parlance jako plik
scp
("script" file) - plik etykiety znany jako plik
mlf
("plik etykiety głównej")
W powyższym fragmentze konfiguracji nie ma jawnych jednostek, które definiują sposób deserializacji formatów scp
lub mlf
.
Wszystko jest hermetyzowane w konfiguracji scp
i mlf
, musisz zmienić HTKMLFReader i dodać tam obsługę.
Aby zwiększyć możliwość komponowania i ponownego użycia, nową konfigurację dla tych samych danych wejściowych jawnie definiuje deserializatory i strumienie wejściowe, które tworzą:
reader = [
verbosity = 0
randomize = true
# A list of deserializers the reader uses.
deserializers = (
[
# Type of deserializer, in this case the one that knows
# how to deserialize HTK feature files.
type = "HTKFeatureDeserializer"
# Module (.dll or .so) where this deserializer is implemented
module = "HTKDeserializers"
# Description of input streams the deserializer provides,
# can be one or many, depending on a particular
# deserializer implementation
# For HTKFeatureDeserializer, just one stream can be described.
input = [
# Description of input stream to feed the Input node named "features"
features = [
dim = 363
scpFile = "$DataDir$/glob_0000.scp"
]
]
]:
[
# Type of deserializer, in this case the one
# that knows how to deserialize mlf files.
type = "HTKMLFDeserializer"
module = "HTKDeserializers"
# Description of input streams the deserializer provides,
# For HTKMLFDeserializer, just one stream can be described.
input = [
# Description of input stream to feed the Input node named "labels"
labels = [
dim = 132
mlfFile = "$DataDir$/glob_0000.mlf"
labelMappingFile = "$DataDir$/state.list"
# whether phone boundary information should be encoded
# set to true in CTC-type training
phoneBoundaries=false
]
]
]
)
]
Sekwencje tworzone przez mlf
i deserializatory htk
są łączone na podstawie ich klucza logicznego (czyli ciągu, który jednoznacznie identyfikuje wypowiedź mowy i jest obecny zarówno w plikach scp
, jak i mlf
).
Jeśli potrzebujesz innego strumienia innego formatu, możesz po prostu dodać odpowiedni deserializator do konfiguracji (nie jest to możliwe w przypadku funkcji HTK i deserializacji HTK MLF w tej chwili, aby uwidocznić więcej niż jeden strumień wejściowy każdy).
Nuta
Obecnie obsługiwane są zarówno stare, jak i nowe konfiguracje czytników. Gdy klucz "deserializatory" jest używany w konfiguracji czytnika, typ czytnika jest niejawnie ustawiony na wartość "CompositeDataReader". Aby upewnić się, że moduł CompositeDataReader można załadować w systemie Windows, Cntk.Composite.dll
powinien znajdować się w tym samym katalogu co plik wykonywalny CNTK. W systemie Linux Cntk.Composite.so
powinien znajdować się w folderze lib
, który znajduje się obok folderu bin
zawierającego plik wykonywalny CNTK.
Obecnie cnTK obsługuje poniższe deserializatory:
Typ deserializacji | Moduł | Opis |
---|---|---|
HTKFeatureDeserializer | HTKDeserializers | Deserializator dla plików funkcji HTK |
HTKMLFDeserializer | HTKDeserializers | Deserializator dla plików MLF HTK |
ImageDeserializer | ImageReader | Deserializator obrazów zakodowanych jako zwykłe pliki lub w archiwum zip. |
Base64ImageDeserializer | ImageReader | Deserializator obrazów zakodowanych jako ciągi base64 w pliku mapowania. |
CNTKTextFormatDeserializer | CNTKTextFormatReader | Deserializator dla plików formatu tekstowego CNTK |
CNTKBinaryFormatDeserializer | CNTKBinaryReader | Deserializator dla plików formatu binarnego CNTK |
Aby uzyskać pełny opis parametrów konfiguracji, zapoznaj się z tabelami poniżej.
Przekształca
Przekształcenie to prosta abstrakcja, która pobiera sekwencję jako dane wejściowe, wykonuje pewne przekształcenia próbek w sekwencji i zwraca sekwencję danych wyjściowych. Typowe przykłady przekształceń to różne przekształcenia obrazów, takie jak przycinanie, skalowanie lub transponowanie. Przekształcenia można konfigurować na podstawie danych wejściowych.
Przyjrzyjmy się, jak można zastosować przekształcenia do danych wejściowych (konfiguracja jest pobierana z testu /EndToEndTests/Image/AlexNet test):
deserializers = ([
type = "ImageDeserializer"
module = "ImageReader"
# Map file which maps images to labels
file = "$ConfigDir$/train_map.txt"
# Description of input streams
input = [
# Description of input stream to feed the Input node named "features"
features = [
transforms = (
[
type = "Crop"
# Possible values: Center, RandomSide, RandomArea, Multiview10. Default: Center
cropType = "RandomSide"
# Crop scale side ratio.
sideRatio = 0.875
# Crop scale ratio jitter type
jitterType = "UniRatio"
]:[
type = "Scale"
width = 224
height = 224
channels = 3
# Interpolation to use when scaling image to width x height size.
interpolations = "linear"
]:[
type = "Mean"
# Stores mean values for each pixel in OpenCV matrix XML format.
meanFile = "$ConfigDir$/ImageNet1K_mean.xml"
]:[
# Changes the image layout from HWC to CHW
type = "Transpose"
]
)
]
# Description of input stream to feed the Input node named "labels"
labels = [
labelDim = 1000
]
]
]
])
W tej konfiguracji cztery przekształcenia są stosowane do strumienia wejściowego features
.
Początkowo deserializator danych obrazu tworzy sekwencje składające się z pojedynczego obrazu w reprezentacji HWC.
Następnie uporządkowana lista przekształceń jest stosowana do obrazu: najpierw przekształcenie Crop, a następnie Scale i Mean.
Ostatnia transformacja jest Transponuj, która zmienia układ obrazu z HWC na CHW.
Obecnie są implementowane następujące przekształcenia. Aby uzyskać szczegółowy opis, zobacz ImageReader.
Typ przekształcenia | Moduł |
---|---|
Wole | ImageReader |
Skala | ImageReader |
Kolor | ImageReader |
Znaczyć | ImageReader |
Transpozycji | ImageReader |
Opis nowego formatu konfiguracji czytnika
Sekcja konfiguracji czytnika do tworzenia kilku deserializacji danych wygląda następująco:
reader = [
randomize = true|false
verbosity = 0|1|2
...
deserializers = (
[<deserializerConfiguration1>]:
[<deserializerConfiguration2>]:
...
[<deserializerConfigurationN>]
)
]
Każda konfiguracja deserializacji jest określona jako:
[
module = "<readerModuleName>" # Name of the external module (.dll or .so) where this particular deserializer is implemented
type = "<deserializerType>" # The type of the deserializer
# There could be more deserializer-specific options in this section
# Date deserializer input - describes a set of streams this deserializer produces.
# It can be one (as in HTK) or many (as in CNTKTextFormat)
input = [
# Replace 'InputNameN' by the name of the corresponding input node in the network.
InputName1 = [<inputConfiguration>]
InputName2 = [<inputConfiguration>]
...
]
]
Konfiguracja danych wejściowych zawiera opcje specyficzne dla danych wejściowych i, opcjonalnie, uporządkowaną listę przekształceń, które mają być stosowane do danych wejściowych:
[
# Per-input data deserializer-specific options
# Optionally a pipeline of transformations, to be implemented by data deserializer's reader module:
transforms = (
[<transformationConfiguration1>]:
[<transformationConfiguration2>]:
...
[<transformationConfigurationN>]
)
]
Konfiguracja przekształcania identyfikuje typ przekształcenia i wszelkie opcje specyficzne dla transformacji:
[
type = "<transformName>"
# Transform-specific options
]
Opcje konfiguracji
Konfiguracja czytelnika ogólnego
Parametr | Opis |
---|---|
verbosity |
Poziom szczegółowości (0 , 1 , 2 ), steruje danymi wyjściowymi diagnostycznymi różnych składników (Randomizer, Deserializer, Bundler itp.) opcjonalne, wartości domyślne 0 . |
randomize |
Określa, czy dane wejściowe powinny być losowe ( true , false ). Metoda randomizacji jest identyczna jak blockRandomize HTKMLFReader.
opcjonalne, wartość domyślna to true . |
randomizationSeed |
Początkowa wartość inicjacji losowej (zwiększana jest każda zamiatanie, gdy dane wejściowe są ponownie losowe).
opcjonalne, wartość domyślna to 0 . |
randomizationWindow |
Określa rozmiar (dodatnia liczba całkowita) okna losowania (tj. zakres losowania). Ten parametr wpływa na ilość zestawu danych, która musi znajdować się w pamięci jednocześnie.
Opcjonalnewartość domyślna to rozmiar całego zestawu danych (w próbkach lub we fragmentach w zależności od wartości sampleBasedRandomizationWindow ). Jeśli jednak jeden z deserializatorów jest CNTKTextFormatDeserializer i sampleBasedRandomizationWindow nie został jawnie ustawiony na true , randomizationWindow będzie domyślnie 128 (czyli około 4 GB miejsca na dysku o wartości fragmentów). Ten parametr jest ignorowany, gdy randomize jest false . |
sampleBasedRandomizationWindow |
Jeśli true , rozmiar okna losowania jest interpretowany jako pewna liczba próbek i jako liczba fragmentów w przeciwnym razie.
Opcjonalnewartość domyślna to true , jeśli CNTKTextFormatDeserializer nie znajduje się na liście deserializacji, a w przeciwnym razie false . Podobnie jak randomizationWindow , ten parametr jest ignorowany, gdy randomize jest false . |
truncationLength |
Określa długość obcięcia w próbkach dla BPTT (dodatnia liczba całkowita).
wymagane tylko wtedy, gdy truncated jest true , ignorowane w przeciwnym razie. |
multiThreadedDeserialization |
Określa, czy należy używać wielu wątków podczas zbierania sekwencji dla minibatch z deserializacji (true , false ).
opcjonalne. |
frameMode |
Określa, czy dane powinny być losowe i zwracane na poziomie ramki lub sekwencji. W przypadku true sekwencja wejściowa jest podzielona na ramki.
opcjonalne. Nie można jednocześnie ustawić true zarówno frameMode , jak i truncated . |
truncated |
Gdy true , włącza obcinanie propagacji wstecznej w czasie (BPTT).
opcjonalne. Nie można jednocześnie ustawić true zarówno frameMode , jak i truncated . |
useNumericSequenceKeys |
Klucze sekwencji są używane do skorelowanych sekwencji między różnymi deserializatorami. W przypadku niektórych deserializacji (tj. HTK i MLF) klucze sekwencji są dowolnymi ciągami. Przechowywanie ich wymaga dużej ilości pamięci na dużym korpusie. Jeśli masz pewność, że klucze sekwencji są numeryczne, ustaw ten parametr na wartość true, w takim przypadku wszystkie klucze ciągów zostaną przekonwertowane na liczby całkowite zmniejszające ciśnienie pamięci.
opcjonalne, domyślne false . |
hashSequenceKeys |
Ze względów pamięci opisanych powyżej można również ustawić skrót kluczy ciągów przez ustawienie tego parametru na wartość true. Użyj go tylko w przypadku deserializacji obsługujących klucze sekwencji ciągów (HTK, MLF).
opcjonalne, domyślne 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 ).
opcjonalne, wartość domyślna to false . Aby uzyskać więcej informacji, zobacz poniższą sekcję.
Nowy w CNTK w wersji 2.1. |
Buforowanie indeksów
Nuta
Nowość w CNTK w wersji 2.1.
Buforowanie indeksów pozwala znacząco (przez współczynnik 2–3x) skrócić czas uruchamiania, szczególnie podczas pracy z dużymi plikami wejściowymi. Ustawienie flagi cacheIndex
na wartość true
zasygnalizuje czytelnikowi zapisanie 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 najlepszym wysiłkiem i jest przeprowadzane na osobnym wątku, aby nie wpływać na wydajność czytnika. Jeśli plik pamięci podręcznej jest obecny i jest up-to-date, czytnik nie będzie już skąski pliku wejściowego w celu 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 frameMode
mogą potencjalnie spowodować indeksy, które mają różną liczbę sekwencji). Z tego powodu plik pamięci podręcznej może zostać zignorowany przez czytelnika z konfiguracją inną niż ta, która wygenerowała pamięć podręczną. Aby zobaczyć pełną korzyść z buforowania, konfiguracja nie powinna być modyfikowana podczas kolejnych ponownych uruchomień.
cacheIndex
nie ma wpływu na ImageDeserializer i CNTKBinaryFormatDeserializer, ponieważ poprzedni nie indeksuje danych wejściowych, a później zawiera informacje o indeksie osadzone w samym formacie.
Ogólna konfiguracja deserializacji
Parametr | Opis |
---|---|
module |
Określa nazwę modułu czytnika, który implementuje deserializator danych. wymagane. |
type |
Określa nazwę deserializacji danych uwidacznianą przez dany moduł czytnika. wymagane. |
Konfiguracja przekształcania ogólnego
Parametr | Opis |
---|---|
type |
Określa nazwę przekształcenia uwidacznianą przez moduł czytelnika implementując deserializacji danych. wymagane. |
Opcje HTKFeatureDeserializer
Parametr | Opis |
---|---|
scpFile |
Lista ścieżek do plików SCP do przetworzenia. Pliki powinny być plikami zgodnymi z zestawem HTK i muszą być określone w formacie "archiwum". Szczegóły korzystania z archiwum opisano w HTKMLF Reader. wymagane. |
dim |
Liczba całkowita określająca pełny wymiar wektora funkcji z żądanym oknem kontekstu.1wymagane |
contextWindow |
Można określić jako parę dodatnich liczb całkowitych lub jako pojedynczą dodatnią liczbę całkowitą (w takim przypadku jest interpretowana jako para z tą samą liczbą powtórzona dwa razy). Określa rozmiar lewej i prawej (pierwsza i druga liczba całkowita pary) okna kontekstu w przykładach.
opcjonalne, wartość domyślna to 1 . |
prefixPathInSCP |
Ciąg prefiksu, który ma być stosowany do ścieżek określonych w plikach SCP. opcjonalne. |
1 Na przykład jeśli masz 72-wymiarowe funkcje (24-wymiarowe funkcje filtru plus współczynniki różnicowe i różnicowe różnicowe), a sieć jest przeznaczona do przetwarzania okna kontekstowego 11 ramek, określony wymiar powinien wynosić 792.
HTKMLFDeserializer opcje
Parametr | Opis |
---|---|
mlfFile |
Ścieżka do pliku mlf w stylu HTK, który zawiera etykiety dla wszystkich wypowiedzi określonych w plikach scp .
wymagane, jeśli nie określono mlfFileList . |
mlfFileList |
Tablica ścieżek do plików mlf w stylu HTK, które zawierają etykiety dla wszystkich wypowiedzi określonych w plikach scp .
wymagane, jeśli nie określono mlfFile . |
dim |
Całkowita kardynalność zestawu etykiet (dodatnia liczba całkowita). wymagane. |
labelMappingFile |
Ścieżka do pliku, który zawiera listę wszystkich etykiet widocznych w pliku mlf , jeden na wiersz.
wymagane. |
labelDim można użyć jako synonimu dim.
Opcje CNTKTextFormatDeserializer
Te same opcje, których można używać z CNTKTextFormatReader
Opcje elementu ImageDeserializer
-
file
: prosty plik tekstowy, w którym każdy wiersz zawiera mapowanie rozdzielane tabulatorami między kluczem sekwencji logicznej, plikiem obrazu (e.g. JPEG, PNG itp.) i etykietą opartą na 0.
Aby uzyskać więcej informacji, zobacz ImageReader.
Opcje base64ImageDeserializer
Ten deserializator obsługuje te same opcje, których można używać z elementem ImageDeserializer. Jedyną różnicą jest format pliku mapowania:
-
file
: prosty plik tekstowy, w którym każdy wiersz zawiera mapowanie rozdzielane tabulatorami między kluczem sekwencji logicznej (opcjonalnie, można pominąć), etykietą kategorii 0 i zakodowanym w formacie base 64 plikiem obrazu (e.g. JPEG, PNG itp.).
Przykłady konfiguracji i testów
Pełne definicje sieci i odpowiadające im przykłady zestawu danych znajdziesz w repozytorium CNTK. W tym miejscu znajdziesz również testy jednostkowe i kompleksowe, które używają deserializacji, tj.
- https://github.com/Microsoft/CNTK/tree/release/latest/Tests/EndToEndTests/Speech/HTKDeserializers/LSTM/FullUtterance
- https://github.com/Microsoft/CNTK/tree/release/latest/Tests/EndToEndTests/Image/AlexNet
- https://github.com/Microsoft/CNTK/tree/release/latest/Tests/UnitTests/ReaderTests/Config/ImageAndTextReaderSimple_Config.cntk
- https://github.com/Microsoft/CNTK/tree/release/latest/Tests/UnitTests/ReaderTests/Config/CNTKTextFormatReader/dense.cntk