Como fazer treinar modelos no BrainScript
- Executar treinamento em camadas?
- Treinar com um objetivo multitarefa?
- Treinar um modelo de regressão em imagens?
- Treinar um classificador multi-rótulo?
- Introdução na sequência à modelagem de sequência?
- Treinar um modelo DSSM (ou convolutional-DSSM)?
- Treinar um codificador automático de imagem usando Deconvolution e Unpooling?
- Detecção de objetos usando o Fast R-CNN?
Treinamento em camadas
Para executar o treinamento em camadas, basta usar vários "comandos" no arquivo de configuração, em que cada comando é do tipo action=train.
command = TrainLayer1:TrainLayer2:TrainLayer3:EndToEndTrain:Test:Output
TrainLayer1= [
action = train
...
]
TrainLayer2= [
action = train
...
]
...
Treinar com um objetivo multitarefa
Basta definir seu critério combinado como uma expressão BrainScript e monitorar todas as perdas de tarefas individuais especificando-as como evaluationNodes
.
task1loss = CrossEntropyWithSoftMax(prediction,label)
task2loss = SquareError(reconstruction,input)
mtloss = task1loss + Constant(0.3) .* task2loss
criterionNodes = (mtloss)
evaluationNodes = (task1loss:task2loss)
Treinar um modelo de regressão em imagens
Abaixo, descrevemos como prever um ou mais valores de ponto flutuante para uma imagem de entrada usando CNTK. Um exemplo de caso de uso é prever uma caixa delimitadora, por exemplo, como (x, y, w, h), de um objeto em uma determinada imagem. Você também poderia pensar em prever o preço de um carro apenas olhando para uma imagem daquele carro (seria realmente interessante). Aqui, usamos um exemplo muito simples no qual treinamos uma rede para prever os valores RGB médios de uma imagem (normalizados para [0, 1]). No entanto, as mesmas etapas se aplicam a outros casos de uso. Essas etapas são:
- Definir tanto a imagem quanto os rótulos de regressão da verdade básica como entradas para sua rede
- Definir uma rede que prevê um número correspondente de valores w.r.t. seus rótulos de regressão
- Definir uma função de perda que compara os valores previstos com a verdade básica
- Adaptar a seção leitor no arquivo de configuração .cntk para ler rótulos de imagem e regressão
Aqui está como você poderia fazê-lo. O arquivo de configuração completo está incluído na pasta Exemplos em Examples/Image/Regression/RegrSimple_CIFAR10.cntk. Essa pasta também contém os scripts para baixar os dados da imagem e gerar a verdade do campo de regressão para treinamento e teste.
1-3) Definindo entradas, rede e função de perda:
BrainScriptNetworkBuilder = [
imageShape = 32:32:3
featScale = Constant(1/256)
labelDim = 3
model (features) = {
featNorm = Scale(features, featScale)
h1 = LinearLayer {100, init="gaussian", initValueScale=1.5} (featNorm)
ol = LinearLayer {labelDim, init="gaussian", initValueScale=1.5} (h1)
}.ol
# inputs
features = Input {imageShape}
regrLabels = Input {labelDim}
# apply model to features
ol = model (features)
# define regression loss
# rmse = sqrt(SquareError(regrLabels, ol) / labelDim)
sqerr = SquareError (regrLabels, ol)
rmse = Sqrt (Constant(1/labelDim).* sqerr)
featureNodes = (features)
labelNodes = (regrLabels)
criterionNodes = (rmse)
evaluationNodes = (rmse)
OutputNodes = (ol)
]
- Definindo um leitor composto usando o ImageReader e o CNTKTextFormatReader:
reader = {
verbosity = 0 ; randomize = true
deserializers = ({
type = "ImageDeserializer" ; module = "ImageReader"
file = "$dataDir$/cifar-10-batches-py/train_map.txt"
input = {
features = { transforms = (
{ type = "Scale" ; width = 32 ; height = 32 ; channels = 3 ; interpolations = "linear" } :
{ type = "Transpose" }
)}
ignored = { labelDim = 10 }
}
} : {
type = "CNTKTextFormatDeserializer" ; module = "CNTKTextFormatReader"
file = "$dataDir$/cifar-10-batches-py/train_regrLabels.txt"
input = {
regrLabels = { dim = 3 ; format = "dense" }
}
})
}
O leitor é um leitor composto que usa o ImageReader para ler imagens e o CNTKTextFormatReader para ler os rótulos de verdade do solo de regressão. Ele faz isso definindo uma matriz de desserializadores (usando {...} : {...}
) e atribuindo as entradas conforme definido na rede acima (cf. features e regrLabels).
Consulte Exemplos/Image/Miscellaneous/CIFAR-10/06_RegressionSimple.cntk para obter o arquivo de configuração completo e o Readme correspondente nessa pasta para executar o exemplo.
Treinar um classificador multilabel
Para classificação multi-rótulo, você deve evitar o uso de CrossEntropy, pois ela só pode lidar com vetores de entrada que somam 1. Uma alternativa sensata é usar uma soma de funções de perda logística, uma para cada saída
...
probabilities = DenseLayer {outputSize, activation=Sigmoid} (hidden)
logisticLoss = Logistic (multiLabels, probabilities)
trainingCriterion = (logisticLoss)
...
Além da perda em si, talvez você queira monitorar outras métricas, como o número de previsões incorretas. Não há nenhuma expressão interna para isso, mas ela pode ser expressa como
...
hammingLoss (y, p) = ReduceSum (y != (p > 0.5))
hl = hammingLoss(multiLabels,probabilities)
evaluationNodes = (hl)
...
Isso conta o número de vezes que y[i] discorda de p[i]>0,5.
Introdução na sequência à modelagem de sequência
Este laboratório prático descreve os principais ingredientes para começar o processamento de sequência, como o formato de texto CNTK e como configurar o leitor para usar aliases curtos para as várias sequências de entrada. O exemplo G2P (grapheme-to-phoneme) demonstra uma tarefa de sequência para sequência real.
Um problema importante para a modelagem sequência a sequência é como decodificar dados de teste com a pesquisa de feixe. Isso pode ser feito em uma seção da configuração em que a ação de nível superior é "write". A decodificação requer uma pesquisa para a sequência mais provável de saídas. O CNTK tem um decodificador de pesquisa de feixe enquanto você pode chamar assim
BrainScriptNetworkBuilder = (BS.Seq2Seq.BeamSearchSequenceDecoderFrom (
BS.Network.Load (decodeModelPath), beamSize))
e executará a pesquisa de feixe com o tamanho do feixe especificado. Para um tamanho de feixe de 1, há um decodificador greedy especializado
BrainScriptNetworkBuilder = (BS.Seq2Seq.GreedySequenceDecoderFrom (
BS.Network.Load (decodeModelPath)))
Ambos os decodificadores têm requisitos específicos para a rede, conforme mostrado no exemplo G2P
Treinar um modelo DSSM (ou DSSM convolucional)
DSSM (ou Modelo de Similaridade Semântica Profunda) é um modelo DNN treinado em pares de textos de destino de origem, para aprender um espaço de inserção de texto curto em que os pares de texto de origem e destino relevantes estão mais próximos. A entrada de texto para o modelo é representada pelo hash de trigrama pré-computado (consulte Huang et al.). Para C-DSSM, o hash de trigrama é calculado por palavra e, em seguida, concatenado na ordem em que as palavras ocorrem no texto. A entrada para ambos os modelos tem tamanho fixo. Se considerarmos trigramas de 50 mil, a entrada DSSM correspondente à origem e ao texto de destino será um vetor de comprimento de 50 mil cada. Para C-DSSM, o vetor teria comprimento de 50K x n, em que os primeiros vetores de palavra n-1 são concatenados e o nº vetor contém uma soma dos vetores correspondentes a todas as palavras restantes no texto. Se houver menos de n palavras no texto, o restante do vetor será acolchoado com zeros. Para desenhar uma analogia com a imagem, você pode pensar na entrada de texto para C-DSSM como uma imagem com dimensões 10x1 e 50K de canais armazenados em um [C x H x W]
formato.
Este exemplo demonstra como treinar um modelo DSSM/C-DSSM usando CNTKTextFormatReader. Os dados devem conter dois recursos (texto de origem e destino) e um rótulo (que sempre é definido como o valor 1 nos dados de treinamento, pois contém apenas amostras positivas – durante o treinamento, os exemplos de destino negativos são gerados por amostragem aleatória). Aqui está a configuração do leitor,
reader = {
verbosity = 0
randomize = true
deserializers = ({
type = "CNTKTextFormatDeserializer"
module = "CNTKTextFormatReader"
file = "data.txt"
input = {
Q = { dim = 500000; format = "sparse" }
D = { dim = 500000; format = "sparse" }
L = { dim = 1; format = "dense" }
}
})
}
Um exemplo dos dados de entrada,
|L 1 |Q 482:1 761:1 1832:1 2117:1 12370:1 17131:1 17854:1 24976:1 27676:1 28055:1 28177:1 29507:1|D 482:1 761:1 1832:1 2117:1 12370:1 17131:1 17854:1 24976:1 27676:1 28055:1 28177:1 29507:1
|L 1 |Q 149:1 153:1 595:1 671:1 675:1 1110:1 1517:1 2077:1 2114:1 5533:1 5662:1 6886:1 6901:1 7294:1 12846:1 13033:1 16614:1 19425:1 22015:1 24839:1 24994:1 26196:1 26358:1 27565:1|D 149:1 153:1 595:1 671:1 675:1 1110:1 1517:1 2077:1 2114:1 5533:1 5662:1 6886:1 6901:1 7294:1 12846:1 13033:1 16614:1 19425:1 22015:1 24839:1 24994:1 26196:1 26358:1 27565:1
|L 1 |Q 187:1 2294:1 2800:1 6920:1|D 187:1 2294:1 2800:1 6920:1
E, por fim, a definição de rede,
BrainScriptNetworkBuilder = {
# Constants scalars
isConvolutional = true
numWords = (if isConvolutional then 10 else 1)
numTrigramsPerWord = 50000
numHiddenNodes = 300
wordWindowSize = 3
numWindows = numWords - wordWindowSize + 1
numNeg = 50
# Constant tensors
CONST_GAMMA = Constant(10)
CONST_SHIFT = Constant(1)
CONST_NEG = Constant(numNeg)
CONST_PAD_NEG = Constant(0, rows=numNeg, cols=1)
CONST_PAD_POS = Constant(1, rows=1, cols=1)
CONST_PAD = Splice(CONST_PAD_POS : CONST_PAD_NEG, axis=1)
# Inputs
Q = Input(500000)
D = Input(500000)
L = Input(1)
qr = if isConvolutional
then TransposeDimensions(ReshapeDimension(Q, 1, numTrigramsPerWord:1:numWords), 1, 3)
else Slice(0, numTrigramsPerWord, Q, axis=1)
dr = if isConvolutional
then TransposeDimensions(ReshapeDimension(D, 1, numTrigramsPerWord:1:numWords), 1, 3)
else Slice(0, numTrigramsPerWord, D, axis=1)
qdssm = Sequential (
DenseLayer {numHiddenNodes, activation=Tanh} :
DenseLayer {numHiddenNodes, activation=Tanh} :
DenseLayer {numHiddenNodes, activation=Tanh})
qcdssm = Sequential (
ConvolutionalLayer {numHiddenNodes, (wordWindowSize:1), pad=false, activation=Tanh} :
MaxPoolingLayer {(numWindows:1), stride=(1:1)} :
DenseLayer {numHiddenNodes, activation=Tanh} :
DenseLayer {numHiddenNodes, activation=Tanh})
ddssm = Sequential (
DenseLayer {numHiddenNodes, activation=Tanh} :
DenseLayer {numHiddenNodes, activation=Tanh} :
DenseLayer {numHiddenNodes, activation=Tanh})
dcdssm = Sequential (
ConvolutionalLayer {numHiddenNodes, (wordWindowSize:1), pad=false, activation=Tanh} :
MaxPoolingLayer {(numWindows:1), stride=(1:1)} :
DenseLayer {numHiddenNodes, activation=Tanh} :
DenseLayer {numHiddenNodes, activation=Tanh})
qembed = if isConvolutional
then qcdssm
else qdssm
dembed = if isConvolutional
then dcdssm
else ddssm
qf = qembed(qr)
df = dembed(dr)
lf = Times(CONST_PAD, L)
c = CosDistanceWithNegativeSamples(qf, df, CONST_SHIFT, CONST_NEG)
s = Slice(0, 1, c, axis=1, tag="output")
ce = CrossEntropyWithSoftmax(lf, Scale(CONST_GAMMA, c), tag="criterion")
}
Observação:
- Embora o C-DSSM tenha sido mostrado para ter um desempenho consistente melhor que o DSSM, ele também treina mais lento (em algum momento até 5-10x mais lento). Portanto, em alguns casos, você pode obter um melhor desempenho do DSSM no mesmo tempo de treinamento, treinando mais dados (ou para mais épocas).
- O DSSM /C-DSSM original foi treinado em pares de título de consulta e documento. Mas você pode aprender outras relações entre textos curtos treinando em outros tipos de dados, como pares de consulta de sessão ou pares de sufixo de prefixo de consulta.
Treinar um codificador automático de imagem usando a desconvolução e a desativação
Há instruções aqui.
Treinar detecção de objetos usando o Fast R CNN
Há instruções aqui.