在自定义keras图层的调用函数中传递附加参数

btqmn9zl  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(215)

我创建了一个自定义的keras层,目的是在推理过程中手动改变前一层的激活。下面是简单地将激活与一个数字相乘的基本层。

import numpy as np
from keras import backend as K
from keras.layers import Layer
import tensorflow as tf

class myLayer(Layer):

    def __init__(self, n=None, **kwargs):
        self.n = n
        super(myLayer, self).__init__(**kwargs)

    def build(self, input_shape):

        self.output_dim = input_shape[1]
        super(myLayer, self).build(input_shape)

    def call(self, inputs):

        changed = tf.multiply(inputs, self.n)

        forTest  = changed
        forTrain = inputs

        return K.in_train_phase(forTrain, forTest)

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

在IRIS数据集上使用时,它工作正常

model = Sequential()
model.add(Dense(units, input_shape=(5,)))
model.add(Activation('relu'))
model.add(myLayer(n=3))
model.add(Dense(units))
model.add(Activation('relu'))
model.add(Dense(3))
model.add(Activation('softmax'))
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
model.summary()

但是现在我想把'n'从init移到call函数中,这样我就可以在训练后应用不同的n值来评估模型。这个想法是用一个占位符代替n,在调用evaluate函数之前,可以用某个值初始化n。我不知道如何实现这个。正确的方法是什么?谢谢

5vf7fwbs

5vf7fwbs1#

您应该使用与“Concatenate”层相同的方法。
这些采用多个输入的层依赖于在列表中传递的输入(和输入形状)。
请参见buildcallcomput_output_shape中的验证部分:

def call(self,inputs):
    if not isinstance(inputs, list):
        raise ValueError('This layer should be called on a list of inputs.')
    
    mainInput = inputs[0]
    nInput = inputs[1]

    changed = tf.multiply(mainInput,nInput)
    #I suggest using an equivalent function in K instead of tf here, if you ever want to test theano or another backend later. 
    #if n is a scalar, then just "changed=nInput * mainInput" is ok

    #....the rest of the code....

然后你调用这个层,传递一个列表给它。但是为了这个,我强烈建议你远离Sequential模型。它们是纯粹的限制。

from keras.models import Model

inputTensor = Input((5,)) # the original input (from your input_shape)

#this is just a suggestion, to have n as a manually created var
#but you can figure out your own ways of calculating n later
nInput = Input((1,))
    #old answer: nInput = Input(tensor=K.variable([n]))

#creating the graph
out = Dense(units, input_shape=(5,),activation='relu')(inputTensor)

#your layer here uses the output of the dense layer and the nInput
out = myLayer()([out,nInput])
    #here you will have to handle n with the same number of samples as x. 
    #You can use `inputs[1][0,0]` inside the layer

out = Dense(units,activation='relu')(out)
out = Dense(3,activation='softmax')(out)

#create the model with two inputs and one output:
model = Model([inputTensor,nInput], out)
    #nInput is now a part of the model's inputs

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])

使用Input(tensor=...)的旧答案,模型将不会像通常发生的那样要求您将2个输入传递给fitpredict方法。
但是使用新选项,对于Input(shape=...),它将需要两个输入,因此:

nArray = np.full((X_train.shape[0],1),n)
model.fit([X_train,nArray],Y_train,....)

不幸的是,我不能让它与只有一个元素的n一起工作。它必须有与完全相同的样本数(这是一个keras限制)。

相关问题