Keras – метод add_weight() не добавляет к общему количеству параметров модели

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

Я создаю пользовательский уровень Keras FConv2D() и добавляю вес в его функции build() с помощью метода add_weight(), как предложено в официальном руководстве Keras по созданию пользовательских уровней.

def build(self, input_shape):
      shape = tf.TensorShape(input_shape).as_list()
      h = shape[1]
      w = shape[2]
      in_channels = shape[3]
      self.kernel = self.add_weight(
            shape=(h,w,in_channels,self.num_outputs),
            initializer="random_normal",
            trainable=True,
        )
      super(FConv2D, self).build(input_shape)

Но когда я печатаю сводку однослойной модели, содержащей только этот уровень, количество параметров в этом уровне оказывается равным 0.

Model: "model_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         [(None, 7, 7, 2)]         0         
_________________________________________________________________
f_conv2d_4 (FConv2D)         (None, 7, 7, 64)          0         
=================================================================
Total params: 0
Trainable params: 0
Non-trainable params: 0

Я пробовал тот же метод в руководстве по пользовательским уровням на официальном сайте, но их метод add_weight, похоже, работает правильно –

class SimpleDense(tf.keras.layers.Layer):

  def __init__(self, units=32):
      super(SimpleDense, self).__init__()
      self.units = units

  def build(self, input_shape):  # Создает состояние уровня (веса)
    self.w = self.add_weight(shape=(input_shape[-1], self.units),
                               initializer="random_normal",
                               trainable=True)
    self.b = self.add_weight(shape=(self.units,),
                               initializer="random_normal",
                               trainable=True)

  def call(self, inputs):  # Определяет вычисление от входов к выходам
      return tf.matmul(inputs, self.w) + self.b

input = tf.keras.layers.Input(shape = (1000,1))
output = SimpleDense(100)(input)
model = tf.keras.Model(inputs = [input], outputs = [output])
model.summary()

Model: "model_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         [(None, 1000, 1)]         0         
_________________________________________________________________
simple_dense_3 (SimpleDense) (None, 1000, 100)         200       
=================================================================
Total params: 200
Trainable params: 200
Non-trainable params: 0

Может ли кто-нибудь сказать, почему веса, добавленные в пользовательском уровне, не отображаются в параметрах модели?

Я столкнулся с такой же проблемой, причиной которой может быть то, что вы использовали def __call__ в своем пользовательском уровне. Как это сделано в официальном образце, попробуйте использовать def call вместо этого.

Столкнулся с такой же проблемой. Как упомянуто в документации по созданию пользовательских уровней, метод build используется для ленивой инициализации весов и вызывается только во время первого вызова метода call. Инициализация весов в методе __init__() исправила проблему.

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

Проблема, с которой вы столкнулись, связана с тем, как Keras обрабатывает добавление весов в пользовательских слоях. При использовании метода add_weight() в методе build() вес будет инициализирован только при первом вызове метода call(). Таким образом, если метод call() не вызывается, Keras не знает о существовании весов, и, соответственно, они не отображаются в сводке модели.

Для решения вашей проблемы, убедитесь, что:

  1. Вы вызываете метод call() — При создании модели обязательно используйте ваш пользовательский слой в вычислениях, чтобы Keras вызвал метод call() и инициализировал параметры. Например:

    input = tf.keras.layers.Input(shape=(7, 7, 2))  # Учтите, что входная форма правильная
    output = FConv2D(num_outputs=64)(input)  # Здесь вызывается метод call, что инициализирует веса
    model = tf.keras.Model(inputs=[input], outputs=[output])
    model.summary()
  2. Почему ваш слой может не иметь весов: Если вы используете метод __call__() вместо call(), это также может привести к проблемам. Keras ожидает, что ваш пользовательский слой будет иметь метод call(). Убедитесь, что вы используете именно call() для определения вычислений, а не __call__().

  3. Правильная инициализация весов: Метод build() служит для ленивой инициализации весов. Таким образом, если вы вызываете свой слой 1 раз, и он не создает весов из-за пропуска вызова call(), вы не получите параметров. Убедитесь, что ваши функции определения параметров правильно связаны с методом, который создаёт их.

В вашем случае проверьте, правильно ли вы определили call() и используется ли он в модели. Если же build() не вызывается, это также может означать, что вы не используете слой должным образом.

Вот пример правильной реализации вашего пользовательского слоя:

import tensorflow as tf

class FConv2D(tf.keras.layers.Layer):
    def __init__(self, num_outputs=64):
        super(FConv2D, self).__init__()
        self.num_outputs = num_outputs

    def build(self, input_shape):
        h = input_shape[1]
        w = input_shape[2]
        in_channels = input_shape[3]
        self.kernel = self.add_weight(
            shape=(h, w, in_channels, self.num_outputs),
            initializer="random_normal",
            trainable=True,
        )
        super(FConv2D, self).build(input_shape)

    def call(self, inputs):
        # Здесь необходимо указать логику использования весов
        return tf.nn.conv2d(inputs, self.kernel, strides=[1, 1, 1, 1], padding='SAME')  # Пример операции

# Создание модели
input = tf.keras.layers.Input(shape=(7, 7, 2))
output = FConv2D(num_outputs=64)(input)
model = tf.keras.Model(inputs=[input], outputs=[output])
model.summary()

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

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

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