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中引用与复制用法实例分析
Jun 04 Python
python批量读取txt文件为DataFrame的方法
Apr 03 Python
对TensorFlow的assign赋值用法详解
Jul 30 Python
django小技巧之html模板中调用对象属性或对象的方法
Nov 30 Python
Flask之请求钩子的实现
Dec 23 Python
解决python ogr shp字段写入中文乱码的问题
Dec 31 Python
python之验证码生成(gvcode与captcha)
Jan 02 Python
python3正则提取字符串里的中文实例
Jan 31 Python
Python定时器线程池原理详解
Feb 26 Python
Python内置函数locals和globals对比
Apr 28 Python
PyCharm2020最新激活码+激活码补丁(亲测最新版PyCharm2020.2激活成功)
Nov 25 Python
详解Python flask的前后端交互
Mar 31 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
re0第二季蕾姆被制作组打入冷宫!艾米莉亚女主扶正,原因唏嘘
2020/04/02 日漫
ThinkPHP中Common/common.php文件常用函数功能分析
2016/05/20 PHP
phpcms中的评论样式修改方法
2016/10/21 PHP
php上传excel表格并获取数据
2017/04/27 PHP
Json和Jsonp理论实例代码详解
2013/11/15 Javascript
js使用for循环及if语句判断多个一样的name
2014/09/09 Javascript
举例详解JavaScript中Promise的使用
2015/06/24 Javascript
Bootstrap页面缩小变形的快速解决办法
2017/02/03 Javascript
浅谈vue项目用到的mock数据接口的两种方式
2019/10/09 Javascript
js实现小星星游戏
2020/03/23 Javascript
vue2.0实现列表数据增加和删除
2020/06/17 Javascript
vue 需求 data中的数据之间的调用操作
2020/08/05 Javascript
解决vant的Toast组件时提示not defined的问题
2020/11/11 Javascript
[01:00] DOTA2英雄背景故事第五期之重力引力法则谜团
2020/07/16 DOTA
Python调用SQLPlus来操作和解析Oracle数据库的方法
2016/04/09 Python
pytorch使用Variable实现线性回归
2019/05/21 Python
Python3.6+Django2.0以上 xadmin站点的配置和使用教程图解
2019/06/04 Python
Python3+Requests+Excel完整接口自动化测试框架的实现
2019/10/11 Python
DJango的创建和使用详解(默认数据库sqlite3)
2019/11/18 Python
Python如何根据时间序列数据作图
2020/05/12 Python
django-orm F对象的使用 按照两个字段的和,乘积排序实例
2020/05/18 Python
使用Keras中的ImageDataGenerator进行批次读图方式
2020/06/17 Python
python软件都是免费的吗
2020/06/18 Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
2020/11/25 Python
Python截图并保存的具体实例
2021/01/14 Python
Python使用tkinter制作在线翻译软件
2021/02/22 Python
职业教育毕业生求职信
2013/11/09 职场文书
汽车技术服务与营销专业推荐信
2013/11/29 职场文书
十佳护士先进事迹
2014/05/08 职场文书
小学假期安全广播稿
2014/09/28 职场文书
2014年党员个人剖析材料
2014/10/08 职场文书
公务员党的群众路线教育实践活动学习心得体会
2014/10/30 职场文书
2016医师资格考试考生诚信考试承诺书
2016/03/25 职场文书
如何写好闭幕词
2019/04/02 职场文书
实战Python爬虫爬取酷我音乐
2022/04/11 Python
Spring中bean集合注入的方法详解
2022/07/07 Java/Android