Пользовательские вложенные слои в keras — как получить выходные значения каждого слоя и задать имя для сводки?

#tensorflow #keras

#tensorflow #keras

Вопрос:

У меня есть пользовательские слои, и я хочу получить выходные данные одного определенного слоя для входных данных. Кроме того, я хочу видеть имена некоторых или всех пользовательских слоев в сводке модели. Но вместо этого он показывает только основной слой, а не все отдельные подслои.

Вот абстрактный пример.

 class EncoderLayer(tf.keras.layers.Layer):
  def __init__(self, d_model, num_heads, dff, rate=0.1):
    super(EncoderLayer, self).__init__()

    self.ffn = point_wise_feed_forward_network(d_model, dff)

    self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
    self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6)

    self.dropout1 = tf.keras.layers.Dropout(rate)
    self.dropout2 = tf.keras.layers.Dropout(rate)

  def call(self, x, training, mask):


    attn_output = self.dropout1(x, training=training)
    out1 = self.layernorm1(x   attn_output)  # (batch_size, input_seq_len, d_model)

    ffn_output = self.ffn(out1)  # (batch_size, input_seq_len, d_model)
    ffn_output = self.dropout2(ffn_output, training=training)
    out2 = self.layernorm2(out1   ffn_output)  # (batch_size, input_seq_len, d_model)

    return out2


class Encoder(tf.keras.layers.Layer):
  def __init__(self,embedding_layer, num_layers, d_model, num_heads, dff, input_vocab_size,
               maximum_position_encoding, rate=0.1):
    super(Encoder, self).__init__()

    self.d_model = d_model
    self.num_layers = num_layers

    self.embedding = tf.keras.layers.Embedding(input_vocab_size, d_model)



    self.enc_layers = [EncoderLayer(d_model, num_heads, dff, rate)
                       for _ in range(num_layers)]

    self.dropout = tf.keras.layers.Dropout(rate)
    
  def call(self, x, training, mask):

    seq_len = tf.shape(x)[1]

    x = self.embedding(x) 

    x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))

    x = self.dropout(self.x_fast, training=training)

    for i in range(self.num_layers):
      x = self.enc_layers[i](x, training, mask)

    return x  # (batch_size, input_seq_len, d_model)




def Model(nb_words=50000,MAX_SEQUENCE_LENGTH=12,d_model=300,act='relu',embedding_matrix=None):


    input_q1 = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
    input_q2 = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')


    Encoder_Layer= Encoder(num_layers=1, d_model=d_model, num_heads=1,
                             dff=64, input_vocab_size=MAX_NB_WORDS,
                             maximum_position_encoding=10000)


    x1 = Encoder_Layer(input_q1, training=False, mask=None)
    x2 = Encoder_Layer(input_q2, training=False, mask=None)


    x = concatenate([x1,x2],1)

    x = GlobalAveragePooling1D()(x)

    merged = Dropout(0.3)(x)
    merged = BatchNormalization()(merged)

    merged = Dense(64, activation=act)(merged)
    merged = Dropout(0.3)(merged)
    x = BatchNormalization()(merged)

    x = Dense(64,activation=act)(x)

    preds = Dense(1,activation='sigmoid')(x)


    model = Model(inputs=[input_q1,input_q2],outputs=preds)
    model.compile(loss='binary_crossentropy',
            optimizer='adam',
            metrics=['accuracy'])
    print(model.summary())

    return model
  

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

 x = self.embedding(x) 
  

Я нашел решение через

 model = build_model() 
# lstm_67 is the second layer.
lstm = K.function([model.layers[0].input], [model.layers[1].output])
lstm_output = lstm([test_x])[0]
  

Но модель.слои и сводка имеют только:

 Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            [(None, 12)]         0
__________________________________________________________________________________________________
input_2 (InputLayer)            [(None, 12)]         0
__________________________________________________________________________________________________
encoder (Encoder)               (None, 12, 300)      580264      input_1[0][0]
                                                                 input_2[0][0]
__________________________________________________________________________________________________
concatenate (Concatenate)       (None, 48, 300)      0           encoder[0][0]
                                                                 encoder[1][0]
                                                                 subtract[0][0]
                                                                 add[0][0]
__________________________________________________________________________________________________
dropout_5 (Dropout)             (None, 48, 300)      0           concatenate[0][0]
__________________________________________________________________________________________________
batch_normalization (BatchNorma (None, 48, 300)      1200        dropout_5[0][0]
__________________________________________________________________________________________________
dense_16 (Dense)                (None, 48, 64)       19264       batch_normalization[0][0]
__________________________________________________________________________________________________
dropout_6 (Dropout)             (None, 48, 64)       0           dense_16[0][0]
__________________________________________________________________________________________________
batch_normalization_1 (BatchNor (None, 48, 64)       256         dropout_6[0][0]
__________________________________________________________________________________________________
dense_17 (Dense)                (None, 48, 64)       4160        batch_normalization_1[0][0]
__________________________________________________________________________________________________
dense_18 (Dense)                (None, 48, 1)        65          dense_17[0][0]
==================================================================================================
Total params: 605,209
Trainable params: 604,481
Non-trainable params: 728
_____________________________
  

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

Таким образом, он показывает только слой кодировщика. Но что, если я хочу, чтобы каждый отдельный слой EncoderLayer-Layer отображался с именем? Кроме того, что, если я действительно хочу, чтобы все подслои были похожи на self.layernorm1 каждого EncoderLayer, который будет показан в модели.слои?

Комментарии:

1. старайтесь использовать не пользовательские слои классов, а простые функции, в которых вы комбинируете слои так, как хотите

2. Я думаю, что речь идет о функции сборки, инициализации и вызова, которую я читал несколько раз назад? Нужна ли мне функция сборки в классе layer? Почему это не отображается? Что мне нужно сделать, чтобы это отображалось, если я хотел бы использовать класс слоев?

3. Эй, извините, что я настаиваю, но как бы вы это сделали, если хотите использовать пользовательские слои?

4. ваш это просто набор существующих слоев… нет необходимости использовать пользовательский класс… используйте функцию

5. Не могли бы вы привести пример? Потому что это пользовательские слои для архитектуры transformer, и было бы неплохо вызвать слой transformer. Пожалуйста, объясните, что мне нужно сделать, потому что для пользовательских слоев вы можете найти много вещей, почему это не показано в сводке.