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
объединяются вместе на основе их логического ключа (это строка, которая однозначно идентифицирует речевой фрагмент речи и присутствует в обоих scp
mlf
файлах).
Если вам нужен другой поток другого формата, вы можете просто добавить соответствующий десериализатор в конфигурацию (невозможно использовать функцию 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 ГБ места на диске объемом фрагментов). Этот параметр игнорируется в том случае randomize false . |
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. Здесь вы также найдете модульные и сквозные тесты, использующие десериализаторы, т. е.
- 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