在这里,我们将需要以下两者之一:
- Lambda 层 - 如果您的参数不可训练(您不希望它们随着反向传播而改变)
- 自定义层 - 如果您需要自定义可训练参数。
Lambda 层:
如果您的参数不可训练,您可以为 lambda 层定义函数。该函数接受一个输入张量,它可以返回任何你想要的:
import keras.backend as K
def customFunction(x):
#x can be either a single tensor or a list of tensors
#if a list, use the elements x[0], x[1], etc.
#Perform your calculations here using the keras backend
#If you could share which formula exactly you're trying to implement,
#it's possible to make this answer better and more to the point
#dummy example
alphaReal = K.variable([someValue])
alphaImag = K.variable([anotherValue]) #or even an array of values
realPart = alphaReal * K.someFunction(x) + ...
imagPart = alphaImag * K.someFunction(x) + ....
#You can return them as two outputs in a list (requires the fuctional API model
#Or you can find backend functions that join them together, such as K.stack
return [realPart,imagPart]
#I think the separate approach will give you a better control of what to do next.
关于您能做什么,请探索backend functions。
对于参数,您可以将它们定义为 keras 常量或变量(K.constant 或 K.variable),在上述函数内部或外部,甚至可以在模型输入中转换它们。 See details in this answer
在您的模型中,您只需添加一个使用该函数的 lambda 层。
- 在顺序模型中:
model.add(Lambda(customFunction, output_shape=someShape))
- 在功能 API 模型中:
output = Lambda(customFunction, ...)(inputOrListOfInputs)
如果您要向函数传递更多输入,则需要函数模型 API。
如果您使用的是 Tensorflow,则 output_shape 将自动计算,我相信只有 Theano 需要它。 (不确定 CNTK)。
自定义层:
自定义层是您创建的新类。仅当您要在函数中具有可训练的参数时,才需要这种方法。 (如:用反向传播优化 alpha)
Keras teaches it here.
基本上,您有一个传递常量参数的__init__ 方法,一个创建可训练参数(权重)的build 方法,一个将进行计算的call 方法(确切地说是什么lambda 层(如果您没有可训练的参数)和 compute_output_shape 方法,以便您可以告诉模型输出形状是什么。
class CustomLayer(Layer):
def __init__(self, alphaReal, alphaImag):
self.alphaReal = alphaReal
self.alphaImage = alphaImag
def build(self,input_shape):
#weights may or may not depend on the input shape
#you may use it or not...
#suppose we want just two trainable values:
weigthShape = (2,)
#create the weights:
self.kernel = self.add_weight(name='kernel',
shape=weightShape,
initializer='uniform',
trainable=True)
super(CustomLayer, self).build(input_shape) # Be sure to call this somewhere!
def call(self,x):
#all the calculations go here:
#dummy example using the constant inputs
realPart = self.alphaReal * K.someFunction(x) + ...
imagPart = self.alphaImag * K.someFunction(x) + ....
#dummy example taking elements of the trainable weights
realPart = self.kernel[0] * realPart
imagPart = self.kernel[1] * imagPart
#all the comments for the lambda layer above are valid here
#example returning a list
return [realPart,imagPart]
def compute_output_shape(self,input_shape):
#if you decide to return a list of tensors in the call method,
#return a list of shapes here, twice the input shape:
return [input_shape,input_shape]
#if you stacked your results somehow in a single tensor, compute a single tuple, maybe with an additional dimension equal to 2:
return input_shape + (2,)