Вопрос или проблема
В 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). Мы обсудим, как реализовать этот процесс так, чтобы бинизированные веса использовались только во время прямого прохода, а реальные веса — для градиентного спуска.
Основные этапы бинизации весов
-
Перевод весов в бинарный формат: В начале каждой пакетной итерации необходимо преобразовать реальные веса в бинарные. Для этого можно использовать функцию создания бинарных весов, основанную на простом пороге или стохастическом методе.
-
Использование бинарных весов в прямом проходе: Бинизированные веса должны использоваться для вычисления активаций нейронов во время прямого прохода.
-
Реальные веса для обратного прохода: Во время обратного прохода используются реальные (!) веса для вычисления градиентов.
-
Обновление весов: Обновление должно производиться только над реальными весами, в то время как бинарные останутся неизменными до следующей пакетной итерации.
Реализация в 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)
Объяснение кода
-
Создание пользовательского слоя: В примере создается
BinaryDense
, который расширяет функциональность слоя Keras. Мы сохраняем реальные значения весов и вычисляем бинарные веса с помощью функцииK.sign
. -
Вызов метода
call
: В этом методе вместо реальных весов используются их бинарные представления для расчета выхода слоя. -
Обновление градиентов: В Keras веса обновляются автоматически при выполнении метода
fit
, основанном на обратном распространении ошибки, используя реальные значение весов.
Заключение
Предложенный подход позволяет осуществить квантование весов в Keras, соблюдая принципы бинизации. Планируя реализацию, важно помнить, что бинарные веса не меняются в процессе одного пакета, что снижает накладные расходы при обучении. Результаты, достигнутые с помощью бинаризации, могут значительно улучшить производительность нейросетей как в плане быстродействия, так и в плане использования памяти.