深度学习 - 43.SeNET、Bilinear Interaction 实现特征交叉 By Keras

news2024/12/26 10:36:50

目录

一.引言

二.SENET Layer

1.简介

2.Keras 实现

2.1 Init Function

2.2 Build Function

2.3 Call Function

2.4 Test Main Function

2.5 完整代码

三.BiLinear Intercation Layer

1.简介

2.Keras 实现

2.1 Init Function

2.2 Build Function

2.3 Call Function

2.4 Test Main Function

2.5 完整代码

四.总结


一.引言

上一篇文章我们对 FiBiNet 网络做了全面的了解,其引入 SENET 与 BiLinear Interaction 实现特征交叉,实验表明 FiBiNet 在浅层网络效果优于 FM、FFM,在深层网络效果优于 DeepFm、XdeepFm。本文用 kears 实现基本的 SENET Layer 与 Bilinear Interaction Layer。

二.SENET Layer

1.简介

SENet 全称为 Squeeze-and-Excitation Networks, 可翻译为压缩与激励网络。

实现流程:

AvgPool 平均池化 => FC + σ 全连接激活 => FC + σ 全连接激活 => Multiply 加权 

这里第一个激活函数 σ 为 ReLU,第二个激活函数有的使用 Sigmoid 有的使用 ReLU。

2.Keras 实现

2.1 Init Function

    def __init__(self, reduction_ratio=3, **kwargs):
        self.field_size = None
        self.embedding_size = None
        self.dense1 = None
        self.dense2 = None
        self.reduction_ratio = reduction_ratio

        super(SETNetLayer, self).__init__(**kwargs)

初始化函数主要定义 SENET 需要的变量,主要是 Field 数量,Embedding 嵌入维度以及 Squeeze 挤压和 Excitation 激发对应的两个 Full Connect 全连接 Dense 层以及对应的 Squeeze 参数 reduction_ratio。

2.2 Build Function

    def build(self, input_shape):
        self.field_size, self.embedding_size = input_shape
        reduction_size = max(1, self.field_size // self.reduction_ratio)

        self.dense1 = Dense(reduction_size, activation='relu', kernel_initializer=glorot_normal_initializer)
        self.dense2 = Dense(self.field_size, activation='sigmoid', kernel_initializer=glorot_normal_initializer)

        super(SETNetLayer, self).build(input_shape)

这里没有调用 add_weight 方法初始化参数矩阵,直接使用 layer 层下的 Dense 层初始化。

2.3 Call Function

    def call(self, inputs, training=None, **kwargs):
        # inputs = F x K
        mean_pooling = tf.expand_dims(tf.reduce_mean(inputs, axis=-1), axis=0)  # 1 x F
        compression = self.dense1(mean_pooling)  # 1 x reduction
        reconstruction = self.dense2(compression)  # 1 x F
        add_weight = tf.squeeze(tf.multiply(inputs, tf.expand_dims(reconstruction, axis=2)))  # F x K

        return add_weight

原始维度为 FxK,F 为 Field_size、K 为 Embedding_dim 输入输出,加权后输出维度仍然为 FxK。

2.4 Test Main Function

if __name__ == '__main__':
    # 数据准备
    F = 6  # Field 数量
    K = 8  # 特征维度
    samples = np.ones(shape=(F, K))
    seNetLayer = SETNetLayer()
    output = seNetLayer(samples)
    print(output)

实际场景同可以通过引入 SENET 达到动态更新 Field 重要性的目的。 

 

2.5 完整代码

import numpy as np
import tensorflow as tf
from tensorflow.python.keras.layers import *
from tensorflow.keras.layers import Layer
from tensorflow.python.ops.init_ops import glorot_normal_initializer


class SETNetLayer(Layer):

    def __init__(self, reduction_ratio=3, **kwargs):
        self.field_size = None
        self.embedding_size = None
        self.dense1 = None
        self.dense2 = None
        self.reduction_ratio = reduction_ratio

        super(SETNetLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.field_size, self.embedding_size = input_shape
        reduction_size = max(1, self.field_size // self.reduction_ratio)

        self.dense1 = Dense(reduction_size, activation='relu', kernel_initializer=glorot_normal_initializer)
        self.dense2 = Dense(self.field_size, activation='sigmoid', kernel_initializer=glorot_normal_initializer)

        super(SETNetLayer, self).build(input_shape)

    def call(self, inputs, training=None, **kwargs):
        # inputs = F x K
        mean_pooling = tf.expand_dims(tf.reduce_mean(inputs, axis=-1), axis=0)  # 1 x F
        compression = self.dense1(mean_pooling)  # 1 x reduction
        reconstruction = self.dense2(compression)  # 1 x F
        add_weight = tf.squeeze(tf.multiply(inputs, tf.expand_dims(reconstruction, axis=2)))  # F x K

        return add_weight

    def compute_output_shape(self, input_shape):
        return input_shape


if __name__ == '__main__':
    # 数据准备
    F = 6  # Field 数量
    K = 8  # 特征维度
    samples = np.ones(shape=(F, K))
    seNetLayer = SETNetLayer()
    output = seNetLayer(samples)
    print(output)

三.BiLinear Intercation Layer

1.简介

BiLinear Inteaction Layer 引入参数交叉矩阵实现 i、j 特征之间的交互代替原有的内积或哈达玛积,其中共设计了三种模式:

- Filed All Type 

所有交叉特征共享一个 kxk 的参数矩阵

- Field Each Type

每个 Field 一个参数矩阵 Wi ∈ R kxk

- Field Interaction Type

每个交叉特征 i、j 一个参数矩阵 W i,j ∈ R kxk

 

2.Keras 实现

2.1 Init Function

    def __init__(self, biLinear_type='all', seed=1024, **kwargs):
        self.biLinear_type = biLinear_type
        self.seed = seed
        self.field_size = None
        self.embedding_size = None
        self.W = None
        self.W_list = None

        super(BiLinearInteraction, self).__init__(**kwargs)

biLinear_type 控制特征交互方式,Filed_size 为特征数量,Embedding_size 为嵌入维度,Filed-All-Type 场景下使用单一 W 参数矩阵,Field-Each-Type 和 Field-Interaction-Type 使用 W_list 多参数矩阵的形式,前者 W 个数为 Field 个,后者为 (F-1)·F / 2 个。

2.2 Build Function

    def build(self, input_shape):
        self.field_size, self.embedding_size = input_shape

        if self.biLinear_type == "all":
            self.W = self.add_weight(shape=(self.embedding_size, self.embedding_size),
                                     initializer=glorot_normal_initializer(seed=self.seed),
                                     name="biLinearWeight")
        elif self.biLinear_type == "each":
            self.W_list = [self.add_weight(shape=(self.embedding_size, self.embedding_size),
                                           initializer=glorot_normal_initializer(seed=self.seed),
                                           name="biLinearWeight" + str(i)) for i in range(self.field_size)]
        elif self.biLinear_type == "interaction":
            self.W_list = [self.add_weight(shape=(self.embedding_size, self.embedding_size),
                                           initializer=glorot_normal_initializer(seed=self.seed),
                                           name="biLinearWeight" + str(i) + '_' + str(j)) for i, j in
                           itertools.combinations(range(self.field_size), 2)]
        else:
            raise NotImplementedError

        super(BiLinearInteraction, self).build(input_shape)

根据 input_shape 解析得到 Field_size 和 Embedding_size,根据 biLinear_type 的不同,初始化不同的参数矩阵 W 与 W_list,itertools.combinations 方法用于生成所有 Filed 的组合。

2.3 Call Function

    def call(self, inputs, **kwargs):

        n = len(inputs)
        if self.biLinear_type == "all":
            # 所有特征交叉公用一个参数矩阵 W
            v_dots = [tf.tensordot(inputs[i], self.W, axes=(-1, 0)) for i in range(n)]  # F x K
            p = [tf.multiply(v_dots[i], inputs[j]) for i, j in itertools.combinations(range(n), 2)]  # (F-1)·F/2 x K
        elif self.biLinear_type == "each":
            # 每个特征一个参数矩阵 Wi
            v_dots = [tf.tensordot(inputs[i], self.W_list[i], axes=(-1, 0)) for i in range(n)]  # F x K
            p = [tf.multiply(v_dots[i], inputs[j]) for i, j in itertools.combinations(range(n), 2)]  # (F-1)·F/2 x K
        elif self.biLinear_type == "interaction":
            # 每一个组合特征 Vi-Vj 以及对应的 Wij
            p = [tf.multiply(tf.tensordot(v[0], w, axes=(-1, 0)), v[1])
                 for v, w in zip(itertools.combinations(inputs, 2), self.W_list)]  # (F-1)·F/2 x K
        else:
            raise NotImplementedError

        # (F-1)·F/2 x K
        _output = tf.reshape(p, shape=(-1, int(self.embedding_size)))
        return _output

分别执行内积与哈达玛积,区别是交互的 W 参数矩阵不同,这里与 SENET 不同,SENET 输入输出维度相同,BiLinear Interaction Layer 输入 F x K,输出 (F-1)·F / 2 x K,因为前者是对 Field 的交叉,后者是对每一个 FF 特征的交叉。

2.4 Test Main Function

if __name__ == '__main__':
    # 数据准备
    F = 4  # Field 数量
    K = 8  # 特征维度
    samples = np.ones(shape=(F, K))

    BiLinearLayer = BiLinearInteraction("interaction")
    output = BiLinearLayer(samples)
    print(output)

F = 4,K = 8,所以输出 6x8。 

2.5 完整代码

import itertools

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Layer
from tensorflow.python.ops.init_ops import glorot_normal_initializer


class BiLinearInteraction(Layer):

    def __init__(self, biLinear_type='interaction', seed=1024, **kwargs):
        self.biLinear_type = biLinear_type
        self.seed = seed
        self.field_size = None
        self.embedding_size = None
        self.W = None
        self.W_list = None

        super(BiLinearInteraction, self).__init__(**kwargs)

    def build(self, input_shape):
        self.field_size, self.embedding_size = input_shape

        if self.biLinear_type == "all":
            self.W = self.add_weight(shape=(self.embedding_size, self.embedding_size),
                                     initializer=glorot_normal_initializer(seed=self.seed),
                                     name="biLinearWeight")
        elif self.biLinear_type == "each":
            self.W_list = [self.add_weight(shape=(self.embedding_size, self.embedding_size),
                                           initializer=glorot_normal_initializer(seed=self.seed),
                                           name="biLinearWeight" + str(i)) for i in range(self.field_size)]
        elif self.biLinear_type == "interaction":
            self.W_list = [self.add_weight(shape=(self.embedding_size, self.embedding_size),
                                           initializer=glorot_normal_initializer(seed=self.seed),
                                           name="biLinearWeight" + str(i) + '_' + str(j)) for i, j in
                           itertools.combinations(range(self.field_size), 2)]
        else:
            raise NotImplementedError

        super(BiLinearInteraction, self).build(input_shape)

    def call(self, inputs, **kwargs):

        n = len(inputs)
        if self.biLinear_type == "all":
            # 所有特征交叉公用一个参数矩阵 W
            v_dots = [tf.tensordot(inputs[i], self.W, axes=(-1, 0)) for i in range(n)]  # F x K
            p = [tf.multiply(v_dots[i], inputs[j]) for i, j in itertools.combinations(range(n), 2)]  # (F-1)·F/2 x K
        elif self.biLinear_type == "each":
            # 每个特征一个参数矩阵 Wi
            v_dots = [tf.tensordot(inputs[i], self.W_list[i], axes=(-1, 0)) for i in range(n)]  # F x K
            p = [tf.multiply(v_dots[i], inputs[j]) for i, j in itertools.combinations(range(n), 2)]  # (F-1)·F/2 x K
        elif self.biLinear_type == "interaction":
            # 每一个组合特征 Vi-Vj 以及对应的 Wij
            p = [tf.multiply(tf.tensordot(v[0], w, axes=(-1, 0)), v[1])
                 for v, w in zip(itertools.combinations(inputs, 2), self.W_list)]  # (F-1)·F/2 x K
        else:
            raise NotImplementedError

        # (F-1)·F/2 x K
        _output = tf.reshape(p, shape=(-1, int(self.embedding_size)))
        return _output


if __name__ == '__main__':
    # 数据准备
    F = 4  # Field 数量
    K = 8  # 特征维度
    samples = np.ones(shape=(F, K))

    BiLinearLayer = BiLinearInteraction("interaction")
    output = BiLinearLayer(samples)
    print(output)

四.总结

如果我们去掉 SENET 层和双线性交互层,我们的浅 FiBiNET 和深 FiBiNET 将降级为 FM 和FNN,为了进一步提高性能,将上述浅层模型与 DNN 结合得到 FiBiNet 由于 DeepFm 和 XdeepFm 等深层模型。上图为 FiBiNet 模型架构,其中绿框部分为 SENET Layer,红框部门为 Bilinear-Interaction Layer,剩下的 Combination Layer 和 DNN 的构建比较基础,有兴趣的同学可以自己实现 FiBiNet。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/458740.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

〖ChatGPT实践指南 - 零基础扫盲篇③〗- 开始使用 ChatGPT 并访问 OpenAI 获取 API Keys

文章目录 ⭐ 访问 ChatGPT 并登录⭐ OpenAI API keys 简介⭐ 获取 OpenAI 的 API keys 文件 请注意,该章节介绍的是如何使用 ChatGPT ,并通过登录ChatGPT后访问 OpenAI 获取 API Keys,并不涉及如何科学的注册 ChatGPT。 ⭐ 访问 ChatGPT 并登…

D. Mysterious Present(Codeforces Beta Round 4 (Div. 2 Only))

https://codeforces.com/contest/4/problem/D 题目大意 给定 n n n 个信封的长和宽,以及一张卡片的长和宽,要求选出最多的信封,并且这些信封的长和宽都比前面的信封要大,并且最小的信封能够装下这张卡片。输出这些信封的数量和…

VS项目常规属性

常规属性页(项目) 常规 目标平台 指定运行项目的平台。例如,Windows,Android或iOS。 在此处,值 Windows 10 表示项目面向通用 Windows 平台。此属性是在创建项目时设置的只读字段。 目标平台版本 指定用于生成项目…

基于html+css的图展示41

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

智慧园区数字化转型下的移动App发展

随着智慧城市的建设和智慧园区的崛起,智慧园区数字一体化建设成为园区发展的重心,当然数字转型离不开移动应用的整合服务。 在过去的几年中,智慧园区移动应用已经发展成为园区管理和服务的重要手段之一,为企业和员工提供了更加便…

OkHttp3源码解析 - 连接机制和缓存机制

系列文章目录 第一章 OkHttp3源码解析 - 请求流程 第二章 OkHttp3源码解析 - 拦截器 第三章 OkHttp3源码解析 - 连接机制和缓存机制 文章目录 系列文章目录前言一、连接机制1.1 创建连接1.2 连接池 二、缓存机制2.1 缓存策略2.2 缓存管理 彩蛋致谢 前言 本文基于okhttp3.12.1…

我的一些实战的漏洞挖掘过程(一)

最近挖到的漏洞,在这里分享一下,有些信息比较敏感就打码处理,目标网站都换为target.com 反射xss漏洞挖掘 跨站脚本攻击(Cross-site Scripting,XSS)是一种常见的Web安全漏洞,攻击者通过在Web应…

Windows上使用gcc

安装 下载x86_64-7.3.0-release-win32-seh-rt_v5-rev0 安装包,解压,将对应解压路径下的bin加入环境变量path,将mingw32-make.exe 改名make.exe,使用gcc同样可以在Windows上生成.o文件和.a文件,也可以生成.lib文件 te…

AI思维导图来了,让活动策划更加简单!

每当有活动的时候,都会让策划的小伙伴绞尽脑汁! ProcessOn一直致力于提升大家的办公效率。新增的AI功能,可以帮助我们一键生成思维导图、流程图。让一切变得更加简单。 没有灵感?没有关系。不知道怎么做,没有关系&a…

五种原因导致孩子易患口腔溃疡,专家为你一一支招

最近,常接到电话咨询:疫情期间,孩子宅在家,反复起“口疮”怎么办? 这里说到的“口疮”,即是一种常见的口腔黏膜疾病——口腔溃疡。口腔溃疡的发病率较高,不仅成年人可能患病,不少儿…

使用PyTorch和Flower 进行联邦学习

本文将介绍如何使用 Flower 构建现有机器学习工作的联邦学习版本。我们将使用 PyTorch 在 CIFAR-10 数据集上训练卷积神经网络,然后将展示如何修改训练代码以联邦的方式运行训练。 什么是联邦学习? 我们将在这篇文章中区分两种主要方法:集中…

数据库的概念?怎么在linux内安装数据库?怎么使用?

目录 一、概念 二、mysql安装及设置 1.安装mysql 2.数据库服务启动停止 三、数据库基本操作 1、数据库的登录及退出 2、数据表的操作 3、mysql查询操作 一、概念 数据库:是存放数据的仓库,它是一个按数据结构来存储和管理数据的计算机软件系统。数据库管理…

BM38-在二叉树中找到两个节点的最近公共祖先

题目 给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。 数据范围:树上节点数满足 1≤n≤10^5 , 节点值val满足区间 [0,n) 要求:时间复杂度 O(n) 注:本题保证二叉树…

深入理解Javascript事件处理机制

深入理解javascript事件处理机制 前言 在开发web应用程序时,事件处理机制是javascript中至关重要的一部分。许多高级特性,如事件冒泡、事件捕获和事件委托,都是通过事件处理来实现的。熟练掌握这些技术可以帮助我们更好地组织代码、提高代码…

腾讯多媒体实验室画质增强技术的前沿应用

全真互联时代,音视频技术内核不断更新迭代,LiveVideoStackCon 2022 北京站邀请到腾讯多媒体实验室视频技术研发负责人——夏珍,与大家分享画质增强技术的一些前沿探索和应用研究,在经典影像中非常重要的画质提升技术人脸修复和去压…

告别web.xml映射Servlet、Filter、Listener,解锁注解新方式开发

编译软件:IntelliJ IDEA 2019.2.4 x64 操作系统:win10 x64 位 家庭版 服务器软件:apache-tomcat-8.5.27 目录 一. Servlet、Filter、Listener的注解方式是什么?二. 为什么要使用Servlet、Filter、Listener的注解方式?三…

【架构】互联网应用开发架构演进历程

文章目录 一、背景二、技术架构演进史三、架构演进一: 早期雏形四、架构演进二: 数据库开发(LAMP特长)五、架构演进三: javaweb的雏形六、架构演进四: javaweb的集群发展​七、架构演进五: javaweb的分布式发展八、架构演进六: javaweb的微服务发展​8.1…

开源 AI 辅助编程工具 AutoDev 现已上架 Jetbrains 插件市场

我们非常高兴地宣布 AutoDev v0.2.0 的发布!AutoDev 是一款强大的 AI 辅助编程工具,可以与 Jetbrains 系列 IDE 无缝集成(VS Code 支持正在开发中)。通过与需求管理系统(如 Github Issue 等)直接对接&#…

WPF教程(八)--数据绑定(1)--基础概述

使用WPF可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能。WPF的数据绑定跟Winform与ASP.NET中的数据绑定功能类似,但也有所不同,在 WPF中以通过后台代码绑定、前台XAML中进行绑定,或者两者组合的方式进行数据绑定。…

用python制作剪刀石头布的小游戏

1 问题 在python中我们学习了条件语句,那么我们是否可以通过python中条件判断的功能来写出可以判断胜负的剪刀石头布小游戏呢? 2 方法 导入随机函数,保证胜负的随机性 设置对应数值,写好判断输赢的条件语句 运行并查看结果 代码清单 1 impor…