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 相关文章推荐
纯Python开发的nosql数据库CodernityDB介绍和使用实例
Oct 23 Python
python服务器与android客户端socket通信实例
Nov 12 Python
python类和函数中使用静态变量的方法
May 09 Python
Python中Continue语句的用法的举例详解
May 14 Python
Python进阶篇之字典操作总结
Nov 16 Python
Python中生成Epoch的方法
Apr 26 Python
Python列表推导式、字典推导式与集合推导式用法实例分析
Feb 07 Python
python3实现SMTP发送邮件详细教程
Jun 19 Python
基于DataFrame改变列类型的方法
Jul 25 Python
python 求一个列表中所有元素的乘积实例
Jun 11 Python
django实现用户注册实例讲解
Oct 30 Python
Python+DeOldify实现老照片上色功能
Jun 21 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之Smarty入门
2007/01/04 PHP
php继承的一个应用
2011/09/06 PHP
php中用memcached实现页面防刷新功能
2014/08/19 PHP
跟我学Laravel之快速入门
2014/10/15 PHP
PHP SPL标准库之文件操作(SplFileInfo和SplFileObject)实例
2015/05/11 PHP
popdiv
2006/07/14 Javascript
javascript 解决表单仍然提交即使监听处理函数返回false
2010/03/14 Javascript
解决jQuery插件tipswindown与hintbox冲突
2010/11/05 Javascript
ASP.NET jQuery 实例12 通过使用jQuery validation插件简单实现用户注册页面验证功能
2012/02/03 Javascript
基于jquery ajax 用户无刷新登录方法详解
2012/04/28 Javascript
深入理解JSON数据源格式
2014/01/10 Javascript
jquery实现图片随机排列的方法
2015/05/04 Javascript
用javascript实现自动输出网页文本
2015/07/30 Javascript
jQuery实现输入框邮箱内容自动补全与上下翻动显示效果【附demo源码下载】
2016/09/20 Javascript
jQuery实现页面滚动时智能浮动定位
2017/01/08 Javascript
利用jquery如何从json中读取数据追加到html中
2017/12/01 jQuery
解决vue项目报错webpackJsonp is not defined问题
2018/03/14 Javascript
js实现input密码框显示/隐藏功能
2020/09/10 Javascript
jQuery提示框插件SweetAlert用法分析
2019/08/05 jQuery
Openlayers实现地图的基本操作
2020/09/28 Javascript
[04:39]显微镜下的DOTA2第十三期—Pis卡尔个人秀
2014/04/04 DOTA
[01:07:19]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第一场
2018/04/06 DOTA
朴素贝叶斯算法的python实现方法
2014/11/18 Python
Python使用scrapy采集数据过程中放回下载过大页面的方法
2015/04/08 Python
python 读取文件并把矩阵转成numpy的两种方法
2019/02/12 Python
python加载自定义词典实例
2019/12/06 Python
pygame用blit()实现动画效果的示例代码
2020/05/28 Python
整理的15个非常有用的 HTML5 开发教程和速查手册
2011/10/18 HTML / CSS
英国二手iPhone、音乐、电影和游戏商店:musicMagpie
2018/10/26 全球购物
华为慧通笔试题
2016/04/22 面试题
弘扬雷锋精神演讲稿
2014/05/10 职场文书
感恩教育月活动总结
2014/07/07 职场文书
庆祝新中国成立65周年“向国旗敬礼”网上签名寄语
2014/09/27 职场文书
党的群众路线教育实践活动学习计划
2014/11/03 职场文书
银行文明优质服务培训心得体会
2016/01/09 职场文书
关于办理居住证的介绍信模板
2019/11/27 职场文书