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

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

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

Существует несколько вариантов квантования после обучения. Вот сводная таблица вариантов и преимуществ, которые они обеспечивают:

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

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

варианты оптимизации после тренировки

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

Квантование динамического диапазона является рекомендуемой отправной точкой, поскольку оно обеспечивает меньшее использование памяти и более быстрые вычисления без необходимости предоставления репрезентативного набора данных для калибровки. Этот тип квантования статически квантует только веса от плавающей запятой до целого числа во время преобразования, что обеспечивает 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-битными весами и активациями. Эта оптимизация обеспечивает задержки, близкие к полностью выводам с фиксированной точкой. Однако выходные данные по-прежнему сохраняются с использованием операций с плавающей запятой, поэтому увеличение скорости операций с динамическим диапазоном меньше, чем полное вычисление с фиксированной точкой.

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

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

Для полного целочисленного квантования необходимо откалибровать или оценить диапазон, т. е. (минимум, максимум) всех тензоров с плавающей запятой в модели. В отличие от постоянных тензоров, таких как веса и смещения, переменные тензоры, такие как входные данные модели, активации (выходные данные промежуточных слоев) и выходные данные модели, не могут быть откалиброваны, если мы не запустим несколько циклов вывода. В результате преобразователю требуется репрезентативный набор данных для их калибровки. Этот набор данных может быть небольшим подмножеством (около 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)]
 

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

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

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

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

Создание только целочисленных моделей — распространенный вариант использования TensorFlow Lite для микроконтроллеров и 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()

Квантование с плавающей запятой 16

Вы можете уменьшить размер модели с плавающей запятой, квантуя веса до 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()

Преимущества квантования с плавающей точкой16 заключаются в следующем:

  • Это уменьшает размер модели до половины (поскольку все веса становятся вдвое меньше их исходного размера).
  • Это вызывает минимальную потерю точности.
  • Он поддерживает некоторые делегаты (например, делегат графического процессора), которые могут работать непосредственно с данными с плавающей запятой 16, что приводит к более быстрому выполнению, чем вычисления с плавающей точкой 32.

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

  • Это не уменьшает задержку так сильно, как квантование до математики с фиксированной точкой.
  • По умолчанию квантованная модель с плавающей запятой16 "деквантует" значения весов до значения с плавающей запятой32 при запуске на ЦП. (Обратите внимание, что делегат GPU не будет выполнять это деквантование, поскольку он может работать с данными типа 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 не поддерживается для некоторых операторов в модели, то модель по-прежнему может быть квантована, но неподдерживаемые операторы остаются в резерве. Чтобы разрешить это, необходимо добавить следующую опцию в 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 с аппаратным ускорением.

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

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

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

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

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

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

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

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

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

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

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