Как исправить "ValueError: Операнды не могут передаваться вместе с фигурами (2592,) (4,)" в Tensorflow?

В настоящее время я проектирую слой NoisyNet, как предлагается здесь: "Шумные сети для исследования", в Tensorflow и получаю ошибку размерности, как указано в заголовке, в то время как размеры двух тензоров должны быть умножены поэлементно в линию filtered_output = keras.layers.merge.Multiply()([output, actions_input]) должны (в принципе) быть совместимыми друг с другом в соответствии с выводом на печать при печати размеров обоих задействованных тензоров, filtered_output а также actions_inputгде оба тензора кажутся размерными shape=(1, 4),

Я использую Tensorflow 1.12.0 в Python3.

Соответствующий код выглядит следующим образом:

import numpy as np
import tensorflow as tf
import keras

class NoisyLayer(keras.layers.Layer):

    def __init__(self, in_shape=(1,2592), out_units=256, activation=tf.identity): 
        super(NoisyLayer, self).__init__()
        self.in_shape = in_shape
        self.out_units = out_units
        self.mu_interval = 1.0/np.sqrt(float(self.out_units))
        self.sig_0 = 0.5
        self.activation = activation
        self.assign_resampling()

    def build(self, input_shape):
        # Initializer
        self.mu_initializer = tf.initializers.random_uniform(minval=-self.mu_interval, maxval=self.mu_interval) # Mu-initializer
        self.si_initializer = tf.initializers.constant(self.sig_0/np.sqrt(float(self.out_units)))      # Sigma-initializer

        # Weights
        self.w_mu = tf.Variable(initial_value=self.mu_initializer(shape=(self.in_shape[-1], self.out_units), dtype='float32'), trainable=True) # (1,2592)x(2592,4) = (1,4)
        self.w_si = tf.Variable(initial_value=self.si_initializer(shape=(self.in_shape[-1], self.out_units), dtype='float32'), trainable=True)

        # Biases
        self.b_mu = tf.Variable(initial_value=self.mu_initializer(shape=(self.in_shape[0], self.out_units), dtype='float32'), trainable=True)
        self.b_si = tf.Variable(initial_value=self.si_initializer(shape=(self.in_shape[0], self.out_units), dtype='float32'), trainable=True)

    def call(self, inputs, resample_noise_flag):
        if resample_noise_flag:
            self.assign_resampling()

        # Putting it all together
        self.w = tf.math.add(self.w_mu, tf.math.multiply(self.w_si, self.w_eps))
        self.b = tf.math.add(self.b_mu, tf.math.multiply(self.b_si, self.q_eps))

        return self.activation(tf.linalg.matmul(inputs, self.w) + self.b)

    def assign_resampling(self):
        self.p_eps = self.f(self.resample_noise([self.in_shape[-1], 1]))
        self.q_eps = self.f(self.resample_noise([1, self.out_units]))
        self.w_eps = self.p_eps * self.q_eps         # Cartesian product of input_noise x output_noise

    def resample_noise(self, shape):
        return tf.random.normal(shape, mean=0.0, stddev=1.0, seed=None, name=None)

    def f(self, x):
        return tf.math.multiply(tf.math.sign(x), tf.math.sqrt(tf.math.abs(x)))


frames_input = tf.ones((1, 84, 84, 4))  # Toy input

conv1 = keras.layers.Conv2D(16, (8, 8), strides=(4, 4), activation="relu")(frames_input)
conv2 = keras.layers.Conv2D(32, (4, 4), strides=(2, 2), activation="relu")(conv1)

flattened = keras.layers.Flatten()(conv2)

actionspace_size = 4  

# NoisyNet        
hidden = NoisyLayer(activation=tf.nn.relu)(inputs=flattened, resample_noise_flag=True)
output = NoisyLayer(in_shape=(1,256), out_units=actionspace_size)(inputs=hidden, resample_noise_flag=True)

actions_input = tf.ones((1,actionspace_size))

print('hidden:\n', hidden)
print('output:\n', output)
print('actions_input:\n', actions_input)

filtered_output = keras.layers.merge.Multiply()([output, actions_input])

Вывод, когда я запускаю код, выглядит следующим образом:

hidden:
 Tensor("noisy_layer_5/Relu:0", shape=(1, 256), dtype=float32)
output:
 Tensor("noisy_layer_6/Identity:0", shape=(1, 4), dtype=float32)
actions_input:
 Tensor("ones_5:0", shape=(1, 4), dtype=float32)

---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-4-f6df621eacab> in <module>()
     68 print('actions_input:\n', actions_input)
     69 
---> 70 filtered_output = keras.layers.merge.Multiply()([output, actions_input])

2 frames

/usr/local/lib/python3.6/dist-packages/keras/layers/merge.py in _compute_elemwise_op_output_shape(self, shape1, shape2)
     59                     raise ValueError('Operands could not be broadcast '
     60                                      'together with shapes ' +
---> 61                                      str(shape1) + ' ' + str(shape2))
     62                 output_shape.append(i)
     63         return tuple(output_shape)

ValueError: Operands could not be broadcast together with shapes (2592,) (4,)

В частности, мне интересно, где число 2592 в Operands could not be broadcast together with shapes (2592,) (4,) происходит, так как число совпадает с длиной сплющенного входного тензора flattened к первому шумному слою, но, как мне кажется, не является частью выходного измерения второго шумного слоя output больше, что, в свою очередь, служит вводом в ошибочную строку, указанную выше.

Кто-нибудь знает, что идет не так?

Заранее спасибо, Даниэль

1 ответ

Решение

Как указано в документе пользовательского уровня, вам необходимо реализовать compute_output_shape(input_shape) метод:

compute_output_shape(input_shape): в случае, если ваш слой изменяет форму своего входа, вы должны указать здесь логику преобразования формы. Это позволяет Keras делать автоматический вывод формы.

Keras не может сделать вывод формы без фактического выполнения вычисления, когда вы не применяете этот метод.

print(keras.backend.int_shape(hidden))
print(keras.backend.int_shape(output))

(1, 2592)
(1, 2592)

Так что вам нужно добавить его следующим образом:

def compute_output_shape(self, input_shape):
    return (input_shape[0], self.out_units)

К тому же, build() метод должен установить self.built = True в конце, что можно сделать, позвонив super(NoisyLayer, self).build(input_shape) согласно документу.

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