Keras自定义实现带masking的meanpooling层方式


Posted in Python onJune 16, 2020

Keras确实是一大神器,代码可以写得非常简洁,但是最近在写LSTM和DeepFM的时候,遇到了一个问题:样本的长度不一样。对不定长序列的一种预处理方法是,首先对数据进行padding补0,然后引入keras的Masking层,它能自动对0值进行过滤。

问题在于keras的某些层不支持Masking层处理过的输入数据,例如Flatten、AveragePooling1D等等,而其中meanpooling是我需要的一个运算。例如LSTM对每一个序列的输出长度都等于该序列的长度,那么均值运算就只应该除以序列长度,而不是padding后的最长长度。

例如下面这个 3x4 大小的张量,经过补零padding的。我希望做axis=1的meanpooling,则第一行应该是 (10+20)/2,第二行应该是 (10+20+30)/3,第三行应该是 (10+20+30+40)/4。

Keras自定义实现带masking的meanpooling层方式

Keras如何自定义层

在 Keras2.0 版本中(如果你使用的是旧版本请更新),自定义一个层的方法参考这里。具体地,你只要实现三个方法即可。

build(input_shape) : 这是你定义层参数的地方。这个方法必须设self.built = True,可以通过调用super([Layer], self).build()完成。如果这个层没有需要训练的参数,可以不定义。

call(x) : 这里是编写层的功能逻辑的地方。你只需要关注传入call的第一个参数:输入张量,除非你希望你的层支持masking。

compute_output_shape(input_shape) : 如果你的层更改了输入张量的形状,你应该在这里定义形状变化的逻辑,这让Keras能够自动推断各层的形状。

下面是一个简单的例子:

from keras import backend as K
from keras.engine.topology import Layer
import numpy as np

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 somewhere!

 def call(self, x):
 return K.dot(x, self.kernel)

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

Keras自定义层如何允许masking

观察了一些支持masking的层,发现他们对masking的支持体现在两方面。

在 __init__ 方法中设置 supports_masking=True。

实现一个compute_mask方法,用于将mask传到下一层。

部分层会在call中调用传入的mask。

自定义实现带masking的meanpooling

假设输入是3d的。首先,在__init__方法中设置self.supports_masking = True,然后在call中实现相应的计算。

from keras import backend as K
from keras.engine.topology import Layer
import tensorflow as tf

class MyMeanPool(Layer):
 def __init__(self, axis, **kwargs):
 self.supports_masking = True
 self.axis = axis
 super(MyMeanPool, self).__init__(**kwargs)

 def compute_mask(self, input, input_mask=None):
 # need not to pass the mask to next layers
 return None

 def call(self, x, mask=None):
 if mask is not None:
 mask = K.repeat(mask, x.shape[-1])
 mask = tf.transpose(mask, [0,2,1])
 mask = K.cast(mask, K.floatx())
 x = x * mask
 return K.sum(x, axis=self.axis) / K.sum(mask, axis=self.axis)
 else:
 return K.mean(x, axis=self.axis)

 def compute_output_shape(self, input_shape):
 output_shape = []
 for i in range(len(input_shape)):
 if i!=self.axis:
 output_shape.append(input_shape[i])
 return tuple(output_shape)

使用举例:

from keras.layers import Input, Masking
from keras.models import Model
from MyMeanPooling import MyMeanPool

data = [[[10,10],[0, 0 ],[0, 0 ],[0, 0 ]],
 [[10,10],[20,20],[0, 0 ],[0, 0 ]],
 [[10,10],[20,20],[30,30],[0, 0 ]],
 [[10,10],[20,20],[30,30],[40,40]]]

A = Input(shape=[4,2]) # None * 4 * 2
mA = Masking()(A)
out = MyMeanPool(axis=1)(mA)

model = Model(inputs=[A], outputs=[out])

print model.summary()
print model.predict(data)

结果如下,每一行对应一个样本的结果,例如第一个样本只有第一个时刻有值,输出结果是[10. 10. ],是正确的。

[[10. 10.]
 [15. 15.]
 [20. 20.]
 [25. 25.]]

在DeepFM中,每个样本都是由ID构成的,多值field往往会导致样本长度不一的情况,例如interest这样的field,同一个样本可能在该field中有多项取值,毕竟每个人的兴趣点不止一项。

采取padding的方法将每个field的特征补长到最长的长度,则数据尺寸是 [batch_size, max_timestep],经过Embedding为每个样本的每个特征ID配一个latent vector,数据尺寸将变为 [batch_size, max_timestep,latent_dim]。

我们希望每一个field的Embedding之后的尺寸为[batch_size, latent_dim],然后进行concat操作横向拼接,所以这里就可以使用自定义的MeanPool层了。希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Win7上搭建Cocos2d-x 3.1.1开发环境
Jul 03 Python
python获取文件版本信息、公司名和产品名的方法
Oct 05 Python
详解python3实现的web端json通信协议
Dec 29 Python
python学生信息管理系统(初级版)
Oct 17 Python
python_opencv用线段画封闭矩形的实例
Dec 05 Python
Django使用AJAX调用自己写的API接口的方法
Mar 06 Python
Python对ElasticSearch获取数据及操作
Apr 24 Python
python基于SMTP协议发送邮件
May 31 Python
python实现简易版学生成绩管理系统
Jun 22 Python
如何用Matplotlib 画三维图的示例代码
Jul 28 Python
PyCharm vs VSCode,作为python开发者,你更倾向哪种IDE呢?
Aug 17 Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
Feb 26 Python
浅谈keras 的抽象后端(from keras import backend as K)
Jun 16 #Python
记录模型训练时loss值的变化情况
Jun 16 #Python
python实现批量转换图片为黑白
Jun 16 #Python
在keras中实现查看其训练loss值
Jun 16 #Python
安装python3.7编译器后如何正确安装opnecv的方法详解
Jun 16 #Python
Keras在训练期间可视化训练误差和测试误差实例
Jun 16 #Python
如何在Windows中安装多个python解释器
Jun 16 #Python
You might like
php短域名转换为实际域名函数
2011/01/17 PHP
PHP中设置一个严格30分钟过期Session面试题的4种答案
2014/07/30 PHP
CodeIgniter读写分离实现方法详解
2016/01/20 PHP
PHP自定义多进制的方法
2016/11/03 PHP
设置iframe的document.designMode后仅Firefox中其body.innerHTML为br
2012/02/27 Javascript
JavaScript字符串String和Array操作的有趣方法
2012/12/18 Javascript
原生JavaScript生成GUID的实现示例
2014/09/05 Javascript
node.js中的fs.chmodSync方法使用说明
2014/12/18 Javascript
有关Promises异步问题详解
2015/11/13 Javascript
jQuery插件支持同一页面被多次调用
2016/02/14 Javascript
jquery设置表单元素为不可用的简单代码
2016/07/04 Javascript
JavaScript实战之菜单特效
2016/08/16 Javascript
JavaScript实现横线提示输入验证码随输入验证码输入消失的方法
2016/09/24 Javascript
Vuex2.0+Vue2.0构建备忘录应用实践
2016/11/30 Javascript
简单谈谈gulp-changed插件
2017/02/21 Javascript
Cookies 和 Session的详解及区别
2017/04/21 Javascript
理解 Node.js 事件驱动机制的原理
2017/08/16 Javascript
cocos creator Touch事件应用(触控选择多个子节点的实例)
2017/09/10 Javascript
VUE组件中的 Drawer 抽屉实现代码
2019/08/06 Javascript
vue 动态添加class,三个以上的条件做判断方式
2020/11/02 Javascript
javascript实现简单页面倒计时
2021/03/02 Javascript
[02:22]完美世界DOTA2联赛PWL S3 集锦第一期
2020/12/15 DOTA
Python实现LRU算法的2种方法
2015/06/24 Python
Python数据结构与算法之图结构(Graph)实例分析
2017/09/05 Python
Python实现自定义顺序、排列写入数据到Excel的方法
2018/04/23 Python
python自动化测试之如何解析excel文件
2019/06/27 Python
Django 接收Post请求数据,并保存到数据库的实现方法
2019/07/12 Python
如何使用Python多线程测试并发漏洞
2019/12/18 Python
flask框架url与重定向操作实例详解
2020/01/25 Python
TensorFlow实现指数衰减学习率的方法
2020/02/05 Python
CSS3 二级导航菜单的制作的示例
2018/04/02 HTML / CSS
使用html2canvas实现浏览器截图的示例代码
2018/01/26 HTML / CSS
H&M美国官网:欧洲最大的服饰零售商
2016/09/07 全球购物
世界上最大的罕见唱片、CD和音乐纪念品网上商店:991.com
2018/05/03 全球购物
《桃花心木》教学反思
2014/02/17 职场文书
幼儿园三八妇女节活动总结
2015/02/06 职场文书