Почему Keras преобразует входную форму из (3,3) в (?, 3,3)?

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

class MyLayer(Layer):

    def __init__(self, **kwargs):
        super(MyLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        print("input_shape: "+str(input_shape))
        self.kernel = self.add_weight(name='kernel',
                                      shape=(input_shape[1], self.output_dim),
                                      initializer='uniform',
                                      trainable=True)
        super(MyLayer, self).build(input_shape)

    def call(self, x):
        print("input tensor: "+str(x))
        return K.dot(x, self.kernel)


inputs = Input(shape=(3,3), dtype='float', name='inputs')
results = MyLayer(input_shape=(3,3))(inputs)

В результате консольный вывод будет следующим:

input_shape: (None, 3, 3)
input tensor: Tensor("inputs:0", shape=(?, 3, 3), dtype=float32)

Как видите, input_shape, который получает слой, не (3,3), как я указал, а фактически (None, 3,3). Это почему? Форма входного тензора также имеет форму (?, 3,3), которую я считал следствием странной input_shape (None, 3,3). Но входной тензор также имеет эту форму с третьим измерением, если вы замените super(MyLayer, self).build(input_shape) на super(MyLayer, self).build((3,3)). Что это за загадочный керас третьего измерения автоматически добавляет и почему?


person Poly-nom-nom-noo    schedule 18.03.2020    source источник


Ответы (3)


В этом нет ничего загадочного, это размерность пакета, поскольку keras (и большинство структур DL) одновременно выполняют вычисления на пакетах данных, поскольку это увеличивает параллелизм и напрямую отображается на пакеты в стохастическом градиентном спуске.

Ваш уровень должен поддерживать вычисления в пакетах, поэтому размер пакета всегда присутствует во входных и выходных данных и автоматически добавляется keras к input_shape.

person Dr. Snoopy    schedule 18.03.2020
comment
Ах, в этом есть смысл. Теперь, что мне интересно, могу ли я как-то указать размер пакета в моей функции вызова? В моем конкретном примере я не просто использую K.dot для вычисления вывода, но мне нужно сгладить ввод с помощью K.flatten. Как я могу сгладить каждый ввод в пакете, не зная размера пакета? - person Poly-nom-nom-noo; 18.03.2020
comment
Вы можете использовать K.reshape (input_tensor, (-1,9)). Здесь использование -1 заставляет функцию K.reshape автоматически определять форму этой оси в соответствии с формой других осей. В вашем случае, поскольку вы хотите преобразовать из (None, 3, 3) в (None, 9), вы можете использовать K.reshape (input_tensor, (-1, (3x3))). В качестве дополнительного примечания вы можете использовать -1 только для одной оси при указании кортежа формы, который вы передаете в функцию K.reshape (). - person doldnh; 18.03.2020
comment
@ Poly-nom-nom-noo Я думаю, что K.flatten уже работает пакетно, большинство, если не все бэкэнд-функции работают именно так. Таким образом, вам не нужно делать ничего особенного для поддержки пакетов. - person Dr. Snoopy; 18.03.2020

Это новое добавленное измерение относится к пакетному измерению, то есть в вашем случае вы будете передавать пакеты размерных тензоров 3x3. Это дополнительное None измерение относится к пакетному измерению, которое неизвестно во время создания графика.

Если вы ознакомились с объяснением входного слоя на веб-странице Core Layers для Keras, https://keras.io/layers/core/, вы увидите, что аргумент формы, который вы передаете при создании входного слоя, определяется следующим образом:

shape: кортеж формы (целое число), не включая размер пакета. Например, shape = (32,) указывает, что ожидаемые входные данные будут пакетами 32-мерных векторов.

person doldnh    schedule 18.03.2020

Если вы хотите указать размер пакета, вы можете сделать это вместо этого:

input = Input (batch_shape = (batch_size, height, width, channel))

person Vincent Yong    schedule 18.03.2020