Compartilhar via


BrainScript CNTK Leitor de Formato de Texto

Esta página documenta o CNTKTextFormatReader do ponto de vista do BrainScript, mas os usuários do Python também podem aprender lendo este documento. Os conceitos, parâmetros e padrões são todos iguais.

O CNTKTextFormatReader (posteriormente simplesmente CTF Reader) foi projetado para consumir dados de texto de entrada formatados de acordo com a especificação abaixo. Ele dá suporte aos seguintes recursos principais:

  • Vários fluxos de entrada (entradas) por arquivo
  • Entradas esparsas e densas
  • Sequências de comprimento variável

formato de texto CNTK (CTF)

Cada linha no arquivo de entrada contém um exemplo para uma ou mais entradas. Como (explicitamente ou implicitamente) cada linha também está anexada a uma sequência, ela define uma ou mais <relações de sequência, entrada e exemplo> . Cada linha de entrada deve ser formatada da seguinte maneira:

[Sequence_Id](Sample or Comment)+

onde

Sample=|Input_Name (Value )*

Comment=|# some content

  • Cada linha começa com uma ID de sequência e contém um ou mais exemplos (em outras palavras, cada linha é uma coleção não ordenada de amostras).
  • A ID da sequência é um número. Ele pode ser omitido, caso em que o número de linha será usado como a ID da sequência.
  • Cada exemplo é efetivamente um par chave-valor que consiste em um nome de entrada e o vetor de valor correspondente (o mapeamento para dimensões mais altas é feito como parte da própria rede).
  • Cada exemplo começa com um símbolo de pipe (|) seguido pelo nome de entrada (sem espaços), seguido por um delimitador de espaço em branco e, em seguida, uma lista de valores.
  • Cada valor é um número ou um número prefixado por índice para entradas esparsas.
  • As guias e os espaços podem ser usados de forma intercambiável como delimitadores.
  • Um comentário começa com um pipe imediatamente seguido por um símbolo de hash: |#, em seguida, seguido pelo conteúdo de fato (corpo) do comentário. O corpo pode conter caracteres, no entanto, um símbolo de pipe dentro do corpo precisa ser escapado acrescentando o símbolo de hash a ele (veja o exemplo abaixo). O corpo de um comentário continua até o fim da linha ou o próximo pipe não escapado, o que vier primeiro.

Exemplo simples

Este exemplo baseia-se em um conjunto mínimo de parâmetros e opções de formato.

Para usar o Leitor de CTF, defina a readerTypeCNTKTextFormatReader seção de leitor da configuração do CNTK:

...
reader = [
    readerType = "CNTKTextFormatReader"
    file = "c:\mydata\SampleInput.txt" # See the second example for Linux path example

    # IMPORTANT!
    # All inputs are grouped within "input" sub-section.
    input = [
        A = [
            dim = 5
            format = "dense"
        ]
        B = [
            dim = 1000000
            format = "sparse"
        ]
        C = [
            dim = 1
            format = "dense"
        ]
    ]
]
# the rest of the cntk config ...

(Esse fragmento, bem como outros exemplos de NDL neste documento, apresentam apenas reader a seção, omitindo o restante da configuração de CNTK; consulte o final desta página para obter ponteiros para um conjunto de redes de exemplo completas e os conjuntos de dados correspondentes)

O Leitor de CTF requer o seguinte conjunto de parâmetros:

  • file - caminho para o arquivo com o conjunto de dados.
  • input– sub-seção definindo entradas identificadas por nomes de entrada (ABe C no exemplo acima). Em cada entrada, os seguintes parâmetros necessários devem ser especificados:
    • format – especifica o tipo de entrada. Deve ser dense ou sparse
    • dim - especifica a dimensão do vetor de valor de entrada (para entrada densa , isso corresponde diretamente ao número de valores em cada amostra , pois isso representa o limite superior no intervalo de valores de índice possíveis).

Os dados de entrada correspondentes à configuração do leitor acima devem ter esta aparência:

|B 100:3 123:4 |C 8 |A 0 1 2 3 4 |# a CTF comment
|# another comment |A 0 1.1 22 0.3 54 |C 123917 |B 1134:1.911 13331:0.014
|C -0.001 |# a comment with an escaped pipe: '|#' |A 3.9 1.11 121.2 99.13 0.04 |B 999:0.001 918918:-9.19

Observe o seguinte sobre o formato de entrada:

  • |Input_Name identifica o início de cada exemplo de entrada. Esse elemento é obrigatório e é seguido pelo vetor de valor correspondente.
  • Vetor denso é apenas uma lista de valores de ponto flutuante; vetor esparso é uma lista de index:value tuplas.
  • As guias e os espaços são permitidos como delimitadores de valor (dentro de vetores de entrada), bem como delimitadores de entrada (entre entradas).
  • Cada linha separada constitui uma "sequência" de comprimento 1 (sequências de comprimento variável "Real" são explicadas no exemplo estendido abaixo).
  • Cada identificador de entrada só pode aparecer uma vez em uma única linha (que se traduz em um exemplo por requisito de entrada por linha ).
  • A ordem dos exemplos de entrada dentro de uma linha NÃO é importante (conceitualmente, cada linha é uma coleção não ordenada de pares chave-valor)
  • Cada linha bem formada deve terminar com símbolos "Feed de Linha" \n ou "Retorno de Carro, Feed \r\n de Linha".

Exemplo estendido

Este exemplo apresenta todos os parâmetros de configuração possíveis e mostra várias opções de formato de entrada. Consulte as tabelas abaixo para obter a descrição completa dos parâmetros de configuração usados neste exemplo.

...
precision="double"

reader = [
    readerType = "CNTKTextFormatReader"
    file = "/home/mydata/SampleInput.txt" # See the first example for Windows style path example
    randomize = true
    randomizationWindow = 30
    skipSequenceIds = false
    maxErrors = 100
    traceLevel = 2

    chunkSizeInBytes = 1024

    keepDataInMemory = true
    frameMode = false

    input = [
        Some_very_long_input_name = [
            alias = "a"
            dim = 3
            format = "dense"
        ]
        Some_other_also_very_long_input_name = [
            alias = "b"
            dim = 2
            format = "dense"
        ]
    ]
]
# the rest of the cntk config ...

Com um leitor de composição, ele gostaria do seguinte:

reader = {
        verbosity = 0 ;
        randomize = true;
        randomizationWindow=30
        deserializers = ({
            type = "CNTKTextFormatDeserializer" ; module = "CNTKTextFormatReader"
            file = "/home/mydata/SampleInput.txt" # See the first example for Windows style path example
            maxErrors = 100
            skipSequenceIds = false
            traceLevel = 2
            input = {
                qu1fea = {alias = "qui"; dim = 95589; format = "sparse"}
                qu2fea = {alias = "quj"; dim = 95589; format = "sparse"}
                pairweight = {alias = "wij"; dim = 1; format = "dense"}
            }
        })
    }

O arquivo de entrada correspondente pode, em seguida, olhar aproximadamente da seguinte maneira:

100 |a 1 2 3 |b 100 200
100 |a 4 5 6 |b 101 201
100 |b 102983 14532 |a 7 8 9
100 |a 7 8 9
200 |b 300 400 |a 10 20 30
333 |b 500 100
333 |b 600 -900
400 |a 1 2 3 |b 100 200
|a 4 5 6 |b 101 201
|a 4 5 6 |b 101 201
500 |a 1 2 3 |b 100 200

Todas as opções discutidas no exemplo acima ainda se aplicam aqui. Além disso, introduzimos dois recursos adicionais:

Aliases de nome de entrada

Os nomes de entrada podem ser arbitrários e, portanto, repeti-los em todo o arquivo de entrada pode não ser eficiente em espaço. Para atenuar isso, o conjunto de dados pode usar "aliases" em vez de nomes de entrada completos. Em seguida, os aliases precisam ser especificados em cada sub-subseção de entrada. Em nosso exemplo, o conjunto de dados usa aliases a e b, que são mapeados para "Some_very_long_input_name" e "Some_other_also_very_long_input_name", respectivamente, na seção de configuração do leitor.

IDs de sequência

Como já mencionado, cada linha separada no arquivo de entrada representa uma sequência que contém um único exemplo para cada entrada. No entanto, se uma linha for prefixada com um número não negativo, o número será usado como a ID de sequência correspondente. Todas as linhas subsequentes que compartilham a mesma ID de sequência são mescladas para se tornarem parte da mesma sequência. Portanto, repetir o mesmo prefixo numérico para linhas N permite criar uma sequência de várias amostras, com cada entrada contendo entre 1 e N amostras. Omitir o prefixo de sequência na segunda e nas linhas a seguir tem o mesmo efeito. Assim, o conjunto de dados de exemplo acima define cinco sequências com ids100, 333200400 e .500

Definir skipSequenceIds o parâmetro na seção de leitor para true, força o leitor a ignorar todas as IDs de sequência explícitas no conjunto de dados e tratar linhas separadas como sequências individuais. Além disso, omitir a ID da sequência na primeira linha do conjunto de dados tem o mesmo efeito : todas as IDs de sequência subsequentes são ignoradas, linhas tratadas como sequências individuais, como neste exemplo:

|a 1 2 3 |b 100 200
100 |a 4 5 6 |b 101 201
200 |b 102983 14532 |a 7 8 9

Algumas coisas finais a serem consideradas ao usar sequências:

  • As IDs de sequência devem ser exclusivas.
  • Os prefixos de ID só podem ser repetidos para linhas consecutivas.
  • O comprimento da sequência em linhas (ou seja, o número de linhas que compartilham o mesmo prefixo de ID) não deve exceder o comprimento máximo de entrada em amostras (o número de amostras em uma entrada) nesta sequência.

Por exemplo, os seguintes conjuntos de dados são inválidos:

100 |a 1 2 3 |b 100 200
200 |a 4 5 6 |b 101 201
100 |b 102983 14532 |a 7 8 9

123 |a 1 2 3 |b 100 200
456 |a 4 5 6
456 |b 101 201

Alguns exemplos de Real-World

  • Classificação: cada linha contém um exemplo, que consiste em um rótulo e recursos. Nenhuma ID de sequência é necessária, pois cada linha é sua própria "sequência" de comprimento 1.
|class 23:1 |features 2 3 4 5 6
|class 13:1 |features 1 2 0 2 3
...
  • DSSM: cada linha contém um par de documentos de destino de origem, expressos por meio de um recipiente de palavras, codificados como vetores esparsos.
|src 12:1 23:1 345:2 45001:1    |tgt 233:1 766:2 234:1
|src 123:1 56:1 10324:1 18001:3 |tgt 233:1 2344:2 8889:1 2234:1 253434:1
  • Marcação de parte da fala: sequências mapeando cada elemento para um rótulo correspondente. As sequências são alinhadas verticalmente (uma palavra + marca por linha).
0 |word 234:1 |tag 12:1
0 |word 123:1 |tag 10:1
0 |word 123:1 |tag 13:1
1 |word 234:1 |tag 12:1
1 |word 123:1 |tag 10:1
...
  • Classificação de sequência: sequências mapeadas para um único rótulo. As sequências são alinhadas verticalmente; O rótulo "class" pode ocorrer em qualquer linha que tenha a mesma sequenceId.

Observação

No momento, o número de linhas não deve exceder o comprimento da sequência mais longa. Isso significa que o rótulo não pode aparecer em uma linha por conta própria. Esse é um detalhe de implementação que será levantado no futuro.

0 |word 234:1 |class 3:1
0 |word 123:1
0 |word 890:1
1 |word 11:1 |class 2:1
1 |word 344:1
  • Sequência para sequência: mapeie uma sequência de origem para uma sequência de destino. As duas sequências são alinhadas verticalmente e, no caso mais fácil, apenas impressas após outra. Eles são unidos por terem a mesma "ID de sequência" geral (que, em seguida, se torna uma "ID da unidade de trabalho" nesse caso).

Observação

No momento, o número de linhas não deve exceder o comprimento da sequência mais longa. Isso significa que as sequências devem ser alinhadas horizontalmente. Esse é um detalhe de implementação que será levantado no futuro.

0 |sourceWord 234:1  |targetWord 344:1
0 |sourceWord 123:1  |targetWord 456:1
0 |sourceWord 123:1  |targetWord 2222:1
0 |sourceWord 11:1
1 |sourceWord 123:1
...
  • Learning para Classificar: uma "sequência" representa uma consulta, cada exemplo de um documento com uma classificação rotulada à mão. Nesse caso, a "sequência" é apenas um multiconjunto que (no contexto de uma função de perda de aprendizado para classificação) não tem uma ordenação.
0 |rating 4 |features 23 35 0 0 0 21 2345 0 0 0 0 0
0 |rating 2 |features 0 123 0 22 44 44 290 22 22 22 33 0
0 |rating 1 |features 0 0 0 0 0 0 1 0 0 0 0 0
1 |rating 1 |features 34 56 0 0 0 45 1312 0 0 0 0 0
1 |rating 0 |features 45 45 0 0 0 12 335 0 0 0 0 0
2 |rating 0 |features 0 0 0 0 0 0 22 0 0 0 0 0
...

Parâmetros de configuração

Parâmetro Descrição
precision Especifica a precisão do ponto flutuante (double ou float) dos valores de entrada. Opcional, o padrão é float.

reader Seção

Parâmetro Descrição
readerType Especifica um dos leitores de CNTK com suporte para carregar (por exemplo, CNTKTextFormatReader). Obrigatório.
file Caminho para o arquivo que contém o conjunto de dados de entrada (estilo Windows ou Linux). Obrigatório.
randomize Especifica se a entrada deve ser aleatória (true, false). Opcional, o padrão é true.
randomizationSeed Valor de semente de randomização inicial (incrementado a cada varredura quando os dados de entrada são realeamensionados). Opcional, o padrão é 0.
randomizationWindow Especifica o tamanho (inteiro positivo) da janela de randomização (ou seja, intervalo de randomização). Esse parâmetro afeta quanto do conjunto de dados precisa residir na memória ao mesmo tempo. Opcional, dependendo do sampleBasedRandomizationWindow valor, o padrão é o tamanho de todo o conjunto de dados em exemplos (ou seja, a entrada é aleatória em todo o conjunto de dados) ou 4 GB de espaço em disco em partes (ou seja, 128 quando o tamanho da parte é igual a 32 MB). Esse parâmetro é ignorado quando randomize é false.
sampleBasedRandomizationWindow Se true, o tamanho da janela de randomização é interpretado como um determinado número de amostras, caso contrário , como um número de partes. Opcional, o padrão é false. Da mesma forma que randomizationWindow, esse parâmetro é ignorado, quando randomize é false.
skipSequenceIds Se true, o leitor ignorará as IDs de sequência no arquivo de entrada, interpretando cada linha separada como uma sequência independente do tamanho 1 (consulte a seção nas IDs da sequência). Opcional, o padrão é false.
maxErrors Número de erros de entrada após os quais uma exceção deve ser gerada. Opcional, o padrão 0é , o que significa que o primeiro valor malformado disparará uma exceção.
traceLevel Nível de verbosidade de saída. 0 - mostrar somente erros; 1 - mostrar erros e avisos; 2 - mostrar toda a saída. Opcional, o padrão é 1.
chunkSizeInBytes Número de bytes consecutivos a serem lidos do disco em uma única operação de leitura. Opcional, o padrão é 33554432 (32 MB).
keepDataInMemory Se true, todo o conjunto de dados será armazenado em cache na memória. Opcional, o padrão é false.
frameMode true sinaliza o leitor para usar um método de empacotamento otimizado para quadros (sequências que contêm apenas um único exemplo). Opcional, o padrão é false.
cacheIndex Especifica se os metadados criados durante a fase de pré-processamento devem ser gravados no disco e carregados no disco, se disponíveis (true, false). Opcional, o padrão é false. Para obter mais detalhes, consulte a seção abaixo. Novidades no CNTK versão 2.1.
Cache de índice

Observação

Novidades no CNTK versão 2.1.

O cache de índice permite reduzir significativamente (por um fator de 2-3x) os tempos de inicialização, especialmente ao trabalhar com arquivos de entrada grandes. Definir o cacheIndex sinalizador para true sinalizar o leitor para gravar os metadados de indexação no disco (mesmo diretório que o arquivo de entrada) se o arquivo de cache não estiver disponível ou se ele estiver obsoleto (mais antigo que o arquivo de entrada). A gravação é o melhor esforço e é executada em um thread separado para não afetar o desempenho do leitor. Se o arquivo de cache estiver presente e estiver atualizado, o leitor não usará mais o arquivo de entrada para compilar o índice. Em vez disso, ele carregará o índice do arquivo de cache. Observe que determinados parâmetros de configuração de leitor têm um impacto direto na indexação (por exemplo, valores frameMode diferentes podem resultar em índices que têm um número diferente de sequências). Por esse motivo, um arquivo de cache pode ser ignorado por um leitor com uma configuração diferente daquela que produziu o cache. Para ver o benefício completo do cache, a configuração não deve ser modificada em execuções subsequentes.

input sub-seção

input combina uma série de entradas individuais, cada uma com uma sub-seção de configuração apropriadamente rotulada. Todos os parâmetros descritos abaixo são específicos para uma sub-seção de nome de entrada associada a uma entrada específica.

Parâmetro Descrição
alias Um nome de abreviação alternativo (cadeia de caracteres) usado para identificar a entrada no conjunto de dados. Opcional
format Especifica o tipo de entrada (dense, sparse). Obrigatório.
dim Dimensão (inteiro positivo) do valor de entrada (ou seja, o número de valores de entrada em um exemplo de entrada densa , o limite superior no intervalo de índice para entrada esparsa ). Obrigatório.
definesMBSize Sinalizador (falso padrão), indicando se o tamanho da minibatch deve ser contado em exemplos desse fluxo específico Opcional.

Você encontrará definições de rede completas e os exemplos de conjunto de dados correspondentes no repositório CNTK. Lá, você também encontrará um teste de ponta a ponta que usa o leitor CNTKTextFormat.