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简单猜数游戏实例
Jul 09 Python
python模拟事件触发机制详解
Jan 19 Python
Python常见字符串操作函数小结【split()、join()、strip()】
Feb 02 Python
设置python3为默认python的方法
Oct 31 Python
详解python 爬取12306验证码
May 10 Python
Python+Pyqt实现简单GUI电子时钟
Feb 22 Python
如何定义TensorFlow输入节点
Jan 23 Python
TensorFlow MNIST手写数据集的实现方法
Feb 05 Python
pandas to_excel 添加颜色操作
Jul 14 Python
Python连接mysql数据库及简单增删改查操作示例代码
Aug 03 Python
python用分数表示矩阵的方法实例
Jan 11 Python
PyMongo 查询数据的实现
Jun 28 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边学边教》(02.Apache+PHP环境配置――上篇)
2006/12/13 PHP
php将数组存储为文本文件方法汇总
2015/10/28 PHP
CodeIgniter针对数据库的连接、配置及使用方法
2016/03/03 PHP
PHP二进制与字符串之间的相互转换教程
2016/10/14 PHP
php 数组处理函数extract详解及实例代码
2016/11/23 PHP
Laravel框架使用monolog_mysql实现将系统日志信息保存到mysql数据库的方法
2018/08/16 PHP
浅析PHP 中move_uploaded_file 上传中文文件名失败
2019/04/17 PHP
document.designMode的功能与使用方法介绍
2007/11/22 Javascript
jquery中this的使用说明
2010/09/06 Javascript
High Performance JavaScript(高性能JavaScript)读书笔记分析
2011/05/05 Javascript
JavaScript实现的简单幂函数实例
2015/04/17 Javascript
js方法数据验证的简单实例
2016/09/17 Javascript
easyui messager alert 三秒后自动关闭提示的实例
2016/11/07 Javascript
jQuery Ajax File Upload实例源码
2016/12/12 Javascript
详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
2017/08/30 Javascript
react-native DatePicker日期选择组件的实现代码
2017/09/12 Javascript
详解nodejs 配置文件处理方案
2019/01/02 NodeJs
微信小程序实现的动态设置导航栏标题功能示例
2019/01/31 Javascript
解决微信授权成功后点击按返回键出现空白页和报错的问题
2020/06/08 Javascript
详解Python编程中包的概念与管理
2015/10/16 Python
关于Python数据结构中字典的心得
2017/12/04 Python
Python中static相关知识小结
2018/01/02 Python
Python语言描述连续子数组的最大和
2018/01/04 Python
Django + Uwsgi + Nginx 实现生产环境部署的方法
2018/06/20 Python
Python学习笔记之自定义函数用法详解
2019/06/08 Python
Python虚拟环境的创建和包下载过程分析
2020/06/19 Python
使用layui框架实现点击左侧导航切换右侧内容且右侧选项卡跟随变化的效果
2020/11/10 HTML / CSS
Free People中国官网:波西米亚风格女装服饰
2016/08/30 全球购物
Hunkemöller瑞士网上商店:欧洲最大的内衣品牌之一
2018/12/03 全球购物
ALDO美国官网:加拿大女鞋品牌
2018/12/28 全球购物
Shopee越南:东南亚与台湾电商平台
2019/02/03 全球购物
公司财务工作总结的自我评价
2013/11/23 职场文书
后勤工作职责
2013/12/22 职场文书
绿化先进工作者事迹材料
2014/01/30 职场文书
2014年大学庆元旦迎新年活动方案
2014/03/09 职场文书
HTML+CSS 实现顶部导航栏菜单制作
2021/06/03 HTML / CSS