Ter uma questão? Conecte-se com a comunidade no Fórum TensorFlow Visite o Fórum

Quantização pós-treinamento

A quantização pós-treinamento é uma técnica de conversão que pode reduzir o tamanho do modelo e, ao mesmo tempo, melhorar a latência da CPU e do acelerador de hardware, com pouca degradação na precisão do modelo. Você pode quantizar um modelo flutuante do TensorFlow já treinado ao convertê-lo para o formato TensorFlow Lite usando o TensorFlow Lite Converter .

Métodos de Otimização

Existem várias opções de quantização pós-treinamento para escolher. Aqui está uma tabela de resumo das opções e os benefícios que elas oferecem:

Técnica Benefícios Hardware
Quantização de faixa dinâmica 4x menor, aumento 2x-3x CPU
Quantização inteira completa 4x menor, 3x + aceleração CPU, Edge TPU, microcontroladores
Quantização Float16 2x menor, aceleração de GPU CPU, GPU

A seguinte árvore de decisão pode ajudar a determinar qual método de quantização pós-treinamento é o melhor para o seu caso de uso:

opções de otimização pós-treinamento

Quantização de faixa dinâmica

A forma mais simples de quantização pós-treinamento quantiza estaticamente apenas os pesos do ponto flutuante ao inteiro, que tem 8 bits de precisão:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

Na inferência, os pesos são convertidos de 8 bits de precisão para ponto flutuante e calculados usando kernels de ponto flutuante. Essa conversão é feita uma vez e armazenada em cache para reduzir a latência.

Para melhorar ainda mais a latência, os operadores de "faixa dinâmica" quantizam dinamicamente as ativações com base em sua faixa de 8 bits e realizam cálculos com pesos e ativações de 8 bits. Essa otimização fornece latências próximas à inferência de ponto fixo totalmente. No entanto, as saídas ainda são armazenadas usando ponto flutuante, de modo que a aceleração com operações de faixa dinâmica seja menor do que um cálculo de ponto fixo completo.

Quantização inteira completa

Você pode obter mais melhorias de latência, reduções no uso de memória de pico e compatibilidade com dispositivos de hardware ou aceleradores somente inteiros, certificando-se de que toda a matemática do modelo seja quantizada por inteiro.

Para a quantização inteira completa, você precisa calibrar ou estimar a faixa, ou seja, (min, max) de todos os tensores de ponto flutuante no modelo. Ao contrário dos tensores constantes, como pesos e vieses, tensores variáveis, como entrada do modelo, ativações (saídas de camadas intermediárias) e saída do modelo, não podem ser calibrados a menos que executemos alguns ciclos de inferência. Como resultado, o conversor requer um conjunto de dados representativo para calibrá-los. Este conjunto de dados pode ser um pequeno subconjunto (cerca de ~ 100-500 amostras) dos dados de treinamento ou validação. Consulte a função representative_dataset() abaixo.

def representative_dataset():
  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
    yield [tf.dtypes.cast(data, tf.float32)]

Para fins de teste, você pode usar um conjunto de dados fictício da seguinte maneira:

def representative_dataset():
    for _ in range(100):
      data = np.random.rand(1, 244, 244, 3)
      yield [data.astype(np.float32)]
 

Inteiro com float fallback (usando a entrada / saída padrão do float)

Para quantizar totalmente o número inteiro de um modelo, mas usar operadores flutuantes quando eles não tiverem uma implementação de número inteiro (para garantir que a conversão ocorra sem problemas), use as seguintes etapas:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
tflite_quant_model = converter.convert()

Inteiro apenas

A criação de modelos somente inteiros é um caso de uso comum para TensorFlow Lite para Microcontroladores e TPUs Coral Edge .

Além disso, para garantir a compatibilidade com dispositivos apenas de número inteiro (como microcontroladores de 8 bits) e aceleradores (como o Coral Edge TPU), você pode aplicar a quantização inteira de número inteiro para todas as operações, incluindo a entrada e a saída, usando as seguintes etapas:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8
tflite_quant_model = converter.convert()

Quantização Float16

Você pode reduzir o tamanho de um modelo de ponto flutuante quantizando os pesos para float16, o padrão IEEE para números de ponto flutuante de 16 bits. Para habilitar a quantização float16 de pesos, use as seguintes etapas:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()

As vantagens da quantização float16 são as seguintes:

  • Ele reduz o tamanho do modelo pela metade (uma vez que todas as gramaturas tornam-se metade do tamanho original).
  • Isso causa uma perda mínima de precisão.
  • Ele suporta alguns delegados (por exemplo, o delegado GPU) que podem operar diretamente em dados float16, resultando em uma execução mais rápida do que cálculos float32.

As desvantagens da quantização float16 são as seguintes:

  • Não reduz a latência tanto quanto uma quantização para matemática de ponto fixo.
  • Por padrão, um modelo quantizado float16 irá "desquantizar" os valores dos pesos para float32 quando executado na CPU. (Observe que o delegado da GPU não realizará essa desquantização, pois pode operar em dados float16.)

Apenas inteiro: ativações de 16 bits com pesos de 8 bits (experimental)

Este é um esquema de quantização experimental. É semelhante ao esquema "somente inteiro", mas as ativações são quantizadas com base em sua faixa de 16 bits, os pesos são quantizados em inteiros de 8 bits e a polarização é quantizada em inteiros de 64 bits. Isso é conhecido como quantização 16x8 adicional.

A principal vantagem dessa quantização é que ela pode melhorar significativamente a precisão, mas apenas aumentar ligeiramente o tamanho do modelo.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]
tflite_quant_model = converter.convert()

Se a quantização 16x8 não for suportada por alguns operadores no modelo, então o modelo ainda pode ser quantizado, mas os operadores sem suporte mantidos em flutuação. A seguinte opção deve ser adicionada ao target_spec para permitir isso.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
tf.lite.OpsSet.TFLITE_BUILTINS]
tflite_quant_model = converter.convert()

Exemplos de casos de uso em que as melhorias de precisão fornecidas por este esquema de quantização incluem: * super-resolução, * processamento de sinal de áudio, como cancelamento de ruído e formação de feixe, * redução de ruído de imagem, * reconstrução HDR de uma única imagem.

A desvantagem dessa quantização é:

  • Atualmente a inferência é visivelmente mais lenta do que o inteiro completo de 8 bits devido à falta de implementação otimizada do kernel.
  • Atualmente, é incompatível com os delegados TFLite acelerados por hardware existentes.

Um tutorial para este modo de quantização pode ser encontrado aqui .

Precisão do modelo

Como os pesos são quantizados após o treinamento, pode haver uma perda de precisão, especialmente para redes menores. Modelos totalmente quantizados pré-treinados são fornecidos para redes específicas no repositório de modelos do TensorFlow Lite . É importante verificar a precisão do modelo quantizado para verificar se qualquer degradação na precisão está dentro dos limites aceitáveis. Existem ferramentas para avaliar a precisão do modelo TensorFlow Lite .

Alternativamente, se a queda da precisão for muito alta, considere o uso de treinamento ciente de quantização . No entanto, fazer isso requer modificações durante o treinamento do modelo para adicionar nós de quantização falsos, enquanto as técnicas de quantização pós-treinamento nesta página usam um modelo pré-treinado existente.

Representação para tensores quantizados

A quantização de 8 bits aproxima os valores de ponto flutuante usando a seguinte fórmula.

$$real\_value = (int8\_value - zero\_point) \times scale$$

A representação tem duas partes principais:

  • Pesos por eixo (também conhecidos por canal) ou por tensor representados por int8 valores de complemento de dois no intervalo [-127, 127] com ponto zero igual a 0.

  • Ativações / entradas por tensor representadas por int8 valores de complemento de dois no intervalo [-128, 127], com um ponto zero no intervalo [-128, 127].

Para uma visão detalhada de nosso esquema de quantização, consulte nossas especificações de quantização . Os fornecedores de hardware que desejam se conectar à interface delegada do TensorFlow Lite são incentivados a implementar o esquema de quantização aqui descrito.