深度学习 - 47.DIN 深度兴趣网络保姆级实现 By Keras

news2024/11/29 20:34:21

目录

一.引言

二.DIN 模型分析

1.Input 输入

2.Embedding & Concat 嵌入与合并

3.DIN 深度兴趣网络

4.MLP 全连接

三.DIN 模型实现

1.Input

2.DIN Layer 

2.1 init 初始化

2.2 build 构建

2.3 call 调用

3.Dice Layer

3.1 init 初始化

3.2 build 构建

3.3 call 调用

四.总结


一.引言

DIN 通过 Attention 机制软搜索用户历史序列中与当前商品匹配的行为,并做加权求和,除此之外引入了 DICE 激活,下面根据思路简易实现下 DIN 逻辑。

二.DIN 模型分析

1.Input 输入

特征包含 User Profile Features 用户基础特征、User Behaviors 用户历史行为、Candidate Ad 候选集广告以及 Context Features 上下文特征,Candidate Ad 包含了 Goods ID 商品、Shop ID 店铺以及 Cate ID 品类。

2.Embedding & Concat 嵌入与合并

所有特征都根据 id 获取对应的 Emd 嵌入随后 concat 合并,除了 User Behaviors 处 concat 的向量后续还有加权求和操作外,其余 Concat 的 Embedding 直接连接到 MLP 的第一个 FC layer 即全连接层作为输入。

3.DIN 深度兴趣网络

将 UserBehaviors Concat 的向量与 Candidate Concat 的向量通过 Activation Unit 的小 MLP 全连接层最后得到 Behavior - Candidate 对应的 Activation Weight 激活权重,然后将对应 Weight 与 Good 进行加权 sum pooling,随后和其他特征的 Embedding 一起加入 FC layer。

 

4.MLP 全连接

将原始 Concat 向量与 Attention 得到的向量一起送到最后的 MLP,激活函数为 PRule 或者 Dice,最后 Softmax 二分类得到对应的分数。

Tips:

本文代码主要以实现 DIN Attention 加权求和部分 With Dice 激活函数,这一部分的创新是论文的主要贡献,其他 Concat、MLP 全连接都是深度学习最常见的用法,这里不做过多讲解。可以看到DIN 是工程导向的,其出自阿里巴巴,逻辑清晰且易于部署上线,下面使用 keras 简单实现。

三.DIN 模型实现

1.Input

模拟用户行为序列 & 候选商品 ID 的输入数据,论文中还有 Shop Id、Cate Id 这里进行简化只取 Goods Id,多个 ID 的需要进行 Concat,有兴趣同学可自己实现。

def genSamples(batch_size=5, T=10, N=1000, seed=0):
    np.random.seed(seed)
    # 用户历史序列
    user_history = np.random.randint(0, N, size=(batch_size, T))
    # 候选 Item
    user_candidate = np.random.randint(0, N, size=(batch_size, 1))
    return user_history, user_candidate

这里使用 numpy 随机生成序列与候选商品 ID,batch_size 为批次大小,T- Times 代表序列长度,N 代表商品库大小。由于是模拟数据实现,这里 N、T、batch_size 的取值并不大。

    # 用户历史行为序列 && 候选商品 ID
    history, candidate = genSamples()

• 用户序列样式

[[684 559 629 192 835 763 707 359   9 723]
 [277 754 804 599  70 472 600 396 314 705]
 [486 551  87 174 600 849 677 537 845  72]]

• 对应商品样式

[[961]
 [265]
 [697]]

Tips:

实际场景下,高频低频用户的序列长度是不同的,为了保证模型能够正常训练推理,需要对过长的序列进行截断,例如选取近 30 日的最新的 100 个浏览商品,而对于过短的序列则需要进行填充,例如用户只有 80 个商品,则需要补充 20 个默认商品,这里最常见的就是为每个补充的商品补零,再到后面 Sum Pooling 的时候减少这些补充商品对用户 Embedding 的影响。

2.DIN Layer 

2.1 init 初始化

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 TruncatedNormal


# 根据用户历史行为 goods 的 id emd 与 candidate id emd 进行 Attention 并输出
class DINLayer(Layer):
    """
        Input
            - User History => [batch_size, T]
            - User Candidate => [batch_size, 1]
        Output
            - Sum Pooling => [batch_size, embedding_dim]
            - Concat => [batch_size, T x embedding_dim]
        Tips
            - T:Time history num
    """

    def __init__(self, embedding_dim=8, N=1000, **kwargs):
        self.N = N  # 商品库大小
        self.embedding_dim = embedding_dim  # 向量维度
        self.kernel = None  # 向量矩阵
        self.T = None  # 序列长度
        self.mask_value = 0  # 掩码
        self.activation = None  # 激活层
        self.weight = None  # 权重层
        self.weight_normalization = True  # 是否归一化权重
        self.pooling_mode = "sum"  # DIN 输出

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

N - 商品库大小,这里指全部 Goods 的数量

embedding_dim - 嵌入向量长度

kernel - Embedding 层用于获取对应 id embedding

T - Times 即序列长度

mask_value - 掩码,主要针对填充的补充向量

activation - Activation Unit 激活层参数

weight - Activation Unit 权重层参数

weight_normalization - 权重是否归一化,论文中表示不归一化可以强化与商品相似行为的权重

pooling_mode - 池化方式,不同 mode 下主要区别为输出向量维度不同

2.2 build 构建

    def build(self, input_shape):
        # 获取序列长度
        history_shape, candidate_shape = input_shape
        self.T = history_shape[1]
        # N x embedding_dim 的参数矩阵
        self.kernel = self.add_weight(name='kernel',
                                      shape=(self.N, self.embedding_dim),
                                      initializer=TruncatedNormal,
                                      trainable=True)

        # Activation Layer
        self.activation = Dense(36, activation=Dice(), name="activation")
        self.weight = Dense(1, activation='sigmoid', name="weight")

        super(DINLayer, self).build(input_shape)

kernel 维度为 [N, embedding_dim] 为每个 good 的嵌入向量,如果还有 Shop、Cate 等属性,则类似 kernel 的数量也会增加,相应的参数量也会增加。

activation 和 weight 主要是 Activation Unit 的权重,论文中隐层中神经元数量为 36,最后一层为 Linear(1) 输出 Activation Weight 激活权重。 

 

2.3 call 调用

这里实现 DIN 利用 Activation Unit 激活单元生成激活权重并执行加权求和,每一步输入输出的维度都会进行标注,方便大家理解 DIN 执行过程中维度的变化。

• 获取历史行为、候选商品 Emd

lookup 获取对应 ID 向量,这里也可以使用 Embedding Layer(goods) 的方式快速获取。

# 1.获取历史行为、候选集 Embedding
_history, _candidate = inputs
_history_emd = tf.nn.embedding_lookup(self.kernel, _history)  # [None, T] => [None, T, embedding_dim]
_candidate_emb = tf.nn.embedding_lookup(self.kernel, _candidate)  # [None, 1] => [None, 1, embedding_dim]

• 构造 Seq Mask

这里 mask_value = 0,主要针对序列长度不足进行补齐的向量计算 mask。

# 2.构造掩码 (None, 1, T)
mask = tf.reduce_mean(_history_emd, axis=-1)
seq_mask = tf.not_equal(mask, tf.constant(self.mask_value, dtype=mask.dtype))
seq_mask = tf.expand_dims(seq_mask, 1)

• 转换 candidate 维度

这里转换候选集 id 商品的维度主要是与历史行为对应的维度进行匹配,匹配后可以将候选集商品与每个历史 good 进行匹配计算。

# 3.转换 candidate 维度,与历史行为匹配 [None, 1, embedding_dim] => [None, T, embedding_dim]
candidates = tf.tile(_candidate_emb, [1, self.T, 1])

• Activation Unit Input

这一步主要实现 candidate 与 history 交互 为 Activation Unit 构造 Input,除了 history 与 候选商品的原始 embedding 向量外,论文中还增加了二者的 Out Product 外积作为 Activation Unit 的输入,也有示意图把外积这里换成了 ⊙、⊕ 等符号代表哈达玛积、对位相加、对位相减等等。按照论文的解释,除了两个原始向量保留原始信息外,这里一系列交互方式的引入为了增加更多显式知识协助建模从而得到更精确的激活权值。例如元素减可以更加显式的让模型学到两个向量是否相似,因为相似的向量相减为 0。实际场景下大家可以尝试不同的交互方式,以供 Activation Unit 更好的学习激活参数。

# 4.通过 candidates history 进行交互 [None, T, embedding_dim] => [None, T, embedding_dim x A]  A:为交互类型数量
din_input = tf.concat([candidates, _history_emd, candidates + _history_emd, candidates * _history_emd], axis=-1)

• Activation Weight Output

将上一步构造的 input 传给 Activation Unit 获取对应 good 与候选商品的激活权重,注意这里原始 Embedding 维度为 K,如果增加 A 种交互方式,则输入向量维度为 A x K。

# 5.构建 DNN 得到权重 [None, T, embedding_dim x A] => [None, T, 36] => [None, T, 1] => [None, 1, T] 代表每个序列行为的权重
din_deep = self.activation(din_input)
din_out = self.weight(din_deep)
din_out = tf.transpose(din_out, (0, 2, 1))

• Padding By Mask

如果使用 softmax 进行参数归一化,则 padding 值为 -2 ** 32 + 1,因为这个 exp(x) 指数函数在这个点会获得一个很小的数,从而填充向量的权重近似为0,不会对用户向量 U(V) 造成影响,如果不进行 softmax 归一化,则直接对应位置为 0。

# 6.根据 mask 与 padding 值,得到有意义的加权平均 [None, 1, T] => [None, 1, T]
if self.weight_normalization:
    # 乘一个很小的数 softmax 会得到近似0,从而忽略补充向量对模型的贡献
    paddings = tf.ones_like(din_out) * (-2 ** 32 + 1)
else:
    # 权重不使用 softmax 归一化默认使用0填充
    paddings = tf.zeros_like(din_out)
din_out = tf.where(seq_mask, din_out, paddings)

 

• Weight Normalization

是否进行 Softmax 归一化权重,论文中阿里巴巴团队认为 w 在某种程度上可以视为激活用户兴趣强度的近似值,所以尝试采用不归一化的方式,这里大家可以根据自己场景尝试效果。

# 7.权重归一化 [None, 1, T]
if self.weight_normalization:
    din_out = tf.nn.softmax(din_out, axis=2)

• Attention Output

上面得到了每个 Good 对应的 Activation Weight,最后执行 SUM Pooling 得到传给 MLP 的一部分 Input。当前示例 T = 10,embedding_dim = 8。

# 8.加权得到 Attention 结果
if self.pooling_mode == "sum":
    # [None, 1, T] x [None, T, embedding_dim] => [None, 1, embedding_dim] 这里使用矩阵乘法
    attention_output = tf.matmul(din_out, _history_emd)
    attention_output = tf.squeeze(attention_output)
else:
    # [None, 1, T] => [None, T, 1]
    din_out = tf.reshape(din_out, [-1, self.T, 1])
    # [B, T, H] * [B, T, 1] => [B, T, H] 此处涉及到Tensor乘法广播机制
    attention_output = _history_emd * din_out
    attention_output = tf.reshape(attention_output, [-1, self.T * self.embedding_dim])

• DIN Last Output

if __name__ == '__main__':
    # 用户历史行为序列 && 候选商品 ID
    history, candidate = genSamples()
    DIN = DINLayer()
    output = DIN((history, candidate))
    print(output)

 mode == "sum" 直接 matmul 矩阵乘法得到 [None, embedding_dim] 的小向量:

mode == "other"  通过哈达玛积计算得到 [None,embedding_dim x T] 的长向量,其中 T 为行为序列长度:

 

3.Dice Layer

Dice 激活函数上一篇 DIN 论文简介中我们已经给出,下面通过 Layer 实现 Dice 激活。

 

3.1 init 初始化

Dice Layer 构造比较简单,参数主要有是否 BN 以及一个调节因此 α。

    def __init__(self):
        self.batch_normal = None
        self.alpha = None
        super(Dice, self).__init__()

3.2 build 构建

BN 层采用 tensorflow.python.keras.layers 类下的 BatchNormalizationV1,按照论文的设置,这里 epsilon 取 1e−8。

    def build(self, input_shape):
        # 参数
        self.alpha = self.add_weight(name='alpha',
                                     shape=input_shape[-1],
                                     initializer=tf.constant_initializer(0.0),
                                     dtype=tf.float32,
                                     trainable=True)
        # BN 层
        self.batch_normal = BatchNormalizationV1(trainable=True,
                                                 epsilon=0.00000001,
                                                 axis=-1,
                                                 center=False,
                                                 scale=False)
        super(Dice, self).build(input_shape)

 

3.3 call 调用

 根据论文公式实现 Dice,其中 P(s) 为 sigmoid 函数:

    def call(self, inputs, **kwargs):
        # [None, T, 36] => [None, T, 36] 保持不变
        inputs_normed = self.batch_normal(inputs)
        x_p = tf.sigmoid(inputs_normed)
        _output = self.alpha * (1.0 - x_p) * inputs + x_p * inputs
        return _output

我们在 Activation Unit 的构建过程中指定了 Dice 激活函数:

后面完整的 MLP 也用到了 Dice 激活,同样可以使用上面的方法。

四.总结

上面给出了 Activation Unit 和 Dice 激活的实现,DIN 还引入了 GAUC 的 Metric 与小批量感知正则化的创新,这里并未给出,除此之外,DIN 也为后面序列特征的发展拉开了序幕,DIEN 也在此基础上提出。按照王喆大佬对此文的评价,对于广大算法工程师来说,知道如何引入 Attention 机制是本文最实用的收获。

参考:

推荐系统中的注意力机制——阿里深度兴趣网络(DIN)

深度学习中Batch Normalization和Dice激活函数

更多推荐算法相关深度学习:深度学习导读专栏 

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

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

相关文章

网络安全:渗透神器 kali 的安装.

网络安全:渗透神器 kali 的安装. Kali Linux是一款基于Debian的Linux发行版,专门用于渗透测试和网络安全评估。它包含了大量的渗透测试工具和网络安全工具,适用于各种不同的渗透测试场景和需求。 目录: 网络安全:渗透…

MS5814可选内置基准、四通道数模转换器

MS5814/5814T 是一款 12bit 四通道输出的电压型 DAC,集成可选内部基准,接口采用四线串口模式,可以兼容 TMS320、SPI、QSPI 和 Microwire 串口。MS5814/5814T 控制数据有 16bit,包括 DAC 地址,控制字节和 12bitDAC 数据…

MySQL——BasicKnowledge

1. Mysql Version ​​​​​​​​​​​​ 2.install & uninstall 2.1 Linux My Content 3.Configure 3.1 设置IP访问 参考链接 3.1.1 方法一:改表法 --登入mysql后,更改"mysql"数据库中"user"表里的 "host&quo…

“三问五步”落地医疗行业数据安全建设体系|盾见

个 文|龚磊 2021年6月10日,我国《数据安全法》颁布,并于2021年9月1日正式施行,作为数据领域的纲领性和基础性法律,以准确定义数据、数据处理、数据安全为出发点,提出解决数据全生命周期中的数据安全问题,达…

深入浅出,理解知识图谱技术及其应用

知识图谱是一个将各种实体之间的关系以图谱的形式呈现出来的技术。这些实体可以是人、地点、组织或任何其他类型的实体。知识图谱将这些实体与它们之间的关系链接在一起,从而形成一个表示知识的图形结构。本文将介绍知识图谱的基础知识,包括它的定义、应…

【TA100】渲染管线

粗粒度剔除:根据物体之间的遮挡关系,剔除遮挡的物体。 多顶点分配到GPU不同单元执行,提升速度 1 应用阶段 1.1 场景阶段 ### 1.2 粗粒度剔除 剔除与摄像机与视锥体不相交的光源或者光线照射方向与与视角不重合的光源。 1.3 渲染设置 1.4 调用…

AVL树的插入

介绍: 在二叉搜索树的前提下,左右高度差(平衡因子)的绝对值不大于1 二叉搜索数->中序排序树->极端情况下时间复杂度高 ->我博客更过不了解去翻翻 (搜索二叉树——寻找节点,插入节点,删除节点_别想闲鱼了!快去学习的博客-CSDN博客)…

硬核推荐!3款私藏的卡通头像在线生成网站,减少撞“头”率

现在各个软件应用都会有自己的头像设置,肯定有很多朋友经常喜欢换头像,我猜大家的头像要么就是明星,要么就是网图,总是出现和别人撞“头”的现象。今天就来给大家推荐几个在线制作头像的网站,保证让撞“头”率减少90%。…

【MYSQL】聚合函数和单表/多表查询练习、子查询、内外连接

目录 1.聚合函数 1.1.group by子句 1.2.having语句 2.单表查询 2.2单表查询 3.多表查询 3.2.子查询 5.内链接 6.外连接 1.聚合函数 函数说明count返回查询到的数据的数量sum返回查询到的数据的总和avg返回查询到的数据的平均值max返回查询到的数据的最大值min返回查询…

WPF MVVM基础教程(五)RelativeSource属性绑定

RelativeSource属性绑定 介绍RelativeSource属性介绍RelativeSource的Mode属性有四种模式: 四种模式用法Self模式FindAncestor模式使用规则: TemplatedParent模式PreviousData模式 特殊用法绑定到其他ViewModel上的命令 介绍 RelativeSource 是一个标记…

前端HTML学习(二)

1、列表标签 列表标签概述:能够使用无序列表、有序列表、自定义列表标签,实现网页中列表结构的搭建。列表应用在网页中按照行展示关联性的内容,如:新闻列表、排行榜、账单等。 特点:按照行的方式,整齐显示内容 种类&a…

大模型遭泄两月后 Meta意外变赢家

一份被意外泄露的谷歌内部文件,将Meta的LLaMA大模型“非故意开源”事件再次推到聚光灯前。 “泄密文件”的作者据悉是谷歌内部的一位研究员,他大胆指出,开源力量正在填平OpenAI与谷歌等大模型巨头们数年来筑起的护城河,而最大的受…

Ae:摄像机命令

Ae 中提供了一些摄像机命令,可帮助更好地运用摄像机,比如实现跟焦、切换对焦对象(图层)、展现指定图层内容等等。 Ae菜单:图层/摄像机 Camera 这些命令也可在摄像机图层的右键菜单中选择。 基于 3D 视图生成摄像机 Cre…

MySQL基础-数据库介绍

本文介绍MySQL基础,包括什么是数据库,什么是关系型数据库,数据库和实例区别,数据库分类 文章目录 前言什么是数据库?什么是数据库管理系统(DBMS)?什么是关系型数据库管理系统&#x…

Springboot +Flowable,设置流程变量的方式(一)

一.简介 为什么需要流程变量。 举个例子,假设有如下一个流程,截图如下: 这是一个请假流程,那么谁请假、请几天、起始时间、请假理由等等,这些都需要说明,不然领导审批的依据是啥?那么如何传递…

HTML + CSS (包含移动Web) 笔记

前言 主要还是比较的一些html css&#xff1b;当然也有一些css样式时平时开发中经常用到的&#xff0c;但是我不晓得的&#xff0c;所以还是记录一下吧&#xff1b;给孩子点点关注吧&#xff01;&#x1f62d; 壹、HTML 一、标签 1.1 标题标签 块级元素 <h1> 好好…

go-micro框架-01-启动微服务及微服务间的调用

文章目录 1. 环境准备1.1 安装protoc1.2 安装 go-micro 2. 创建微服务项目2.1 创建第一个服务2.2 初始化2.3 同法再创建2个服务2.4 初始化项目 3. 微服务间调用4. 使用 consul4.1 启动consul4.2 修改代码 1. 环境准备 1.1 安装protoc https://github.com/protocolbuffers/pro…

webpack: 5 报错,错误

webpack-报错&#xff1a;Uncaught ReferenceError: $ is not defined (webpack) webpack打包jquery的插件&#xff08;EasyLazyLoad&#xff09;时&#xff0c;报错 方法一&#xff1a; //多个js文件用到jquery&#xff0c;用这种方法 在jquery.min.js的做最后写上下面的代码…

中交路桥科技浅谈:边坡稳定的影响因素及边坡主要监测内容

边坡稳定的影响因素 岩&#xff08;土&#xff09;性质的影响&#xff1a;包括岩石的坚硬程度、抗风化能力、抗软化能力、强度、组成、透水性等&#xff1b; 岩土结构的影响&#xff1a;表现为节理裂缝的发育程度及其分布规律、结构面的胶结情况、软弱面和破碎带的分布与边坡…

记录--ThreeJs手搓一个罗盘特效

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 先上效果 前言 最近在学Three.js.,对着文档看了一周多&#xff0c;正好赶上码上掘金的活动&#xff0c;就顺便写了一个小demo&#xff0c;手搓一个罗盘特效。 太极 先来看一下太极的实现方式&#xff…