Как исправить «ValueError: Операнды не могут передаваться вместе с фигурами (2592,) (4,)» в Tensorflow? - PullRequest
4 голосов
/ 10 мая 2019

В настоящее время я проектирую слой 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 Ответ

1 голос
/ 10 мая 2019

Как указано в документе пользовательского слоя , вам необходимо реализовать метод 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) в соответствии с документом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...