数学基础
- 线性代数
- 概率论与随机过程
- 数值计算
- 蒙特卡洛方法与 MCMC 采样
- 机器学习方法概论
统计学习
深度学习
- 深度学习简介
- 深度前馈网络
- 反向传播算法
- 正则化
- 深度学习中的最优化问题
- 卷积神经网络
- CNN:图像分类
- 循环神经网络 RNN
- Transformer
- 一、Transformer [2017]
- 二、Universal Transformer [2018]
- 三、Transformer-XL [2019]
- 四、GPT1 [2018]
- 五、GPT2 [2019]
- 六、GPT3 [2020]
- 七、OPT [2022]
- 八、BERT [2018]
- 九、XLNet [2019]
- 十、RoBERTa [2019]
- 十一、ERNIE 1.0 [2019]
- 十二、ERNIE 2.0 [2019]
- 十三、ERNIE 3.0 [2021]
- 十四、ERNIE-Huawei [2019]
- 十五、MT-DNN [2019]
- 十六、BART [2019]
- 十七、mBART [2020]
- 十八、SpanBERT [2019]
- 十九、ALBERT [2019]
- 二十、UniLM [2019]
- 二十一、MASS [2019]
- 二十二、MacBERT [2019]
- 二十三、Fine-Tuning Language Models from Human Preferences [2019]
- 二十四 Learning to summarize from human feedback [2020]
- 二十五、InstructGPT [2022]
- 二十六、T5 [2020]
- 二十七、mT5 [2020]
- 二十八、ExT5 [2021]
- 二十九、Muppet [2021]
- 三十、Self-Attention with Relative Position Representations [2018]
- 三十一、USE [2018]
- 三十二、Sentence-BERT [2019]
- 三十三、SimCSE [2021]
- 三十四、BERT-Flow [2020]
- 三十五、BERT-Whitening [2021]
- 三十六、Comparing the Geometry of BERT, ELMo, and GPT-2 Embeddings [2019]
- 三十七、CERT [2020]
- 三十八、DeCLUTR [2020]
- 三十九、CLEAR [2020]
- 四十、ConSERT [2021]
- 四十一、Sentence-T5 [2021]
- 四十二、ULMFiT [2018]
- 四十三、Scaling Laws for Neural Language Models [2020]
- 四十四、Chinchilla [2022]
- 四十七、GLM-130B [2022]
- 四十八、GPT-NeoX-20B [2022]
- 四十九、Bloom [2022]
- 五十、PaLM [2022] (粗读)
- 五十一、PaLM2 [2023](粗读)
- 五十二、Self-Instruct [2022]
- 句子向量
- 词向量
- 传统CTR 预估模型
- CTR 预估模型
- 一、DSSM [2013]
- 二、FNN [2016]
- 三、PNN [2016]
- 四、DeepCrossing [2016]
- 五、Wide 和 Deep [2016]
- 六、DCN [2017]
- 七、DeepFM [2017]
- 八、NFM [2017]
- 九、AFM [2017]
- 十、xDeepFM [2018]
- 十一、ESMM [2018]
- 十二、DIN [2017]
- 十三、DIEN [2019]
- 十四、DSIN [2019]
- 十五、DICM [2017]
- 十六、DeepMCP [2019]
- 十七、MIMN [2019]
- 十八、DMR [2020]
- 十九、MiNet [2020]
- 二十、DSTN [2019]
- 二十一、BST [2019]
- 二十二、SIM [2020]
- 二十三、ESM2 [2019]
- 二十四、MV-DNN [2015]
- 二十五、CAN [2020]
- 二十六、AutoInt [2018]
- 二十七、Fi-GNN [2019]
- 二十八、FwFM [2018]
- 二十九、FM2 [2021]
- 三十、FiBiNET [2019]
- 三十一、AutoFIS [2020]
- 三十三、AFN [2020]
- 三十四、FGCNN [2019]
- 三十五、AutoCross [2019]
- 三十六、InterHAt [2020]
- 三十七、xDeepInt [2023]
- 三十九、AutoDis [2021]
- 四十、MDE [2020]
- 四十一、NIS [2020]
- 四十二、AutoEmb [2020]
- 四十三、AutoDim [2021]
- 四十四、PEP [2021]
- 四十五、DeepLight [2021]
- 图的表达
- 一、DeepWalk [2014]
- 二、LINE [2015]
- 三、GraRep [2015]
- 四、TADW [2015]
- 五、DNGR [2016]
- 六、Node2Vec [2016]
- 七、WALKLETS [2016]
- 八、SDNE [2016]
- 九、CANE [2017]
- 十、EOE [2017]
- 十一、metapath2vec [2017]
- 十二、GraphGAN [2018]
- 十三、struc2vec [2017]
- 十四、GraphWave [2018]
- 十五、NetMF [2017]
- 十六、NetSMF [2019]
- 十七、PTE [2015]
- 十八、HNE [2015]
- 十九、AANE [2017]
- 二十、LANE [2017]
- 二十一、MVE [2017]
- 二十二、PMNE [2017]
- 二十三、ANRL [2018]
- 二十四、DANE [2018]
- 二十五、HERec [2018]
- 二十六、GATNE [2019]
- 二十七、MNE [2018]
- 二十八、MVN2VEC [2018]
- 二十九、SNE [2018]
- 三十、ProNE [2019]
- Graph Embedding 综述
- 图神经网络
- 一、GNN [2009]
- 二、Spectral Networks 和 Deep Locally Connected Networks [2013]
- 三、Fast Localized Spectral Filtering On Graph [2016]
- 四、GCN [2016]
- 五、神经图指纹 [2015]
- 六、GGS-NN [2016]
- 七、PATCHY-SAN [2016]
- 八、GraphSAGE [2017]
- 九、GAT [2017]
- 十、R-GCN [2017]
- 十一、 AGCN [2018]
- 十二、FastGCN [2018]
- 十三、PinSage [2018]
- 十四、GCMC [2017]
- 十五、JK-Net [2018]
- 十六、PPNP [2018]
- 十七、VRGCN [2017]
- 十八、ClusterGCN [2019]
- 十九、LDS-GNN [2019]
- 二十、DIAL-GNN [2019]
- 二十一、HAN [2019]
- 二十二、HetGNN [2019]
- 二十三、HGT [2020]
- 二十四、GPT-GNN [2020]
- 二十五、Geom-GCN [2020]
- 二十六、Graph Network [2018]
- 二十七、GIN [2019]
- 二十八、MPNN [2017]
- 二十九、UniMP [2020]
- 三十、Correct and Smooth [2020]
- 三十一、LGCN [2018]
- 三十二、DGCNN [2018]
- 三十三、AS-GCN
- 三十四、DGI [2018]
- 三十五、DIFFPOLL [2018]
- 三十六、DCNN [2016]
- 三十七、IN [2016]
- 图神经网络 2
- 图神经网络 3
- 推荐算法(传统方法)
- 一、Tapestry [1992]
- 二、GroupLens [1994]
- 三、ItemBased CF [2001]
- 四、Amazon I-2-I CF [2003]
- 五、Slope One Rating-Based CF [2005]
- 六、Bipartite Network Projection [2007]
- 七、Implicit Feedback CF [2008]
- 八、PMF [2008]
- 九、SVD++ [2008]
- 十、MMMF 扩展 [2008]
- 十一、OCCF [2008]
- 十二、BPR [2009]
- 十三、MF for RS [2009]
- 十四、 Netflix BellKor Solution [2009]
- 推荐算法(神经网络方法 1)
- 一、MIND [2019](用于召回)
- 二、DNN For YouTube [2016]
- 三、Recommending What Video to Watch Next [2019]
- 四、ESAM [2020]
- 五、Facebook Embedding Based Retrieval [2020](用于检索)
- 六、Airbnb Search Ranking [2018]
- 七、MOBIUS [2019](用于召回)
- 八、TDM [2018](用于检索)
- 九、DR [2020](用于检索)
- 十、JTM [2019](用于检索)
- 十一、Pinterest Recommender System [2017]
- 十二、DLRM [2019]
- 十三、Applying Deep Learning To Airbnb Search [2018]
- 十四、Improving Deep Learning For Airbnb Search [2020]
- 十五、HOP-Rec [2018]
- 十六、NCF [2017]
- 十七、NGCF [2019]
- 十八、LightGCN [2020]
- 十九、Sampling-Bias-Corrected Neural Modeling [2019](检索)
- 二十、EGES [2018](Matching 阶段)
- 二十一、SDM [2019](Matching 阶段)
- 二十二、COLD [2020 ] (Pre-Ranking 模型)
- 二十三、ComiRec [2020](https://www.wenjiangs.com/doc/0b4e1736-ac78)
- 二十四、EdgeRec [2020]
- 二十五、DPSR [2020](检索)
- 二十六、PDN [2021](mathcing)
- 二十七、时空周期兴趣学习网络ST-PIL [2021]
- 推荐算法之序列推荐
- 一、FPMC [2010]
- 二、GRU4Rec [2015]
- 三、HRM [2015]
- 四、DREAM [2016]
- 五、Improved GRU4Rec [2016]
- 六、NARM [2017]
- 七、HRNN [2017]
- 八、RRN [2017]
- 九、Caser [2018]
- 十、p-RNN [2016]
- 十一、GRU4Rec Top-k Gains [2018]
- 十二、SASRec [2018]
- 十三、RUM [2018]
- 十四、SHAN [2018]
- 十五、Phased LSTM [2016]
- 十六、Time-LSTM [2017]
- 十七、STAMP [2018]
- 十八、Latent Cross [2018]
- 十九、CSRM [2019]
- 二十、SR-GNN [2019]
- 二十一、GC-SAN [2019]
- 二十二、BERT4Rec [2019]
- 二十三、MCPRN [2019]
- 二十四、RepeatNet [2019]
- 二十五、LINet(2019)
- 二十六、NextItNet [2019]
- 二十七、GCE-GNN [2020]
- 二十八、LESSR [2020]
- 二十九、HyperRec [2020]
- 三十、DHCN [2021]
- 三十一、TiSASRec [2020]
- 推荐算法(综述)
- 多任务学习
- 系统架构
- 实践方法论
- 深度强化学习 1
- 自动代码生成
工具
- CRF
- lightgbm
- xgboost
- scikit-learn
- spark
- numpy
- matplotlib
- pandas
- huggingface_transformer
- 一、Tokenizer
- 二、Datasets
- 三、Model
- 四、Trainer
- 五、Evaluator
- 六、Pipeline
- 七、Accelerate
- 八、Autoclass
- 九、应用
- 十、Gradio
Scala
- 环境搭建
- 基础知识
- 函数
- 类
- 样例类和模式匹配
- 测试和注解
- 集合 collection(一)
- 集合collection(二)
- 集成 Java
- 并发
二十五、CAN [2020]
随着机器学习模型,尤其是推荐系统模型的日益复杂,如何有效地处理丰富的输入特征成为一个关键问题。对于工业环境中的在线推荐器
recommender
,模型通常使用one-hot
编码的十亿级二元稀疏特征进行训练。每个特征也可以视为一个unique ID
:它首先被映射到一个低维的embedding
,然后被输入到模型中。处理大规模输入的一种简单方法是考虑特征之间相互独立。在这种假设下,特征之间没有联系,因此可以直接训练广义线性模型,从而基于特征的组合来估计点击率
CTR
。然而,推荐系统中的target item
和 “用户历史点击” 等特征是高度相关的,即存在对最终预测目标(如点击率)的特征协作效应feature collective effect
,称作feature co-action
。例如,点击历史中有 “泳衣” 的一名女性用户,由于 “泳衣” 和 “泳镜” 的co-action
,很可能会点击推荐的 “泳镜”。feature co-action
可以被认为是对一组原始特征的子图进行建模。如果子图仅包含两个特征,那么建模feature co-action
相当于对两个ID
之间的边进行建模。co-action effect
解释了一组特征如何与优化目标相关联。如下图所示,feature co-action
显式地将特征pair
对[A, B]
连接到target label
。近年来,已有一些工作致力于建模
feature co-action
,这些方法可以分为三类:- 基于聚合
aggregation
的方法聚焦于学习如何聚合用户的历史行为序列,从而获得CTR
预估的有区分性discriminative
的representation
。这些方法利用feature co-action
对历史行为序列中的每个user action
的权重进行建模,然后对加权的用户行为序列进行sum
池化从而表示用户兴趣。 - 基于图的方法将特征视为节点,这些节点被连接成有向图或无向图。在这种情况下,
feature co-action
作为信息沿着边传播的edge weight
。 - 和基于聚合的方法、基于图的方法不同(这两种方法将
feature co-action
建模为权重),组合嵌入combinatorial embedding
方法通过显式组合特征embedding
来对feature co-action
进行建模。
尽管这些方法以不同的方式导致
CTR
预估的提升,但是它们仍然存在一些缺点:基于聚合的方法和基于图的方法仅通过
edge weight
对feature co-action
进行建模,但是edge
仅用于信息聚合information aggregation
而不是用于信息增强information augmentation
。combinatorial embedding
方法将两个特征的embedding
相结合,从而对feature co-action
进行建模。 例如,PNN
执行两个特征的内积或外积以增强augment
输入。combinatorial embedding
方法的一个主要缺点是:embedding
同时承担了representation learning
和co-action modeling
的责任。representation learning
任务和co-action modeling
可能会相互冲突,从而限制了性能。
在论文
《 CAN: Revisiting Feature Co-Action for Click-Through Rate Prediction》
中,论文强调了feature co-action
建模的重要性,并认为state-of-the-art
方法严重低估了co-action
的重要性。由于表达能力有限,这些方法无法捕获到feature co-action
。捕获feature co-action
以增强输入的重要性在于它可以降低模型学习和捕获co-action
的难度。假设存在一个最优函数 $ F_*(A,B) $ 来建模特征 $ A $ 和 $ B $ 之间的co-action
,通过在输入阶段显式提供 $ F_*(A,B) $ 可以大大减轻学习难度。为了验证论文的假设,即当前的方法无法完全捕获
feature co-action
,论文回顾了state-of-the-art
的方法和设计实验,从而表明探索feature co-action
潜力的简单方法可以提高性能。例如,如果选择了特征 $ A $ 和 $ B $ ,那么 $ A,B $ 的共现co-occurrence
将被视为一个新特征并馈入到模型中。作者将这个baseline
称作笛卡尔积cartesian product
模型。虽然笛卡尔积是co-action modeling
的直接方法,但是它存在一些严重的缺陷,如参数量太大、特征完全独立的embedding learning
。然而令人惊讶的是,根据论文的一些初步实验,作者发现大多数state-of-the-art
的combinatorial embedding
方法完全被笛卡尔积击败。作者推测这种情况可能是因为这些方法的表达能力差,并且无法学到平衡representation
和co-action modeling
的embedding
。为此,作者提出了
feature co-action
网络Co-Action Network: CAN
,它可以在输入阶段捕获feature co-action
,并有效利用不同特征pair
对的互信息mutual information
和公共信息common information
。CAN
不是直接参数化parameterize
笛卡尔积embedding
,而是参数化embedding
生成网络generation network
。这种参数化将追加参数的规模从 $ O(N^2\times D) $ 降低到 $ O(N\times T) $ 而且实现更好的性能,其中 $ N $ 为特征数量、 $ D $ 为特征维度、 $ T $ 为embedding
维度, $ T\ll N, D\lt T $ 。具体而言,
CAN
区分了用于representation learning
和co-action modeling
的embedding
空间,其中embedding
生成网络派生自co-action modeling
空间。通过这种方式,CAN
丰富了它的表达能力,缓解了representation learning
和co-action learning
的之间的冲突。与笛卡尔积模型相比,CAN
由于提高了参数的利用率,因此显著降低了存储成本和计算成本。本文主要贡献:
- 作者强调了
feature co-action
建模的重要性,而state-of-the-art
方法严重低估了这一点。具体而言,论文重新回顾了现有的建模feature co-action
的方法。实验结果表明:这些方法无法捕获笛卡尔积baseline
的性能。这表明当前的CTR
模型没有充分探索原始feature co-action
的潜力。 - 受观察的启发,作者提出了一个轻量级模型
Co-Action Network: CAN
,从而建模原始特征之间的co-action
。CAN
可以有效地捕获feature co-action
,在降低存储代价和计算代价的同时提高模型性能。 - 论文对公共数据集和工业数据集进行了广泛的实验,一致的优势验证了
CAN
的有效性。到目前为止,CAN
已经部署在阿里巴巴的展示广告系统中,带来了平均12%
的点击率提升、平均8%
的RPM
提升。 - 论文介绍了在工业环境中部署
CAN
的技术。CAN
利用feature co-action
的思想和作者学到的经验教训可以泛化到其它的setup
,因此受到研究人员和业界从业者的关注。
- 基于聚合
相关工作::一些研究工作致力于
CTR
预估中建模feature co-action
。这些方法可以分为三类:aggregation-based
方法、graph-based
方法、combinatorial embedding
方法。aggregation-based
方法:深度CTR
预估模型通常遵循embedding & MLP
的范式。在这些方法中,大规模稀疏输入特征(即ID
特征)首先映射到低维向量,然后以group-wise
的方式聚合为固定长度的向量。最终拼接好的向量馈入多层感知机MLP
。一系列工作聚焦于学习如何聚合特征以获得
CTR
预估的、有区分性discriminative
的representation
。CNN
、RNN
、Transformer
、Capsule
等不同的神经架构被用于聚合特征。DIN
是采用注意力机制进行特征聚合的代表性工作之一。它使用注意力来激活关于给定target item
的局部历史行为,并成功地捕获到用户兴趣的多样性特点diversity characteristic
。DIEN
进一步提出了一种辅助损失来从历史行为中捕获潜在的兴趣。此外,DIEN
将注意力机制和GRU
相结合,对用户兴趣的动态演化进行建模从而进行特征聚合。MIND
认为单个向量可能不足以捕获用户和item
中的复杂模式。MIND
引入了胶囊网络和动态路由机制来学习多个representation
来聚合原始特征。- 受到
self-attention
架构在seq-to-seq learning
任务中取得成功的启发,DSIN
引入了Transformer
以进行特征聚合。 MIMN
提出了一种memory-based
的架构来聚合特征并解决长期long-term
用户兴趣建模的挑战。
graph-based
方法:图包含节点和边,其中ID
特征可以由节点embedding
表示,feature co-action
可以沿着边建模。基于图的方法(如Graph Neural Network: GNN
)对每个节点进行特征传播,并在传播过程中聚合了邻域信息。feature co-action
被建模为边权重,用于特征传播从而沿着边局部平滑节点embedding
。《Spectral Networks and Locally Connected Networks on Graphs》
首先提出了一种基于谱图spectral graph
的卷积网络扩展,从而用于特征传播。GCN
进一步简化了图卷积层。在GCN
中,边是预定义的,边的权重是一维实数。边的权重用于聚合邻域信息以建模feature co-action
。GAT
学习每个中间层intermediate layer
分配不同的边权重。GAT
也通过边权重对feature co-action
进行建模,但是由于注意力机制,GAT
中的权重是节点的函数。因此注意力机制使得GAT
更有效地对feature co-action
进行建模。- 还有一些工作利用不同节点之间的
meta-path
进行embedding learning
。
尽管基于图的方法在图结构化数据中取得了巨大的成功,但是
feature co-action
仅由表示连接强度的一维权重来建模。这种表达能力可能不足以建模feature co-action
。combinatorial embedding
方法:组合embedding
方法根据组合embedding
来度量feature co-action
。FM
是浅层模型时代的代表性方法。在FM
中,feature co-action
被建模为特征的latent vector
的内积。然而,FM
在不同类型的inter-field
相互作用中使用相同的latent vector
,这可能会导致耦合梯度coupled gradient
问题并降低模型容量。假设有三个特征:性别、地点、星期。某个样本的特征为:“男性”、“上海”、“周日”。因此有:
$ \hat y_{\text{FM}} = b + w_男 + w_{上海} + w_{周日} + \mathbf{\vec v}_{男}\cdot \mathbf{\vec v}_{上海} + \mathbf{\vec v}_{男}\cdot \mathbf{\vec v}_{周日} + \mathbf{\vec v}_{上海}\cdot \mathbf{\vec v}_{周日} $因此有梯度:
$ \nabla_{\mathbf{\vec v}_男} \hat y_{\text{FM}} = \mathbf{\vec v}_{上海} + \mathbf{\vec v}_{周日} $假设性别和星期是独立的,那么理想情况下 $ \mathbf{\vec v}_{男} $ 应该和 $ \mathbf{\vec v}_{周日} $ 是正交的。但是上述梯度会沿着 $ \mathbf{\vec v}_{周日} $ 的方向更新 $ \mathbf{\vec v}_{男} $ 。这就是梯度耦合问题,这是由于在不同类型的
inter-field
相互作用中使用相同的latent vector
引起的。此外,
FM
的表达能力也受到浅层的限制。受到深度学习成功的启发,最近的
CTR
预估模型也已经从传统的浅层方法过度到现代的深度方法。DNN
在bit-wise level
建模非线性交互的能力非常强大,但是feature co-action
是隐式学习的。许多工作已经表明: 通过组合特征embedding
来显式建模feature co-action
有利于CTR
预估。Wide&Deep
手动设计的笛卡尔积作为wide
模块的输入,其中wide
模块是一个广义的线性模型。wide
模块结合深度神经网络来预估CTR
。DeepFM
在Wide&Deep
中将wide
部分替换为FM
模块,从而无需手动构建笛卡尔积。Productbased Neural Network: PNN
引入一个product layer
来捕获inter-field category
之间的feature co-action
。product layer
的输出馈入到后续的DNN
来执行最终的预测。Deep & Cross Network: DCN
在每一层应用特征交叉。
尽管和普通
DNN
相比,这些方法取得了显著的性能提升,但是它们仍然存在一些局限性。具体而言,每个ID embedding
同时承担representation learning
和co-action modeling
的责任。representation learning
和co-action modeling
之间的相互干扰可能会损害性能。因此,combinatorial embedding
的限制没有充分利用feature co-action
的能力。
25.1 模型
feature co-action
回顾:这里我们首先简要介绍一下CTR
预估中的feature co-action
,然后我们回顾建模feature co-action
的state-of-the-art
方法。在广告系统中,用户 $ u $ 点击广告 $ a $ 的预估点击率 $ \hat y $ 是通过以下方式计算:
$ \hat y = \text{DNN}(E(u_1),\cdots,E(u_i), E(a_1),\cdots,E(a_j)) $其中:
- $ \{u_1,\cdots,u_i\} $ 为用户 $ u $ 的特征集合,包括浏览历史、点击历史、用户画像等等特征。
- $ \{a_1,\cdots,a_j\} $ 为广告 $ a $ 的特征集合。
- $ E(\cdot)\in \mathbb R^d $ 为
embedding
函数,它将稀疏的ID
特征映射到可学习的、稠密的embedding
向量。其中 $ d $ 为embedding
维度。
除了这些一元特征,一些工作将特征交互建模为
$ \hat y = \text{DNN}\left(E(u_1),\cdots,E(u_i), E(a_1),\cdots,E(a_j),\{F(u_s,a_t)\}_{(s,t)=(1,1)}^{(i,j)}\right) $DNN
的附加输入:其中 $ F(u_s,a_t) \in \mathbb R^d $ 表示用户特征 $ u_s $ 和广告特征 $ a_t $ 之间的特征交互。
特征交互的融合改善了预测结果,这表明来自不同
group
的特征组合提供了额外的信息。直观的原因是:在CTR
预估任务中,某些特征组合与label
的关系,比单独isolated
的特征本身与label
的关系更强。以用户点击行为为例,由于用户兴趣的存在,用户点击历史与用户可能点击的target item
之间存在很强的关联。因此,用户点击历史和target item
的组合是CTR
预估的有效共现co-occurrence
特征。我们将这种与label
关系密切的特征交互称作特征协同feature co-action
。仔细回顾以前的
DNN-based
方法,可以发现一些深度神经网络即使不使用组合特征作为输入,也可以捕获特定特征之间的交互。例如,DIN
和DIEN
使用注意力机制来捕获用户行为特征和item
之间的交互。然而,这些方法的弱点在于它们仅局限于用户兴趣序列的特征交互,并且都是处理特征的embedding
向量。而低维空间中的embedding
向量往往会丢失很多原始信息。最直接的实现方法是为每个组合特征学习一个
embedding
向量,即笛卡尔积cartesian product
。然而,这也存在一些严重的缺陷:第一个问题是参数爆炸问题。例如,取值空间大小为 $ M $ 和 $ N $ 的两个特征做笛卡尔积,那么参数空间从 $ O(M+N) $ 扩展到 $ M(M\times N) $ ,这会给在线系统带来很大的负担。
此外,包含相同特征的两个组合之间没有信息共享,这也限制了笛卡尔积的表达能力。
另外,笛卡尔积的方式也无法泛化到训练期间
unseen
的特征组合。
一些工作尝试使用特殊的网络结构来建模
feature co-action
。然而,大多数这种相互交互的结构,与特征组feature groups
的representation
之间没有任何区别。为了不受笛卡尔积和其它先前工作缺陷的情况下利用
feature co-action
,我们提出了一个Co-Action Network: CAN
模型来有效地捕获inter-field
交互。根据以上分析,以往的工作并没有充分挖掘feature co-action
的潜力。受笛卡尔积中特征组合独立编码的启发,CAN
引入了一个可插拔pluggable
模块:协同单元co-action unit
。co-action unit
聚焦于扩展参数空间parameter space
,并有效地应用参数来建模feature co-action
。具体而言,co-action unit
充分利用一侧(例如用户侧)的参数来构建应用于另一侧(例如广告侧)的多层感知机MLP
。这种特征交叉范式给模型带来了更大的灵活性。- 一方面,增加参数维度意味着扩展
MLP
参数和层数。 - 另一方面,和在具有相同特征的不同组合之间不共享信息的笛卡尔积相比,
co-action unit
提高了参数利用率,因为MLP
直接使用feature embedding
。 - 此外,为了在模型中融入高阶信息,我们引入了多阶增强
multi orders enhancement
,它显式地为co-action unit
构建了一个多项式输入。多阶信息促进了模型的非线性,有助于更好的feature co-action
。
此外,我们提出了包括
embedding
独立性、组合独立性、阶次独立性的multi-level independence
,并通过拓宽broadening
参数空间来保证co-action learning
的独立性。- 一方面,增加参数维度意味着扩展
CAN
的整体架构如下图所示。用户特征和target item
特征以两种方式输入到CAN
中。在第一种方式中,所有的用户特征 $ \mathbf{\vec x}_\text{user} $ 和
target item
特征 $ \mathbf{\vec x}_\text{item} $ 都使用embedding layer
编码为稠密向量,然后分别拼接为 $ \mathbf{\vec e}_\text{user} $ 和 $ \mathbf{\vec e}_\text{item} $ 。在第二种方式中,来自 $ \mathbf{\vec x}_\text{user} $ 和 $ \mathbf{\vec x}_\text{item} $ 的部分特征被选择并映射到
$ H(\vec {\mathbf p}_\text{user},\vec {\mathbf p}_\text{item}) $co-action unit
的 $ \vec {\mathbf p}_\text{user} $ 和 $ \vec {\mathbf p}_\text{item} $ 从而进行co-action modeling
。co-action unit
的算子operator
定义为:它扮演
MLP
的角色,它的参数来自于 $ \vec {\mathbf p}_\text{item} $ 、输入来自于 $ \vec {\mathbf p}_\text{user} $ 。co-action unit
的细节后面详述。
$ \hat y = \text{DNN}\left(\mathbf{\vec e}_\text{user},\mathbf{\vec e}_\text{item}, H\left(\mathbf{\vec p}_\text{user},\mathbf{\vec p}_\text{item};\Theta_\text{CAN}\right);\Theta_\text{DNN}\right) $CAN
的最终架构形式化为:其中: $ \hat y $ 为预估的点击率, $ \Theta_\text{CAN} $ 为
co-action unit
的lookup table
的参数, $ \Theta_\text{DNN} $ 为DNN
的参数。
$ \min_{\Theta_\text{CAN},\Theta_e,\Theta_\text{DNN}} -y\log \hat y - (1-y)\log \left(1-\hat y\right) $ground truth
记作 $ y\in \{0,1\} $ 。我们最终最小化 $ \hat y $ 和 $ y $ 之间的交叉熵损失函数:其中 $ \Theta_e $ 为
feature embedding
的参数(用于计算 $ \mathbf{\vec e}_\text{user},\mathbf{\vec e}_\text{item} $ )。co-action unit
:co-action unit
的详细结构如上图左侧部分所示。每个item
特征通过MLP table lookup
从而对应一个多层感知机 $ \text{MLP}_\text{can} $ ,而用户特征被视为这些MLP
的输入。 输出的feature co-action
和common feature embeddings
一起用于最终的CTR
预估。注意:上图中
Parameter lookup
独立于Embedding Layer
,这使得representation learning
和co-action modeling
是独立的。$ \mathbf P_\text{item}\in \mathbb R^{M\times T} $ 作为 $ \text{MLP}_\text{can} $ 中每一层的
weight
和bias
, $ \mathbf P_\text{user}\in \mathbb R^{M\times D} $ 作为 $ \text{MLP}_\text{can} $ 的输入从而得到co-action
输出 $ \mathbf H $ ,其中 $ M $ 为unique ID
数量, $ D $ 和 $ T $ 为向量维度, $ D\lt T $ 。- 事实上 $ \mathbf P_\text{user} $ 也可以作为 $ \text{MLP}_\text{can} $ 的参数、 $ \mathbf P_\text{item} $ 也可以作为 $ \text{MLP}_\text{can} $ 的输入。根据经验,在广告系统中,候选
item
是所有item
中的一小部分,因此其数量小于用户点击历史中的item
数量。因此,我们选择 $ \mathbf P_\text{item} $ 作为 $ \text{MLP}_\text{can} $ 的参数。 - $ \mathbf P_\text{user} $ 的维度和 $ \text{MLP}_\text{can} $ 输入的维度相同;而 $ \mathbf P_\text{item} $ 的维度更高,因为它需要
reshape
为 $ K $ 层MLP
的权重矩阵和bias
向量。
给定某个
$ \vec {\mathbf p}_\text{item} = \text{concate}\left(\left\{\text{flatten}\left(\mathbf W^{(i)},\mathbf{\vec b}^{(i)}\right)\right\}_{i=0,1,\cdots,K-1}\right) $item ID
特征的参数 $ \vec {\mathbf p}_\text{item}\in \mathbb R^T $ 、给定某个user ID
特征的参数 $ \vec {\mathbf p}_\text{user}\in \mathbb R^D $ 。我们首先将一维向量 $ \vec {\mathbf p}_\text{item} $reshape
为 $ \text{MLP}_\text{can} $ 中所有层的权重矩阵和bias
向量,即:其中 $ \mathbf W^{(i)} $ 和 $ \mathbf{\vec b}^{(i)} $ 为 $ \text{MLP}_\text{can} $ 第 $ i $ 层的权重和偏置,一共有 $ K $ 层。
然后
$ \mathbf{\vec h}^{(0)} = \vec {\mathbf p}_\text{user}\\ \mathbf{\vec h}^{(i)} = \sigma\left(\mathbf W^{(i-1)} \mathbf{\vec h}^{(i-1)} + \mathbf{\vec b}^{(i-1)}\right),i=1,2,\cdots,K-1\\ \mathbf{\vec h} = H(\vec {\mathbf p}_\text{user},\vec {\mathbf p}_\text{item}) = \mathbf{\vec h}^{(K)} $feature co-action
计算为:其中: $ \sigma $ 为激活函数, $ \mathbf{\vec h} $ 为
feature co-action
。读者注:本质上是将向量内积这种线性交互形式替换为
MLP
这种非线性交互形式。在MLP
中,输入为用户侧embedding
、权重为广告侧embedding
的respahe
。对于像用户点击历史这样的序列特征,
co-action unit
应用于每个历史点击item
,然后对序列进行sum
池化;对于用户画像这样的非序列特征,co-action unit
并未进行池化。和其它方法相比,我们提出的
co-action unit
至少有三个优势:- 和以往在不同类型的
inter-field
相互作用中使用相同的latent
向量不同,co-action unit
利用DNN
的计算能力,通过动态参数和输入而不是固定模型来耦合两个分特征component feature
,从而提供更大容量来保证两个field
特征的更新并且避免耦合梯度。 - 其次,可学习参数的规模较小。
co-action learning
的最终目标是学习每个co-action feature
的良好的representation
向量。但是,直接学习分特征component feature
的笛卡尔积的embedding
需要学习相当大规模的参数。例如,考虑两个具有 $ N $ 个ID
数量的特征。如果我们通过学习笛卡尔积的embedding
来学习co-action representation
,则参数的规模应该是 $ O(N^2\times D) $ ,其中 $ D $ 为embedding
维度。但是,通过使用co-action unit
,这个规模可以降低到 $ O(N\times T) $ ,其中 $ T $ 为co-action unit
的维度。更少的参数不仅有利于学习,还可以有效减轻在线系统的负担。 - 第三,和之前的其他工作相比,
co-action unit
对新的特征组合具有更好的泛化能力。给定一个新的特征组合,只要之前训练过两侧的embedding
,co-action unit
仍然可以工作。
- 事实上 $ \mathbf P_\text{user} $ 也可以作为 $ \text{MLP}_\text{can} $ 的参数、 $ \mathbf P_\text{item} $ 也可以作为 $ \text{MLP}_\text{can} $ 的输入。根据经验,在广告系统中,候选
读者注:为简化讨论,假设
co-action unit
没有非线性激活函数、也没有bias
。用户侧的embedding
$ \vec {\mathbf p}_\text{user}\in \mathbb R^D $ ,item
侧有一组 $ D_1 $ 个embedding
$ \{\mathbf{\vec q}_\text{item,i}^{(1)}\}_{i=1}^{D_1 }\in \mathbb R^{D_1 \times D} $ ,因此特征组合得到新的交叉特征为 $ \vec {\mathbf p}_\text{user}^{(1)} =\left(\vec {\mathbf p}_\text{user}\cdot \mathbf{\vec q}_\text{item,1}^{(1)}, \cdots,\vec {\mathbf p}_\text{user}\cdot \mathbf{\vec q}_{\text{item},D_1}^{(1)}\right)\in \mathbb R^{D_1} $ 。如果
$ \{\mathbf{\vec q}_\text{item,i}^{(1)}\}_{i=1}^{D_1 }\in \mathbb R^{D_1 \times D},\cdots,\{\mathbf{\vec q}_\text{item,i}^{(K)}\}_{i=1}^{D_K }\in \mathbb R^{D_K \times D_{K-1}} $co-action unit
为 $ K $ 层,则item
侧的embedding
为:得到的交叉特征为:
$ \vec {\mathbf p}_\text{user}^{(K)} =\left(\vec {\mathbf p}_\text{user}^{(K-1)}\cdot \mathbf{\vec q}_\text{item,1}^{(K)}, \cdots,\vec {\mathbf p}_\text{user}^{(K-1)}\cdot \mathbf{\vec q}_{\text{item},D_K}^{(K)}\right)\in \mathbb R^{D_K} $因此
item
侧的embedding
可以视为高阶的( $ K $ 阶)、multi-head
(第 $ k $ 阶的head
数量为 $ D_k $ )的embedding
。如果muti-head
退化为single-head
、并且不同阶次的item embedding
共享,则co-action unit
退化回Deep Cross Network
。- 一方面,
co-action unit
类似于DIN
,它们都是仅考虑和target item
的交互。但是它们交互的方式(即交互函数)不同。 - 另一方面,
co-action unit
类似于xDeepFM
,它们都是显式建模特征交互,但是xDeepFM
考虑了更field
的特征交互。
因此这篇论文创新点存疑,并且
co-action unit
是否能够捕获feature co-action
也是存疑的。- 一方面,
多阶加强
$ \mathbf{\vec h} = H(\vec {\mathbf p}_\text{user},\vec {\mathbf p}_\text{item})=\sum_{c=1}^C \text{MLP}_\text{can} \left((\vec {\mathbf p}_\text{item})^c\right)\simeq \text{MLP}_\text{can}\left(\sum_{c=1}^C (\vec {\mathbf p}_\text{user})^c\right) $Multi-order Enhancement
:前面提到的feature co-action
基本上是基于一阶特征形成的,也可以在高阶上估计特征交互。虽然co-action unit
可以利用深层MLP
隐式地学习高阶特征交互,但是学习过程被认为很漫长。为此,我们在co-action unit
中显式引入多阶信息从而获得多项式输入。这是通过将 $ \text{MLP}_\text{can} $ 应用于 $ \mathbf{\vec p}_\text{user} $ 的不同阶次来实现的:其中 $ C $ 为阶次。
这里的近似是假设不同阶次之间的权重是共享的。
注意:当 $ c=1 $ 时,使用
SeLU
作为激活函数;当 $ c\gt 1 $ 时我们使用tanh
激活函数,从而避免由于高阶项引起的数值问题。多阶增强
multi-order enhancement
有效地提升了模型对co-action modeling
的非线性拟合能力,而不会带来额外的计算和存储成本。多
level
独立性Multi-level Independence
:learning independence
是co-action modeling
的主要关注点之一。为了确保学习的独立性,我们根据重要性从不同方面提出了三个level
的策略:level 1
:参数独立性,这是必须的。如前所述,我们的方法区分了representation learning
和co-action modeling
的参数。参数独立性是我们CAN
的基础。
$ |\mathbf{\vec p}_\text{item}| = \left(\sum_{i=1}^K |\mathbf W^{(i)}| + |\mathbf{\vec b}|\right)\times N,\quad |\mathbf{\vec p}_\text{user}| = |\mathbf{\vec x}|\times M $level 2
:组合独立性,这是推荐的。随着特征组合数量的增加,feature co-action
线性增长。根据经验,target item
特征像item_id, category_id
被选为权重侧embedding
,而用户特征则用于输入侧embedding
。由于权重侧embedding
可以和多个输入侧embedding
组合,反之亦然,因此我们的方法以指数方式扩大了它们的维度。假设有 $ M $ 个权重侧embedding
和 $ N $ 个输入侧embedding
,那么我们将权重侧embedding
的维度扩大 $ N $ 倍、将输入侧embedding
的维度扩大 $ M $ 倍:其中 $ |\mathbf{\vec x}| $ 为 $ \text{MLP}_\text{can} $ 的输入维度, $ |\cdot| $ 为参数维度。
在前向传播中,这些
embedding
被分为几个部分来完成MLP
操作。level 3
:阶次独立性,这是可选的。为了进一步提高多阶输入中co-action modeling
的灵活性,我们的方法对不同的阶次使用了不同的权重侧embedding
。权重侧embedding
的维度也相应增加了orders
倍。注意,此时由于 $ \text{MLP}_\text{can} $ 在不同阶次中不共享参数,因此以下的近似不可行:
$ \sum_{c=1}^C \text{MLP}_\text{can} \left((\vec {\mathbf p}_\text{item})^c\right)\neq \text{MLP}_\text{can}\left(\sum_{c=1}^C (\vec {\mathbf p}_\text{user})^c\right) $
协作独立性
co-action independence
有助于co-action modeling
,但是同时也带来了额外的内存访问和计算成本。在独立性level
和部署成本之间存在tradeoff
。从经验上来讲,模型使用的独立性level
越高,模型需要的训练数据就越多。在我们的广告系统中,我们使用了 三个level
的独立性。但是由于缺乏训练样本,我们在公共数据集中仅使用了embedding
独立性。
25.2 实验
数据集:我们使用三个公开可访问的数据集进行
CTR
预估任务的实验:Amazon
数据集:包含来自Amazon
的产品评论和元数据。在24
个产品类目中,我们选择Books
子集,其中包含75053
个用户、358367
个item
、1583
个类目。由于
Amazon
数据集最初不是CTR
预估数据集,因此未提供负样本。遵从前人的工作,我们随机选择未被特定用户评论的item
作为该用户的负样本,并创建相应的用户行为序列(点击和未点击)。最大序列长度限制为100
。Taobao
数据集:来自淘宝推荐系统中用户行为的集合。数据集包含大约100
万用户,用户行为包括点击、购买、加购物车、收藏。我们获取每个用户的点击行为,并根据时间戳进行排序从而构建用户行为序列。最大序列长度限制为200
。Avazu
数据集:是Avazu
提供的移动广告数据,包含11
天的真实工业数据,前10
天用于训练、第11
天用于测试。对于
Amazon
数据集和Taobao
数据集,我们根据用户行为序列对feature co-action
进行建模。相反,对于Avazu
数据集,我们使用离散特征对feature co-action
进行建模,因为Avazu
数据集包含各种数据字段,适合验证序列/非序列对feature co-action
建模的影响。在训练期间,第
10
天被视为验证集。
数据集的统计信息如下表所示。
baseline
方法:在本文中,我们使用DIEN
作为CAN
的base model
。请注意,由于co-action unit
是可插拔模块,因此允许使用其它任何模型。为了验证我们方法的有效性,我们将
CAN
和当前聚焦于特征交互的方法进行了比较。为了公平比较,DIEN
被用作这些方法的basis
。DIEN
:它设计了一个兴趣抽取层来从用户行为序列中捕获用户兴趣。兴趣演化层进一步用于对兴趣演化过程进行建模。- 笛卡尔积
Cartesian Product
:它是将两个集合相乘从而形成所有有序pair
对的集合。有序pair
对的第一个元素属于第一组集合、第二个元素属于第二组集合。 PNN
:它使用product layer
和全连接层来探索高阶特征交互。NCF
:它提出了一种神经网络架构来学习user
和item
的潜在特征,这些特征用于使用神经网络对协同过滤进行建模。DeepFM
:它是一种新的神经网络架构,它结合了FM
和深度学习的能力。
实现:我们使用
Tensorflow
实现了CAN
。- 对于 $ \mathbf{\vec p}_\text{item} $ ,我们使用八层的
MLP
,权重维度为4 x 4
,这导致 $ \mathbf{\vec p}_\text{item} $ 的维度为(4 x 4 + 4) x 8 = 160
(包括bias
)。 - 我们使用多阶加强,其中 $ \mathbf{\vec p}_\text{user} $ 的阶次为
2
。 - 模型从头开始训练,模型参数初始化为高斯分布(均值为
0
、标准差为0.01
)。优化器为Adam
,batch size = 128
,学习率为0.001
。 - 我们使用三层
MLP
来预测最终的CTR
,隐层维度为200 x 100 x 2
。
模型的评估指标为
AUC
。- 对于 $ \mathbf{\vec p}_\text{item} $ ,我们使用八层的
下表给出了
Amazon
数据集和Taobao
数据集上的实验结果。可以看到:CAN
在两个数据集上都优于其它state-of-the-art
的方法。和
base
模型DIEN
相比,CAN
分别将AUC
提高了1.7%
和2.1%
。同时CAN
在很大程度上优于其它co-action
方法,这证明了我们的方法在co-action modeling
上的有效性。值得注意的是,作为纯粹的
representation learning
方法,笛卡尔积方法和其它组合embedding
方法(如PNN
、NCF
、DeepFM
)相比,可以获得更好的性能。这表明虽然这些组合embedding
方法可以抽取一些co-action
特征,但是笛卡尔积确实可以学习具有良好representation
和co-action
的embedding
。相比之下,
CAN
取得了比笛卡尔积和组合embedding
方法更好的结果,这意味着基于网络机制的CAN
可以同时学习representation
和co-action
。
消融研究:为了研究每个组件的影响,我们进行了几项消融研究,如下表所示。
多阶
multi order
:首先我们评估多阶的影响。在 $ \mathbf{\vec p}_\text{user} $ 一阶项的基础上,我们逐渐增加了二阶项、三阶项、四节项。可以看到:- 从一阶到二阶,
AUC
提升了很多。 - 之后随着阶次的增加,差距开始缩小甚至造成负向影响。
多阶对于性能增益的影响很小,因此在实践中我们使用
2
阶或者3
阶是合适的。- 从一阶到二阶,
MLP
深度:其次,我们展示了 $ \text{MLP}_\text{can} $ 架构对于co-action modeling
的影响。具体而言,我们分别训练了具有不同MLP
层数的模型,分别为1/2/4/8
。MLP
层的输入和输出维度不变。可以看到:
- 一般而言,更深的
MLP
会带来更高的性能。 - 但是当层数超过
4
时,没有明显的AUC
增益,即8
层MLP
相比较4
层MLP
仅增加了0.02%
的AUC
。主要原因是训练样本对于如此深的架构来说是不够的。
- 一般而言,更深的
激活函数:最后,我们比较了不同激活函数的影响。可以看到:
- 非线性使得
AUC
提高了0.03% ~ 0.41%
。 - 在阶次为
2
的情况下,Tanh
相比SeLU
表现出更显著的性能,因为Tanh
起到了normalizer
的作用,从而避免高阶次的数值稳定性问题。
- 非线性使得
模型通用性
universality
和泛化generalization
:为了验证CAN
的特征通用性和泛化能力,我们从两个方面对CAN
和其它方法进行比较:验证具有非序列的co-action
特征,并预测训练期间未见过的co-action
特征的样本。通用性:虽然
CAN
主要针对包含大量行为序列的真实工业数据而设计,但是它仍然能够处理非序列输入。Avazu
数据集包含24
个数据字段,我们从中选择9
个字段构建16
种特征组合。实验结果如下表所示。可以看到:CAN
优于大多数方法并且和笛卡尔积相当。DNN
作为basic
模型,没有包含任何序列特征。因此除了DNN
之外,其它方法都包含了16
种组合特征。泛化能力:在真实的商业场景中,每天都会出现无数的特征组合,这就需要
CTR
模型的快速响应。泛化能力对于实际应用非常重要。为此,我们从
Amazon
测试集中删除了包含现有特征组合的样本。通过这种方式,我们获得了一个新的测试集,其特征组合对于训练好的模型而言是全新的。注意:我们仅要求特征组合为zero shot
,而不是所有特征都是zero shot
。实验结果如下表所示可以看到:
- 笛卡尔积在这种场景下是无效的(
DIEN+Cartesian
相比于DIEN
几乎没有提升),因为它依赖于训练好的co-action embedding
,但是测试集中这种co-action embedding
不可用。 - 相反,
CAN
仍然运行良好。与其它方法相比,CAN
显示出对新特征组合的出色泛化能力。
在真实的工业环境中,特征组合非常稀疏,只要 $ \mathbf P_\text{item} $ 和 $ \mathbf P_\text{user} $ 训练好,使用
CAN
处理新的特征组合就容易的多。- 笛卡尔积在这种场景下是无效的(
工业数据集上的结果:
在线
Serving
和挑战:一开始我们在我们的系统上部署了笛卡尔积模型,这造成了很多麻烦。- 一方面,即使使用
ID
低频过滤,模型大小也以极大的速度扩大。 - 另一方面,额外的 $ M\times N $ 的
ID
也带来了无法接受的embedding look up
操作的数量以及系统响应延迟。
相比之下,
CAN
在这方面要有好的多。为了在我们的广告系统上部署CAN
,我们选择了21
个特征,包括6
个广告特征、15
个用户特征来生成特征组合,以便由于co-action
独立性而分配了额外的21
个embedding
空间。显著增加的
embedding
空间仍然导致在线serving
的巨大压力。由于用户特征大多数为长度超过100
的行为序列,因此需要额外的内存访问,导致响应延迟上升。此外,feature co-action
的计算成本根据特征组合的数量线性增加,这也给我们的系统带来了相当大的响应延迟。- 一方面,即使使用
解决方案:为了解决这些问题,我们付出了很多努力来减少响应延迟。我们从三个方面简化模型:
序列截断:
16
个用户特征的长度从50
到500
不等。为了降低内存访问成本,我们简单地对我们的用户特征应用序列截断。例如,长度为200
的所有用户行为序列都截断到50
。最近的用户行为被保留。序列截断将
Query Per Second: QPS
提高20%
,但是导致AUC
降低0.1%
,这是可以接受的。组合缩减:
6
个广告特征和15
个用户特征最多可以获得90
个特征组合,这是一个沉重的负担。经验上,同一类型的广告特征和用户特征的组合可以更好地对特征共现co-occurrence
进行建模。根据这个原则,我们保留item_id
、item_click_history
、category_id
、category_click_history
等组合,并删除一些不相关的组合。这样,组合的数量从90
减少到48
个,QPS
提高了30%
。计算
kernel
优化:co-action
计算涉及到 $ \mathbf {P}_\text{item} $ 和 $ \mathbf P_\text{user} $ 之间的一个耗时的大矩阵乘法,它们的形状分别为[batch_size, K, dim_in, dim_out]
和[batch_size, K, seq_len, dim_in]
。其中K, seq_len, dim_in, dim_out
分别指的是co-action
特征数量、用户行为序列长度、MLP
输入维度、MLP
输出维度。在我们的场景中,
dim_in
和dim_out
不是常用的形状,因此这种矩阵没有被Basic Linear Algebra Subprograms:BLAS
很好地优化。为了解决这个问题,我们重写了内部计算逻辑,带来了60%
的QPS
提升。此外,由于该矩阵乘法之后是
seq_len
维度上的sum
池化,我们进一步在矩阵乘法和sum
池化之间进行了kernel fusion
。通过这种方式,避免了矩阵乘法输出的中间结果写入GPU
内存,这又带来了47%
的QPS
提升。
通过这一系列的优化,使得
CAN
能够在主流量main traffic
中稳定地在线serving
。在我们的系统中,每个GPU
可以处理将近1K QPS
。下表给出了我们的在线A/B test
中CAN
对CTR
和RPM:Revenue Per Mille
的提升。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论