Как создать слой взвешенной суммы с обучаемым весом и определенным количеством входных данных?

#python #tensorflow #keras

Вопрос:

Я пытаюсь создать слой взвешенной суммы, который выполняет взвешенную сумму из нескольких параллельных слоев, аналогичную той, что опубликована здесь, за исключением того, что я хочу иметь возможность определять количество входных слоев (т. Е. Количество весов n, где n определяется как создание экземпляра), и я хочу использовать нормализованные веса. Однако я получаю эту ошибку:

 Traceback (most recent call last):
  File "multi_fidelity_training_full_link.py", line 341, in <module>
    main()
  File "multi_fidelity_training_full_link.py", line 283, in main
    linked_model.fit(x,y,batch_size = batch_size, epochs = mult_of*(1 i), verbose = 2, initial_epoch = mult_of*i)
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/keras/engine/training.py", line 1183, in fit
    tmp_logs = self.train_function(iterator)
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py", line 889, in __call__
    result = self._call(*args, **kwds)
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/def_function.py", line 950, in _call
    return self._stateless_fn(*args, **kwds)
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/function.py", line 3024, in __call__
    filtered_flat_args, captured_inputs=graph_function.captured_inputs)  # pylint: disable=protected-access
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/function.py", line 1961, in _call_flat
    ctx, args, cancellation_manager=cancellation_manager))
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/function.py", line 596, in call
    ctx=ctx)
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/execute.py", line 75, in quick_execute
    raise e
  File "/usr/WS2/mvander/py3venv/py3venv/lib/python3.7/site-packages/tensorflow/python/eager/execute.py", line 60, in quick_execute
    inputs, attrs, num_outputs)
TypeError: An op outside of the function building code is being passed
a "Graph" tensor. It is possible to have Graph tensors
leak out of the function building context by including a
tf.init_scope in your function building code.
For example, the following function will fail:
  @tf.function
  def has_init_scope():
    my_constant = tf.constant(1.)
    with tf.init_scope():
      added = my_constant * 2
The graph tensor has name: linked_model/high_fidelity_model/weighted_sum/truediv:0
 

Мой код таков:

 class WeightedSum(krs.layers.Layer):
    def __init__( self, n_models = 2, **kwargs):
        super( WeightedSum, self ).__init__( **kwargs)
        self.n_models = n_models
        w_init = tf.random_uniform_initializer()
        self.sum_weights = tf.Variable(initial_value = w_init(shape=(1,self.n_models)),trainable=True)
        self.sum_weights = tf.divide(self.sum_weights,tf.math.reduce_sum(self.sum_weights))

    def call(self,inputs):
        self.sum_weights = tf.divide(self.sum_weights,tf.math.reduce_sum(self.sum_weights))
        output = tf.multiply(tf.cast(self.sum_weights[0,0],inputs[0].dtype),inputs[0])
        for i in range(1,len(inputs)):
            output  = tf.multiply(inputs[i],tf.cast(self.sum_weights[0,i],inputs[0].dtype))

        return output
 

Как мне заставить это работать?

Примечание: У меня есть другая версия этого кода, которая выглядит совсем по-другому, которая строится и обучается, но выдает ошибку unicode при попытке сохранения. Ошибка почти наверняка исходит от моего слоя WeightedSum.

Ответ №1:

Решение проблемы требует реализации ограничения и использования add_weight функции. Ограничение требуется, потому что по какой-то причине tf.divide его нельзя использовать так, как показано в вопросе.

 class NormalizeSumWeights(krs.constraints.Constraint):
    def __init__(self,**kwargs):
        super(NormalizeSumWeights,self).__init__(**kwargs)

    def call(self,w):
        return tf.math.divide(w,tf.math.reduce_sum(w))
 

с изменением класса WeightedSum на этот.

 class WeightedSum(krs.layers.Layer):
    def __init__( self, n_models = 2, **kwargs):
        super( WeightedSum, self ).__init__( **kwargs)
        self.n_models = n_models

    def build(self,input_shape):
        self.sum_weights = self.add_weight(name="sum_weights",shape=(1,self.n_models),
                                    initializer = krs.initializers.RandomUniform(0,1.0),
                                    constraint = NormalizeSumWeights(),
                                    trainable = True)

    def call(self,inputs):
        output = tf.multiply(tf.cast(self.sum_weights[0,0],inputs[0].dtype),inputs[0])
        for i in range(1,len(inputs)):
            output  = tf.multiply(inputs[i],tf.cast(self.sum_weights[0,i],inputs[0].dtype))

        return output

    def get_config(self):
        data = { "n_models": self.n_models}
        return data