активационная функция для бинаризованных нейронных сетей

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

Я пытаюсь реализовать бинарную нейронную сеть с использованием keras и tensorflow. Вот мой текущий код:

import tensorflow as tf
from tensorflow import keras
from keras import datasets
from keras.utils.vis_utils import plot_model

from keras.layers import Activation
from keras import backend as K
from keras.utils.generic_utils import get_custom_objects


def sign(x):
    result = K.sign(x)
    return result


get_custom_objects().update({'custom_activation': Activation(sign)})

digit_data = datasets.mnist
(train_images, train_labels), (test_images, test_labels) = digit_data.load_data()

# import matplotlib.pyplot as plt
# plt.imshow(train_images[0])
# print(train_labels[0])
# print(train_images[0])

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(784, Activation(sign, name="SpecialActivation")),
    keras.layers.Dense(10, activation=tf.nn.softmax)
])


# model = keras.Sequential([
#     keras.layers.Flatten(input_shape=(28, 28)),
#     keras.layers.Dense(128, activation=tf.nn.relu),
#     keras.layers.Dense(10, activation=tf.nn.softmax)
# ])

# plot_model(model, to_file="model_plot.png", show_shapes=True, show_layer_names=True)

model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss="sparse_categorical_crossentropy",
              metrics=['accuracy'])

model.fit(train_images, train_labels, epochs=5)
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(test_loss, test_acc)

Активационная функция, которую я сейчас использую, – это функция знака, которая возвращает -1, если x < 0 | 0, если x=0 | 1, если x > 0. Бинарной нейронной сети необходимо иметь функцию побитовой операции, которая возвращает +1, если x >= 0, и -1, если x < 0 (насколько я понимаю).

Я не уверен, как реализовать такой тип активационной функции.

Создайте пользовательскую функцию
Как объяснено в документации Keras для пользовательской активационной функции

Создание пользовательских активаций
Вы также можете использовать вызываемый TensorFlow в качестве активации (в этом случае он должен принимать тензор и возвращать тензор той же формы и типа):
model.add(layers.Dense(64, activation=tf.nn.tanh))

def custom_bin(x):
    return tf.where(x >= 0, 1.0 , -1)
import tensorflow as tf
from tensorflow import keras
model = keras.Sequential()

model.add(keras.layers.Dense( 3, activation="linear",input_shape=(5,)))
model.add(keras.layers.Dense( 3, activation="linear"))
model.add(keras.layers.Dense( 4, activation=custom_bin))
model.add(keras.layers.Dense( 2, activation="linear"))

model.summary()

Игрушечная НС для проверки выходного значения активации

Простая нейронная сеть со всеми весами = 1 и смещением = 0. Поэтому она будет сохранять знак выходного значения таким же, как и входного, т.е. (+Ve, 0, -Ve). Затем примените соответствующую функцию активации в выходном слое. Затем сделайте предсказание, используя 3 варианта использования.

def custom_bin(x):
    return tf.where(x >= 0, 1.0 , -1) 
   
import tensorflow as tf
from tensorflow import keras

#Случай I - tf.math.sign 
initializer = tf.keras.initializers.Ones()
model = keras.Sequential()
model.add(keras.layers.Dense( 2, activation="linear",input_shape=(2,),kernel_initializer=initializer))
model.add(keras.layers.Dense( 1, activation=tf.math.sign,kernel_initializer=initializer))
print(model.predict([[-5,-5],[0,0],[5, 5]]))

#Случай II - пользовательский if-then-else 
initializer = tf.keras.initializers.Ones()
model = keras.Sequential()
model.add(keras.layers.Dense( 2, activation="linear",input_shape=(2,),kernel_initializer=initializer))
model.add(keras.layers.Dense( 1, activation=custom_bin, kernel_initializer=initializer))
print(model.predict([[-5,-5],[0,0],[5, 5]]))

Выходные данные
[[-1.] [ 0.] [ 1.]]
[[-1.] [ 1.] [ 1.]]

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

Активационная функция для бинаризованных нейронных сетей

Ваша задача по реализации бинаризованной нейронной сети (BNN) с использованием Keras и TensorFlow является интересной и актуальной. Как вы правильно заметили, активационная функция играет ключевую роль в успешной инициализации и работе такой сети. Ниже я опишу, как правильным образом можно настроить активационную функцию для вашей модели.

Понимание бинаризации

Бинаризованные нейронные сети работают с ограниченным числом значений для состояний нейронов. Основная идея заключается в том, чтобы вместо стандартных значений (обычно в диапазоне от -∞ до +∞) использовать всего два состояния: +1 и -1. Это позволяет существенно снизить требования к ресурсам для хранения и вычисления, специфичным для нейронных сетей.

Реализация активационной функции

Ваша входная активационная функция sign, основанная на K.sign(), имеет недостаток в том, что возвращает вектор нулей для нулевых значений. Вместо этого мы можем адаптировать ее, чтобы возвращать значения +1 для положительных входов и -1 для отрицательных, а в случае нуля можно либо игнорировать, либо обрабатывать по-другому.

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

import tensorflow as tf
from keras import backend as K

def custom_bin(x):
    return tf.where(x >= 0, 1.0, -1.0)

Этот подход использует функцию tf.where(), которая позволяет эффективно векторизовать операцию по каждому элементу тенсовра, возвращая +1 для всех элементов, которые больше или равны нулю, и -1 для остальных.

Обновление вашей модели

Теперь можно применить эту активационную функцию в вашей существующей модели. Измените создание модели следующим образом:

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(784, activation=custom_bin, name="BinarizedActivation"),
    keras.layers.Dense(10, activation='softmax')
])

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

Тестирование модели

После внесения изменений в определение модели вы можете протестировать её на загруженных данных MNIST. Не забудьте обновить ваши параметры компиляции и проверки:

model.compile(optimizer=tf.keras.optimizers.Adam(),
              loss="sparse_categorical_crossentropy",
              metrics=['accuracy'])

model.fit(train_images, train_labels, epochs=5)
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(test_loss, test_acc)

Заключение

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

Если у вас возникнут дополнительные вопросы или потребуется дальнейшая помощь, пожалуйста, не стесняйтесь обращаться!

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

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