Partager via


BrainScript et Python : Présentation et extension des lecteurs

À partir de la version 1.5, CNTK s’éloigne de la conception de lecteur monolithique vers un modèle plus composable qui vous permet de spécifier et de composer des données d’entrée de différents formats.

Avant, chaque lecteur était responsable de différents aspects de la lecture des données, y compris, mais pas limité à :

  • Désérialisation des données du stockage externe en représentation en mémoire
  • Randomisation de l’ensemble du corpus
  • Différentes transformations de séquences/exemples d’entrée (par exemple, rognage ou mise à l’échelle d’images)
  • Création de minibatches pour différents modes (par exemple, frame, séquence ou BPTT tronqué) avec une disposition qui peut être consommée par GPU
  • Prérécupération au niveau des minibatches et des blocs d’E/S

Dans la version 1.5, les principaux éléments de la fonctionnalité ci-dessus ont été pris en compte et déplacés vers le CNTK principal pour être partagés entre différents lecteurs. Cette version introduit également deux abstractions principales qui peuvent être étendues afin de prendre en charge les nouveaux formats de données :

  • désérialiseur : il est responsable de la désérialisation de l’entrée à partir d’un stockage externe dans des séquences en mémoire
  • transformation : elle transforme une séquence d’entrée en séquence de sortie

Dans les sections suivantes, nous abordons plus en détail ces abstractions.

Configuration d’un lecteur (source minibatch) dans Python

Cette section fournit plusieurs exemples sur la façon dont un lecteur composite (également appelé MinibatchSource) peut être configuré dans Python.

L’exemple suivant a été adapté à partir de AlexNet_ImageNet_Distributed.py, il montre l’équivalent Python du lecteur AlexNet de la section Transformations .

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

L’exemple suivant (adapté à partir de A2_RunCntk_py3.py) montre comment plusieurs désérialiseurs peuvent être combinés.

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

Désérialiseurs

Examinons le fragment de configuration suivant pour HTKMLFReader du test LSTM/FullUtterance de bout en bout (configuration complète ici) :

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

Ce fragment de configuration déclare un lecteur qui produit deux flux de données avec des noms "features" et "labels". Il prend comme entrée deux types de fichiers :

  • une liste de fichiers de fonctionnalités connus dans l’analyseur HTK sous la forme d’un scp fichier (« fichier de script »)
  • un fichier d’étiquette appelé mlf fichier (« fichier d’étiquette principale »)

Dans le fragment de configuration ci-dessus, il n’existe aucune entité explicite qui définirait comment scp ou mlf les formats sont désérialisés. Tout est encapsulé dans la configuration HTKMLFReader . Par conséquent, si vous devez exposer un autre flux d’entrée de différents formats de données avec scp et mlf, vous devez modifier HTKMLFReader et y ajouter la prise en charge.

Pour augmenter la composabilité et la réutilisation, la nouvelle configuration pour la même entrée définit explicitement les désérialiseurs et les flux d’entrée qu’ils produisent :

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

Les séquences produites par les mlf désérialiseurs et htk les désérialiseurs sont combinées en fonction de leur clé logique (qui est une chaîne qui identifie de manière unique un énoncé vocal et est présente dans les deux scp fichiers et mlf les fichiers). Lorsque vous avez besoin d’un autre flux de différents formats, vous pouvez simplement ajouter le désérialiseur correspondant à la configuration (il n’est pas possible avec la fonctionnalité HTK et les désérialiseurs HTK MLF pour exposer plusieurs flux d’entrée chacun).

Notes

Actuellement, les configurations des lecteurs anciennes et nouvelles sont prises en charge. Lorsque la clé « désérialiseurs » est utilisée dans la configuration du lecteur, le type de lecteur est implicitement défini sur « CompositeDataReader ». Pour vous assurer que le module CompositeDataReader peut être chargé sur Windows, il Cntk.Composite.dll doit se trouver dans le même répertoire que l’exécutable CNTK. Sur Linux Cntk.Composite.so , il doit se trouver dans le lib dossier qui se trouve côte à côte dans le bin dossier contenant l’exécutable CNTK.

Actuellement, CNTK prend en charge les désérialiseurs ci-dessous :

Type de désérialiseur Module Description
HTKFeatureDeserializer HTKDeserializers Désérialiseur pour les fichiers de fonctionnalités HTK
HTKMLFDeserializer HTKDeserializers Désérialiseur pour les fichiers MLF HTK
ImageDeserializer ImageReader Désérialiseur pour les images encodées sous forme de fichiers bruts ou dans l’archive zip.
Base64ImageDeserializer ImageReader Désérialiseur pour les images encodées en base64 dans le fichier de mappage.
CNTKTextFormatDeserializer CNTKTextFormatReader Désérialiseur pour les fichiers de format texte CNTK
CNTKBinaryFormatDeserializer CNTKBinaryReader Désérialiseur pour les fichiers de format binaire CNTK

Reportez-vous aux tableaux ci-dessous pour obtenir la description complète des paramètres de configuration.

Transformations

Une transformation est une abstraction simple qui prend une séquence en tant qu’entrée, effectue une transformation d’exemples dans la séquence et retourne la séquence de sortie. Les exemples typiques de transformations sont des transformations différentes d’images telles que rognage, mise à l’échelle ou transposer. Les transformations peuvent être configurées par entrée.

Voyons comment les transformations peuvent être appliquées à l’entrée (la configuration est extraite du test 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
            ]
        ]
    ]
])

Dans cette configuration, quatre transformations sont appliquées au flux featuresd’entrée. Initialement, le désérialiseur de données d’image produit des séquences composées d’une seule image dans la représentation HWC. Après cela, la liste triée des transformations est appliquée à l’image : premièrement, la transformation Rogner , suivie de Scale and Mean. La dernière transformation est Transposer qui modifie la disposition de l’image de HWC en CHW.

Actuellement, les transformations suivantes sont implémentées. Pour obtenir une description détaillée, consultez ImageReader.

Type de transformation Module
Rogner ImageReader
Scale ImageReader
Couleur ImageReader
Moyenne ImageReader
Transposer ImageReader

Description du nouveau format de configuration du lecteur

Une section de configuration de lecteur pour composer plusieurs désérialiseurs de données ressemble à ceci :

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

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

Chaque configuration du désérialiseur est spécifiée comme suit :

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

Une configuration d’entrée contient des options spécifiques aux entrées et, éventuellement, une liste ordonnée de transformations qui doivent être appliquées à l’entrée :

[
    # 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 configuration de transformation identifie le type de transformation et toutes les options spécifiques à la transformation :

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

Options de configuration

Configuration générale du lecteur

Paramètre Description
verbosity Niveau de détail (0, 1, 2), contrôle la sortie de diagnostic de différents composants (Randomr, Désérialiseur, Bundler, etc.) Facultatif, la valeur par défaut est 0.
randomize Spécifie si l’entrée doit être aléatoire ( true, false). La méthode de randomisation est identique à blockRandomize du HTKMLFReader. Facultatif, la valeur par défaut est true.
randomizationSeed Valeur initiale de randomisation initiale (incrémentée chaque balayage lorsque les données d’entrée sont réécrites aléatoires). Facultatif, la valeur par défaut est 0.
randomizationWindow Spécifie la taille (entier positif) de la fenêtre de randomisation (par exemple, plage de randomisation). Ce paramètre affecte la quantité de jeu de données qui doit résider en mémoire à la fois. Facultatif, la taille par défaut du jeu de données entier (dans les exemples ou en blocs, en fonction de la sampleBasedRandomizationWindow valeur). Toutefois, si l’un des désérialiseurs est CNTKTextFormatDeserializer et sampleBasedRandomizationWindown’a pas été défini trueexplicitement sur , randomizationWindow est défini par défaut 128 (ce qui représente environ 4 Go d’espace disque de blocs). Ce paramètre est ignoré quand randomize est false.
sampleBasedRandomizationWindow Si true, la taille de la fenêtre de randomisation est interprétée comme un certain nombre d’exemples, et comme un certain nombre de blocs sinon. Facultatif, par défaut true , s’il CNTKTextFormatDeserializer n’est pas présent dans la liste des désérialiseurs, et dans false le cas contraire. De la même façon que randomizationWindow, ce paramètre est ignoré, quand randomize est false.
truncationLength Spécifie la longueur de troncation dans les exemples pour BPTT (entier positif). Obligatoire uniquement si truncated c’est true, ignoré sinon.
multiThreadedDeserialization Spécifie si plusieurs threads doivent être utilisés lors de la collecte de séquences pour un minibatch à partir des désérialiseurs (,truefalse ). Facultatif.
frameMode Spécifie si les données doivent être aléatoires et retournées au niveau de la trame ou de la séquence. Quand true, la séquence d’entrée est divisée en images. Facultatif. Les deux frameMode et truncated ne peuvent pas être définis true en même temps.
truncated Quand true, active la propagation back-propagation tronquée par le temps (BPTT). Facultatif. Les deux frameMode et truncated ne peuvent pas être définis true en même temps.
useNumericSequenceKeys Les clés de séquence sont utilisées pour mettre en corrélation des séquences entre différents désérialiseurs. Pour certains désérialiseurs (c’est-à-dire HTK et MLF), les clés de séquence sont des chaînes arbitraires. Les stocker nécessite beaucoup de mémoire sur le big corpus. Si vous êtes sûr que vos clés de séquence sont numériques, définissez ce paramètre sur true, dans ce cas, toutes les clés de chaîne seront converties en entiers réduisant la pression de la mémoire. Facultatif, valeur par défaut false.
hashSequenceKeys Pour les raisons de mémoire décrites ci-dessus, les clés de chaîne peuvent également être hachées en définissant ce paramètre sur true. Utilisez-le uniquement pour les désérialiseurs qui prennent en charge les clés de séquence de chaînes (HTK, MLF). Facultatif, valeur par défaut false.
cacheIndex Spécifie si les métadonnées créées au cours de la phase de prétraitement doivent être écrites sur le disque et chargées à partir du disque si disponibles (,truefalse ). Facultatif, valeur par défaut .false Pour plus d’informations, consultez la section ci-dessous. Nouveautés de CNTK version 2.1.
Mise en cache d’index

Notes

Nouveautés de CNTK version 2.1.

La mise en cache d’index permet de réduire considérablement (par un facteur de 2 à 3x) les temps de démarrage, en particulier lors de l’utilisation de fichiers d’entrée volumineux. La définition de l’indicateur cacheIndex pour true signaler au lecteur d’écrire les métadonnées d’indexation sur le disque (même répertoire que le fichier d’entrée) si le fichier cache n’est pas disponible ou s’il est obsolète (plus ancien que le fichier d’entrée). L’écriture est le meilleur effort et est effectuée sur un thread distinct afin de ne pas affecter les performances du lecteur. Si le fichier de cache est présent et est à jour, le lecteur n’écrémera plus le fichier d’entrée pour générer l’index, mais il chargera l’index à partir du fichier de cache. Notez que certains paramètres de configuration de lecteur ont un impact direct sur l’indexation (par exemple, différentes valeurs frameMode peuvent entraîner des index qui ont un nombre différent de séquences). Pour cette raison, un fichier de cache peut être ignoré par un lecteur avec une configuration différente de celle qui a produit le cache. Pour voir l’avantage complet de la mise en cache, la configuration ne doit pas être modifiée lors des réexécutions suivantes.

cacheIndex n’a aucun effet sur ImageDeserializer et CNTKBinaryFormatDeserializer, car l’ancien n’indexe pas les données d’entrée et les informations d’index ultérieures sont incorporées dans le format lui-même.

Configuration générale du désérialiseur

Paramètre Description
module Spécifie le nom du module lecteur qui implémente le désérialiseur de données. Requis.
type Spécifie un nom de désérialiseur de données exposé par le module lecteur donné. Requis.

Configuration générale de la transformation

Paramètre Description
type Spécifie un nom de transformation exposé par le module lecteur implémentant le désérialiseur de données. Requis.

Options htKFeatureDeserializer

Paramètre Description
scpFile Liste des chemins d’accès aux fichiers SCP à traiter. Les fichiers doivent être compatibles HTK et doivent être spécifiés au format « archive ». Les détails de l’utilisation d’une archive sont décrits dans le lecteur HTKMLF. Requis.
dim Entier qui spécifie la dimension de vecteur de fonctionnalité complète avec la fenêtre de contexte souhaitée. 1Obligatoire
contextWindow Peut être spécifié sous la forme d’une paire d’entiers positifs ou d’un entier positif unique (dans ce cas, il est interprété comme une paire avec le même nombre répété deux fois). Spécifie la taille gauche et droite (premier et deuxième entier de la paire) de la fenêtre de contexte dans les exemples. Facultatif, valeur par défaut .1
prefixPathInSCP Chaîne de préfixe à appliquer aux chemins spécifiés dans les fichiers SCP. Facultatif.

1 Par exemple, si vous avez des caractéristiques 72 dimensions (caractéristiques de la banque de filtres 24 dimensions plus delta et delta-delta coefficients) et que le réseau est conçu pour traiter une fenêtre de contexte de 11 images, la dimension spécifiée doit être 792.

Options htKMLFDeserializer

Paramètre Description
mlfFile Chemin d’accès à un fichier de style mlf HTK qui contient les étiquettes pour tous les énoncés spécifiés dans le ou les scp fichiers. Obligatoire s’il mlfFileList n’est pas spécifié.
mlfFileList Tableau de chemins d’accès aux fichiers de style mlf HTK qui contient les étiquettes pour tous les énoncés spécifiés dans le scp ou les fichiers. Obligatoire s’il mlfFile n’est pas spécifié.
dim Cardinalité totale du jeu d’étiquettes (entier positif). Requis.
labelMappingFile Chemin d’accès à un fichier qui répertorie toutes les étiquettes affichées dans le mlf fichier, une par ligne. Requis.

labelDim peut être utilisé comme synonyme de dim.

Options CNTKTextFormatDeserializer

Mêmes options qui peuvent être utilisées avec CNTKTextFormatReader

Options ImageDeserializer

  • file: fichier texte simple où chaque ligne contient un mappage séparé par des onglets entre une clé de séquence logique, un fichier image (par exemple JPEG, PNG, etc.) et une étiquette basée sur 0.

Pour plus d’informations, consultez ImageReader.

Options de Base64ImageDeserializer

Ce désérialiseur prend en charge les mêmes options que celles qui peuvent être utilisées avec ImageDeserializer. La seule différence est au format du fichier de mappage :

  • file: fichier texte simple où chaque ligne contient un mappage séparé par onglet entre une clé de séquence logique (facultatif, peut être omis), une étiquette de catégorie basée sur 0 et un fichier image codé en base 64 (par exemple JPEG, PNG, etc.).

Exemples de configurations et de tests

Vous trouverez des définitions réseau complètes et des exemples de jeu de données correspondants dans le référentiel CNTK. Vous trouverez également des tests unitaires et de bout en bout qui utilisent des désérialiseurs, c’est-à-dire des tests unitaires et finaux.