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

目录

一.引言

二.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.mfbz.cn/a/14023.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用AI优化慢SQL,开发秒变DBA

“AI不会替代他们,但善用AI的人会” 慢 SQL 经常会让应用程序响应变慢,轻者影响用户体验,严重的时候可能会导致服务不可用。如果,每次遇到慢 SQL 都求助于 DBA,一方面效率很低,另一方面也会很没面子。所以…

聊聊如何通过APT+AST来实现AOP功能

前言 如果有使用过spring aop功能的小伙伴,应该都会知道spring aop主要是通过动态代理在运行时,对业务进行切面拦截操作。今天我们就来实现一下如何通过APTAST在编译期时实现AOP功能。不过在此之前先科普一下APT和AST相关内容 APT(注解处理…

openEuler-linux下部署zabbix-超级详细

一、准备工作 下载:zabbix包 地址:下载Zabbix 准备2台openEuler-linux虚拟机: linux-1:当服务器端 IP地址:192.168.100.100 修改hosts文件 [rootzbx ~]# vim /etc/hosts 192.168.100.100 zbx.xx.cn linux-2&…

[Java]JavaWeb开发中的MVC设计模式

一、有关Java Web与MVC设计模式 学习过基本Java Web开发的人都已经了解了如何编写基本的Servlet,如何编写jsp及如何更新浏览器中显示的内容。但是我们之前自己编写的应用一般存在无条理性,对于一个小型的网站这样的编写没有任何问题,但是一但…

ETL工具-pentaho企业实战部署

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

TinyOS 配置教程

系列文章目录 TinyOS 系列文章【一】:TinyOS 配置教程 TinyOS 系列文章【二】:Tossim 教程 文章目录 系列文章目录前言1. 安装1.1. 实验环境1.2. TinyOS基础工作1.3. TinyOS 的配置1.4. 安装 java1.5. 安装编译器 2. 测试仿真程序总结 前言 本文主要用…

kafka集群搭建

1.本次搭建涉及3台centos7主机,防火墙与selinux服务均关闭 2.主机参数如下表所示 nameIPportserviceA10.1.60.1122128、2888、3888、9092kafka、zookeeperB10.1.60.1142128、2888、3888、9092kafka、zookeeperC10.1.60.1152128、2888、3888、9092kafka、zookeeper…

让人悲观的国内ChatGPT的未来

最近关于ChatGPT的火爆已经不是简单的AI圈的事了,它已经席卷了所有的IT、媒体圈子,甚至是不同领域不同行业的人,只要你还对于变化与AI有一定的了解,那我相信你一定能知道ChatGPT是什么了。ChatGPT在某种程度上已经是相当于AGI通用…

图论-匈牙利算法学习

本文讲述的是匈牙利算法,即图论中寻找最大匹配的算法。解决的问题是从二分图中找到尽量多的匹配。 原题-华为-HJ28 素数伴侣 描述 题目描述 若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用…

【已解决】SpringBoot 工程 war包服务部署与调用测试

1.开发环境:IDEA,JDK1.8 2.服务打包类型: war包 3.war包部署环境:Linux系统,tomcat服务器,端口号:8081 4.war包部署位置:tomcat-8081/webapps/temp.war 5.服务名为:t…

瑞吉外卖项目——瑞吉外卖

软件开发整体介绍 软件开发流程 需求分析:产品原型、需求规格说明书 设计:产品文档、UI界面设计、概要设计、详细设计、数据库设计 编码:项目代码、单元测试 测试:测试用例、测试报告 上线运维:软件环境安装、配置…

python-day6(补充四:私有属性与函数)

私有属性与函数 私有属性与函数的用途如何定义私有属性与函数如何访问私有属性与函数 私有属性与函数的用途 在面向对象的封装中,私有的属性与函数其根本目的是防止它们在类的外部被使用,python中主要通过命名来进行区分。 把可能使用到的东西封装起来…

从零基础到条码高手:傻瓜式操作,告别excel、AI和PS的烦恼

条形码是一种用于商品识别、库存管理等方面的编码标识系统,它是通过将数字和字符以特定的图案排列组合起来,从而形成一组能被机器扫描和识别的条纹图案。 通常情况下,条形码的生成可以分为如下几个步骤: 1、编号:首先…

数据可视化工具汇总:数字孪生产品的得力助手

数字孪生技术是一项快速发展的新兴技术,已经在许多领域得到广泛应用。数字孪生技术不仅可以提供完整的虚拟模型,还可以模拟物理系统的行为。在数字孪生技术的推动下,越来越多的数字孪生产品开始涌现出来,为不同的领域提供支持和解…

如何通过FAQ页面减轻客户支持压力,提高工作效率?

作为现代企业不可或缺的一部分,客户支持服务是为客户提供解决方案、回答问题和解决技术难题的关键部分。无论是产品管理还是销售环节,客户支持都是重要的一环。然而,有效地处理技术支持问题和客户请求并不容易。卓越的客户支持需要组织结构&a…

excle表格打印相关问题

ps:无论是打印word,还是打印excel, 最后最好都保存成pdf,再打印。 ps:无论是打印word,还是打印excel, 最后最好都保存成pdf,再打印。 ps:无论是打印word,还是打印excel, 最后最好都保存成pdf,再打印。 …

ThreadLocal InheritableThreadLocal TransmittableThreadLocal的使用以及原理

ThreadLocal 每个线程向ThreadLocal设置值&#xff0c;再取值&#xff0c;实现线程之间的隔离 public class ThreadLocalCase1 {private static ThreadLocal<Integer> threadLocal new ThreadLocal<>();public static void main(String[] args) {Random random …

浅析提高倾斜摄影超大场景的三维模型轻量化的数据质量关键技术

浅析提高倾斜摄影超大场景的三维模型轻量化的数据质量关键技术 倾斜摄影超大场景的三维模型轻量化的质量关键技术主要包括&#xff1a; 1、保持数据精度。在进行轻量化处理时&#xff0c;必须确保数据的精度不受损失&#xff0c;否则会影响后续分析和应用方案。因此&#xff0…

【Leetcode -剑指Offer 22.链表中倒数第k个结点 -203.移除链表元素】

Leetcode Leetcode -剑指Offer 22.链表中倒数第k个结点Leetcode -203.移除链表元素 Leetcode -剑指Offer 22.链表中倒数第k个结点 题目&#xff1a;输入一个链表&#xff0c;输出该链表中倒数第k个节点。为了符合大多数人的习惯&#xff0c;本题从1开始计数&#xff0c;即链表…

DAY829

学习目标&#xff1a;成就上瘾&#xff0c;学到欲罢不能 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 暴力英语&#xff1a;背单词150个&#xff0c;背《死亡诗社》经典语段&#xff0c;抄写…
最新文章