Path: blob/master/site/pt-br/tutorials/generative/deepdream.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
DeepDream
Este tutorial contém uma implementação mínima do DeepDream, conforme descrito nesta postagem de blog por Alexander Mordvintsev.
O DeepDream é um experimento que visualiza os padrões aprendidos por uma rede neural. Similar a quando uma criança observa nuvens e tenta interpretar os formatos aleatórios, o DeepDream interpreta e aprimora os padrões que vê em uma imagem.
Para fazer isso, ele encaminha uma imagem pela rede e depois calcula o gradiente da imagem quanto às ativações de uma camada específica. Em seguida, a imagem é modificada para aumentar essas ativações, aprimorando os padrões vistos pela rede, o que resulta em uma imagem parecida com a de um sonho. Esse processo foi chamado de “Inceptionism” (uma referência a InceptionNet e ao filme A Origem, cujo título em inglês é Inception).
Vamos demonstrar como você pode fazer uma rede neural “sonhar” e aprimorar os padrões surreais que ela vê em uma imagem.
Escolha de uma imagem para transformar em uma imagem de sonho
Neste tutorial, vamos usar a imagem de um labrador.
Preparar o modelo de extração de características
Baixe e prepare um modelo de classificação de imagens pré-treinado. Você usará o InceptionV3, similar ao modelo usado originalmente no DeepDream. Qualquer modelo pré-treinado funcionará, embora você precise ajustar os nomes das camadas abaixo, se alterar isto.
A ideia do DeepDream é escolher uma camada (ou camadas) e maximizar a “perda” de forma que a imagem “estimule” cada vez mais as camadas. A complexidade das características incorporadas depende das camadas escolhidas: camadas mais baixas produzem pinceladas ou padrões simples, enquanto camadas profundas proporcionam características sofisticadas nas imagens ou até mesmo objetos inteiros.
A arquitetura do InceptionV3 é bem grande (para ver um grafo da arquitetura do modelo, confira o repositório de pesquisas do TensorFlow). Para o DeepDream, as camadas de interesse são aquelas em que as convoluções estão concatenadas. Há 11 camadas dessas no InceptionV3, chamadas de 'mixed0' a 'mixed10'. O uso de camadas diferentes resultará em imagens diferentes de um sonho. As camadas mais profundas produzem características de alto nível (como olhos e rostos), enquanto as camadas anteriores produzem características mais simples (como contornos, formatos e texturas). Fique à vontade para fazer experimentos com as camadas selecionadas abaixo, mas lembre-se de que camadas mais profundas (aquelas com um índice maior) levam mais tempo para serem treinadas, já que a computação dos gradientes é mais profunda.
Calcular a perda
A perda é a soma das ativações nas camadas escolhidas. A perda é normalizada em cada camada para que a contribuição de camadas maiores não seja superior à de camadas menores. Geralmente, a perda é a quantidade que você deseja minimizar pelo método do gradiente descendente. No DeepDream, você maximizará essa perda pelo método do gradiente ascendente.
Método do gradiente ascendente
Após calcular a perda para as camadas escolhidas, basta calcular os gradientes quanto à imagem e adicioná-los à imagem original.
Ao adicionar os gradientes à imagem, os padrões vistos pela rede são aprimorados. Em cada passo, você terá criado uma imagem que estimula cada vez mais as ativações de determinadas camadas da rede.
O método que faz isso, mostrado abaixo, é encapsulado em uma função tf.function
por questões de desempenho. Ele usa um input_signature
para garantir que não seja feito trace novamente da função para tamanhos de imagem diferentes ou valores de steps
/step_size
diferentes. Confira mais detalhes no guia Funções concretas.
Loop principal
Uso de oitavas
Muito bem, mas essa primeira tentativa tem alguns problemas:
A saída tem ruído (isso pode ser tratado com uma perda
tf.image.total_variation
).A imagem tem resolução baixa.
Os padrões aparecem como se estivessem todos acontecendo com a mesma granularidade.
Uma estratégia que trata todos esses problemas é aplicar o método do gradiente ascendente em diferentes escalas. Isso permitirá que padrões gerados com escalas menores sejam incorporados aos padrões com escalas maiores e preenchidos com detalhes adicionais.
Para fazer isso, você pode usar o método do gradiente ascendente anterior, aumentar o tamanho da imagem (o que é chamado de oitava) e repetir esse processo para diversas oitavas.
Opcional: aumentar a escala com blocos
Um aspecto a se considerar é que, à medida que o tamanho da imagem aumenta, o tempo e a memória necessários para realizar o cálculo de gradientes também aumentam. A implementação de oitava acima não funcionará para imagens muito grandes ou para muitas oitavas.
Para evitar esse problema, você pode dividir a imagem em blocos e computar o gradiente para cada bloco.
A aplicação de mudanças aleatórias à imagem antes da computação de cada bloco evita que apareçam marcas entre os blocos.
Comece implementando a mudança aleatória:
Veja abaixo um equivalente da função deepdream
com blocos definida anteriormente:
Ao juntar tudo, você tem uma implementação do DeepDream escalável e que usa oitavas.
Muito melhor! Faça experimentos com o número de oitavas, a escala das oitavas e as camadas ativadas para mudar a aparência da imagem do DeepDream.
Os leitores também podem se interessar pelo TensorFlow Lucid, que expande as ideias apresentadas neste tutorial para visualizar e interpretar redes neurais.