特征交叉-MaskNet文章总结代码实现

MaskNet 这个模型是微博21年提出的,23年twitter(X)开源的推荐系统排序模块使用的backbone结构。
核心思想是认为DNN为主的特征交叉是addictive,交叉效率不高;所以设计了一种multiplicatvie的特征交叉
如何设计muliplicative特征交叉呢?
1)首先设计了一个instance-guide-mask,下图是instance-guide-mask的设计,其实就是两层feed-forward-layer,第一层把原始输入维度扩增,第二层再还原回去,总结而言,就是这个公式:
V m a s k = W d 2 ( R e l u ( W d 1 V e m b + β d 1 ) ) + β d 2 V_{mask} = W_{d2}(Relu(W_{d1} V_{emb} + \beta_{d1})) + \beta_{d2} Vmask=Wd2(Relu(Wd1Vemb+βd1))+βd2

𝑉 𝑒 𝑚 𝑏 ∈ R 𝑚 = 𝑓 × 𝑘 𝑉_{𝑒𝑚𝑏}∈ R^{𝑚=𝑓 ×𝑘} VembRm=f×k 输入的embedding结果, f是输入特征的数量,k是特征embedding维度。
最终输出的是一个处理后的embedding向量,后面简称为mask
instance-guide-mask2) 这个embedding得到后,怎么使用呢,这个就是MaskBlock干的事情。
主要有两种使用,一个是对embedding进行处理,图里LN-EMB里的LN指的是Layer Normalization
V 𝑚 𝑎 𝑠 𝑘 𝑒 𝑑 𝐸 𝑀 𝐵 = V 𝑚 𝑎 𝑠 𝑘 ⊙ L N _ E M B ( V 𝑒 𝑚 b ) V_{𝑚𝑎𝑠𝑘𝑒𝑑𝐸𝑀𝐵} = V_{𝑚𝑎𝑠𝑘} ⊙ LN\_EMB(V_{𝑒𝑚b}) VmaskedEMB=VmaskLN_EMB(Vemb), 把mask的结果和LN-EMB 进行element-wide product, 然后在接一个linear,LN后应用在Relu做下非线性激活,这个就是MaskBLock的全部了, 总结成一个公式:
V o u t p u t = L N _ H I D ( W i V m a s k e d E M B ) = R e L U ( L N ( W i ( V m a s k ⊙ L N _ E M B ( V 𝑒 𝑚 b ) ) ) V_{output} = LN\_HID(W_i V_{maskedEMB}) = ReLU(LN(W_i (V_{mask} ⊙ LN\_EMB(V_{𝑒𝑚b}))) Voutput=LN_HID(WiVmaskedEMB)=ReLU(LN(Wi(VmaskLN_EMB(Vemb)))
Embedding除了对Embedding进行element-wide-product,还可以对神经网络的输出再和mask做一次处理,这个就是另一种mask的应用方式:
V o u t p u t = L N _ H I D ( W i V m a s k d H I D ) = R e L U ( L N ( W i ( V m a s k ⊙ V o u t p u t p ) ) ) V_{output} = LN\_HID(W_i V_{maskdHID}) = ReLU(LN(W_i(V_{mask} ⊙ V_{output}^p))) Voutput=LN_HID(WiVmaskdHID)=ReLU(LN(Wi(VmaskVoutputp)))
在这里插入图片描述
1) 2) 结束之后,文章的核心内容也基本结束,后面3)是MaskBlock的应用
3)MaskNet
所有特征都和Instance-guide-mask进行运算,可以是串行的也可以是并行的。
串行的第一个是一个MaskBlock on feature embedding,后面接的都是MaskBlock on MaskBlock;
并行的比较简单,每一个都是一个MaskBlock on feature embedding,然后concat到一起
在这里插入图片描述

二 Implementation
1)torch 代码实现,摘录自twitter开源代码:

def _init_weights(module):if isinstance(module, torch.nn.Linear):torch.nn.init.xavier_uniform_(module.weight)torch.nn.init.constant_(module.bias, 0)class MaskBlock(torch.nn.Module):def __init__(self, mask_block_config: config.MaskBlockConfig, input_dim: int, mask_input_dim: int) -> None:super(MaskBlock, self).__init__()self.mask_block_config = mask_block_configoutput_size = mask_block_config.output_sizeif mask_block_config.input_layer_norm: # twitter实现的这里layer normalization做了可配置的self._input_layer_norm = torch.nn.LayerNorm(input_dim)else:self._input_layer_norm = None# instace-guide-mask第一层aggregation的神经元数量配置# 如果指定了压缩量,就是input * 压缩量;如果没有,那么也可以手动指定大小if mask_block_config.reduction_factor:aggregation_size = int(mask_input_dim * mask_block_config.reduction_factor)elif mask_block_config.aggregation_size is not None:aggregation_size = mask_block_config.aggregation_sizeelse:raise ValueError("Need one of reduction factor or aggregation size.")# instance-guide-mask is here# 两层Linearself._mask_layer = torch.nn.Sequential(torch.nn.Linear(mask_input_dim, aggregation_size),torch.nn.ReLU(),torch.nn.Linear(aggregation_size, input_dim),)# 参数初始化self._mask_layer.apply(_init_weights)self._hidden_layer = torch.nn.Linear(input_dim, output_size)self._hidden_layer.apply(_init_weights)self._layer_norm = torch.nn.LayerNorm(output_size)def forward(self, net: torch.Tensor, mask_input: torch.Tensor):# LNif self._input_layer_norm:net = self._input_layer_norm(net)# self._mask_layer(mask_input)-- V_mask# net * V_maskhidden_layer_output = self._hidden_layer(net * self._mask_layer(mask_input))return self._layer_norm(hidden_layer_output)class MaskNet(torch.nn.Module):def __init__(self, mask_net_config: config.MaskNetConfig, in_features: int):super().__init__()self.mask_net_config = mask_net_configmask_blocks = []if mask_net_config.use_parallel:total_output_mask_blocks = 0# 从local_prod参数看,用了4个blockfor mask_block_config in mask_net_config.mask_blocks:mask_blocks.append(MaskBlock(mask_block_config, in_features, in_features))total_output_mask_blocks += mask_block_config.output_sizeself._mask_blocks = torch.nn.ModuleList(mask_blocks)else:input_size = in_featuresfor mask_block_config in mask_net_config.mask_blocks:mask_blocks.append(MaskBlock(mask_block_config, input_size, in_features))input_size = mask_block_config.output_sizeself._mask_blocks = torch.nn.ModuleList(mask_blocks)total_output_mask_blocks = mask_block_config.output_sizeif mask_net_config.mlp:self._dense_layers = mlp.Mlp(total_output_mask_blocks, mask_net_config.mlp)self.out_features = mask_net_config.mlp.layer_sizes[-1]else:self.out_features = total_output_mask_blocksself.shared_size = total_output_mask_blocksdef forward(self, inputs: torch.Tensor):if self.mask_net_config.use_parallel:# 并行化的网络结构实现mask_outputs = []# 对于多个Block,每一个block输入都是一样,只是其中学习到的参数有所不同for mask_layer in self._mask_blocks:# mask_input,net 都是inputsmask_outputs.append(mask_layer(mask_input=inputs, net=inputs)) # Share the outputs of the MaskBlocks.all_mask_outputs = torch.cat(mask_outputs, dim=1)# 最终输出处理output = (all_mask_outputsif self.mask_net_config.mlp is Noneelse self._dense_layers(all_mask_outputs)["output"])return {"output": output, "shared_layer": all_mask_outputs}else:# 串行net = inputsfor mask_layer in self._mask_blocks:# mask_input 是inputs,net输入是上一层的输出net = mask_layer(net=net, mask_input=inputs)# Share the output of the stacked MaskBlocks.output = net if self.mask_net_config.mlp is None else self._dense_layers[net]["output"]return {"output": output, "shared_layer": net}

2)tensorflow实现
摘录自EasyRec(阿里开源推荐工具)

# Copyright (c) Alibaba, Inc. and its affiliates.
import tensorflow as tf
from tensorflow.python.keras.layers import Activation
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras.layers import Layer
from easy_rec.python.layers.keras.blocks import MLP
from easy_rec.python.layers.keras.layer_norm import LayerNormalization
from easy_rec.python.layers.utils import Parameterclass MaskBlock(Layer):"""MaskBlock use in MaskNet.Args:projection_dim: project dimension to reduce the computational cost.Default is `None` such that a full (`input_dim` by `aggregation_size`) matrixW is used. If enabled, a low-rank matrix W = U*V will be used, where Uis of size `input_dim` by `projection_dim` and V is of size`projection_dim` by `aggregation_size`. `projection_dim` need to be smallerthan `aggregation_size`/2 to improve the model efficiency. In practice, we'veobserved that `projection_dim` = d/4 consistently preserved theaccuracy of a full-rank version."""def __init__(self, params, name='mask_block', reuse=None, **kwargs):super(MaskBlock, self).__init__(name=name, **kwargs)self.config = params.get_pb_config()self.l2_reg = params.l2_regularizerself._projection_dim = params.get_or_default('projection_dim', None)self.reuse = reuseself.final_relu = Activation('relu', name='relu')def build(self, input_shape):if type(input_shape) in (tuple, list):assert len(input_shape) >= 2, 'MaskBlock must has at least two inputs'input_dim = int(input_shape[0][-1])mask_input_dim = int(input_shape[1][-1])else:input_dim, mask_input_dim = input_shape[-1], input_shape[-1]# 这里实现和pytorch一样if self.config.HasField('reduction_factor'):aggregation_size = int(mask_input_dim * self.config.reduction_factor)elif self.config.HasField('aggregation_size') is not None:aggregation_size = self.config.aggregation_sizeelse:raise ValueError('Need one of reduction factor or aggregation size for MaskBlock.')# instance-guide-mask第一层      self.aggr_layer = Dense(aggregation_size,activation='relu',kernel_initializer='he_uniform',kernel_regularizer=self.l2_reg,name='aggregation')# instance-guide-mask第二层self.weight_layer = Dense(input_dim, name='weights')# 对比pytorch实现,增加了projection_dim, 低秩矩阵(详见DCN)if self._projection_dim is not None:logging.info('%s project dim is %d', self.name, self._projection_dim)self.project_layer = Dense(self._projection_dim,kernel_regularizer=self.l2_reg,use_bias=False,name='project')if self.config.input_layer_norm:# 推荐在调用MaskBlock之前做好 layer norm,否则每一次调用都需要对input做lnif tf.__version__ >= '2.0':self.input_layer_norm = tf.keras.layers.LayerNormalization(name='input_ln')else:self.input_layer_norm = LayerNormalization(name='input_ln')if self.config.HasField('output_size'):self.output_layer = Dense(self.config.output_size, use_bias=False, name='output')# tensorflow遗留问题,兼容1/2if tf.__version__ >= '2.0':self.output_layer_norm = tf.keras.layers.LayerNormalization(name='output_ln')else:self.output_layer_norm = LayerNormalization(name='output_ln')super(MaskBlock, self).build(input_shape)def call(self, inputs, training=None, **kwargs):if type(inputs) in (tuple, list):net, mask_input = inputs[:2]else:net, mask_input = inputs, inputs# LNif self.config.input_layer_norm:net = self.input_layer_norm(net)# tensorflow实现aggregate层和projection层是分开的,上面pytorch是用一个sequenceif self._projection_dim is None:aggr = self.aggr_layer(mask_input)else:u = self.project_layer(mask_input)aggr = self.aggr_layer(u)# 得到mask结果weights = self.weight_layer(aggr)# elemnet-wide productmasked_net = net * weightsif not self.config.HasField('output_size'):return masked_net# 最终处理,一个Liner+layer norm层hidden = self.output_layer(masked_net)ln_hidden = self.output_layer_norm(hidden)return self.final_relu(ln_hidden)class MaskNet(Layer):def __init__(self, params, name='mask_net', reuse=None, **kwargs):super(MaskNet, self).__init__(name=name, **kwargs)self.reuse = reuseself.params = paramsself.config = params.get_pb_config()if self.config.HasField('mlp'):p = Parameter.make_from_pb(self.config.mlp)p.l2_regularizer = params.l2_regularizerself.mlp = MLP(p, name='mlp', reuse=reuse)else:self.mlp = Noneself.mask_layers = []for i, block_conf in enumerate(self.config.mask_blocks):params = Parameter.make_from_pb(block_conf)params.l2_regularizer = self.params.l2_regularizermask_layer = MaskBlock(params, name='block_%d' % i, reuse=self.reuse)self.mask_layers.append(mask_layer)if self.config.input_layer_norm:if tf.__version__ >= '2.0':self.input_layer_norm = tf.keras.layers.LayerNormalization(name='input_ln')else:self.input_layer_norm = LayerNormalization(name='input_ln')def call(self, inputs, training=None, **kwargs):# 与pytorch版本对比,对输入也进行了一次layer normif self.config.input_layer_norm:inputs = self.input_layer_norm(inputs)# 下面的并行/串行实现逻辑无差if self.config.use_parallel:mask_outputs = [mask_layer((inputs, inputs)) for mask_layer in self.mask_layers]all_mask_outputs = tf.concat(mask_outputs, axis=1)if self.mlp is not None:output = self.mlp(all_mask_outputs, training=training)else:output = all_mask_outputsreturn outputelse:net = inputsfor i, _ in enumerate(self.config.mask_blocks):mask_layer = self.mask_layers[i]net = mask_layer((net, inputs))if self.mlp is not None:output = self.mlp(net, training=training)else:output = netreturn output

Reference:
MaskNet: Introducing Feature-Wise Multiplication to CTR Ranking Models by Instance-Guided Mask
tesorflow实现
twitter-alg-ml

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

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

相关文章

QT 实现仿制 网络调试器(未实现连接唯一性) QT5.12.3环境 C++实现

网络调试助手&#xff1a; 提前准备&#xff1a;在编写代码前&#xff0c;要在.pro工程文件中&#xff0c;添加network模块。 服务端&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QtWidgets> #inclu…

Vscode写markdown快速插入python代码

如图当我按下快捷键CRTLSHIFTK 自动出现python代码片段 配置方法shortcuts’ 打开这个json文件 输入 {"key": "ctrlshiftk","command": "editor.action.insertSnippet","when": "editorTextFocus","args&…

【案例】泛微.齐业成助力北京中远大昌汽车实现数电票全流程管理

中远大昌统一发票共享平台上线三个多月以来&#xff0c;实现&#xff1a; 5000份 60000元 发票开具 成本节约 客户简介及需求分析 北京中远大昌汽车服务有限公司&#xff08;以下简称“中远大昌”&#xff09;成立于2002年&#xff0c;是中远海运集团所属香远&#xff08;北…

使用docker快速部署Nginx、Redis、MySQL、Tomcat以及制作镜像

文章目录 应用快速部署NginxRedisMySQLTomcat 制作镜像镜像原理基于已有容器创建使用 Dockerfile 创建镜像指令说明构建应用创建 Dockerfile 文件创建镜像 应用快速部署 Nginx docker run -d -p 80:80 nginx使用浏览器访问虚拟机地址 Redis docker pull redis docker run --…

雅思阅读TFNG题型7大解题思路

雅思阅读TFNG题型7大解题思路&#xff0c;全在这了‼️ ⚠️在徘徊在6-6.5的同学有很大的共性就是对题型不够熟悉&#xff0c;我记得我当时卡6.5的时候我有时候分不清NG和F&#xff0c;有时候又分不清NG 和True&#xff0c;也不知道他有哪几种考我的方法&#xff0c;脑子里没有…

家政服务系统开发,智慧家政,便捷生活

近年来&#xff0c;大众对家政服务的需求不断增加&#xff0c;家政服务种类也逐渐多样化&#xff0c;涵盖了日常生活中的各个方面&#xff0c;为大众带来更急优质的服务&#xff0c;进一步提升了家政市场的发展。 在数字化发展的推动下&#xff0c;互联网家政服务的模式应运而…

重生之我在学环境变量

环境变量 基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如&#xff1a;我们在编写C/C代码的时候&#xff0c;在链接的时候&#xff0c;从来不知道我们的所链接的动态静态库在哪里&#xff0c;但 是照样可以链接成功&#…

Java基础夯实——2.7 线程上下文切换

线程上下文切换&#xff08;Thread Context Switching&#xff09;是操作系统在多线程环境中&#xff0c;切换CPU从执行一个线程的上下文到另一个线程的上下文的过程。这种切换是实现多线程并发执行的核心机制之一。 1 上下文: 线程的上下文指线程在某一时刻的执行状态,如&am…

AI模型简介

深度学习模型种类繁多&#xff0c;可以根据任务类型和应用场景进行分类。以下是主要模型类型的详细介绍&#xff0c;每种模型包含了其特点、功能、代表性模型&#xff0c;以及常见应用。 1. 分类模型 分类模型是深度学习中最基本也是最广泛应用的模型类型&#xff0c;其目标是…

Failed to start Docker Application Container Engine

说明&#xff1a; 1&#xff09;访问应用业务&#xff0c;读取不到数据&#xff0c;show databases;查看数据库报错 2&#xff09;重启docker服务&#xff0c;服务启动失败&#xff0c;查看日志报错如下图所示 3&#xff09;报错信息&#xff1a;chmod /data/docker: read-only…

SQL 语句执行计划中的连接方式

SQL 语句执行计划中的连接方式 join操作 join操作基本分为3大类&#xff1a;外连接&#xff08;细分为&#xff1a;左连接&#xff08;Left outer join/ left join&#xff09;、右连接&#xff08;right outer join/ right join&#xff09;、全连接&#xff08;full outer …

如何理解Lua 使用虚拟堆栈

虚拟堆栈的基本概念 Lua使用虚拟堆栈来实现Lua和C&#xff08;或其他宿主语言&#xff09;之间的交互。这个虚拟堆栈是一个数据结构&#xff0c;用于存储Lua的值&#xff0c;如数字、字符串、表、函数等。它在Lua状态机&#xff08;lua_State&#xff09;内部维护&#xff0c;为…

FileProvider高版本使用,跨进程传输文件

高版本的android对文件权限的管控抓的很严格,理论上两个应用之间的文件传递现在都应该是用FileProvider去实现,这篇博客来一起了解下它的实现原理。 首先我们要明确一点,FileProvider就是一个ContentProvider,所以需要在AndroidManifest.xml里面对它进行声明: <provideran…

【大数据知识】ClickHouse入门

ClickHouse入门 概述一、主要应用场景二、技术特点三、性能表现四、限制与不足五、使用建议 分布式架构一、架构特点二、核心组件三、数据组织方式四、分布式查询原理五、优势与局限性 核心架构一、ClickHouse执行过程架构二、ClickHouse数据存储架构 为什么速度这么快存储层&a…

C# .Net Core通过StreamLoad向Doris写入CSV数据

以下代码可以只关注StreamLoad具体实现。 1.创建StreamLoad返回值Model public class StreamLoadResponse {public long TxnId { get; set; }public string Label { get; set; }public string Comment { get; set; }public string TwoPhaseCommit { get; set; }public string…

golang 嵌入式armv7l压缩编译打包

编译 Go 应用程序 go build -ldflags"-s -w" -o myapp.exe . 使用 UPX 压缩可执行文件&#xff08;window下载并设置环境变量&#xff09; upx --best --lzma myapp.exe 可从10M压缩到1M 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 …

45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题

点赞收藏加关注&#xff0c;你也能主打别墅&#xff01; 一、问题描述 Mac上终端运行如下命令&#xff1a; sudo npm install typescript -g //全局安装ts提示成功安装后&#xff0c;我测试tsc -v这个命令时出现如下错误&#xff1a; 也就是说找不到 tsc 命令。 二、解决方…

CircuitBreaker机制详解:Elasticsearch中的资源管理

CircuitBreaker机制详解:Elasticsearch中的资源管理 在现代软件架构中,熔断器(CircuitBreaker)是一种重要的模式,用于防止系统过载并保护系统稳定性。在Elasticsearch中,熔断器机制尤其关键,因为它们帮助管理资源使用,防止节点因资源耗尽而崩溃。本文将深入探讨Elasti…

测试岗位应该学什么

以下是测试岗位需要学习的一些关键内容&#xff1a; 1. 测试理论和方法 - 了解不同类型的测试&#xff0c;如功能测试、性能测试、压力测试、安全测试、兼容性测试等。 - 掌握测试策略和测试计划的制定。 2. 编程语言 - 至少熟悉一种编程语言&#xff0c;如 Python、Java…

【图像检测】深度学习与传统算法的区别(识别逻辑、学习能力、泛化能力)

识别逻辑 深度学习 使用了端到端的学习策略&#xff0c;直接学习从图像到检测结果的映射关系&#xff0c;自动提取特征&#xff0c;并且根据特征与特征之间的关系&#xff0c;计算出检测结果。 传统算法 则是人工提取特征&#xff0c;比如边缘特征&#xff0c;直线特征&#x…