Преобразование вектора из float в int

Вопрос или проблема

У меня есть вектор с типом данных float, в основном float32. Нулевое значение является базовой линией, то есть средним/центром данных.

Он имеет форму (размер_пакета, длина_последовательности).

Я хочу уменьшить использование памяти, преобразовав их в пространство int8 при сохранении в файл. Как я могу сделать это в NumPy?

Это то же самое, что и проблема масштабирования мин-макс?

Квантизация float32 в int8 теряет много информации; если вы сделаете очевидное движение, масштабируя числа с плавающей запятой в диапазон [-128,127], то потеряете слишком много точности. Вам также нужно будет иметь способ хранения информации о обратной трансформации, чтобы корректно прочитать это обратно.

Смотрите https://huggingface.co/docs/optimum/en/concept_guides/quantization#quantization-to-int8 для обсуждения данной проблемы.

Если вы работаете в контексте LLM или подобного, то для правильной квантизации модели до fp8 уже будет поддержка библиотек.

Вместо этого рассмотрите:

  • Просто сохранить как np.float16, чтобы сэкономить место и немного потерять точность; очень просто
  • Сохранить с сжатием
  • Рассмотрите возможность предварительного разреживания тензора. Если вы можете сильно разжать, то существуют разреженные представления, которые более эффективны. Если нет, то установка некоторых значений, близких к 0, в 0, где это не будет иметь большого значения, может сэкономить место при сжатии.

Ответ или решение

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

1. Понимание проблемы

Ваш вектор содержит данные типа float32, и имеет форму (batch_size, seq_len). Поскольку вы хотите сжать данные до int8, важно отметить, что данный подход может привести к потере значительной информации. Преобразование float32 в int8 требует выбора правильного метода масштабирования, чтобы избежать чрезмерной потери данных и сохранить возможность дальнейшей интерпретации преобразованных значений.

2. Масштабирование

Традиционно процесс, который вы связываете с преобразованием данных, напоминает масштабирование min-max, где значения данных сопоставляются диапазону, соответствующему целевому формату (в вашем случае, [-128, 127] для int8). Однако, как верно подметили, просто перенастройка значений в этот диапазон будет слишком грубой, поскольку это приведет к потере точности.

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

Вычисление параметров масштабирования

  1. Нормализация данных: Вычислите минимальное и максимальное значение вашего вектора.
  2. Скалирование: Примените формулу для преобразования данных:
    [
    x’ = \left(\frac{x – \text{min}}{\text{max} – \text{min}}\right) \cdot 255 – 128
    ]
    Это обеспечит, что все ваши значения будут отмасштабированы в диапазон [-128, 127].

3. Сохранение информации о трансформации

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

4. Альтернативные подходы

Варианты работы с памятью в вашем случае могут включать:

  • Использование np.float16 вместо int8: Это уменьшает использование памяти, сохраняя в то же время большую часть информации.
  • Сжатие: Сохраните данные в сжатом формате. Такие библиотеки как numpy поддерживают сохранение массивов с помощью сжатия.
  • Сжимаемые представления: Рассмотрите возможность разреженного представления данных, если в вашем векторе много нулевых или близких к нулю значений.

5. Пример реализации в NumPy

Пример реализация преобразования будет выглядеть следующим образом:

import numpy as np

# Исходный массив
data = np.random.rand(batch_size, seq_len).astype(np.float32)  # Пример данных

# Вычисление минимального и максимального значения
data_min, data_max = data.min(), data.max()

# Преобразование в int8
data_scaled = ((data - data_min) / (data_max - data_min) * 255).astype(np.int8)

# Сохранение данных
np.save('data_int8.npy', data_scaled)

# Сохранение информации о трансформации
np.save('scaling_info.npy', np.array([data_min, data_max]))

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...