Поделиться через


BrainScript и Python: понимание и расширение средств чтения

Начиная с версии 1.5, CNTK отходит от монолитного средства чтения к более составной модели, которая позволяет задавать и создавать входные данные различных форматов.

До этого каждый читатель отвечал за различные аспекты чтения данных, включая, но не только:

  • Десериализация данных из внешнего хранилища в представление в памяти
  • Рандомизация всего корпуса
  • Различные преобразования входных последовательностей и примеров (например, обрезка или масштабирование изображений)
  • Создание мини-пакетов для различных режимов (например, фрейма, последовательности или усечения BPTT) с макетом, который может использоваться GPU
  • Предварительная выборка на уровне мини-пакетов и блоков ввода-вывода

В версии 1.5 основные компоненты перечисленных выше функций были факторированы и перемещены в основной CNTK для совместного использования между различными средствами чтения. В этой версии также представлены две основные абстракции, которые можно расширить для поддержки новых форматов данных:

  • десериализатор — он отвечает за десериализацию входных данных из внешнего хранилища в последовательности в памяти.
  • преобразование — он преобразует входную последовательность в выходную последовательность.

В следующих разделах мы более подробно обсудим эти абстракции.

Настройка средства чтения (источника minibatch) в Python

В этом разделе приведено несколько примеров настройки составного средства чтения (aka MinibatchSource) в Python.

В следующем примере было адаптировано из файла AlexNet_ImageNet_Distributed.py, в нем показан эквивалент Python средства чтения AlexNet из раздела "Преобразования ".

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)))) 

В следующем примере (адаптированном на основе A2_RunCntk_py3.py) показано, как можно объединить несколько десериализаторов.

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

Десериализаторы

Давайте рассмотрим следующий фрагмент конфигурации для HTKMLFReader из сквозного теста LSTM/FullUtterance (полная конфигурация здесь):

...
# 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"
    ]
]

Этот фрагмент конфигурации объявляет средство чтения, которое создает два потока данных с именами "features" и "labels". Он принимает в качестве входных двух типов файлов:

  • список файлов компонентов, известных в языке HTK как scp файл (файл скрипта)
  • файл метки, известный как mlf файл ("файл главной метки")

В приведенном выше фрагменте конфигурации нет явных сущностей, которые определяют scp способ десериализации или mlf форматы. Все инкапсулируется в конфигурации HTKMLFReader . Поэтому, если вам нужно предоставить еще один входной поток другого формата данных вместе с scp и mlf, вам потребуется изменить HTKMLFReader и добавить поддержку.

Чтобы повысить компостируемость и повторное использование, новая конфигурация для одного и того же входного ввода явно определяет десериализаторы и входные потоки, которые они создают:

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
                ]
            ]
        ]
    )
]

Последовательности, созданные mlf десериализаторами, htk объединяются вместе на основе их логического ключа (это строка, которая однозначно идентифицирует речевой фрагмент речи и присутствует в обоих scpmlf файлах). Если вам нужен другой поток другого формата, вы можете просто добавить соответствующий десериализатор в конфигурацию (невозможно использовать функцию HTK и десериализаторы MLF HTK прямо сейчас для предоставления нескольких входных потоков).

Примечание

В настоящее время поддерживаются старые и новые конфигурации чтения. Если ключ "десериализаторы" используется в конфигурации средства чтения, тип средства чтения неявно имеет значение CompositeDataReader. Чтобы убедиться, что модуль CompositeDataReader можно загрузить в Windows, Cntk.Composite.dll он должен находиться в том же каталоге, что и исполняемый файл CNTK. В Linux Cntk.Composite.so должна находиться в lib папке, которая находится рядом с bin папкой, содержащей исполняемый файл CNTK.

В настоящее время CNTK поддерживает следующие десериализаторы:

Тип десериализатора Модуль Описание
HTKFeatureDeserializer HTKDeserializers Десериализатор для файлов компонентов HTK
HTKMLFDeserializer HTKDeserializers Десериализатор для файлов HTK MLF
ImageDeserializer ImageReader Десериализатор для изображений, закодированных как обычные файлы или zip-архив.
Base64ImageDeserializer ImageReader Десериализатор для изображений, закодированных в виде строк base64 в файле сопоставления.
CNTKTextFormatDeserializer CNTKTextFormatReader Десериализатор для файлов текстового формата CNTK
CNTKBinaryFormatDeserializer CNTKBinaryReader Десериализатор для файлов двоичного формата CNTK

Полный описание параметров конфигурации см. в таблицах ниже .

Преобразования

Преобразование — это простая абстракция, которая принимает последовательность в качестве входных данных, выполняет некоторое преобразование образцов в последовательности и возвращает выходную последовательность. Типичными примерами преобразований являются различные преобразования изображений, таких как обрезка, масштабирование или транспонирование. Преобразования можно настроить на основе входных данных.

Давайте посмотрим, как можно применить преобразования к входным данным (конфигурация берется из теста Tests/EndToEndTests/Image/AlexNet ):

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
            ]
        ]
    ]
])

В этой конфигурации четыре преобразования применяются к входной потоку features. Изначально десериализатор данных изображения создает последовательности, состоящие из одного изображения в представлении HWC. После этого к изображению применяется упорядоченный список преобразований: сначала преобразование "Обрезка ", а затем " Масштаб " и "Среднее". Последнее преобразование — транспонирование , которое изменяет макет изображения с HWC на CHW.

В настоящее время реализованы следующие преобразования. Подробное описание см. в разделе ImageReader.

Тип преобразования Модуль
Crop ImageReader
Масштабирование ImageReader
Color ImageReader
Среднее значение ImageReader
Транспонировать ImageReader

Описание формата конфигурации нового средства чтения

Раздел конфигурации средства чтения для создания нескольких десериализаторов данных выглядит следующим образом:

reader = [
    randomize = true|false
    verbosity = 0|1|2
    ...

    deserializers = (
        [<deserializerConfiguration1>]:
        [<deserializerConfiguration2>]:
        ...
        [<deserializerConfigurationN>]
    )
]

Каждая конфигурация десериализатора указывается следующим образом:

[
    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>]
        ...
    ]
]

Входная конфигурация содержит параметры, относящиеся к входным данным, и при необходимости упорядоченный список преобразований, которые должны применяться к входным данным:

[
    # Per-input data deserializer-specific options

    # Optionally a pipeline of transformations, to be implemented by data deserializer's reader module:
    transforms = (
       [<transformationConfiguration1>]:
       [<transformationConfiguration2>]:
       ...
       [<transformationConfigurationN>]
    )
]

Конфигурация преобразования определяет тип преобразования и все параметры преобразования:

[
    type = "<transformName>"
    # Transform-specific options
]

Параметры конфигурации

Общая конфигурация чтения

Параметр Описание
verbosity Уровень детализации (0, , 1), 2управляет диагностическими выходными данными различных компонентов (Randomizer, Deserializer, Bundler и т. д.) Необязательный, по умолчанию — 0.
randomize Указывает, должны ли входные данные быть случайными ( true, , false). Метод randomization идентичен blockRandomize объекта HTKMLFReader. Необязательный, по умолчанию — true.
randomizationSeed Начальное начальное значение рандомизации (увеличивается каждый раз, когда входные данные повторно рандомизированы). Необязательный, по умолчанию — 0.
randomizationWindow Задает размер (положительное целое число) окна рандомизации (т. е. диапазон случайной выборки). Этот параметр влияет на то, сколько набор данных должен находиться в памяти одновременно. Необязательный, по умолчанию используется размер всего набора данных (в примерах или фрагментах в зависимости от sampleBasedRandomizationWindow значения). Однако если один из десериализаторов CNTKTextFormatDeserializer и sampleBasedRandomizationWindowне был явно задан, randomizationWindow по умолчанию 128 будет задано trueзначение (то есть около 4 ГБ места на диске объемом фрагментов). Этот параметр игнорируется в том случае randomizefalse.
sampleBasedRandomizationWindow Если trueразмер окна случайной выборки интерпретируется как определенное количество выборок, а в противном случае — как число блоков. Необязательный параметр, по умолчанию true — если CNTKTextFormatDeserializer он отсутствует в списке десериализаторов, а false в противном случае — значение. Аналогично этому параметру randomizationWindowигнорируется, когда randomize он имеет falseзначение .
truncationLength Указывает длину усечения в примерах для BPTT (положительное целое число). Требуется только в том случае, если truncated оно trueигнорируется в противном случае.
multiThreadedDeserialization Указывает, следует ли использовать несколько потоков при сборе последовательностей для мини-batch из десериализаторов (true, false). Необязательно.
frameMode Указывает, следует ли случайным образом возвращать данные на уровне кадра или последовательности. Когда trueвходная последовательность разбивается на кадры. Необязательно. И то frameMode , и truncated другое не может быть задано true одновременно.
truncated Когда trueвключает усечение обратного распространения по времени (BPTT). Необязательно. И то frameMode , и truncated другое не может быть задано true одновременно.
useNumericSequenceKeys Ключи последовательностей используются для корреляции последовательностей между различными десериализаторами. Для некоторых десериализаторов (т. е. HTK и MLF) ключи последовательности являются произвольными строками. Для их хранения требуется много памяти на большом корпусе. Если вы уверены, что ключи последовательности являются числовыми, задайте для этого параметра значение true, в этом случае все строковые ключи будут преобразованы в целые числа, уменьшая нехватку памяти. Необязательный, по умолчанию false.
hashSequenceKeys По причинам памяти, описанным выше, ключи строки также можно хэшировать, задав этому параметру значение true. Используйте его только для десериализаторов, поддерживающих ключи последовательности строк (HTK, MLF). Необязательный, по умолчанию false.
cacheIndex Указывает, должны ли метаданные, созданные на этапе предварительной обработки, записываться на диск и загружаться с диска, если они доступны (true, false). Необязательный, по умолчанию — false. Дополнительные сведения см. в разделе ниже. Новые возможности CNTK версии 2.1.
Кэширование индексов

Примечание

Новые возможности CNTK версии 2.1.

Кэширование индексов позволяет значительно (в 2–3 раза) сократить время запуска, особенно при работе с большими входными файлами. Задание флага cacheIndex сигнализирует средству true чтения записывать метаданные индексирования на диск (тот же каталог, что и входной файл), если файл кэша недоступен или если он устарел (старше входного файла). Написание является лучшим усилием и выполняется в отдельном потоке, чтобы не влиять на производительность средства чтения. Если файл кэша присутствует и обновлен, средство чтения больше не будет пропускать входной файл для сборки индекса, вместо этого он загрузит индекс из файла кэша. Обратите внимание, что некоторые параметры конфигурации средства чтения напрямую влияют на индексирование (например, различные значения frameMode могут привести к индексам с разными последовательностями). По этой причине файл кэша может игнорироваться средством чтения с конфигурацией, отличной от конфигурации, которая создала кэш. Чтобы увидеть все преимущества кэширования, конфигурация не должна быть изменена при последующих повторных запусках.

cacheIndex не влияет на ImageDeserializer и CNTKBinaryFormatDeserializer, так как первый не индексирует входные данные, а затем содержит сведения об индексе, внедренные в сам формат.

Общая конфигурация десериализатора

Параметр Описание
module Указывает имя модуля чтения, реализующего десериализатор данных. Обязательно.
type Указывает имя десериализатора данных, предоставляемое заданным модулем чтения. Обязательно.

Общая конфигурация преобразования

Параметр Описание
type Указывает имя преобразования, предоставляемое модулем чтения, реализующим десериализатор данных. Обязательно.

Параметры HTKFeatureDeserializer

Параметр Описание
scpFile Список путей к обрабатываемых файлам SCP. Файлы должны быть совместимыми с HTK и должны быть указаны в формате archive. Сведения об использовании архива описаны в средстве чтения HTKMLF. Обязательно.
dim Целое число, указывающее полное измерение вектора признаков с требуемым контекстным окном. 1Обязательный
contextWindow Можно либо указать как пару положительных целых чисел, либо как одно положительное целое число (в этом случае оно интерпретируется как пара с одинаковым числом повторяющихся дважды). Указывает левый и правый размер (первое и второе целое число пары) окна контекста в примерах. Необязательный, по умолчанию — 1.
prefixPathInSCP Строка префикса, применяемая к путям, указанным в файлах SCP. Необязательно.

1 Например, если у вас есть 72-мерные признаки (24-мерные фильтры, а также коэффициенты дельта и дельта) и сеть предназначена для обработки контекстного окна 11 кадров, указанное измерение должно иметь значение 792.

Параметры HTKMLFDeserializer

Параметр Описание
mlfFile Путь к файлу в стиле mlf HTK, который содержит метки для всех речевых фрагментов, указанных в scp файлах. Обязательный , если mlfFileList он не указан.
mlfFileList Массив путей к файлам в стиле mlf HTK, содержащим метки для всех речевых фрагментов, указанных в scp файлах. Обязательный , если mlfFile он не указан.
dim Общая кратность набора меток (положительное целое число). Обязательно.
labelMappingFile Путь к файлу, в котором перечислены все метки, видимые в mlf файле, по одной на строку. Обязательно.

labelDim можно использовать в качестве синонима для dim.

Параметры CNTKTextFormatDeserializer

Те же параметры, которые можно использовать с CNTKTextFormatReader

Параметры ImageDeserializer

  • file: простой текстовый файл, в котором каждая строка содержит сопоставление между ключом логической последовательности, файлом изображения (например, JPEG, PNG и т. д.) и меткой на основе 0.

Дополнительные сведения см. в разделе ImageReader.

Параметры Base64ImageDeserializer

Этот десериализатор поддерживает те же параметры, которые можно использовать с ImageDeserializer. Единственное различие заключается в формате файла сопоставления:

  • file: простой текстовый файл, в котором каждая строка содержит сопоставление между ключом логической последовательности (необязательно), меткой категории на основе 0 и файлом изображения в кодировке Base 64 (например, JPEG, PNG и т. д.).

Примеры конфигураций и тестов

Полные определения сети и соответствующие примеры набора данных находятся в репозитории CNTK. Здесь вы также найдете модульные и сквозные тесты, использующие десериализаторы, т. е.