实现自己的Keras层
来源:互联网 发布:东莞金拓软件 编辑:程序博客网 时间:2024/05/17 02:04
一. 所有keras层的基类:Layer
keras的所有层的基类定义在keras/engine/topology.py文件中的Layer类中。
python语言基础
用到的装饰器:
@property
让类函数能像类变量一样操作@interfaces.legacy_xxx_support
让函数支持keras 1.x的 API@classmothod
类函数,属于整个类,类似于C++/JAVA中的静态函数。类方法有类变量cls传入,从而可以用cls做一些相关的处理。子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。既可以在类内部使用self访问,也可以通过实例、类名访问。@staticmethod
将外部函数集成到类体中,既可以在类内部使用self访问,也可以通过实例、类名访问。基本上等同于一个全局函数。
magic函数:
__call__
让类的实例可以像函数一样调用,正是python的这种特性让我们可以像这样进行层之间的连接:
inputs = Input(shape=(784,))# 前面的Dense(64, activation='relu')生成了类Dense的一个实例# 后面的(input)将调用类Dense的__call__函数x = Dense(64, activation='relu')(inputs)
InputSpec
: 确定层的ndim,dtype,shape,每一层都应有一个input_spec属性,保存InputSpec的实例的list(每一个输入tensor都对应一个)
重点关注以下函数
1. add_weight
每层的参数通过这个函数来设定。可以看到它最终调用的是 K.variable 来生成变量,打开 keras/backend/tensorflow_backend.py 可以看到它生成变量的方式:
v = tf.Variable(value, dtype=tf.as_dtype(dtype), name=name)
让人惊讶的是,keras从居然不是使用tf.get_variable的方式生成变量,可见keras在设计时就根本没有考虑到变量共享,从之前的经验来看,要用keras设计多GPU程序是非常棘手的。(要想让Keras支持多GPU并行,必须从这一步开始修改代码,而这里已经是keras非常底层的代码了。)
2. call / __call__
call是最重要的函数,它用于实现层的功能,子类必须实现。
魔法函数 __call__ 会将收到的输入传递给 call 函数,然后调用 call 函数实现具体的功能。
3. comput_output_shape
根据input_shape 计算输出的shape,子类必须实现。用于自动推断下一层的输入尺寸。
4. build
用来创建当前层的weights,子类必须实现。
5. get_config / from_config
get_config 返回一个字典,获取当前层的参数信息。
from_config 使用根据参数生成一个新的层。代码只有一行:
@classmethoddef from_config(cls, config): return cls(**config)
可见from_config是一个classmethod,根据传入的参数,使用当前类的构造函数来生成一个实例。通过子类调用时,cls是子类而不是基类Layer。
二、实现自己的keras层
官方文档的说明:
对于简单的定制操作,我们或许可以通过使用layers.core.Lambda层来完成。但对于任何具有可训练权重的定制层,你应该自己来实现。
build(input_shape)
:这是定义权重的方法,可训练的权应该在这里被加入列表self.trainable_weights
中。其他的属性还包括self.non_trainabe_weights
(列表)和self.updates
(需要更新的形如(tensor, new_tensor)的tuple的列表)。你可以参考BatchNormalization层的实现来学习如何使用上面两个属性。这个方法必须设置self.built = True,可通过调用super([layer],self).build()实现call(x)
:这是定义层功能的方法,除非你希望你写的层支持masking,否则你只需要关心call的第一个参数:输入张量compute_output_shape(input_shape)
:如果你的层修改了输入数据的shape,你应该在这里指定shape变化的方法,这个函数使得Keras可以做自动shape推断
代码示例(来自keras代码库)
最简单的层Activation层(没有参数):
class Activation(Layer): def __init__(self, activation, **kwargs): super(Activation, self).__init__(**kwargs) self.supports_masking = True self.activation = activations.get(activation) def call(self, inputs): return self.activation(inputs) def get_config(self): config = {'activation': activations.serialize(self.activation)} base_config = super(Activation, self).get_config() return dict(list(base_config.items()) + list(config.items()))
Dropout层:
class Dropout(Layer): @interfaces.legacy_dropout_support def __init__(self, rate, noise_shape=None, seed=None, **kwargs): super(Dropout, self).__init__(**kwargs) self.rate = min(1., max(0., rate)) self.noise_shape = noise_shape self.seed = seed self.supports_masking = True def _get_noise_shape(self, inputs): if self.noise_shape is None: return self.noise_shape symbolic_shape = K.shape(inputs) noise_shape = [symbolic_shape[axis] if shape is None else shape for axis, shape in enumerate(self.noise_shape)] return tuple(noise_shape) def call(self, inputs, training=None): if 0. < self.rate < 1.: noise_shape = self._get_noise_shape(inputs) def dropped_inputs(): return K.dropout(inputs, self.rate, noise_shape, seed=self.seed) return K.in_train_phase(dropped_inputs, inputs, training=training) return inputs def get_config(self): config = {'rate': self.rate, 'noise_shape': self.noise_shape, 'seed': self.seed} base_config = super(Dropout, self).get_config() return dict(list(base_config.items()) + list(config.items()))
Dense 层:
class Dense(Layer): @interfaces.legacy_dense_support def __init__(self, units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, **kwargs): if 'input_shape' not in kwargs and 'input_dim' in kwargs: kwargs['input_shape'] = (kwargs.pop('input_dim'),) super(Dense, self).__init__(**kwargs) self.units = units self.activation = activations.get(activation) self.use_bias = use_bias self.kernel_initializer = initializers.get(kernel_initializer) self.bias_initializer = initializers.get(bias_initializer) self.kernel_regularizer = regularizers.get(kernel_regularizer) self.bias_regularizer = regularizers.get(bias_regularizer) self.activity_regularizer = regularizers.get(activity_regularizer) self.kernel_constraint = constraints.get(kernel_constraint) self.bias_constraint = constraints.get(bias_constraint) self.input_spec = InputSpec(min_ndim=2) self.supports_masking = True def build(self, input_shape): assert len(input_shape) >= 2 input_dim = input_shape[-1] self.kernel = self.add_weight(shape=(input_dim, self.units), initializer=self.kernel_initializer, name='kernel', regularizer=self.kernel_regularizer, constraint=self.kernel_constraint) if self.use_bias: self.bias = self.add_weight(shape=(self.units,), initializer=self.bias_initializer, name='bias', regularizer=self.bias_regularizer, constraint=self.bias_constraint) else: self.bias = None self.input_spec = InputSpec(min_ndim=2, axes={-1: input_dim}) self.built = True def call(self, inputs): output = K.dot(inputs, self.kernel) if self.use_bias: output = K.bias_add(output, self.bias) if self.activation is not None: output = self.activation(output) return output def compute_output_shape(self, input_shape): assert input_shape and len(input_shape) >= 2 assert input_shape[-1] output_shape = list(input_shape) output_shape[-1] = self.units return tuple(output_shape) def get_config(self): config = { 'units': self.units, 'activation': activations.serialize(self.activation), 'use_bias': self.use_bias, 'kernel_initializer': initializers.serialize(self.kernel_initializer), 'bias_initializer': initializers.serialize(self.bias_initializer), 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer), 'bias_regularizer': regularizers.serialize(self.bias_regularizer), 'activity_regularizer': regularizers.serialize(self.activity_regularizer), 'kernel_constraint': constraints.serialize(self.kernel_constraint), 'bias_constraint': constraints.serialize(self.bias_constraint) } base_config = super(Dense, self).get_config() return dict(list(base_config.items()) + list(config.items()))
- 实现自己的Keras层
- 用keras实现3层BP网络的训练、保存、加载和导入自己手写的数字进行测试
- keras的Embedding层
- keras slice layer 层 实现
- seq2seq 的 keras 实现
- keras的lenet实现
- GAN 的 keras 实现
- GAN 的 keras 实现
- keras Lambda自定义层实现数据的切片,Lambda传参数
- keras的自编码实现
- 自己弄的一种数据层的实现
- [神经网络]keras中的层
- keras中的层layer
- 编写keras层
- 模仿与学习MyBatis - 实现自己的ORM层框架
- Keras学习笔记02——常用的网络层
- keras加入lambda层时shape的问题
- Keras框架下LSTM的一种实现
- Java复习题
- Java练习求完数,求指导!
- Java并发编程
- 文章标题
- 讯飞语音的使用及常遇到的问题
- 实现自己的Keras层
- 常微分方程的近似计算和误差估计(2)
- Linux Centos 6.5网络启动不起来Bringing up interface eth0: Error:Connection activation failed:Device not man
- CCF-2017-9
- Rust : link.exe failed的bug
- JSP重点知识
- CentOS Linux解决Device eth0 does not seem to be present
- 【NOIP 2016提高组D1T2】 天天爱跑步 Running Maverick_Frank
- 类装饰器