Квантование после обучения

Квантование после обучения — это метод преобразования, позволяющий уменьшить размер модели, одновременно снижая задержку процессора и аппаратного ускорителя, практически не снижая точности модели. Вы можете квантовать уже обученную модель TensorFlow с плавающей точкой, конвертируя её в формат LiteRT с помощью конвертера LiteRT .

Методы оптимизации

Существует несколько вариантов квантования после обучения. Ниже представлена ​​сводная таблица вариантов и их преимуществ:

Техника Преимущества Аппаратное обеспечение
Квантование динамического диапазона В 4 раза меньше, в 2-3 раза быстрее Процессор
Полное целочисленное квантование В 4 раза меньше, в 3 раза быстрее ЦП, Edge TPU, микроконтроллеры
Квантование Float16 В 2 раза меньше, ускорение на GPU Центральный процессор, графический процессор

Следующее дерево решений поможет определить, какой метод квантования после обучения лучше всего подходит для вашего варианта использования:

варианты оптимизации после обучения

Нет квантования

Рекомендуется начать с преобразования в модель TFLite без квантования. Это позволит создать модель TFLite с плавающей точкой.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
tflite_quant_model = converter.convert()

Мы рекомендуем сделать это в качестве начального шага для проверки совместимости операторов исходной модели TF с TFLite и возможности использования их в качестве основы для отладки ошибок квантования, внесённых последующими методами квантования после обучения. Например, если квантованная модель TFLite даёт неожиданные результаты, а модель TFLite с плавающей точкой точна, мы можем сузить проблему до ошибок, внесённых квантованной версией операторов TFLite.

Квантование динамического диапазона

Квантование с динамическим диапазоном обеспечивает сокращение использования памяти и ускорение вычислений без необходимости предоставления репрезентативного набора данных для калибровки. Этот тип квантования статически квантует только весовые коэффициенты из числа с плавающей запятой в целое число во время преобразования, что обеспечивает точность 8 бит:

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()

Для дальнейшего снижения задержки во время вывода операторы «динамического диапазона» динамически квантуют активации на основе их диапазона до 8 бит и выполняют вычисления с 8-битными весами и активациями. Эта оптимизация обеспечивает задержки, близкие к полностью фиксированным вычислениям. Однако выходные данные по-прежнему хранятся в формате с плавающей точкой, поэтому увеличение скорости операций динамического диапазона меньше, чем при вычислениях с полной фиксированной точкой.

Полное целочисленное квантование

Вы можете добиться дальнейшего снижения задержек, снижения пикового использования памяти и совместимости с аппаратными устройствами или ускорителями, работающими только с целыми числами, убедившись, что все математические вычисления модели квантованы целыми числами.

Для полного целочисленного квантования необходимо откалибровать или оценить диапазон (min, max) всех тензоров с плавающей точкой в ​​модели. В отличие от постоянных тензоров, таких как веса и смещения, переменные тензоры, такие как входные данные модели, активации (выходные данные промежуточных слоёв) и выходные данные модели, невозможно откалибровать без выполнения нескольких циклов вывода. Поэтому для калибровки преобразователю требуется репрезентативный набор данных. Этот набор данных может представлять собой небольшое подмножество (около 100–500 выборок) обучающих или проверочных данных. См. функцию representative_dataset() ниже.

Начиная с версии TensorFlow 2.7 вы можете указать репрезентативный набор данных с помощью подписи , как в следующем примере:

def representative_dataset():
  for data in dataset:
    yield {
      "image": data.image,
      "bias": data.bias,
    }

Если в данной модели TensorFlow имеется более одной сигнатуры, вы можете указать множественный набор данных, указав ключи сигнатуры:

def representative_dataset():
  # Feed data set for the "encode" signature.
  for data in encode_signature_dataset:
    yield (
      "encode", {
        "image": data.image,
        "bias": data.bias,
      }
    )

  # Feed data set for the "decode" signature.
  for data in decode_signature_dataset:
    yield (
      "decode", {
        "image": data.image,
        "hint": data.hint,
      },
    )

Вы можете создать репрезентативный набор данных, предоставив входной список тензоров:

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

Начиная с версии TensorFlow 2.7 мы рекомендуем использовать подход на основе сигнатур вместо подхода на основе списка входных тензоров, поскольку порядок входных тензоров можно легко изменить.

Для тестирования можно использовать фиктивный набор данных следующим образом:

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

Целое число с откатом в формат float (используется ввод/вывод float по умолчанию)

Чтобы полностью квантовать модель целыми числами, но использовать операторы с плавающей точкой, когда у них нет целочисленной реализации (чтобы гарантировать гладкость преобразования), выполните следующие шаги:

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()

Только целые числа

Создание моделей, содержащих только целые числа, является распространенным вариантом использования LiteRT для микроконтроллеров и TPU Coral Edge .

Кроме того, чтобы обеспечить совместимость с устройствами, работающими только с целыми числами (например, 8-битными микроконтроллерами), и ускорителями (например, Coral Edge TPU), можно принудительно применить полное целочисленное квантование для всех операций, включая ввод и вывод, выполнив следующие шаги:

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()

Квантование Float16

Вы можете уменьшить размер модели с плавающей точкой, квантовав весовые коэффициенты до float16, стандарта IEEE для 16-битных чисел с плавающей точкой. Чтобы включить квантование весовых коэффициентов до float16, выполните следующие действия:

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()

Преимущества квантования float16 следующие:

  • Уменьшает размер модели до половины (поскольку все грузики становятся вдвое меньше своего первоначального размера).
  • Это приводит к минимальной потере точности.
  • Он поддерживает некоторые делегаты (например, делегат GPU), которые могут работать напрямую с данными float16, что приводит к более быстрому выполнению по сравнению с вычислениями float32.

Недостатки квантования float16 следующие:

  • Это не уменьшает задержку так сильно, как квантование в арифметике с фиксированной точкой.
  • По умолчанию квантованная модель float16 при запуске на ЦП «деквантует» значения весов до float32. (Обратите внимание, что делегат графического процессора не будет выполнять эту деквантизацию, поскольку он может работать с данными float16.)

Только целые числа: 16-битные активации с 8-битными весами (экспериментально)

Это экспериментальная схема квантования. Она похожа на схему «только целые числа», но активации квантуются на основе их диапазона до 16 бит, веса квантуются в 8-битном целом числе, а смещение — в 64-битном целом числе. Далее это называется квантованием 16x8.

Главное преимущество такого квантования состоит в том, что оно может значительно повысить точность, но при этом лишь незначительно увеличить размер модели.

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()

Если для некоторых операторов модели квантование 16x8 не поддерживается, то модель всё равно может быть квантована, но неподдерживаемые операторы будут сохранены в формате float. Для этого необходимо добавить следующий параметр в target_spec.

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()

Примеры случаев использования, в которых данная схема квантования обеспечивает повышение точности, включают:

  • супер-разрешение,
  • обработка аудиосигнала, такая как шумоподавление и формирование луча,
  • подавление шума на изображении,
  • HDR-реконструкция из одного изображения.

Недостатком такого квантования является:

  • В настоящее время вывод происходит заметно медленнее, чем 8-битное полное целое число из-за отсутствия оптимизированной реализации ядра.
  • В настоящее время он несовместим с существующими делегатами TFLite с аппаратным ускорением.

Учебное пособие по этому режиму квантования можно найти здесь .

Точность модели

Поскольку веса квантуются после обучения, возможна потеря точности, особенно для небольших сетей. Предварительно обученные полностью квантованные модели для конкретных сетей доступны на сайте Kaggle Models . Важно проверить точность квантованной модели, чтобы убедиться, что любое её снижение находится в приемлемых пределах. Существуют инструменты для оценки точности модели LiteRT .

В качестве альтернативы, если падение точности слишком велико, рассмотрите возможность использования обучения с учётом квантования . Однако это потребует внесения изменений в процесс обучения модели для добавления фиктивных узлов квантования, тогда как методы квантования после обучения, представленные на этой странице, используют существующую предварительно обученную модель.

Представление квантованных тензоров

8-битное квантование аппроксимирует значения с плавающей запятой с помощью следующей формулы.

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

Представление состоит из двух основных частей:

  • Веса по каждой оси (или по каналу) или по тензору, представленные значениями int8 в дополнительном коде в диапазоне [-127, 127] с нулевой точкой, равной 0.

  • Активации/входы для каждого тензора представлены значениями int8 в дополнительном коде в диапазоне [-128, 127] с нулевой точкой в ​​диапазоне [-128, 127].

Подробную информацию о нашей схеме квантования см. в нашей спецификации квантования . Поставщикам оборудования, желающим подключиться к интерфейсу делегата TensorFlow Lite, рекомендуется реализовать описанную там схему квантования.