Search
Write a publication
Pull to refresh
498.83
OTUS
Развиваем технологии, обучая их создателей

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

Level of difficultyEasy
Reading time5 min
Views2K

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

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 рассматривают в рамках практических онлайн-курсов. Напомню, что с полным каталогом курсов можно ознакомиться по ссылке.

Tags:
Hubs:
Total votes 10: ↑7 and ↓3+7
Comments1

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS