Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
(Nota: As versões mais antigas da CNTK usavam "MEL" (Model Editing Language) para este fim. Ainda estamos no processo de conversão dos exemplos. Para obter documentação sobre o MEL, consulte o aqui.)
A CNTK permite que os modelos sejam editados após o fato. Isso é feito criando um novo modelo enquanto clona (partes de) um modelo existente com modificações aplicadas. Para isso, a CNTK disponibiliza três funções básicas:
-
BS.Network.Load()carregar um modelo existente -
BS.Network.CloneFunction()extrair uma seção de um modelo existente para reutilização -
BS.Network.Edit()clonar um modelo com modificações nó a nó aplicadas
A operação de edição não é uma etapa separada. Em vez disso, um comando que deve funcionar a partir de um modelo modificado não especificaria um modelPath para carregar o modelo, mas sim uma seção de BrainScriptNetworkBuilder que carrega o modelo dentro e constrói um novo modelo fora do carregado em tempo real.
Exemplo: Pré-formação discriminativa
O pré-treinamento discriminativo é uma técnica onde uma rede profunda é criada treinando uma sequência de redes mais rasas. Comece com uma rede de 1 camada oculta, treine para convergência parcial e, em seguida, remova a camada de saída, adicione uma nova camada oculta e adicione uma nova camada de saída. Repita até atingir o número desejado de camadas ocultas.
Vamos supor com um modelo de partida muito simples
BrainScriptNetworkBuilder = [
N = 40; M = 9000; H = 512
W1 = Parameter (H, N); b1 = Parameter (H)
Wout = Parameter (M, H); bout = Parameter (M)
x = Input (N, tag=‘feature’) ; labels = Input (M, tag=‘labels’)
h1 = Sigmoid (W1 * x + b1)
z = Wout * h1 + bout
ce = CrossEntropyWithSoftmax (labels, z, tag=‘criterion’)
]
Vamos treinar este modelo e economizar em "model.1.dnn". Em seguida, queremos treinar um modelo com duas camadas ocultas, onde a primeira camada oculta é inicializada a partir dos valores treinados acima. Para isso, criamos uma ação de treinamento separada que cria um novo modelo, mas reutilizando partes do anterior, da seguinte forma:
BrainScriptNetworkBuilder = {
# STEP 1: load 1-hidden-layer model
inModel = BS.Network.Load ("model.1.dnn")
# get its h1 variable --and also recover its dimension
h1 = inModel.h1
H = h1.dim
# also recover the number of output classes
M = inModel.z.dim
# STEP 2: create the rest of the extended network as usual
W2 = Parameter (H, H); b2 = Parameter (H)
Wout = Parameter (M, H); bout = Parameter (M)
h2 = Sigmoid (W2 * h1 + b2)
z = Wout * h2 + bout
ce = CrossEntropyWithSoftmax (labels, z, tag=‘criterion’)
}
Primeiro, o PASSO 1 usa Load() para carregar a rede em uma variável BrainScript. A rede se comporta como um registro BrainScript, onde todos os nós de nível superior (todos os nós que não contêm um . ou [ em seus nomes de nós) são acessíveis através da sintaxe de registro. Uma nova rede pode fazer referência a qualquer nó em uma rede carregada. Neste exemplo, a rede carregada contém um nó h1 que é a saída da primeira camada oculta e um nó z que é a probabilidade posterior de log não normalizada das classes de saída (entrada para a função Softmax). Ambos os nós podem ser acessados a partir do BrainScript através da sintaxe de pontos, por exemplo, inModel.h1 e inModel.z.
Observe que as constantes não são armazenadas em modelos, portanto, nem N nem M estão disponíveis no modelo. No entanto, é possível reconstruí-los a partir do modelo carregado. Para esse propósito, os nós de computação também se comportam como registros do BrainScript e expõem uma propriedade dim.
Em seguida, o PASSO 2 constrói o resto da nova rede usando o BrainScript regular. Observe que esta nova seção simplesmente usa o nó h1 do modelo de entrada como uma entrada, como faria com qualquer outro nó. A referência a um nó da rede de entrada fará com que todos os nós dos quais esse nó depende também façam parte da rede recém-criada. Por exemplo, o nó de entrada x se tornará automaticamente parte da nova rede.
Observe também que a camada de saída é construída novamente. Desta forma, seus parâmetros de modelo serão criados recentemente. (Para não fazer isso e, em vez disso, reutilizar os parâmetros existentes, pode-se usar inModel.Wout, mas observe que isso não faz sentido do ponto de vista do design de rede neste exemplo específico.)
Exemplo: Usando um modelo pré-treinado
A seguir está um exemplo de uso de um modelo pré-treinado (do arquivo "./featext.dnn") como um extrator de recursos:
BrainScriptNetworkBuilder = {
# STEP 1: load existing model
featExtNetwork = BS.Network.Load ("./featext.dnn")
# STEP 2: extract a read-only section that is the feature extractor function
featExt = BS.Network.CloneFunction (
featExtNetwork.input, # input node that AE model read data from
featExtNetwork.feat, # output node in AE model that holds the desired features
parameters="constant") # says to freeze that part of the network
# STEP 3: define the part of your network that uses the feature extractor
# from the loaded model, which above we isolated into featExt().
# featExt() can be used like any old BrainScript function.
input = Input (...)
features = featExt (input) # this will instantiate a clone of the above network
# STEP 4: and add the remaining bits of the network in BrainScript, e.g.
h = Sigmoid (W_hid * features + b_hid) # whatever your hidden layer looks like
z = W_out * h + b_out
ce = CrossEntropyWithSoftmax (labels, z)
criterionNodes = (ce)
}
O PASSO 1 utiliza Load() para carregar a rede numa variável BrainScript.
A ETAPA 2 usa CloneFunction() para clonar a seção relacionada à extração de recursos da rede carregada, que é o subgráfico que conecta featExtNetwork.input a featExtNetwork.feat. Como especificamos parameters="constant", todos os parâmetros dos quais featExtNetwork.feat depende também são clonados e tornados somente leitura.
Nos PASSOS 3 e 4, a nova rede é definida. Isso é feito como qualquer outro modelo BrainScript, só que agora podemos usar a função featExt() ao fazê-lo.
Problemas com nomes de nó com .[ e ]
Para fazer referência a um nó em uma rede que contém . ou [ ou ], substitua esses caracteres por _.
Por exemplo, se network contiver um nó chamado result.z, network.result.z falhará; em vez disso, diga network.result_z.
Exemplo: Modificando nós de uma rede existente
Para modificar partes internas de uma rede existente, pode-se realmente clonar a rede, enquanto as modificações são aplicadas como parte do processo de clonagem. Isto é conseguido por BS.Network.Edit().
Edit() iterará em todos os nós de uma rede e oferecerá cada nó, um a um, para funções lambda passadas pelo chamador. Essas funções lambda podem então inspecionar o nó e retornar o nó sem modificações ou retornar um novo nó em seu lugar.
Edit() irá iterar sobre nós em ordem não especificada. Se um nó de substituição fizer referência a um nó de rede que, por sua vez, foi substituído, Edit() irá, como etapa final, atualizar todas essas referências para as respetivas substituições (também conhecido como "fazer a coisa certa").
TODO: Exemplo.