Path: blob/master/site/pt-br/tutorials/generative/data_compression.ipynb
25118 views
Copyright 2022 The TensorFlow Compression Authors.
Compactação de dados aprendidos
Visão geral
Este notebook mostra como fazer uma compactação de dados com perda usando redes neurais e o TensorFlow Compression.
A compactação com perda envolve equilibrar a taxa – o número esperado de bits necessários para codificar uma amostra – e a distorção – o erro esperado na reconstrução da amostra.
Os exemplos abaixo usam um modelo tipo autoencoder para compactar imagens do dataset MNIST. O método baseia-se no artigo Compactação de imagens de ponta a ponta.
Confira mais detalhes sobre a compactação de dados aprendidos neste artigo, criado para quem já conhece a compactação de dados clássica, ou nesta pesquisa, para um público de aprendizado de máquina.
Configuração
Instale o TensorFlow Compression pelo pip
.
Importe as dependências de biblioteca.
Definir o modelo do treinador
Como o modelo parece um autoencoder e precisamos realizar um conjunto diferente de funções durante o treinamento e a inferência, a configuração é um pouco diferente de um classificador, por exemplo.
O modelo do treinamento é composto por três partes:
A transformação de análise (ou encoder), convertendo a imagem em um espaço latente.
A transformação de síntese (ou decoder), convertendo o espaço latente de volta no espaço de imagem.
Um modelo de prior e entropia, que modela as probabilidades marginais dos latentes.
Primeiro, defina as transformações:
O treinador armazena uma instância das duas transformações, bem como os parâmetros do prior.
Seu método call
é configurado para computar:
A taxa, uma estimativa do número de bits necessários para representar o lote de dígitos.
A distorção, a diferença absoluta média entre os pixels dos dígitos originais e suas reconstruções.
Computar a taxa e a distorção
Mostraremos o passo a passo, usando uma imagem do conjunto de treinamento. Carregue o dataset MNIST para treinamento e validação:
Extraia uma imagem :
Para obter a representação latente , precisamos convertê-la em float32
, adicionar uma dimensão de lote e passá-la pela transformação de análise.
Os latentes serão quantizados no momento do teste. Para modelar de uma maneira diferenciável durante o treinamento, adicionamos ruído uniforme no intervalo e chamamos o resultado de . Essa é a mesma terminologia usada no artigo Compactação de imagens de ponta a ponta.
O “prior” é uma densidade de probabilidade que treinamos para modelar a distribuição marginal dos latentes com ruído. Por exemplo, poderia ser um conjunto de distribuições logísticas independentes com escalas diferentes para cada dimensão de latente. tfc.NoisyLogistic
leva em consideração que os latentes têm ruído aditivo. À medida que a escala se aproxima de zero, uma distribuição logística se aproxima de um delta de Dirac (pico), mas o ruído adicionado faz a distribuição “com ruído” se aproximar de uma distribuição uniforme.
Durante o treinamento, tfc.ContinuousBatchedEntropyModel
adiciona ruído uniforme e usa o ruído e o prior para computar um limite superior (diferenciável) da taxa (o número médio de bits necessários para codificar a representação latente). Esse limite pode ser minimizado como uma perda.
Por fim, os latentes com ruído são passados de volta pela transformação de síntese para produzir uma reconstrução da imagem . A distorção é o erro entre a imagem original e a reconstrução. Obviamente, com as transformações não treinadas, a reconstrução não é muito útil.
Para cada lote de dígitos, uma chamada a MNISTCompressionTrainer
produz a taxa e a distorção como uma média para esse lote:
Na próxima seção, vamos configurar o modelo para fazer o método do gradiente descendente nessas duas perdas.
Treinar o modelo
Compilamos o treinador de uma forma que ele otimiza a taxa-distorção de Lagrange, ou seja, uma soma da taxa e da distorção, em que um dos termos é ponderado pelo parâmetro de Lagrange .
Essa função de perda afeta partes diferentes do modelo de forma diferente:
A transformação de análise é treinada para produzir uma representação latente que atinge o equilíbrio desejado entre taxa e distorção.
A transformação de síntese é treinada para minimizar a distorção, dada a representação latente.
Os parâmetros do prior são treinados para minimizar a taxa, dada a representação latente. Isso é idêntico a colocar o prior na distribuição marginal de latentes quanto à verossimilhança máxima.
Agora, treine o modelo. Anotações humanas não são necessárias aqui, já que queremos compactar as imagens, então as colocamos em um map
e adicionamos alvos “simulados” para a taxa e a distorção.
Compactar algumas imagens do MNIST
Para a compactação e descompactação no momento do teste, dividimos o modelo treinado em duas partes:
O lado do encoder é composto pela transformação de análise e pelo modelo de entropia.
O lado do decoder é composto pela transformação de síntese e pelo mesmo modelo de entropia.
No momento do teste, os latentes não terão ruído aditivo, mas serão quantizados e depois compactados sem perda, então damos novos nomes a eles. Fazemos uma chamada a eles e à reconstrução da imagem e , respectivamente (conforme o artigo Compactação de imagens de ponta a ponta).
Quando instanciado com compression=True
, o modelo de entropia converte o prior aprendido em tabelas, para um algoritmo de codificação de intervalo. Quando fazemos uma chamada a compress()
, esse algoritmo é chamado para converter o vetor de espaço latente em sequências de bits. O tamanho de cada string binária aproxima o conteúdo de informação do latente (a verossimilhança logarítmica negativa do latente para o prior).
O modelo de entropia para compactação e descompactação deve ser a mesma instância, pois as tabelas de codificação de intervalo precisam ser idênticas nos dois lados. Caso contrário, poderão ocorrer erros de decodificação.
Pegue 16 imagens do dataset de validação. Você pode selecionar um subconjunto diferente alterando o argumento para skip
.
Compacte-as em strings e controle o conteúdo de informação de cada uma delas em bits.
Descompacte as imagens das strings.
Exiba cada um dos 16 dígitos originais junto com sua representação binária compactada e o dígito reconstruído.
O tamanho da string codificada difere do conteúdo de informação de cada dígito.
Isso ocorre porque o processo de codificação de intervalo funciona com probabilidades discretas e uma pequena quantidade de sobrecarga. Portanto, especificamente para strings pequenas, a correspondência é apenas aproximada. Entretanto, a codificação de intervalo é ideal de forma assintótica: no limite, a quantidade esperada de bits se aproximará da entropia cruzada (o conteúdo de informação esperado), em que a taxa no modelo de treinamento é um limite superior.
Equilíbrio entre taxa e distorção
Acima, o modelo foi treinado para um equilíbrio específico (dado lmbda=2000
) entre o número médio de bits usados para representar cada dígito e o erro decorrente na reconstrução.
O que acontece quando repetimos o experimento com valores diferentes?
Vamos começar reduzindo para 500.
A taxa de bits do nosso código cai, assim como a fidelidade dos dígitos. Entretanto, a maioria dos dígitos permanece reconhecível.
Vamos reduzir ainda mais.
As strings começam a ficar muito menores agora, da ordem de um byte por dígito. Entretanto, isso acarreta um custo. Mais dígitos estão ficando irreconhecíveis.
Isso demonstra que esse modelo é agnóstico quanto às percepções humanas de erro; ele apenas mensura o desvio absoluto quando aos valores de pixels. Para conseguir uma qualidade de imagem melhor, teríamos que substituir a perda de pixel por uma perda perceptiva.
Usar o decoder como modelo generativo
Se alimentarmos bits aleatórios no decoder, será feita uma amostragem da distribuição que o modelo aprendeu para representar dígitos.
Primeiro, instancie novamente o compactador/descompactador sem uma verificação que detectaria se a string de entrada não está totalmente decodificada.
Agora, alimente strings aleatórias grandes o suficiente no descompactador para que ele possa decodificar/amostrar dígitos.