Path: blob/master/site/pt-br/tutorials/optimization/compression.ipynb
25118 views
Copyright 2022 The TensorFlow Compression Authors.
Compressão de modelo escalável
Visão geral
Este notebook mostra como fazer a compressão de um modelo usando o TensorFlow Compression.
No exemplo abaixo, comprimimos os pesos de um classificador MNIST para um tamanho muito menor do que a representação de ponto flutuante dele, ainda retendo a exatidão da classificação. Isso é feito em um processo de duas etapas, baseado no artigo Scalable Model Compression by Entropy Penalized Reparameterization (Compressão de modelo escalável pela reparametrização de entropia penalizada):
Treinando um modelo "compressível" com uma penalidade entrópica explícita durante o treinamento, o que incentiva a compressibilidade dos parâmetros do modelo. O peso dessa penalidade, , permite o controle contínuo do trade-off entre o tamanho do modelo comprimido e a exatidão dele.
Codificando o modelo compressível em um modelo comprimido usando um esquema de codificação compatível com a penalidade, o que significa que a penalidade é um bom indicador do tamanho do modelo. Isso garante que o método não exija várias iterações de treinamento, compressão e retreinamento do modelo para ajuste.
Esse método é estritamente relacionado ao tamanho do modelo comprimido, e não à complexidade computacional. Ele pode ser combinado com uma técnica como o pruning de modelos para reduzir o tamanho e a complexibilidade.
Exemplo de resultados da compressão em vários modelos:
Modelo (dataset) | Tamanho do modelo | Razão de comp. | Erro top-1 de comp. (não comp.) |
---|---|---|---|
LeNet300-100 (MNIST) | 8,56 KB | 124x | 1,9% (1,6%) |
LeNet5-Caffe (MNIST) | 2,84 KB | 606x | 1,0% (0,7%) |
VGG-16 (CIFAR-10) | 101 KB | 590x | 10,0% (6,6%) |
ResNet-20-4 (CIFAR-10) | 128 KB | 134x | 8,8% (5,0%) |
ResNet-18 (ImageNet) | 1,97 MB | 24x | 30,0% (30,0%) |
ResNet-50 (ImageNet) | 5,49 MB | 19x | 26,0% (25,0%) |
As aplicações incluem:
Implantar/transmitir modelos para dispositivos de borda em grande escala, economizando largura de banda no trânsito.
Comunicar o estado de modelo global aos clientes no aprendizado federado. A arquitetura do modelo (número de unidades ocultas etc.) não muda em relação ao modelo inicial, e os clientes podem continuar aprendendo com o modelo descomprimido.
Realizar a inferência em clientes de memória extremamente limitada. Durante a inferência, os pesos de cada camada podem ser descomprimidos em sequência e descartados logo após as ativações serem computadas.
Configuração
Instale o Tensorflow Compression pelo pip
.
Importe as dependências de biblioteca.
Defina e treine um classificador MNIST básico
Para comprimir camadas convolucionais e densas de maneira eficaz, precisamos definir classes de camadas personalizadas. Elas são análogas às camadas em tf.keras.layers
, mas vamos dividi-las depois em subclasses para implementar com eficácia a Reparametrização de Entropia Penalizada (EPR). Para esse fim, também adicionamos um construtor de cópia.
Primeiro, definimos uma camada densa padrão:
E, de maneira similar, uma camada convolucional 2D:
Antes de continuar com a compressão do modelo, vamos conferir se podemos treinar um classificador regular.
Defina a arquitetura do modelo:
Carregue os dados de treinamento:
Por fim, treine o modelo:
Sucesso! O modelo foi treinado e alcançou uma exatidão de mais de 98% no dataset de validação em 5 épocas.
Treine um classificador compressível
A Reparametrização de Entropia Penalizada (EPR) tem dois ingredientes principais:
Aplicar uma penalidade aos pesos do modelo durante o treinamento que corresponde à entropia deles em um modelo probabilístico, que é compatível com o esquema de codificação dos pesos. Abaixo, definimos um
Regularizer
do Keras que implementa essa penalidade.Reparametrizar os pesos, ou seja, trazê-los para uma representação latente mais compressível (gera um melhor trade-off entre a compressibilidade e o desempenho do modelo). Para kernels convolucionais, mostrou-se que o domínio Fourier é uma boa representação. Para outros parâmetros, o exemplo abaixo simplesmente usa a quantização escalar (arredondamento) com um tamanho de passo de quantização variável.
Primeiro, defina a penalidade.
O exemplo abaixo usa um modelo probabilístico/código implementado na classe tfc.PowerLawEntropyModel
, inspirado no artigo Optimizing the Communication-Accuracy Trade-off in Federated Learning with Rate-Distortion Theory (Otimizando o trade-off entre comunicação e exatidão no aprendizado federado com a teoria taxa-distorção). A penalidade é definida como: em que é um elemento do parâmetro do modelo ou a representação latente dele, e é uma pequena constante para a estabilidade numérica em torno de valores 0.
A penalidade é efetivamente uma perda de regularização (às vezes chamada de "perda de peso"). O fato de ser côncava com uma cúspide no zero incentiva a dispersão de peso. O esquema de codificação aplicado para a compressão dos pesos, um código Elias gamma, produz códigos de comprimento de bits para a magnitude do elemento. Ou seja, é compatível com a penalidade, e a aplicação da penalidade minimiza o comprimento de código esperado.
Segundo, defina subclasses de CustomDense
e CustomConv2D
, que têm a seguinte funcionalidade adicional:
Elas pegam uma instância do regularizer acima e a aplicam aos kernels e biases durante o treinamento.
Elas definem o kernel e bias como uma
@property
, que realiza a quantização com gradientes diretos quando as variáveis são acessadas. Isso reflete exatamente a computação realizada mais tarde no modelo comprimido.Elas definem variáveis
log_step
adicionais, que representam o logaritmo do tamanho do passo de quantização. Quanto mais espessa a quantização, menor será o tamanho do modelo e também a exatidão. Os tamanhos do passo de quantização são treináveis para cada parâmetro do modelo, então a otimização na função de perda penalizada determinará o melhor tamanho.
O passo de quantização é definido da seguinte maneira:
Com isso, podemos definir a camada densa:
A camada convolucional é análoga. Além disso, o kernel de convolução é armazenado como a transformada discreta de Fourier de valor real (RDFT) quando o kernel é definido, e a transformada é invertida sempre que o kernel é usado. Como os componentes de frequência diferente do kernel tendem a ser mais ou menos compressíveis, cada um recebe seu próprio tamanho de passo de quantização.
Defina a transformada de Fourier e o inverso dela da seguinte maneira:
Com isso, defina a camada convolucional como:
Defina um modelo classificador com a mesma arquitetura que acima, mas usando estas camadas modificadas:
E treine o modelo:
O modelo compressível alcançou uma exatidão semelhante ao classificador básico.
No entanto, o modelo ainda não foi comprimido. Para fazer isso, precisamos definir outro conjunto de subclasses que armazenam os kernels e biases na forma comprimida — como uma sequência de bits.
Comprima o classificador
As subclasses de CustomDense
e CustomConv2D
definidas abaixo convertem os pesos de uma camada densa compressível em strings binárias. Além disso, elas armazenam o logaritmo do tamanho de passo da quantização com metade da exatidão para poupar espaço. Quando o kernel ou bias é acessado pela @property
, eles são descomprimidos da representação da string e desquantizados.
Primeiro, defina as funções para comprimir e descomprimir um parâmetro de modelo:
Com elas, podemos definir CompressedDense
:
A classe de camada convolucional é análoga à acima.
Para transformar o modelo compressível em comprimido, podemos usar de maneira conveniente a função clone_model
. compress_layer
converte qualquer camada compressível em uma comprimida e simplesmente passa por qualquer outro tipo de camada (como Flatten
, etc.).
Agora, vamos validar se o modelo comprimido ainda tem o desempenho esperado:
A exatidão da classificação do modelo comprimido é idêntica à alcançada durante o treinamento!
Além disso, o tamanho dos pesos do modelo comprimido é bem menor do que o tamanho do modelo original:
O armazenamento de modelos no disco exige um pouco de sobrecarga para armazenar a arquitetura do modelo, os grafos de função, etc.
Métodos de compressão sem perda como o ZIP são bons para comprimir esse tipo de dados, mas não os próprios pesos. Por isso, a EPR ainda tem um benefício significativo ao contar o tamanho do modelo incluindo essa sobrecarga, após aplicar a compressão de ZIP:
Efeito de regularização e trade-off entre tamanho e exatidão
Acima, o hiperparâmetro foi definido como 2 (normalizado pelo número de parâmetros no modelo). Conforme aumentamos o , os pesos do modelo são penalizados cada vez mais pela compressibilidade.
Para valores baixos, a penalidade pode agir como um regularizer de peso. Na verdade, ela tem um efeito benéfico no desempenho de generalização do classificador e pode levar a uma exatidão ligeiramente mais alta no dataset de validação:
Para valores mais altos, vemos um tamanho de modelo cada vez menor, mas também uma exatidão que diminui gradualmente. Para ver isso, vamos treinar alguns modelos e plotar o tamanho em comparação com a exatidão:
O ideal é que o plot mostre um trade-off entre o tamanho e a exatidão em formato de cotovelo, mas é normal que as métricas de exatidão tenham algum ruído. Dependendo da inicialização, a curva pode exibir algumas falhas.
Devido ao efeito de regularização, o modelo comprimido de EPR tem maior exatidão no dataset de teste que o modelo original para valores pequenos de . O modelo comprimido de EPR também é diversas vezes menor, mesmo se compararmos os tamanhos após compressão de ZIP adicional.
Descomprima o classificador
CompressedDense
e CompressedConv2D
descomprimem seus pesos a cada passo para frente. Isso faz com que sejam ideais para dispositivos com memória limitada, mas a descompressão pode ser computacionalmente cara, especialmente para tamanhos de lotes pequenos.
Para descomprimir o modelo uma vez e usá-lo para treinamento ou inferência adicional, podemos convertê-lo de volta para um modelo usando camadas regulares ou compressíveis. Isso pode ser útil na implantação de modelos ou em casos de aprendizado federado.
Primeiro, ao converter de volta para um modelo básico, podemos realizar a inferência e/ou continuar com o treinamento regular sem uma penalidade de compressão:
Observe que a exatidão da validação cai após o treinamento para uma época adicional, já que o treinamento é feito sem regularização.
Como alternativa, podemos converter o modelo de volta para o "compressível", para inferência e/ou treinamento adicional com uma penalidade de compressão:
Aqui, a exatidão melhora após o treinamento para uma época adicional.