Dela via


BrainScript och Python: Förstå och utöka läsare

Från och med version 1.5 rör sig CNTK från den monolitiska läsardesignen till en mer sammansättningsbar modell som gör att du kan ange och skapa indata i olika format.

Tidigare var varje läsare ansvarig för olika aspekter av dataläsning, inklusive men inte begränsat till:

  • Deserialisering av data från extern lagring till minnesintern representation
  • Randomisering av hela korpusen
  • Olika omvandlingar av indatasekvenser/exempel (dvs. beskärning eller skalning av bilder)
  • Skapa minibatches för olika lägen (t.ex. ram, sekvens eller trunkerad BPTT) med en layout som kan användas av GPU
  • Prefetch på nivån för minibatches och IO segment

I version 1.5 räknades de viktigaste delarna av ovanstående funktioner ut och flyttades till centrala CNTK för att delas mellan olika läsare. Den här versionen introducerar också två huvudabstraktioner som kan utökas för att stödja nya dataformat:

  • deserialiserare – den ansvarar för deserialisering av indata från extern lagring till minnesintern sekvenser
  • transform – den omvandlar en indatasekvens till en utdatasekvens

I nästa avsnitt diskuterar vi dessa abstraktioner mer detaljerat.

Konfigurera en läsare (minibatchkälla) i Python

Det här avsnittet innehåller flera exempel på hur en sammansatt läsare (även kallad MinibatchSource) kan konfigureras i Python.

Följande exempel har anpassats från AlexNet_ImageNet_Distributed.py. Det visar Python-motsvarigheten till avsnittet AlexNet-läsare från transformeringar .

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

Följande exempel (anpassat från A2_RunCntk_py3.py) visar hur flera deserialiserare kan kombineras.

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

Deserialiserare

Låt oss ta en titt på följande konfigurationsfragment för HTKMLFReader från LSTM/FullUtterance-testet från slutpunkt till slutpunkt (fullständig konfiguration här):

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

Det här konfigurationsfragmentet deklarerar en läsare som producerar två dataströmmar med namn "features" och "labels". Det tar som indata två typer av filer:

  • en lista över funktionsfiler som är kända i HTK-parlance som en scp fil ("skript"-fil)
  • en etikettfil som mlf kallas fil ("huvudetikettfil")

I konfigurationsfragmentet ovan finns det inga explicita entiteter som definierar hur scp eller mlf format deserialiseras. Allt är inkapslat i HTKMLFReader-konfigurationen . Så om du behöver exponera ytterligare en indataström med olika dataformat tillsammans med scp och mlf, skulle du behöva ändra HTKMLFReader och lägga till stöd där.

För att öka sammansättning och återanvändning definierar den nya konfigurationen för samma indata explicit deserialiserare och indataströmmar som de producerar:

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

Sekvenserna som skapas av deserialiserarna mlf och htk kombineras baserat på deras logiska nyckel (som är en sträng som unikt identifierar ett talyttrande och finns i både scp - och mlf -filer). När du behöver en annan ström med olika format kan du helt enkelt lägga till motsvarande deserialiserare i konfigurationen (det är inte möjligt med HTK-funktionen och HTK MLF-deserialiserare just nu för att exponera mer än en indataström vardera).

Anteckning

För närvarande stöds både gamla och nya läsarkonfigurationer. När nyckeln "deserializers" används i läsarkonfigurationen anges läsartypen implicit till "CompositeDataReader". För att se till att CompositeDataReader-modulen kan läsas in i Windows Cntk.Composite.dll ska den finnas i samma katalog som den körbara CNTK-filen. I Linux Cntk.Composite.so ska vara i mappen lib som finns sida vid sida till mappen bin som innehåller den körbara CNTK-filen.

För närvarande stöder CNTK nedanstående deserialiserare:

Deserialiserartyp Modul Description
HTKFeatureDeserializer HTKDeserializers Deserializer för HTK-funktionsfiler
HTKMLFDeserializer HTKDeserializers Deserializer för HTK MLF-filer
ImageDeserializer ImageReader Deserialiserare för bilder som kodats som oformaterade filer eller i zip-arkiv.
Base64ImageDeserializer ImageReader Deserialiserare för bilder som kodats som base64-strängar i mappningsfilen.
CNTKTextFormatDeserializer CNTKTextFormatReader Deserializer för CNTK-textformatfiler
CNTKBinaryFormatDeserializer CNTKBinaryReader Deserializer för filer i binärt CNTK-format

Se tabellerna nedan för en fullständig beskrivning av konfigurationsparametrarna.

Transformering

En transformering är en enkel abstraktion som tar en sekvens som indata, utför viss transformering av exempel i sekvensen och returnerar utdatasekvensen. Vanliga exempel på transformeringar är olika omvandlingar av bilder, till exempel beskärning, skalning eller transponering. Transformeringar kan konfigureras per indata.

Nu ska vi titta på hur transformeringar kan tillämpas på indata (konfigurationen hämtas från testerna/EndToEndTests/Image/AlexNet-testet ):

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

I den här konfigurationen tillämpas fyra transformeringar på indataströmmen features. Från början skapar deserialiseraren av avbildningsdata sekvenser som består av en enda avbildning i HWC-representation. Därefter tillämpas den ordnade listan över transformeringar på bilden: först beskärningstransformen följt av Skala och Medelvärde. Den senaste omvandlingen är Transponera som ändrar bildlayouten från HWC till CHW.

För närvarande implementeras följande transformeringar. Detaljerad beskrivning finns i ImageReader.

Transformeringstyp Modul
Beskär ImageReader
Skala ImageReader
Färg ImageReader
Medelvärde ImageReader
Transponera ImageReader

Beskrivning av konfigurationsformat för ny läsare

Ett läsarkonfigurationsavsnitt för att skapa flera data deserialiserare ser ut så här:

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

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

Varje deserialiserarkonfiguration anges som:

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

En indatakonfiguration innehåller indataspecifika alternativ och eventuellt en ordnad lista över transformeringar som ska tillämpas på indata:

[
    # Per-input data deserializer-specific options

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

Transformeringskonfigurationen identifierar transformeringstypen och eventuella transformeringsspecifika alternativ:

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

Konfigurationsalternativ

Allmän läsarkonfiguration

Parameter Beskrivning
verbosity Detaljnivå (0, 1, 2), styr diagnostikutdata för olika komponenter (Randomizer, Deserializer, Bundler osv.) Valfritt, standardvärdet är 0.
randomize Anger om indata ska randomiseras ( true, false). Randomiseringsmetoden är identisk med blockRandomize för HTKMLFReader. Valfritt, standardvärdet är true.
randomizationSeed Startvärde för randomiseringsfrö (ökas varje svep när indata randomiseras igen). Valfritt, standardvärdet är 0.
randomizationWindow Anger storleken (positivt heltal) för slumpmässighetsfönstret (dvs. slumpmässigt intervall). Den här parametern påverkar hur mycket av datauppsättningen som måste finnas i minnet samtidigt. Valfritt, som standard till storleken på hela datauppsättningen (i exempel eller i segment, beroende på sampleBasedRandomizationWindow värdet). Men om en av deserialiserarna är CNTKTextFormatDeserializer och sampleBasedRandomizationWindowinte uttryckligen har angetts till true, randomizationWindow kommer standardvärdet ( 128 som är cirka 4 GB diskutrymme värt segment). Den här parametern ignoreras när randomize är false.
sampleBasedRandomizationWindow Om truetolkas storleken på randomiseringsfönstret som ett visst antal exempel och som ett antal segment annars. Valfritt, standardvärdet true är om CNTKTextFormatDeserializer inte finns i listan över deserialiserare och på false annat sätt. randomizationWindowPå samma sätt ignoreras den här parametern när randomize är false.
truncationLength Anger trunkeringslängden i exempel för BPTT (positivt heltal). Krävs endast om truncated är true, ignoreras annars.
multiThreadedDeserialization Anger om flera trådar ska användas vid insamling av sekvenser för en minibatch från deserialiserarna (true, false). Valfritt.
frameMode Anger om data ska randomiseras och returneras på ram- eller sekvensnivå. När truedelas indatasekvensen upp i bildrutor. Valfritt. Både frameMode och truncated kan inte anges till true på samma gång.
truncated När trueaktiverar du trunkerad bakåtspridning genom tid (BPTT). Valfritt. Både frameMode och truncated kan inte anges till true på samma gång.
useNumericSequenceKeys Sekvensnycklar används för att korrelera sekvenser mellan olika deserialiserare. För vissa deserialiserare (t.ex. HTK och MLF) är sekvensnycklarna godtyckliga strängar. Att lagra dem kräver mycket minne på stora corpus. Om du är säker på att dina sekvensnycklar är numeriska anger du den här parametern till sant, i så fall konverteras alla strängnycklar till heltal som minskar minnestrycket. Valfritt, standard false.
hashSequenceKeys Av de minnesskäl som beskrivs ovan kan strängnycklarna också hashas genom att ange den här parametern till true. Använd den endast för deserialiserare som stöder strängsekvensnycklar (HTK, MLF). Valfritt, standard false.
cacheIndex Anger om metadata som skapats under förbearbetningssteget ska skrivas ut till disken och läsas in från disken om det är tillgängligt (true, false). Valfritt, standardvärdet falseär . Mer information finns i avsnittet nedan. Nytt i CNTK version 2.1.
Cachelagring av index

Anteckning

Nytt i CNTK version 2.1.

Indexcachelagring gör det möjligt att avsevärt (med en faktor på 2–3 x) minska starttiden, särskilt när du arbetar med stora indatafiler. cacheIndex Om du anger flaggan till true kommer läsaren att skriva indexeringsmetadata till disk (samma katalog som indatafilen) om cachefilen inte är tillgänglig eller om den är inaktuell (äldre än indatafilen). Skrivandet är bäst och utförs på en separat tråd för att inte påverka läsarens prestanda. Om cachefilen finns och är uppdaterad kommer läsaren inte längre att skumma indatafilen för att skapa indexet. I stället läses indexet in från cachefilen. Observera att vissa konfigurationsparametrar för läsare har en direkt inverkan på indexering (till exempel kan olika värden frameMode för potentiellt resultera i index som har olika antal sekvenser). Därför kan en cachefil ignoreras av en läsare med en annan konfiguration än den som skapade cachen. Om du vill se den fullständiga fördelen med cachelagring bör konfigurationen inte ändras vid efterföljande omkörningar.

cacheIndex har ingen effekt på ImageDeserializer och CNTKBinaryFormatDeserializer, eftersom den förstnämnda inte indexera indata och senare har indexinformationen inbäddad i själva formatet.

Allmän deserialiserarkonfiguration

Parameter Beskrivning
module Anger namnet på läsarmodulen som implementerar datadeserialiseraren. Krävs.
type Anger ett data deserialiserarnamn som exponeras av den angivna läsarmodulen. Krävs.

Allmän transformeringskonfiguration

Parameter Beskrivning
type Anger ett transformeringsnamn som exponeras av läsarmodulen som implementerar datadeserialiseraren. Krävs.

HTKFeatureDeserializer-alternativ

Parameter Beskrivning
scpFile En lista över sökvägar till SCP-filer som ska bearbetas. Filerna ska vara HTK-kompatibla filer och måste anges i formatet "arkiv". Information om hur du använder ett arkiv beskrivs i HTKMLF Reader. Krävs.
dim Ett heltal som anger den fullständiga funktionsvektordimensionen med önskat kontextfönster. 1Krävs
contextWindow Kan antingen anges som ett par positiva heltal eller som ett enda positivt heltal (i så fall tolkas det som ett par med samma tal som upprepas två gånger). Anger vänster och höger storlek (första och andra heltal för paret) i kontextfönstret i exempel. Valfritt, standardvärdet 1är .
prefixPathInSCP En prefixsträng som ska tillämpas på sökvägarna som anges i SCP-filerna. Valfritt.

1 Om du till exempel hade 72-dimensionella funktioner (24-dimensionella filterbanksfunktioner plus delta- och delta-deltakoefficienter) och nätverket är utformat för att bearbeta ett kontextfönster med 11 bildrutor, bör den angivna dimensionen vara 792.

HTKMLFDeserializer-alternativ

Parameter Beskrivning
mlfFile Sökväg till en HTK-fil mlf som innehåller etiketterna för alla yttranden som anges i scp filen eller filerna. Krävs om mlfFileList inte har angetts.
mlfFileList Matris med sökvägar till HTK-formatfiler mlf som innehåller etiketterna för alla yttranden som anges i scp filen eller filerna. Krävs om mlfFile inte har angetts.
dim Total kardinalitet för etikettuppsättningen (positivt heltal). Krävs.
labelMappingFile Sökväg till en fil som visar alla etiketter som visas i mlf filen, en per rad. Krävs.

labelDim kan användas som synonym för dim.

CNTKTextFormatDeserializer-alternativ

Samma alternativ som kan användas med CNTKTextFormatReader

ImageDeserializer-alternativ

  • file: en enkel textfil där varje rad innehåller en tabbavgränsad mappning mellan logisk sekvensnyckel, bildfil (t.ex. JPEG, PNG osv.) och en 0-baserad etikett.

Mer information finns i ImageReader.

Base64ImageDeserializer-alternativ

Den här deserialiseraren stöder samma alternativ som kan användas med ImageDeserializer. Den enda skillnaden är i mappningsfilens format:

  • file: en enkel textfil där varje rad innehåller en tabbavgränsad mappning mellan logisk sekvensnyckel (valfritt, kan utelämnas), 0-baserad kategorietikett och bas 64-kodad bildfil (t.ex. JPEG, PNG osv.).

Exempel på konfigurationer och tester

Du hittar fullständiga nätverksdefinitioner och motsvarande datauppsättningsexempel i CNTK-lagringsplatsen. Där hittar du även enhets- och slutpunkt-till-slutpunkt-tester som använder deserialiserare, dvs.