Compartir a través de


BrainScript y Python: Descripción y extensión de lectores

A partir de la versión 1.5, CNTK se aleja del diseño del lector monolítico hacia un modelo más composable que le permite especificar y componer datos de entrada de diferentes formatos.

Antes, cada lector era responsable de diferentes aspectos de la lectura de datos, entre los que se incluyen, entre otros:

  • Deserialización de los datos del almacenamiento externo en representación en memoria
  • Selección aleatoria de todo el corpus
  • Diferentes transformaciones de secuencias o ejemplos de entrada (es decir, recorte o escalado de imágenes)
  • Creación de minibachas para diferentes modos (es decir, fotograma, secuencia o BPTT truncado) con un diseño que la GPU puede consumir.
  • Captura previa en el nivel de minibatches y fragmentos de E/S

En la versión 1.5, las principales partes de la funcionalidad anterior se factorizaron y se trasladaron a CNTK principal para compartirse entre diferentes lectores. Esta versión también presenta dos abstracciones principales que se pueden ampliar para admitir nuevos formatos de datos:

  • de deserializador: es responsable de la deserialización de la entrada del almacenamiento externo en secuencias en memoria.
  • transformar: transforma una secuencia de entrada en una secuencia de salida.

En las secciones siguientes se describen estas abstracciones con más detalle.

Configuración de un lector (origen de minibatch) en Python

En esta sección se proporcionan varios ejemplos sobre cómo se puede configurar un lector compuesto (también conocido como MinibatchSource) en Python.

En el ejemplo siguiente se adaptó de AlexNet_ImageNet_Distributed.py, se muestra el equivalente de Python del lector de AlexNet de sección Transformaciones.

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

En el ejemplo siguiente (adaptado de A2_RunCntk_py3.py) se muestra cómo se pueden combinar varios deserializadores.

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

Deserializadores

Echemos un vistazo al siguiente fragmento de configuración para el de HTKMLFReader del LSTM/FullUtterance (configuración completa aquí):

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

Este fragmento de configuración declara un lector que genera dos flujos de datos con nombres "features" y "labels". Toma como entrada dos tipos de archivos:

  • una lista de archivos de características conocidos en HTK parlance como un archivo scp (archivo "script")
  • un archivo de etiqueta conocido como archivo mlf ("archivo de etiqueta maestra")

En el fragmento de configuración anterior no hay entidades explícitas que definirían cómo se deserializan los formatos scp o mlf. Todo está encapsulado en la configuración de HTKMLFReader. Por lo tanto, si necesita exponer otro flujo de entrada de formato de datos diferente junto con scp y mlf, tendría que cambiar HTKMLFReader y agregar compatibilidad allí.

Para aumentar la capacidad de composición y la reutilización, el nueva configuración de para la misma entrada define explícitamente deserializadores y los flujos de entrada que producen:

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

Las secuencias producidas por los mlf y los deserializadores de htk se combinan en función de su clave lógica (que es una cadena que identifica de forma única una expresión de voz y está presente en archivos scp y mlf). Cuando necesite otra secuencia de formato diferente, simplemente puede agregar el deserializador correspondiente a la configuración (no es posible con la característica HTK y deserializadores HTK MLF ahora mismo para exponer más de un flujo de entrada cada uno).

Nota

Actualmente, se admiten las configuraciones de lector antiguas y nuevas. Cuando se usa la clave "deserializadores" en la configuración del lector, el tipo de lector se establece implícitamente en "CompositeDataReader". Para asegurarse de que el módulo CompositeDataReader se puede cargar en Windows, el Cntk.Composite.dll debe encontrarse en el mismo directorio que el ejecutable de CNTK. En linux Cntk.Composite.so debe estar en la carpeta lib que se encuentra en paralelo a la carpeta bin que contiene el ejecutable de CNTK.

Actualmente, CNTK admite los deserializadores siguientes:

Tipo de deserializador Módulo Descripción
HTKFeatureDeserializer HTKDeserializers Deserializador para archivos de características de HTK
HTKMLFDeserializer HTKDeserializers Deserializador para archivos HTK MLF
ImageDeserializer ImageReader Deserializador para imágenes codificadas como archivos sin formato o en archivo ZIP.
Base64ImageDeserializer ImageReader Deserializador para imágenes codificadas como cadenas base64 en el archivo de asignación.
CNTKTextFormatDeserializer CNTKTextFormatReader Deserializador para archivos de formato de texto CNTK
CNTKBinaryFormatDeserializer CNTKBinaryReader Deserializador para archivos de formato binario de CNTK

Consulte las tablas siguientes para obtener la descripción completa de los parámetros de configuración.

Transforma

Una transformación es una abstracción simple que toma una secuencia como entrada, realiza algunas transformaciones de muestras en la secuencia y devuelve la secuencia de salida. Los ejemplos típicos de transformaciones son diferentes transformaciones de imágenes como recortar, escalar o transponer. Las transformaciones se pueden configurar por entrada.

Echemos un vistazo a cómo se pueden aplicar las transformaciones a la entrada (la configuración se toma de la prueba 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
            ]
        ]
    ]
])

En esta configuración se aplican cuatro transformaciones al flujo de entrada features. Inicialmente, el deserializador de datos de imagen genera secuencias que constan de una sola imagen en la representación de HWC. Después de eso, la lista ordenada de transformaciones se aplica a la imagen: en primer lugar, la transformación Recortar , seguida de Escalado y Media. La última transformación es Transponer que cambia el diseño de imagen de HWC a CHW.

Actualmente se implementan las siguientes transformaciones. Para obtener su descripción detallada, consulte ImageReader.

Tipo de transformación Módulo
Cosecha ImageReader
Escama ImageReader
Color ImageReader
Significar ImageReader
Transponer ImageReader

Nueva descripción del formato de configuración del lector

Una sección de configuración del lector para componer varios deserializadores de datos tiene el siguiente aspecto:

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

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

Cada configuración de deserializador se especifica como:

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

Una configuración de entrada contiene opciones específicas de entrada y, opcionalmente, una lista ordenada de transformaciones que se deben aplicar a la entrada:

[
    # Per-input data deserializer-specific options

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

La configuración de transformación identifica el tipo de transformación y las opciones específicas de la transformación:

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

Opciones de configuración

Configuración general del lector

Parámetro Descripción
verbosity Nivel de detalle (0, 1, 2), controla la salida de diagnóstico de diferentes componentes (Aleatorio, Deserializador, Agrupador, etc.) Opcional, el valor predeterminado es 0.
randomize Especifica si la entrada debe ser aleatoria ( true, false). El método de selección aleatoria es idéntico a blockRandomize del HTKMLFReader. opcional, el valor predeterminado es true.
randomizationSeed Valor inicial de inicialización de inicialización (incrementó cada barrido cuando los datos de entrada se vuelven a asignar de forma aleatoria). opcional, el valor predeterminado es 0.
randomizationWindow Especifica el tamaño (entero positivo) de la ventana de selección aleatoria (es decir, intervalo de selección aleatoria). Este parámetro afecta a la cantidad de datos que debe residir en la memoria a la vez. opcional, el tamaño predeterminado del conjunto de datos completo (en muestras o en fragmentos, según el valor de sampleBasedRandomizationWindow). Sin embargo, si uno de los deserializadores es CNTKTextFormatDeserializer y sampleBasedRandomizationWindow no se establecido explícitamente en true, randomizationWindow se establecerá de forma predeterminada en 128 (que es aproximadamente 4 GB de espacio en disco de fragmentos). Este parámetro se omite cuando randomize es false.
sampleBasedRandomizationWindow Si true, el tamaño de la ventana de selección aleatoria se interpreta como un número determinado de muestras y, de lo contrario, como un número de fragmentos. opcional, el valor predeterminado es true si CNTKTextFormatDeserializer no está presente en la lista de deserializadores y en false de lo contrario. De forma similar a randomizationWindow, este parámetro se omite cuando randomize es false.
truncationLength Especifica la longitud de truncamiento en muestras para BPTT (entero positivo). Obligatorio solo si truncated es true, se omite de lo contrario.
multiThreadedDeserialization Especifica si se deben usar varios subprocesos al recopilar secuencias para un minibatch de los deserializadores (true, false). opcional.
frameMode Especifica si los datos deben ser aleatorios y devueltos en el nivel de fotograma o secuencia. Cuando true, la secuencia de entrada se divide en fotogramas. opcional. Tanto frameMode como truncated no se pueden establecer en true al mismo tiempo.
truncated Cuando true, habilita la propagación inversa truncada a través del tiempo (BPTT). opcional. Tanto frameMode como truncated no se pueden establecer en true al mismo tiempo.
useNumericSequenceKeys Las claves de secuencia se usan para correlacionar secuencias entre diferentes deserializadores. Para algunos deserializadores (es decir, HTK y MLF), las claves de secuencia son cadenas arbitrarias. Almacenarlos requiere mucha memoria en el gran corpus. Si está seguro de que las claves de secuencia son numéricas, establezca este parámetro en true, en ese caso, todas las claves de cadena se convertirán en enteros que reducen la presión de memoria. Opcional, falsepredeterminado.
hashSequenceKeys Por los motivos de memoria descritos anteriormente, las claves de cadena también se pueden aplicar hash estableciendo este parámetro en true. Utilícelo solo para deserializadores que admitan claves de secuencia de cadenas (HTK, MLF). Opcional, falsepredeterminado.
cacheIndex Especifica si los metadatos creados durante la fase de preprocesamiento deben escribirse en el disco y cargarse desde el disco si están disponibles (true, false). opcional, el valor predeterminado es false. Para obtener más información, consulte la sección siguiente. Novedad de CNTK versión 2.1.
Almacenamiento en caché de índices

Nota

Novedades de CNTK versión 2.1.

El almacenamiento en caché de índices permite reducir significativamente (por un factor de 2 a 3x) los tiempos de inicio, especialmente cuando se trabaja con archivos de entrada grandes. Al establecer la marca cacheIndex en true se indicará al lector que escriba los metadatos de indexación en el disco (el mismo directorio que el archivo de entrada) si el archivo de caché no está disponible o si está obsoleto (anterior al archivo de entrada). La escritura es el mejor esfuerzo y se lleva a cabo en un subproceso independiente para no afectar al rendimiento del lector. Si el archivo de caché está presente y está up-to-date, el lector dejará de esquiar el archivo de entrada para compilar el índice, en su lugar cargará el índice desde el archivo de caché. Tenga en cuenta que determinados parámetros de configuración del lector tienen un impacto directo en la indexación (por ejemplo, distintos valores de frameMode podrían dar lugar a índices que tienen un número diferente de secuencias). Por ese motivo, un lector podría omitir un archivo de caché con una configuración diferente de la que generó la memoria caché. Para ver la ventaja completa del almacenamiento en caché, la configuración no se debe modificar en las repeticiones posteriores.

cacheIndex no tiene ningún efecto en ImageDeserializer y CNTKBinaryFormatDeserializer, ya que el primero no indexa los datos de entrada y, posteriormente, tiene la información de índice incrustada en el propio formato.

Configuración general del deserializador

Parámetro Descripción
module Especifica el nombre del módulo de lector que implementa el deserializador de datos. obligatorio.
type Especifica un nombre de deserializador de datos expuesto por el módulo de lector especificado. obligatorio.

Configuración de transformación general

Parámetro Descripción
type Especifica un nombre de transformación expuesto por el módulo lector que implementa el deserializador de datos. obligatorio.

Opciones de HTKFeatureDeserializer

Parámetro Descripción
scpFile Lista de rutas de acceso a archivos SCP que se van a procesar. Los archivos deben ser archivos compatibles con HTK y deben especificarse en el formato "archivo". Los detalles del uso de un archivo se describen en lector HTKMLF. obligatorio.
dim Entero que especifica la dimensión de vector de característica completa con la ventana de contexto deseada.1 requerido
contextWindow Puede especificarse como un par de enteros positivos o como un único entero positivo (en cuyo caso se interpreta como un par con el mismo número repetido dos veces). Especifica el tamaño izquierdo y derecho (primer y segundo entero del par) de la ventana de contexto en ejemplos. opcional, el valor predeterminado es 1.
prefixPathInSCP Cadena de prefijo que se va a aplicar a las rutas de acceso especificadas en los archivos SCP. opcional.

1 Por ejemplo, si tenía características 72 dimensionales (características de filtro 24 dimensionales más coeficientes delta y delta-delta) y la red está diseñada para procesar una ventana de contexto de 11 fotogramas, la dimensión especificada debe ser 792.

Opciones de HTKMLFDeserializer

Parámetro Descripción
mlfFile Ruta de acceso a un archivo de estilo HTK mlf que contiene las etiquetas de todas las expresiones especificadas en los archivos de scp. obligatorio si no se especifica mlfFileList.
mlfFileList Matriz de rutas de acceso a archivos de estilo HTK mlf que contiene las etiquetas de todas las expresiones especificadas en los archivos de scp. obligatorio si no se especifica mlfFile.
dim Cardinalidad total del conjunto de etiquetas (entero positivo). obligatorio.
labelMappingFile Ruta de acceso a un archivo que enumera todas las etiquetas que se ven en el archivo mlf, una por línea. obligatorio.

labelDim se puede usar como sinónimo de dim.

Opciones de CNTKTextFormatDeserializer

Las mismas opciones que se pueden usar con CNTKTextFormatReader

Opciones de ImageDeserializer

  • file: un archivo de texto simple donde cada línea contiene una asignación separada por tabulaciones entre la clave de secuencia lógica, el archivo de imagen (e.g. JPEG, PNG, etc.) y la etiqueta basada en 0.

Para obtener más información, consulte ImageReader.

Opciones de Base64ImageDeserializer

Este deserializador admite las mismas opciones que se pueden usar con ImageDeserializer. La única diferencia es en el formato del archivo de asignación:

  • file: un archivo de texto simple donde cada línea contiene una asignación separada por tabulaciones entre la clave de secuencia lógica (opcional, se puede omitir), la etiqueta de categoría basada en 0 y el archivo de imagen codificado en base 64 (e.g. JPEG, PNG, etc.).

Ejemplos de configuraciones y pruebas

Encontrará definiciones de red completas y los ejemplos de conjuntos de datos correspondientes en el repositorio de CNTK. Allí también encontrará pruebas unitarias y de un extremo a otro que usan deserializadores, es decir,