Se você usou keras para criar redes neurais, sem dúvida está familiarizado com o API seqüencialque representa modelos como uma pilha linear de camadas. O API funcional Fornece opções adicionais: Usando camadas de entrada separadas, você pode combinar a entrada de texto com dados tabulares. Usando várias saídas, você pode executar regressão e classificação ao mesmo tempo. Além disso, você pode reutilizar camadas dentro e entre modelos.
Com a execução ansiosa do TensorFlow, você ganha ainda mais flexibilidade. Usando modelos personalizadosvocê outline o passe para a frente completamente advert libitum. Isso significa que muitas arquiteturas ficam muito mais fáceis de implementar, incluindo os aplicativos mencionados acima: redes adversárias generativas, transferência de estilo neural, várias formas de modelos de sequência para sequência. Além disso, como você tem acesso direto a valores, não tensores, o desenvolvimento de modelos e a depuração são bastante acelerados.
Como funciona?
Na execução ansiosa, as operações não são compiladas em um gráfico, mas definidas diretamente no seu código R. Eles retornam valores, não alças simbólicas para nós em um gráfico computacional – significando, você não precisa acessar um tensorflow session
para avaliá -los.
tf.Tensor(
(( 50 114)
( 60 140)), form=(2, 2), dtype=int32)
Execução ansiosa, por mais recente, já é suportada nos lançamentos atuais de cran de keras
e tensorflow
. O Guia de execução ansiosa descreve o fluxo de trabalho em detalhes.
Aqui está um esboço rápido: você outline um modeloum otimizador e uma função de perda. Os dados são transmitidos through tfdatasetsincluindo qualquer pré -processamento, como redimensionamento da imagem. Em seguida, o treinamento de modelos é apenas um loop sobre as épocas, oferecendo complete liberdade sobre quando (e se) executar alguma ação.
Como funciona a retropagação nessa configuração? O passe para a frente é registrado por um GradientTape
e, durante o passe para trás, calculamos explicitamente os gradientes da perda em relação aos pesos do modelo. Esses pesos são então ajustados pelo otimizador.
with(tf$GradientTape() %as% tape, {
# run mannequin on present batch
preds <- mannequin(x)
# compute the loss
loss <- mse_loss(y, preds, x)
})
# get gradients of loss w.r.t. mannequin weights
gradients <- tape$gradient(loss, mannequin$variables)
# replace mannequin weights
optimizer$apply_gradients(
purrr::transpose(record(gradients, mannequin$variables)),
global_step = tf$practice$get_or_create_global_step()
)
Veja o Guia de execução ansiosa Para um exemplo completo. Aqui, queremos responder à pergunta: Por que estamos tão empolgados com isso? Pelo menos três coisas vêm à mente:
- As coisas que costumavam ser complicadas se tornam muito mais fáceis de realizar.
- Os modelos são mais fáceis de desenvolver e mais fáceis de depurar.
- Há uma correspondência muito melhor entre nossos modelos mentais e o código que escrevemos.
Ilustraremos esses pontos usando um conjunto de estudos de caso de execução ansiosos que apareceram recentemente neste weblog.
Coisas complicadas facilitadas
Um bom exemplo de arquiteturas que se tornam muito mais fáceis de definir com a execução ansiosa são os modelos de atenção. A atenção é um ingrediente importante dos modelos de sequência a sequência, por exemplo (mas não apenas) na tradução da máquina.
Ao usar LSTMs na codificação e nos lados decodificadores, o decodificador, sendo uma camada recorrente, conhece a sequência que ela gerou até agora. Ele também (em todos os modelos, exceto os mais simples), tem acesso à sequência de entrada completa. Mas onde na sequência de entrada está a informação necessária para gerar o próximo token de saída? É essa questão de que a atenção se destina a abordar.
Agora considere implementar isso no código. Cada vez que é chamado para produzir um novo token, o decodificador precisa obter a entrada atual do mecanismo de atenção. Isso significa que não podemos simplesmente apertar uma camada de atenção entre o codificador e o decodificador LSTM. Antes do advento da execução ansiosa, uma solução teria sido implementar isso no código Tensorflow de baixo nível. Com execução ansiosa e modelos personalizados, podemos simplesmente Use Keras.
A atenção não é apenas relevante para problemas de sequência para sequência. Em Legenda da imagema saída é uma sequência, enquanto a entrada é uma imagem completa. Ao gerar uma legenda, a atenção é usada para se concentrar em partes da imagem relevantes para diferentes etapas de tempo no processo de geração de texto.
Inspeção fácil
Em termos de depuração, apenas o uso de modelos personalizados (sem execução ansiosa) já simplifica as coisas. Se tivermos um modelo personalizado como simple_dot
Do recente incorporação submit e não sabem saber se temos as formas corretas, podemos simplesmente adicionar declarações de registro, assim:
operate(x, masks = NULL) {
customers <- x(, 1)
motion pictures <- x(, 2)
user_embedding <- self$user_embedding(customers)
cat(dim(user_embedding), "n")
movie_embedding <- self$movie_embedding(motion pictures)
cat(dim(movie_embedding), "n")
dot <- self$dot(record(user_embedding, movie_embedding))
cat(dim(dot), "n")
dot
}
Com a execução ansiosa, as coisas ficam ainda melhores: podemos imprimir os próprios valores dos tensores.
Mas a conveniência não termina aí. No ciclo de treinamento que mostramos acima, podemos obter perdas, pesos de modelo e gradientes apenas imprimindo -os. Por exemplo, adicione uma linha após a chamada para tape$gradient
Para imprimir os gradientes para todas as camadas como uma lista.
gradients <- tape$gradient(loss, mannequin$variables)
print(gradients)
Combinando o modelo psychological
Se você leu Aprendizado profundo com rvocê sabe que é possível programar fluxos de trabalho menos diretos, como os necessários para o treinamento de Gans ou fazer transferência de estilo neural, usando a API funcional do Keras. No entanto, o código do gráfico não facilita o controle de onde você está no fluxo de trabalho.
Agora examine o exemplo do gerando dígitos com Gans publicar. Gerador e discriminador são configurados como atores em um drama:
<- operate(identify = NULL) {
generator keras_model_custom(identify = identify, operate(self) {
# ...
}}
<- operate(identify = NULL) {
discriminator keras_model_custom(identify = identify, operate(self) {
# ...
}}
Ambos são informados sobre suas respectivas funções de perda e otimizadores.
Então, o duelo começa. O loop de treinamento é apenas uma sucessão de ações geradoras, ações discriminadoras e retropropagação através dos dois modelos. Não há necessidade de se preocupar com pesos congelantes/descongelados nos lugares apropriados.
with(tf$GradientTape() %as% gen_tape, { with(tf$GradientTape() %as% disc_tape, {
# generator motion
<- generator(# ...
generated_images
# discriminator assessments
<- discriminator(# ...
disc_real_output <- discriminator(# ...
disc_generated_output
# generator loss
<- generator_loss(# ...
gen_loss # discriminator loss
<- discriminator_loss(# ...
disc_loss
})})
# calcucate generator gradients
<- gen_tape$gradient(#...
gradients_of_generator
# calcucate discriminator gradients
<- disc_tape$gradient(# ...
gradients_of_discriminator
# apply generator gradients to mannequin weights
$apply_gradients(# ...
generator_optimizer
# apply discriminator gradients to mannequin weights
$apply_gradients(# ... discriminator_optimizer
O código acaba tão perto de como imaginamos mentalmente a situação de que quase nenhuma memorização é necessária para ter em mente o design geral.
Da mesma forma, essa maneira de programar se presta a uma extensa modularização. Isso é ilustrado pelo Segundo submit em Gans Isso inclui a rede U, como as etapas de amostragem e upsampling.
Aqui, as camadas de downsampling e upsampling são fatoradas em seus próprios modelos
<- operate(# ...
downsample keras_model_custom(identify = NULL, operate(self) { # ...
de modo que eles possam ser compostos de maneira razoável no método de chamada do gerador:
# mannequin fields
$down1 <- downsample(# ...
self$down2 <- downsample(# ...
self# ...
# ...
# name technique
operate(x, masks = NULL, coaching = TRUE) {
<- x %>% self$down1(coaching = coaching)
x1 <- self$down2(x1, coaching = coaching)
x2 # ...
# ...
Embrulhando
A execução ansiosa ainda é uma característica muito recente e em desenvolvimento. Estamos convencidos de que muitos casos de uso interessantes ainda aparecerão, pois esse paradigma é adotado mais amplamente entre os profissionais de aprendizagem profunda.
No entanto, agora já temos uma lista de casos de uso que ilustram as vastas opções, ganhos em usabilidade, modularização e elegância oferecidos pelo Código de Execução A ansiosa.
Para referência rápida, estes capa:
Tradução da máquina neural com atenção. Este submit fornece uma introdução detalhada à execução ansiosa e seus blocos de construção, bem como uma explicação aprofundada do mecanismo de atenção utilizado. Juntamente com o próximo, ele ocupa um papel muito especial nesta lista: ele usa execução ansiosa para resolver um problema que, de outra forma, só poderia ser resolvido com código de baixo nível difícil de ler e difícil de ler.
Legenda da imagem com atenção. Esta postagem se baseia no primeiro, pois não reexplica a atenção em detalhes; No entanto, ele porta o conceito para a atenção espacial aplicada sobre as regiões da imagem.
Gerando dígitos com redes adversárias generativas convolucionais (DCGANS). Esta postagem é apresentada usando dois modelos personalizados, cada um com suas funções de perda e otimizadores associados, e fazê-los passar por adiante e retropacagação em sincronia. Talvez seja o exemplo mais impressionante de como a execução ansiosa simplifica a codificação por melhor alinhamento ao nosso modelo psychological da situação.
Tradução de imagem para imagem com Pix2pix é outra aplicação de redes adversárias generativas, mas usa uma arquitetura mais complexa com base na redução de downsampling e upsampling do tipo U-Internet. Ele demonstra muito bem como a execução ansiosa permite a codificação modular, tornando o programa last muito mais legível.
Transferência de estilo neural. Finalmente, este pós -reformula o problema de transferência de estilo de maneira ansiosa, resultando novamente em código conciso e legível.
Ao mergulhar nessas aplicações, é uma boa ideia se referir também ao Guia de execução ansiosa Então você não perde de vista a floresta para as árvores.
Estamos empolgados com os casos de uso que nossos leitores apresentarão!