当先锋百科网

首页 1 2 3 4 5 6 7

Keras是一个高度封装的库,它的优点是可以进行快速的建模,缺点是它不处理底层运算,如张量内积等。为了弥补这个问题,Keras提供“后端引擎”来实现底层运算操作。目前Keras支持的后端引擎有tensorflow,CNTK,Theano。默认的是使用tensorflow,你可以在.keras/keras.json文件中更改backend。我们可以使用keras提供的后端来实现任意你想实现的layer。
1.首先来看下keras官方给的示例:
只有一个张量输入输出:

from keras import backend as K
from keras.layers import Layer

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.kernel = self.add_weight(name='kernel', 
                                      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.kernel)

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

有多个张量输入输出时:

from keras import backend as K
from keras.layers import Layer

class MyLayer(Layer):

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

    def build(self, input_shape):
        assert isinstance(input_shape, list)
        # Create a trainable weight variable for this layer.
        self.kernel = self.add_weight(name='kernel',
                                      shape=(input_shape[0][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):
        assert isinstance(x, list)
        a, b = x
        return [K.dot(a, self.kernel) + b, K.mean(b, axis=-1)]

    def compute_output_shape(self, input_shape):
        assert isinstance(input_shape, list)
        shape_a, shape_b = input_shape
        return [(shape_a[0], self.output_dim), shape_b[:-1]]
1

 

2. 如何自定义一个层
基本的需要实现以下四个方法:
  1. __init __ (self, output_dim, **kwargs) :这个方法是用来初始化并自定义自定义层所需的属性,比如output_dim,以及一个必需要执行的super().__init __(**kwargs),这行代码是去执行Layer类中的初始化函数,当它执行了你就没有必要去管input_shape,weights,trainable等关键字参数了因为父类(Layer)的初始化函数实现了它们与layer实例的绑定。
  2. build(self, input_shape): 创建层权重的地方。你可以通过Layer类的add_weight方法来自定义并添加一个权重矩阵。这个方法一定有input_shape参数。这个方法必须设self.built = True,目的是为了保证这个层的权重定义函数build被执行过了,这个self.built其实是个标记而已,当然也可以通过调用super([MyLayer], self).build(input_shape)来完成。build这个方法是用来创建权重的,在这个函数中我们需要说明这个权重各方面的属性比如shape,初始化方式以及可训练性等信息,这也是为什么keras设计单独的一个方法来定义权重。
  3. call(self, x): 这里是编写层的功能逻辑的地方。你只需要关注传入call的第一个参数:输入张量x,而且它只能是一种形式不能是具体的变量也就是它说它不能被定义。如果你希望你的层能支持masking,我们建议直接使用官方给的Masking层即可。这个call函数就是该层的计算逻辑,或计算图了,当创建好了这个层实例后,这个实例可以使用像函数调用那样的语法来执行call函数(不懂的可以了解一下python中的__call__魔法方法)。显然,这个层的核心应该是一段符号式的输入张量到输出张量的计算过程。再次强调因为输入只是个形式,所以输入变量不能被事先定义。这个跟python中的匿名函数类似,在python中没有被赋过值的变量就是未定义的。
  4. compute_output_shape(self, input_shape):为了能让Keras内部shape的匹配检查通过,这里需要重写compute_output_shape方法去覆盖父类中的同名方法,来保证输出shape是正确的。父类Layer中的compute_output_shape方法直接返回的是input_shape这明显是不对的,所以需要我们重写这个方法。所以这个方法也是4个要实现的基本方法之一。
  当然你还可以根据需要自定义实现一些其他的方法。
 

相关参考:

https://keras.io/layers/writing-your-own-keras-layers/ 

https://blog.csdn.net/buchidanhuang/article/details/99210547