Расширяем возможности Keras с помощью кастомных слоев

от автора

Привет, Хабр!

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

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

Создание кастомных слоев

Каждый кастомный слой начинается с определения нового класса, наследующего от tf.keras.layers.Layer. В __init__ происходит инициализация слоя, где можно задать параметры, необходимые для работы слоя:

import tensorflow as tf  class CustomLayer(tf.keras.layers.Layer):     def __init__(self, units=32, activation=None, **kwargs):         super(CustomLayer, self).__init__(**kwargs)         self.units = units         self.activation = tf.keras.activations.get(activation)

Тут units определяет количество нейронов, а activation указывает функцию активации. super(CustomLayer, self).__init__(**kwargs) вызывает конструктор базового класса Layer.

Метод build вызывается Keras при первом использовании слоя. Его юзают для создания параметров слоя, которые зависят от размера входных данных:

    def build(self, input_shape):         self.kernel = self.add_weight(shape=(input_shape[-1], self.units),                                       initializer='glorot_uniform',                                       trainable=True)         self.bias = self.add_weight(shape=(self.units,),                                     initializer='zeros',                                     trainable=True)         super(CustomLayer, self).build(input_shape)

В методе создаются веса kernel и bias. Функция add_weight создает и регистрирует переменные слоя, которые будут обновляться во время тренировки.

Метод call содержит основную логику вычислений слоя. Он принимает входные данные и возвращает выходные:

    def call(self, inputs):         output = tf.matmul(inputs, self.kernel) + self.bias         if self.activation is not None:             output = self.activation(output)         return output

В этом методе выполняется умножение входных данных на веса и добавление смещения. Если определена функция активации, она применяется к выходным данным.

После определения кастомного слоя его можно использовать в моделях Keras как обычный слой:

model = tf.keras.Sequential([     tf.keras.layers.Input(shape=(8,)),     CustomLayer(units=64, activation='relu'),     tf.keras.layers.Dense(10, activation='softmax') ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')

Другие полезные методы:

  • add_weight: Добавляет переменную веса в слой.

  • compute_output_shape: Возвращает форму выходных данных на основе формы входных.

  • get_config: Возвращает конфигурацию слоя в виде словаря, что полезно для сериализации.

Примеры реализации: Dense, Convolutional и еще три типа других слоев

Dense слой выполняет простую линейную операцию: умножение входного вектора на матрицу весов и добавление смещения, а затем применяется функция активации:

import tensorflow as tf  class CustomDenseLayer(tf.keras.layers.Layer):     def __init__(self, units=32, activation=None):         super(CustomDenseLayer, self).__init__()         self.units = units         self.activation = tf.keras.activations.get(activation)      def build(self, input_shape):         self.w = self.add_weight(shape=(input_shape[-1], self.units),                                  initializer='glorot_uniform',                                  trainable=True)         self.b = self.add_weight(shape=(self.units,),                                  initializer='zeros',                                  trainable=True)      def call(self, inputs):         z = tf.matmul(inputs, self.w) + self.b         if self.activation is not None:             return self.activation(z)         return z  # example model = tf.keras.Sequential([     tf.keras.layers.Input(shape=(8,)),     CustomDenseLayer(units=64, activation='relu'),     tf.keras.layers.Dense(10, activation='softmax') ])

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

class CustomConvLayer(tf.keras.layers.Layer):     def __init__(self, filters, kernel_size, strides=(1, 1), padding='valid', activation=None):         super(CustomConvLayer, self).__init__()         self.filters = filters         self.kernel_size = kernel_size         self.strides = strides         self.padding = padding         self.activation = tf.keras.activations.get(activation)      def build(self, input_shape):         self.kernel = self.add_weight(shape=(*self.kernel_size, input_shape[-1], self.filters),                                       initializer='glorot_uniform',                                       trainable=True)      def call(self, inputs):         conv = tf.nn.conv2d(inputs, self.kernel, strides=self.strides, padding=self.padding.upper())         if self.activation is not None:             return self.activation(conv)         return conv  # example model = tf.keras.Sequential([     tf.keras.layers.Input(shape=(28, 28, 1)),     CustomConvLayer(filters=32, kernel_size=(3, 3), activation='relu'),     tf.keras.layers.Flatten(),     tf.keras.layers.Dense(10, activation='softmax') ])

Recurrent слои используются для обработки последовательных данных. Один из наиболее распространнных типов рекуррентных слоев — это LSTM:

class CustomLSTMLayer(tf.keras.layers.Layer):     def __init__(self, units):         super(CustomLSTMLayer, self).__init__()         self.units = units      def build(self, input_shape):         self.lstm_cell = tf.keras.layers.LSTMCell(self.units)      def call(self, inputs, states):         return self.lstm_cell(inputs, states)  # example model = tf.keras.Sequential([     tf.keras.layers.Input(shape=(None, 8)),     tf.keras.layers.RNN(CustomLSTMLayer(units=64)),     tf.keras.layers.Dense(10, activation='softmax') ])

Dropout слой используется для регуляризации модели, предотвращая переобучение путем случайного зануления некоторых нейронов во время тренировки:

class CustomDropoutLayer(tf.keras.layers.Layer):     def __init__(self, rate):         super(CustomDropoutLayer, self).__init__()         self.rate = rate      def call(self, inputs, training=None):         return tf.nn.dropout(inputs, rate=self.rate) if training else inputs  # example model = tf.keras.Sequential([     tf.keras.layers.Input(shape=(8,)),     tf.keras.layers.Dense(64, activation='relu'),     CustomDropoutLayer(rate=0.5),     tf.keras.layers.Dense(10, activation='softmax') ])

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

class CustomBatchNormalizationLayer(tf.keras.layers.Layer):     def __init__(self):         super(CustomBatchNormalizationLayer, self).__init__()      def build(self, input_shape):         self.gamma = self.add_weight(shape=(input_shape[-1],),                                      initializer='ones',                                      trainable=True)         self.beta = self.add_weight(shape=(input_shape[-1],),                                     initializer='zeros',                                     trainable=True)         self.moving_mean = self.add_weight(shape=(input_shape[-1],),                                            initializer='zeros',                                            trainable=False)         self.moving_variance = self.add_weight(shape=(input_shape[-1],),                                                initializer='ones',                                                trainable=False)      def call(self, inputs, training=None):         if training:             mean, variance = tf.nn.moments(inputs, axes=[0])             self.moving_mean.assign(self.moving_mean * 0.9 + mean * 0.1)             self.moving_variance.assign(self.moving_variance * 0.9 + variance * 0.1)         else:             mean, variance = self.moving_mean, self.moving_variance          return tf.nn.batch_normalization(inputs, mean, variance, self.beta, self.gamma, variance_epsilon=1e-3)  # example model = tf.keras.Sequential([     tf.keras.layers.Input(shape=(8,)),     CustomBatchNormalizationLayer(),     tf.keras.layers.Dense(64, activation='relu'),     tf.keras.layers.Dense(10, activation='softmax') ])

Больше практических инструментов и кейсов коллеги из OTUS рассматривают в рамках практических онлайн-курсов. Напомню, что с полным каталогом курсов можно ознакомиться по ссылке.


ссылка на оригинал статьи https://habr.com/ru/articles/818791/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *