Condividi tramite


BrainScript e Python: Informazioni ed estensione dei lettori

A partire dalla versione 1.5, CNTK si allontana dalla progettazione del lettore monolitico verso un modello più componibile che consente di specificare e comporre dati di input di formati diversi.

In precedenza, ogni lettore era responsabile di diversi aspetti della lettura dei dati, tra cui, a titolo esemplificativo:

  • Deserializzazione dei dati dall'archiviazione esterna nella rappresentazione in memoria
  • Randomizzazione dell'intero corpus
  • Trasformazioni diverse di sequenze/campioni di input (ad esempio ritaglio o ridimensionamento delle immagini)
  • Creazione di minibatches per diverse modalità (ad esempio frame, sequenza o troncato BPTT) con un layout che può essere utilizzato dalla GPU
  • Prelettura sul livello di minibatches e blocchi di I/O

Nella versione 1.5, i componenti principali della funzionalità precedente sono stati inseriti in fattori e spostati in CNTK core per essere condivisi tra lettori diversi. Questa versione introduce anche due astrazioni principali che possono essere estese per supportare nuovi formati di dati:

  • deserializzatore: è responsabile della deserializzazione dell'input dall'archiviazione esterna in sequenze in memoria
  • trasformare: trasforma una sequenza di input in una sequenza di output

Nelle sezioni successive queste astrazioni vengono illustrate in modo più dettagliato.

Configurazione di un lettore (origine minibatch) in Python

Questa sezione fornisce diversi esempi su come è possibile configurare un lettore composito (noto anche come MinibatchSource) in Python.

L'esempio seguente è stato adattato da AlexNet_ImageNet_Distributed.py, mostra l'equivalente Python del lettore AlexNet dalla sezione 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)))) 

Nell'esempio seguente (adattato da A2_RunCntk_py3.py) viene illustrato come combinare diversi deserializzatori.

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

Deserializzatori

Di seguito è riportato il frammento di configurazione seguente per il HTKMLFReader dall'end-to-end LSTM/FullUtterance test (configurazione completa qui):

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

Questo frammento di configurazione dichiara un lettore che produce due flussi di dati con nomi "features" e "labels". Accetta come input due tipi di file:

  • un elenco di file di funzionalità noti in HTK parlance come file scp ("file script")
  • un file di etichetta noto come file di mlf ("file etichetta master")

Nel frammento di configurazione precedente non sono presenti entità esplicite che definiscono come scp o mlf formati vengono deserializzati. Tutto è incapsulato nella configurazione di HTKMLFReader . Pertanto, se è necessario esporre un altro flusso di input di un formato di dati diverso insieme a scp e mlf, è necessario modificare HTKMLFReader e aggiungere il supporto.

Per aumentare la componibilità e il riutilizzo, la nuova configurazione di per lo stesso input definisce in modo esplicito i deserializzatori e i flussi di input che producono:

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

Le sequenze prodotte dall'mlf e htk deserializer vengono combinate in base alla relativa chiave logica (ovvero una stringa che identifica in modo univoco un'espressione vocale ed è presente sia in scp che nei file di mlf). Quando è necessario un altro flusso di formato diverso, è sufficiente aggiungere il deserializzatore corrispondente alla configurazione (non è possibile con la funzionalità HTK e i deserializzatori MLF HTK in questo momento per esporre più di un flusso di input ciascuno).

Nota

Attualmente sono supportate entrambe le configurazioni dei lettori precedenti e nuove. Quando la chiave "deserializers" viene usata nella configurazione del lettore, il tipo di lettore viene impostato in modo implicito su "CompositeDataReader". Per assicurarsi che il modulo CompositeDataReader possa essere caricato in Windows, il Cntk.Composite.dll deve trovarsi nella stessa directory dell'eseguibile CNTK. In Linux Cntk.Composite.so deve trovarsi nella cartella lib affiancata alla cartella bin contenente l'eseguibile CNTK.

Attualmente CNTK supporta i deserializzatori seguenti:

Tipo deserializzatore Modulo Descrizione
HTKFeatureDeserializer HTKDeserializers Deserializzatore per i file di funzionalità HTK
HTKMLFDeserializer HTKDeserializers Deserializzatore per i file MLF HTK
ImageDeserializer ImageReader Deserializzatore per le immagini codificate come file semplici o in archivio ZIP.
Base64ImageDeserializer ImageReader Deserializzatore per le immagini codificate come stringhe base64 nel file di mapping.
CNTKTextFormatDeserializer CNTKTextFormatReader Deserializzatore per i file di formato di testo CNTK
CNTKBinaryFormatDeserializer CNTKBinaryReader Deserializzatore per i file in formato binario CNTK

Per la descrizione completa dei parametri di configurazione, vedere le tabelle seguenti.

Trasforma

Una trasformazione è una semplice astrazione che accetta una sequenza come input, esegue alcune trasformazioni di campioni nella sequenza e restituisce la sequenza di output. Esempi tipici di trasformazioni sono trasformazioni diverse di immagini, ad esempio ritaglio, scala o trasposizione. Le trasformazioni possono essere configurate in base all'input.

Di seguito viene illustrato come applicare le trasformazioni all'input (la configurazione viene ricavata dal test Test/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
            ]
        ]
    ]
])

In questa configurazione vengono applicate quattro trasformazioni al flusso di input features. Inizialmente, il deserializzatore di dati immagine produce sequenze costituite da una singola immagine nella rappresentazione HWC. Dopo che l'elenco ordinato di trasformazioni viene applicato all'immagine: in primo luogo la trasformazione ritaglio , seguita da Scala e Mean. L'ultima trasformazione è Trasponi che modifica il layout dell'immagine da HWC a CHW.

Attualmente vengono implementate le trasformazioni seguenti. Per la descrizione dettagliata, vedere ImageReader.

Tipo di trasformazione Modulo
Raccolto ImageReader
Scala ImageReader
Colore ImageReader
Significare ImageReader
Trasporre ImageReader

Nuova descrizione del formato di configurazione lettore

Una sezione di configurazione del lettore per comporre diversi deserializzatori di dati è simile alla seguente:

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

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

Ogni configurazione deserializzatore viene specificata come:

[
    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 configurazione di input contiene opzioni specifiche dell'input e, facoltativamente, un elenco ordinato di trasformazioni che devono essere applicate all'input:

[
    # 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 configurazione della trasformazione identifica il tipo di trasformazione e le opzioni specifiche della trasformazione:

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

Opzioni di configurazione

Configurazione del lettore generale

Parametro Descrizione
verbosity Livello di dettaglio (0, 1, 2), controlla l'output diagnostico di componenti diversi (Randomizer, Deserializer, Bundler e così via) Facoltativo, per impostazione predefinita 0.
randomize Specifica se l'input deve essere casuale ( true, false). Il metodo di randomizzazione è identico a blockRandomize di HTKMLFReader. Facoltativo, per impostazione predefinita true.
randomizationSeed Valore di inizializzazione casuale (incrementato ogni sweep quando i dati di input vengono ri-casualizzati). Facoltativo, per impostazione predefinita 0.
randomizationWindow Specifica le dimensioni (numero intero positivo) della finestra di casualizzazione (ad esempio, intervallo di casualizzazione). Questo parametro influisce sulla quantità di set di dati che deve risiedere in memoria contemporaneamente. Facoltativo, per impostazione predefinita corrisponde alla dimensione del intero set di dati (in esempi o in blocchi, a seconda del valore ). Tuttavia, se uno dei deserializzatori è CNTKTextFormatDeserializer e sampleBasedRandomizationWindow non è stato non impostato in modo esplicito su true, randomizationWindow verrà impostato per impostazione predefinita su 128 (ovvero circa 4 GB di spazio su disco di blocchi). Questo parametro viene ignorato quando randomize è false.
sampleBasedRandomizationWindow Se true, le dimensioni della finestra di casualizzazione sono interpretate come un determinato numero di campioni e come numero di blocchi in caso contrario. Facoltativo, per impostazione predefinita true se CNTKTextFormatDeserializer non è presente nell'elenco di deserializer e per false in caso contrario. Analogamente a randomizationWindow, questo parametro viene ignorato quando randomize è false.
truncationLength Specifica la lunghezza del troncamento nei campioni per BPTT (numero intero positivo). obbligatorio solo se truncated è true, ignorato in caso contrario.
multiThreadedDeserialization Specifica se devono essere usati più thread durante la raccolta di sequenze per un minibatch dai deserializzatori (true, false). facoltativo .
frameMode Specifica se i dati devono essere casuali e restituiti a livello di frame o sequenza. Quando true, la sequenza di input viene suddivisa in fotogrammi. facoltativo . Non è possibile impostare sia frameMode che truncated su true contemporaneamente.
truncated Quando true, abilita la propagazione back-end troncata nel tempo (BPTT). facoltativo . Non è possibile impostare sia frameMode che truncated su true contemporaneamente.
useNumericSequenceKeys Le chiavi di sequenza vengono usate per correlare le sequenze tra deserializzatori diversi. Per alcuni deserializzatori (ad esempio HTK e MLF), le chiavi di sequenza sono stringhe arbitrarie. L'archiviazione richiede molta memoria su grandi corpus. Se si è certi che le chiavi di sequenza siano numeriche, impostare questo parametro su true, in tal caso tutte le chiavi stringa verranno convertite in numeri interi che riducono la pressione di memoria. Facoltativo, impostazione predefinita false.
hashSequenceKeys Per i motivi di memoria descritti in precedenza, è anche possibile eseguire l'hashing delle chiavi stringa impostando questo parametro su true. Usare solo per deserializzatori che supportano chiavi di sequenza di stringhe (HTK, MLF). Facoltativo, impostazione predefinita false.
cacheIndex Specifica se i metadati compilati durante la fase di pre-elaborazione devono essere scritti su disco e caricati dal disco, se disponibili (true, false). Facoltativo, per impostazione predefinita false. Per altri dettagli, vedere la sezione seguente. Novità in CNTK versione 2.1.
Memorizzazione nella cache degli indici

Nota

Novità di CNTK versione 2.1.

La memorizzazione nella cache degli indici consente di ridurre significativamente (per un fattore di 2-3 volte) i tempi di avvio, soprattutto quando si lavora con file di input di grandi dimensioni. L'impostazione del flag cacheIndex su true segnalerà al lettore di scrivere i metadati di indicizzazione su disco (stessa directory del file di input) se il file della cache non è disponibile o se è obsoleto (precedente al file di input). La scrittura è il miglior sforzo e viene eseguita su un thread separato per non influire sulle prestazioni del lettore. Se il file della cache è presente ed è up-to-date, il lettore non scaricherà più il file di input per compilare l'indice, ma caricherà l'indice dal file della cache. Si noti che alcuni parametri di configurazione del lettore hanno un impatto diretto sull'indicizzazione (ad esempio, valori diversi di frameMode potrebbero causare indici con un numero diverso di sequenze). Per questo motivo, un file di cache potrebbe essere ignorato da un lettore con una configurazione diversa da quella che ha generato la cache. Per visualizzare il vantaggio completo della memorizzazione nella cache, la configurazione non deve essere modificata nelle riesecuzioni successive.

cacheIndex non ha alcun effetto su ImageDeserializer e CNTKBinaryFormatDeserializer, perché il primo non indicizza i dati di input e successivamente include le informazioni sull'indice incorporate nel formato stesso.

Configurazione generale del deserializzatore

Parametro Descrizione
module Specifica il nome del modulo lettore che implementa il deserializzatore di dati. obbligatorio.
type Specifica un nome di deserializzatore dati esposto dal modulo lettore specificato. obbligatorio.

Configurazione della trasformazione generale

Parametro Descrizione
type Specifica un nome di trasformazione esposto dal modulo reader che implementa il deserializzatore di dati. obbligatorio.

Opzioni HTKFeatureDeserializer

Parametro Descrizione
scpFile Elenco dei percorsi dei file SCP da elaborare. I file devono essere compatibili con HTK e devono essere specificati nel formato "archivio". I dettagli dell'uso di un archivio sono descritti in lettore HTKMLF. obbligatorio.
dim Intero che specifica la dimensione del vettore di funzionalità completa con la finestra di contesto desiderata.1obbligatorio
contextWindow Può essere specificato come coppia di numeri interi positivi o come singolo numero intero positivo (nel qual caso viene interpretato come coppia con lo stesso numero ripetuto due volte). Specifica le dimensioni sinistra e destra (primo e secondo intero della coppia) della finestra di contesto negli esempi. Facoltativo, per impostazione predefinita 1.
prefixPathInSCP Stringa di prefisso da applicare ai percorsi specificati all'interno dei file SCP. facoltativo .

1 Ad esempio, se si dispone di caratteristiche 72 dimensionali (caratteristiche di filtro 24 dimensionali più coefficienti delta e delta-delta) e la rete è progettata per elaborare una finestra di contesto di 11 fotogrammi, la dimensione specificata deve essere 792.

Opzioni di HTKMLFDeserializer

Parametro Descrizione
mlfFile Percorso di un file di mlf di tipo HTK che contiene le etichette per tutte le espressioni specificate nei file di scp. obbligatorio se non è specificato mlfFileList.
mlfFileList Matrice di percorsi di file di mlf in stile HTK che contiene le etichette per tutte le espressioni specificate nei file di scp. obbligatorio se non è specificato mlfFile.
dim Cardinalità totale del set di etichette (numero intero positivo). obbligatorio.
labelMappingFile Percorso di un file che elenca tutte le etichette visualizzate nel file mlf, una per riga. obbligatorio.

labelDim può essere usato come sinonimo dim.

Opzioni CNTKTextFormatDeserializer

Stesse opzioni che possono essere usate con CNTKTextFormatReader

Opzioni imageDeserializer

  • file: file di testo semplice in cui ogni riga contiene un mapping separato da tabulazioni tra chiave di sequenza logica, file di immagine (e.g. JPEG, PNG e così via) e etichetta basata su 0.

Per altre informazioni, vedere ImageReader.

Opzioni base64ImageDeserializer

Questo deserializzatore supporta le stesse opzioni che possono essere usate con ImageDeserializer. L'unica differenza è nel formato del file di mapping:

  • file: file di testo semplice in cui ogni riga contiene un mapping delimitato da tabulazioni tra la chiave di sequenza logica (facoltativa, può essere omessa), l'etichetta di categoria basata su 0 e il file di immagine con codifica base 64 (e.g. JPEG, PNG e così via).

Esempi di configurazioni e test

Sono disponibili definizioni di rete complete e gli esempi di set di dati corrispondenti nel repository CNTK. Qui troverete anche unit test e end-to-end che usano deserializer, ad esempio