如何在Keras张量中加入一系列可训练的权重?

时间:2018-05-08 19:54:45

标签: keras add shapes

遵循"时间编码" https://arxiv.org/pdf/1503.08895.pdf第5页的部分(顺便说一句优秀的论文),我已经说过N个很多M维的嵌入向量。所以我的Keras张量是(批量大小,N,M),我想加一个N通过M矩阵的权重对每个批量大小的样本。为此,我创建了自己的Keras图层:

from constants import BATCH_SIZE
class Added_Weights(Layer):

  def __init__(self, input_dim, output_dim, **kwargs):
      self.output_dim = output_dim
      self.input_dim = input_dim

      super(Added_Weights, self).__init__(**kwargs)

  def build(self, input_shape):
      # Create a trainable weight variable for this layer.
      self.kernel = self.add_weight(name='kernel',
                                  shape=(BATCH_SIZE, self.input_dim[0], self.input_dim[1]),
                                  initializer=RandomNormal(mean=0., stddev=0.05, seed=None),
                                  trainable=True)

      print("kernel has shape "+self.kernel.shape + " or "+K.int_shape(self.kernel))
      super(Added_Weights, self).build(input_shape)  

  def call(self, x, **kwargs):
      return Add()([x, self.kernel])

  def compute_output_shape(self, input_shape):
      return (BATCH_SIZE, self.input_dim[0], self.input_dim[1])

这就行了,但问题是每个BATCH_SIZE很多矩阵都有不同的权重。我需要为批次中的每个样本添加相同的权重。

所以我尝试了几件事。 Keras有一个内置的RepeatVector层,所以我尝试给出内核形状(N,M)并执行RepeatVector(BATCH_SIZE)(内核),但由于某种原因最终形状(N,BATCH_SIZE,M)。我想在那里使用Reshape,但Reshape()将第一个维度视为batch_size,并且不允许我修改它。 Permute()也有同样的问题。

另一个想法是在代码中创建初始形状,然后在张量上循环以将切片1到BATCH_SIZE-1设置为等于切片0,因此它们都保持相同的权重,但是我不允许以这种方式为Keras张量赋值。

我唯一的另一个想法是尝试使用形状(N,M)并希望Keras足够智能将它添加到输入的每个切片中,但是在将Add()应用于我的(?, N,M)和(N,M)内核,不知怎的,我最终得到一个(N,N,M)张量,此时我们已经死了。

1 个答案:

答案 0 :(得分:1)

我认为你过于复杂。只需将权重定义为build中的N x M张量,并在call中与输入张量执行求和。我调整了你的代码如下:

from keras.engine.topology import Layer
from keras.models import Model
from keras.layers import Input
import numpy as np

N = 3
M = 4
BATCH_SIZE = 1

class Added_Weights(Layer):
    def __init__(self, **kwargs):
        super(Added_Weights, self).__init__(**kwargs)

    def build(self, input_shape):
        # Create a trainable weight variable for this layer.
        self.kernel = self.add_weight(name='kernel',
                                      shape=(input_shape[1], input_shape[2]),
                                      initializer='ones',  # TODO: Choose your initializer
                                      trainable=True)
        super(Added_Weights, self).build(input_shape)

    def call(self, x, **kwargs):
        # Implicit broadcasting occurs here.
        # Shape x: (BATCH_SIZE, N, M)
        # Shape kernel: (N, M)
        # Shape output: (BATCH_SIZE, N, M)
        return x + self.kernel

    def compute_output_shape(self, input_shape):
        return input_shape


a = Input(shape=(N, M))
layer = Added_Weights()(a)
model = Model(inputs=a,
              outputs=layer)

a = np.zeros(shape=(BATCH_SIZE, N, M))
pred = model.predict(a)
print(pred)

请注意self.kernel隐式广播call以匹配x的形状,因此批量中的每个样本都会添加相同的权重。