Как квантизировать веса в прямом проходе во время обучения в Keras?

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

В Keras я хотел бы обучить сеть с бинарными весами подобно Кубарьяу, и др., но не могу понять, где должна происходить квантизация (бинаризация) в коде.

Ключевым аспектом метода обучения является следующее:

  • В начале каждой партии в процессе обучения сохраненные вещественные (например, int32) веса конвертируются в бинарные значения (либо округлением, либо случайным/вероятностным способом) и хранятся отдельно от вещественных весов.
  • Бинарные веса используются при прямом проходе для вычисления активаций.
  • Вещественные веса используются при обратном проходе для вычисления градиентов.
  • Обновления весов применяются к вещественным весам, а не к бинарным.
  • Бинарные веса не изменяются до следующей партии, в это время они пересчитываются путем бинаризации недавно обновленных вещественных весов.

Если я делаю бинаризацию в Layer.call(), я полагаю, что это произойдет для каждого прямого прохода (для каждого образца), но это должно происходить только один раз за партию.

Если я делаю бинаризацию в Callback.on_batch_begin(), я не думаю, что смогу указать использование бинарных весов для прямого прохода и вещественных весов для вычисления градиентов.

Есть ли какие-либо предложения? К сожалению, мои знания Python не глубоки, поэтому мне довольно сложно понять поток кода.

** Обратите внимание, что когда я говорю о бинарных значениях, я не имею в виду 1-битные (например, 8 бинарных значений, помещенных в int8). Бинарные веса все еще могут представляться как int32, float32 и т.д.

Бинаризация может быть невозможна в Keras. В TensorFlow это можно сделать с помощью tensorflow.clip_by_value(x, 0.0, 1.0).

Сайт Papers With Code имеет много реализаций статьи о Бинаризованных Нейронных Сетях.

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

Как квантовать веса во время прямого прохода в процессе обучения в Keras

Введение

Квантование весов, а именно их бинизация, — это интересный подход к снижению объемов памяти и улучшению вычислительной эффективности нейросетей. Следующее руководство объяснит, как правильно квантовать веса в Keras, учитывая особенности, описанные в работе Coubariaux et al. (2016). Мы обсудим, как реализовать этот процесс так, чтобы бинизированные веса использовались только во время прямого прохода, а реальные веса — для градиентного спуска.

Основные этапы бинизации весов

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

  2. Использование бинарных весов в прямом проходе: Бинизированные веса должны использоваться для вычисления активаций нейронов во время прямого прохода.

  3. Реальные веса для обратного прохода: Во время обратного прохода используются реальные (!) веса для вычисления градиентов.

  4. Обновление весов: Обновление должно производиться только над реальными весами, в то время как бинарные останутся неизменными до следующей пакетной итерации.

Реализация в Keras

Для реализации описанного поведения, можно воспользоваться пользовательским слоем в Keras. Ниже приведён пример кода, которое иллюстрирует это:

import keras.backend as K
from keras.layers import Layer
import numpy as np

class BinaryDense(Layer):
    def __init__(self, units=32, **kwargs):
        self.units = units
        super(BinaryDense, self).__init__(**kwargs)

    def build(self, input_shape):
        # Создаем переменные для весов
        self.w = self.add_weight(name='kernel', 
                                  shape=(input_shape[-1], self.units),
                                  initializer='random_normal',
                                  trainable=True)
        super(BinaryDense, self).build(input_shape)

    def call(self, inputs):
        # Для 저장ения бинарных весов между проходами
        binary_weights = K.sign(self.w)
        return K.dot(inputs, binary_weights)

    def compute_output_shape(self, input_shape):
        return (input_shape[0], self.units)

# Использование BinaryDense в модели
from keras.models import Sequential

model = Sequential([
    BinaryDense(32, input_shape=(784,)),
    # Добавьте другие слои по мере необходимости
])

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# Обучение модели
model.fit(X_train, y_train, epochs=10, batch_size=32)

Объяснение кода

  1. Создание пользовательского слоя: В примере создается BinaryDense, который расширяет функциональность слоя Keras. Мы сохраняем реальные значения весов и вычисляем бинарные веса с помощью функции K.sign.

  2. Вызов метода call: В этом методе вместо реальных весов используются их бинарные представления для расчета выхода слоя.

  3. Обновление градиентов: В Keras веса обновляются автоматически при выполнении метода fit, основанном на обратном распространении ошибки, используя реальные значение весов.

Заключение

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

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

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