【问题标题】:How to add a trainable hadamard product layer in keras?如何在 keras 中添加可训练的 hadamard 产品层?
【发布时间】:2017-10-19 02:06:09
【问题描述】:

我正在尝试在训练样本中引入稀疏性。我的数据矩阵的大小为(比如)NxP,我想将它传递给一个层(keras 层),该层的权重与输入大小相同。也就是说,可训练的权重矩阵 W 的形状为 NxP。我想对这一层进行输入矩阵的 hadamard 乘积(逐元素乘法)。 W 将元素与输入相乘。在这种情况下如何获得 W 的可训练层?

编辑: 顺便说一句,非常感谢您的快速回复。但是,我想做的 hadamard 产品是在两个矩阵之间,一个是输入,我们称之为 X,我的 X 是 NxP 的形状。而且我希望我在 hadamard 层中的内核与 X 的大小相同。所以内核也应该具有 NxP 的大小。两个矩阵的元素乘法是通过调用函数实现的。

但当前的实现仅将内核大小设为 P。另外,我尝试在构建中更改内核的形状,如下所示:

self.kernel = self.add_weight(name='kernel',
                                      shape=input_shape,
                                      initializer='uniform',
                                      trainable=True)

但它给了我以下错误:

TypeError:无法将类型对象转换为张量。内容:(无,16)。考虑将元素转换为支持的类型。

这里 P 是 16,我会在运行时得到我的 N,N 与训练样本的数量相似。

提前感谢您的帮助。

【问题讨论】:

    标签: keras


    【解决方案1】:

    documentation为例创建一个图层,在call函数中定义为x * self.kernel

    这是我的 POC:

    from keras import backend as K
    from keras.engine.topology import Layer
    from keras.models import Sequential
    from keras.layers import Dense, Activation
    import numpy as np
    np.random.seed(7)
    
    class Hadamard(Layer):
    
        def __init__(self, **kwargs):
            super(Hadamard, self).__init__(**kwargs)
    
        def build(self, input_shape):
            # Create a trainable weight variable for this layer.
            self.kernel = self.add_weight(name='kernel', 
                                          shape=(1,) + input_shape[1:],
                                          initializer='uniform',
                                          trainable=True)
            super(Hadamard, self).build(input_shape)  # Be sure to call this somewhere!
    
        def call(self, x):
            print(x.shape, self.kernel.shape)
            return x * self.kernel
    
        def compute_output_shape(self, input_shape):
            print(input_shape)
            return input_shape
    
    N = 10
    P = 64
    
    model = Sequential()
    model.add(Dense(128, input_shape=(N, P), activation='relu'))
    model.add(Dense(64))
    model.add(Hadamard())
    model.add(Activation('relu'))
    model.add(Dense(32))
    model.add(Dense(1))
    
    model.compile(loss='mean_squared_error', optimizer='adam')
    
    print(model.summary())
    
    model.fit(np.ones((10, N, P)), np.ones((10, N, 1)))
    
    print(model.predict(np.ones((20, N, P))))
    

    如果您需要将其用作第一层,则应包含输入形状参数:

    N = 10
    P = 64
    
    model = Sequential()
    model.add(Hadamard(input_shape=(N, P)))
    
    model.compile(loss='mean_squared_error', optimizer='adam')
    
    print(model.summary())
    

    这会导致:

    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    hadamard_1 (Hadamard)       (None, 10, 64)            640       
    =================================================================
    Total params: 640
    Trainable params: 640
    Non-trainable params: 0
    

    【讨论】:

    • 哇!!那是一些快速的答复。非常感谢。
    • 实际上没有,我已经编辑了我的问题以包含更多详细信息
    • 我的 POC 也应该适用于这种情况,看看我的体重定义,我使用了shape=input_shape[1:]
    • 更新了概念证明以排除 NxP 和 fit 函数调用
    • 权重的数量只有 10 (P),因为我希望可训练的参数为 (NxP) = (64x10 = 640)。运行上面的代码后,我只将它作为 P:Layer (type) Output Shape Param # ============================== =================================== hadamard_1(Hadamard)(无,10)10 ===== ==================================================== ========== 总参数:10 可训练参数:10
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    相关资源
    最近更新 更多