我该如何在Keras中创建可训练参数?

9
感谢查看我的问题。
例如,最终输出是两个矩阵A和B的总和,如下所示:
output = keras.layers.add([A, B])

现在,我想建立一个新的参数x来改变输出结果。

我想让新的输出结果为Ax+B(1-x)

而且x是我的网络中一个可训练参数

我该怎么做呢? 请帮帮我~ 非常感谢!

编辑(代码的一部分):

conv1 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(input)
drop1 = Dropout(0.5)(conv1)
pool1 = MaxPooling2D(pool_size=(2, 2))(drop1)

conv2 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1)
conv2 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2)
drop2 = Dropout(0.5)(conv2)

up1 = Conv2D(512, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(drop2))

#the line I want to change:
merge = add([drop2,up1])
#this layer is simply add drop2 and up1 layer.now I want to add a trainable parameter x to adjust the weight of thoese two layers.

我尝试使用这些代码,但仍然遇到了一些问题:
1. 我如何使用自己的图层?
merge = Mylayer()(drop2,up1)

还有其他方式吗?

2.out_dim的含义是什么? 这些参数都是三维矩阵。out_dim的含义是什么?

谢谢...T.T

编辑2(已解决)

from keras import backend as K
from keras.engine.topology import Layer
import numpy as np

from keras.layers import add

class MyLayer(Layer):

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

def build(self, input_shape):

    self._x = K.variable(0.5)
    self.trainable_weights = [self._x]

    super(MyLayer, self).build(input_shape)  # Be sure to call this at the end

def call(self, x):
    A, B = x
    result = add([self._x*A ,(1-self._x)*B])
    return result

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

感谢您提供的二次编辑代码块!这终于让我开始使用TF 1.12和Keras 2.2.4。这无疑是有史以来最令人困惑的API...对于那些遇到问题的人,请检查model.summary()是否报告该层中存在可训练参数。对于我来说,我必须在build()中调用add_weight(shape=())才能将权重正确添加到模型图中。shape=()表示该权重是标量,您可以将其直接添加/乘/除到张量中。 - dant
1个回答

6
你需要创建一个继承自Layer的自定义类,并使用self.add_weight(...)创建可训练参数。你可以在这里那里找到一个例子。
对于你的示例,该层看起来应该像这样:
from keras import backend as K
from keras.engine.topology import Layer
import numpy as np

class MyLayer(Layer):

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

    def build(self, input_shape):
        # Create a trainable weight variable for this layer.
        self._A = self.add_weight(name='A', 
                                    shape=(input_shape[1], self.output_dim),
                                    initializer='uniform',
                                    trainable=True)
        self._B = self.add_weight(name='B', 
                                    shape=(input_shape[1], self.output_dim),
                                    initializer='uniform',
                                    trainable=True)
        super(MyLayer, self).build(input_shape)  # Be sure to call this at the end

    def call(self, x):
        return K.dot(x, self._A) + K.dot(1-x, self._B)

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

编辑:基于名称,我(错误地)认为x是层输入,您想要优化AB。但是,正如您所述,您想要优化x。为此,您可以执行以下操作:

from keras import backend as K
from keras.engine.topology import Layer
import numpy as np

class MyLayer(Layer):

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

    def build(self, input_shape):
        # Create a trainable weight variable for this layer.
        self._x = self.add_weight(name='x', 
                                    shape=(1,),
                                    initializer='uniform',
                                    trainable=True)
        super(MyLayer, self).build(input_shape)  # Be sure to call this at the end

    def call(self, x):
        A, B = x
        return K.dot(self._x, A) + K.dot(1-self._x, B)

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

Edit2: 您可以使用以下方式调用此层

merge = Mylayer()([drop2,up1])

我有一个问题:对于我的例子,x是可训练参数,A/B矩阵是输入参数。为什么在构建函数中不添加x呢? - lomo
抱歉,先生,我仍然无法运行我的代码。请查看我的编辑。 - lomo
@lomo,请查看我的编辑更改。我原以为你想要x成为张量,但我猜你只是想让它成为标量,对吗? - zimmerrol
是的,但我该如何在我的模型中使用这个层呢?代码:{ merge = Mylayer()(layer1, layer2) } 没有起作用。 - lomo
错误信息为:TypeError: call() 接受 2 个位置参数,但实际给出了 3 个。 - lomo
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接