Compartilhar via


BrainScript por meio de regras de análise de linha de comando

Abaixo, descrevemos as regras de análise de linha de comando CNTK. CNTK consiste em vários componentes para concluir uma tarefa. A maioria desses componentes precisa de algumas informações de configuração disponíveis para funcionar e esses parâmetros de configuração são fornecidos por meio de arquivos de configuração no CNTK.

Os arquivos de configuração são coleções de pares nome-valor. Os dados de configuração podem ser um dos seguintes tipos:

  • Simples: um único valor é atribuído ao parâmetro de configuração. Por exemplo, deviceId = "Auto".
  • Matriz: um parâmetro de configuração é atribuído a uma matriz de valores que não precisam ser de um tipo uniforme. : é o separador padrão para matrizes. O separador pode ser alterado colocando os valores da matriz entre parênteses e colocando o novo caractere separador imediatamente após o parêntese aberto. O * caractere permite que um valor específico seja repetido várias vezes na matriz. Por exemplo, minibatchSize = 256:512:512:512:1024 é igual a minibatchSize = 256:512*3:1024.
  • Conjunto: os conjuntos de parâmetros contêm conjuntos de parâmetros de configuração de qualquer tipo. Os conjuntos de parâmetros podem ser aninhados. O separador padrão para conjuntos de parâmetros será ; se vários itens forem incluídos em uma linha. Separadores de linha também servem como separadores para itens. Por exemplo:

block1 = [id=1;size=256]

block2 = [
    subblock = [string="hi";num=5]
    value = 1e-10
    array = 10:"this is a test":1.25
]

Em CNTK, os arquivos de configuração são organizados de forma hierárquica. Os valores de dados reais não são avaliados até que um componente CNTK solicite o valor. Quando um valor é solicitado por um componente, CNTK pesquisará primeiro dentro do bloco de componentes. Se o valor não for encontrado, ele continuará procurando no conjunto de parâmetros pai e avô até que o parâmetro seja encontrado ou o nível superior da hierarquia de configuração seja atingido sem uma correspondência. Isso permite que o compartilhamento dos mesmos valores de parâmetro seja mais fácil em blocos diferentes. Como discutimos anteriormente, para executar CNTK você precisa especificar o arquivo de configuração na linha de comando, pois cntk configFile=yourExp.cntk isso carregará o arquivo de configuração solicitado e executará qualquer bloco de comando listado nos parâmetros de comando no arquivo de configuração.

Comandos e ações

Deve haver um parâmetro de comando de nível superior, que define os comandos (separados com :) que serão executados no arquivo de configuração. Cada comando faz referência a um bloco de comando no arquivo, que deve conter um parâmetro de ação que define a operação que o bloco executará. Por exemplo, o comando a seguir executará o mnistTrain bloco, que executa a ação de trem, seguido pelo mnistTest bloco, que avalia o modelo.

command = mnistTrain:mnistTest

mnistTrain = [
    action = "train"
    ...
]

mnistTest = [
    action = "eval"
    ...
]

Sobrecargas de configuração na linha de comando

É comum ter uma configuração que pode ser usada como uma configuração base e modificar apenas alguns parâmetros para cada execução experimental. Isso pode ser feito de algumas maneiras diferentes, uma delas é substituir as configurações na linha de comando. Por exemplo, para substituir o caminho do arquivo de modelo, basta modificar a linha de comando da seguinte maneira:

cntk configFile=yourExp.cntk stderr="c:\temp\newpath"

Isso substituirá a configuração atual para stderr, que é definida no nível raiz do arquivo de configuração, com o novo valor. Se um parâmetro dentro de um bloco de comando precisar ser modificado, o bloco também precisará ser especificado. Por exemplo, é possível alterar o minibatchSize para um experimento na linha de comando como

cntk configFile=yourExp.cntk mnistTrain=[minibatchSize=256]

ou modificar o arquivo de dados usado para um experimento como

cntk configFile=yourExp.cntk mnistTrain=[reader=[file="mynewfile.txt"]]

Arquivos de configuração em camadas

Em vez de substituir algumas partes de um arquivo de configuração usando parâmetros de linha de comando, também é possível especificar vários arquivos de configuração, em que os últimos arquivos substituem os anteriores. Isso permite que um usuário tenha um arquivo de configuração mestre e especifique, em um arquivo de configuração separado, quais parâmetros do mestre eles gostariam de substituir para uma determinada execução de CNTK. Isso pode ser feito especificando uma lista "+" separada de arquivos de configuração ou usando a configFile= marca várias vezes. Os seguintes são equivalentes.

cntk configFile=yourExp1.cntk+yourExp2.cntk

cntk configFile=yourExp1.cntk configFile=yourExp2.cntk

Se yourExp2.cntk apenas contiver a cadeia mnistTrain=[reader=[file=mynewfile.txt]]de caracteres, ambos os comandos serão equivalentes a:

cntk configFile=yourExp1.cntk mnistTrain=[reader=[file="mynewfile.txt"]]

Observe que o valor de uma variável é sempre determinado pela última vez que ela é atribuída. Também é possível misturar parâmetros de linha de comando e arquivos de configuração em camadas em combinações arbitrárias. Por exemplo,

cntk configFile=yourExp1.cntk+yourExp2.cntk var1=value configFile=yourExp3.cntk

processaria esses parâmetros de configuração na ordem em que eles aparecem na linha de comando e qualquer valor atribuído por último é o valor usado.

Além de poder especificar vários arquivos de configuração na linha de comando, um usuário pode incluir um arquivo de configuração dentro de outro. Por exemplo, se a primeira linha de yourExp2.cntk foi

include=yourExp1.cntk

em seguida, simplesmente executando

cntk configFile=yourExp2.cntk

seria equivalente à execução

cntk configFile=yourExp1.cntk+yourExp2.cntk

em que, neste último caso, yourExp2.cntk não contém a instrução include. Observe que essas instruções incluem podem aparecer em qualquer lugar dentro de um arquivo de configuração; onde quer que a instrução include seja exibida, é aí que o arquivo de configuração especificado será incluído. Incluir um arquivo de configuração é equivalente a colar o conteúdo desse arquivo no local da instrução include. As instruções include são resolvidas recursivamente (usando uma pesquisa detalhada), o que significa que, se yourExpA.cntk incluir yourExpB.cntk, e yourExpB.cntk incluir yourExpC.cntk, a cadeia completa será resolvida e yourExpC.cntk será efetivamente incluída em yourExpA.cntk. Se um arquivo de configuração for incluído várias vezes (por exemplo, 'A' inclui 'B' e 'C', e 'B' também inclui 'C'), ele será efetivamente incluído apenas na primeira vez que for encontrado.

Variáveis stringize

Embora os arquivos de configuração em camadas permitam que os usuários reutilizem arquivos de configuração em experimentos, esse ainda pode ser um processo complicado. Para cada experimento, um usuário pode ter que substituir vários parâmetros, alguns dos quais podem ser longos caminhos de arquivo (por exemplo, , stderr, modelPath, file). A funcionalidade "stringize" pode facilitar muito esse processo. Ele permite que um usuário especifique uma configuração como a seguinte:

command = SpeechTrain
stderr = "$Root$\$RunName$.log"
speechTrain = [
    modelPath = "$Root$\$RunName$.cn"
    SGD = [
        reader = [
            features = [
                type = "real"
                dim = "$DataSet1_Dim$"
                file = "$DataSet1_Features$"
            ]
        ]
    ]
]

Aqui, RooteRunNameDataSet1_DimDataSet1_Features são variáveis especificadas em outro lugar na configuração (em um escopo visível do ponto em que são usadas). Ao interpretar esse arquivo de configuração, o analisador substituiria cada cadeia de caracteres do formulário $VarName$ pela cadeia de caracteres VarValue, em que VarValue representa o valor da variável chamada VarName. O processo de resolução de variável é recursivo; por exemplo, se A=$B$, B=$C$e C=HelloWorld.txt, A será resolvido como "HelloWorld.txt". Verifique se não há nenhum loop de referência no arquivo de configuração. Caso contrário, o analisador entrará em loop infinito neste momento.

Observe que, como é equivalente para um usuário especificar o valor de uma variável em um arquivo de configuração versus na linha de comando, os valores dessas variáveis podem ser especificados em qualquer local. Lembre-se de que o valor de uma variável é determinado pela última vez que ela é atribuída, seja em um arquivo de configuração ou na linha de comando. Portanto, se Root for definido em config1.txt, mas substituído na linha de comando, o valor especificado na linha de comando será o usado para resolver instâncias de $Root$ configFile1.txt. Um recurso útil é que, se stderr ou modelPath apontar para diretórios que não existem, esses diretórios serão criados por CNTK; isso permite que você especifique algo comostderr = $Root$\$RunName$\$RunName$.log, mesmo que o diretório $Root$\$RunName$ não exista.

Padrão, valores repetidos e comentários

A maioria dos parâmetros em arquivos de configuração tem um valor padrão que será usado se nenhum valor de configuração for especificado. Se não houver nenhum valor padrão e o valor não puder ser encontrado em uma pesquisa, uma exceção será exibida e o programa será encerrado. Se um nome de parâmetro for especificado mais de uma vez, o último valor definido para esse valor será o que será mantido. A única exceção a isso está nos conjuntos de parâmetros, que são cercados por [ chaves quadradas ], nesses casos os valores dentro das chaves são considerados um conjunto de parâmetros e serão adicionados ao conjunto de parâmetros atualmente existente. Por exemplo:

params=[a=1;b=2;c=3]
params=[c=5;d=6;e=7]

é efetivamente igual a:

params=[a=1;b=2;c=5;d=6;e=7]

Observe que esse processamento de acréscimo NÃO é usado para elementos de matriz e toda a matriz será substituída se estiver definida várias vezes. O # caractere significa o início de um comentário, tudo o que ocorre depois que ele # é ignorado. O # espaço em branco deve ser precedido ou estar no início da linha para ser interpretado como um comentário. O comentário a seguir é válido

stderr="c:\cntk\log\cntk" # "_mnistTrain_mnistTest.log"

Veja a seguir um exemplo de um valor que não será interpretado como um comentário. Ele define um parâmetro var como infinito, pois o # in 1#INF não é um marcador de comentário

var=1#INF