在keras中实现复杂的激活功能

时间:2017-10-30 22:04:35

标签: keras

我刚读了一篇有趣的论文:A continuum among logarithmic, linear, and exponential functions, and its potential to improve generalization in neural networks

我想尝试在Keras中实现此激活功能。我之前已实施过自定义激活,例如正弦激活:

def sin(x):
  return K.sin(x)
get_custom_objects().update({'sin': Activation(sin)})

然而,本文中的激活功能有3个独特的属性:

  1. 它使输入的大小加倍(输出是输入的2倍)
  2. 参数化
  3. 它的参数应该正规化
  4. 我认为,一旦我有处理上述3个问题的骨架,我可以自己计算出数学,但我会得到任何帮助!

3 个答案:

答案 0 :(得分:5)

在这里,我们需要这两个中的一个:

  • 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.constantK.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)。

自定义图层:

自定义图层是您创建的新类。只有在您的函数中具有可训练参数时,才需要使用此方法。 (例如:用反向传播优化α)

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,)

答案 1 :(得分:4)

您需要实现" Layer"而不是常见的激活功能。

我认为在Keras中实施pReLU将是您的任务的一个很好的例子。见pReLU

答案 2 :(得分:1)

激活中的lambda函数对我有用。也许不是您想要的,但是比简单地使用内置激活功能要复杂得多。

encoder_outputs = Dense(units=latent_vector_len, activation=k.layers.Lambda(lambda z: k.backend.round(k.layers.activations.sigmoid(x=z))), kernel_initializer="lecun_normal")(x)

此代码将密集的输出从实数更改为0,1(即二进制)。

Keras发出警告,但代码仍然有效。