Поделитесь весами для блока слоев в керасе

В этом другом вопросе было показано, что можно повторно использовать плотный слой на разных входных слоях, чтобы обеспечить разделение веса. Теперь мне интересно, как распространить этот принцип на целый блок слоев; моя попытка заключается в следующем:

from keras.layers import Input, Dense, BatchNormalization, PReLU
from keras.initializers import Constant
from keras import backend as K

def embedding_block(dim):
    dense = Dense(dim, activation=None, kernel_initializer='glorot_normal')
    activ = PReLU(alpha_initializer=Constant(value=0.25))(dense)
    bnorm = BatchNormalization()(activ)
    return bnorm
def embedding_stack():
    return embedding_block(32)(embedding_block(16)(embedding_block(8)))
                                                                           
common_embedding = embedding_stack()

Здесь я создаю «встраиваемые блоки» с одним плотным слоем переменной размерности, которые я пытаюсь объединить в «встраиваемый стек», состоящий из блоков с увеличивающимся размером. Затем я хотел бы применить это «общее вложение» к нескольким входным слоям (все они имеют одинаковую форму), чтобы веса были общими.

Приведенный выше код не работает с

<ipython-input-33-835f06ed7bbb> in embedding_block(dim)
      1 def embedding_block(dim):
      2     dense = Dense(dim, activation=None, kernel_initializer='glorot_normal')
----> 3     activ = PReLU(alpha_initializer=Constant(value=0.25))(dense)
      4     bnorm = BatchNormalization()(activ)
      5     return bnorm

/localenv/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, *args, **kwargs)
    980       with ops.name_scope_v2(name_scope):
    981         if not self.built:
--> 982           self._maybe_build(inputs)
    983 
    984         with ops.enable_auto_cast_variables(self._compute_dtype_object):

/localenv/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py in _maybe_build(self, inputs)
   2641         # operations.
   2642         with tf_utils.maybe_init_scope(self):
-> 2643           self.build(input_shapes)  # pylint:disable=not-callable
   2644       # We must set also ensure that the layer is marked as built, and the build
   2645       # shape is stored since user defined build functions may not be calling

/localenv/lib/python3.8/site-packages/tensorflow/python/keras/utils/tf_utils.py in wrapper(instance, input_shape)
    321     if input_shape is not None:
    322       input_shape = convert_shapes(input_shape, to_tuples=True)
--> 323     output_shape = fn(instance, input_shape)
    324     # Return shapes from `fn` as TensorShapes.
    325     if output_shape is not None:

/localenv/lib/python3.8/site-packages/tensorflow/python/keras/layers/advanced_activations.py in build(self, input_shape)
    138   @tf_utils.shape_type_conversion
    139   def build(self, input_shape):
--> 140     param_shape = list(input_shape[1:])
    141     if self.shared_axes is not None:
    142       for i in self.shared_axes:

TypeError: 'NoneType' object is not subscriptable

Каков правильный способ сделать это? Спасибо!

Вы можете расширить tf.keras.Layer и определить «подслои» внутри. Затем определите переменную общих весов в вашем расширенном слое и замените веса ваших «подслоев».

Sebastian R. 10.12.2020 12:39

Вы хотите построить общий блок и использовать его на разных этапах вашей модели, вызывая его с разными параметрами (например, kernel_size, stride, padding и т. д.)?

Innat 10.12.2020 13:03

Привет @SebastianR. ах, я надеялся сделать это без переопределения чего-либо... :/

Demosthene 10.12.2020 13:32

Привет @M.Innat, функция embedding_stack() здесь только для удобства - я хочу определить один такой стек для модели и передать ему разные входные слои, чтобы веса были общими. Затем я могу собрать вывод из внедрения каждого ввода, объединить их и что-то с этим сделать. Но сам стек встраивания обучается на всех входных данных вместе с одним набором весов. Имеет ли это смысл?

Demosthene 10.12.2020 13:35

Я думаю, что не понимаю его полностью. Тем не менее, не могли бы вы добавить диаграмму того, что вы хотите? Это было бы намного понятнее. И вы можете проверить этот блог, я написал его несколько дней назад. Пожалуйста, посмотрите на строительный блок небольшой начальной модели, это то, что вам нужно?

Innat 10.12.2020 13:52

@M.Innat хорошо, вот пример: я хочу, чтобы общий блок BatchNorm(PReLU(Dense(8)(input))) применялся к двум головкам ввода одинакового размера=4. Затем я могу объединить два выходных тензора с размерностью 8 каждый и передать их остальной части сети (например, слою Dense(16)). Это легко сделать, если я определяю две такие последовательности BatchNorm(PReLU(Dense(8)(input))), по одной для каждого входа (в основном это просто объединение двух отдельных моделей). Что я хочу сделать, так это распределить веса между этими двумя ветвями. Это яснее?

Demosthene 10.12.2020 14:03
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
6
441
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам необходимо отделить создание экземпляров слоев от создания модели.

Вот простой метод с использованием цикла for:

from tensorflow.keras import layers, initializers, Model

def embedding_block(dim):
    dense = layers.Dense(dim, activation=None, kernel_initializer='glorot_normal')
    activ = layers.PReLU(alpha_initializer=initializers.Constant(value=0.25))
    bnorm = layers.BatchNormalization()
    return [dense, activ, bnorm]

stack = embedding_block(8) + embedding_block(16) + embedding_block(32)

inp1 = layers.Input((5,))
inp2 = layers.Input((5,))

x,y = inp1,inp2
for layer in stack:
    x = layer(x)
    y = layer(y)

concat_layer = layers.Concatenate()([x,y])
pred = layers.Dense(1, activation = "sigmoid")(concat_layer)

model = Model(inputs = [inp1, inp2], outputs=pred)

Сначала мы создаем каждый слой, а затем итерируем их, используя функциональный API для создания модели.

Вы можете проанализировать сеть в netron, чтобы убедиться, что веса действительно разделены:

Спасибо! именно то, что мне было нужно :) а про нетрон я и не знал, он реально крут!

Demosthene 10.12.2020 14:22

Другие вопросы по теме