ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PNN网络:从内积到外积的显式特征交叉经典模型

PNN网络:从内积到外积的显式特征交叉经典模型 CTR预估这个方向做了几年的人大概率都绕不开一个词特征交叉。无论是推荐系统还是广告系统用户行为、物品属性、上下文信息最终都要转化成能落地的预估值而怎么让模型真正“理解”特征之间的交互关系是决定效果上限的关键。PNN网络Product-based Neural Network就是解决这个问题的一个经典方案它提出了一种比简单拼接Embedding更直观、更强力的特征交叉方式在进入深度网络之前先用内积或外积把特征对“显式地”交叉一遍。这篇博客我打算从PNN的设计动机、网络结构、核心公式、代码实现到实际训练中踩过的坑完整展开聊聊希望对正在做推荐模型、或者刚接触深度CTR模型的朋友有帮助。1. 为什么会出现PNN从传统CTR模型到深度特征交叉在讲PNN之前得先理解当时2016年前后CTR预估模型遇到了什么问题。那个阶段主流的做法是LRLogistic Regression加人工特征组合而FMFactorization Machine虽然通过隐向量的内积实现了二阶特征交叉但它本质上还是线性模型交叉的表达能力有限而且只停留在二阶。深度学习兴起后大家开始思考怎么把神经网络用在CTR预估上。比较早的尝试是Deep Crossing模型把所有特征的Embedding拼接成一个长向量直接喂给多层全连接网络。这种做法的优点是结构简单但问题也很明显——特征交叉完全依赖DNN去“隐式学习”。DNN对特征交叉的确有建模能力但它是非结构化的、难以控制的很多情况下需要非常深的网络和大量数据才能拟合出有效的交叉信息实际工程中往往不够高效。1.1 FM模型带来的启发FM的核心是对于每一对特征i和j用两个隐向量Vi和Vj的内积来表示它们的交叉权重。这个设计妙在没有引入额外的全局参数而是用特征自身的向量表达来计算交互这样即使遇到训练中没出现过的特征组合只要它们对应的Embedding存在也能计算出交叉结果。这种“向量内积”的思路直接启发了PNN的Product层设计。不过我最初看FM的时候心里也有个疑问内积的表达能力够吗两个向量做内积得到的是一个标量等于把两个向量的逐元素乘积全部加起来这个标量只能表达一种“相似度”或者说“共现强度”。真实场景里特征交叉的形式显然更丰富——比如用户性别为“男”和物品类目为“游戏”的交叉和用户性别为“男”与物品类目为“运动”的交叉它们的影响方向可能完全不同用单一标量去表达难免有些粗糙。这也是后来OPNN外积版本出现的原因之一外积能保留更多的交互信息不再压缩成一个点。1.2 FNN与Deep Crossing交叉不够直观的问题FNNFactorization-machine supported Neural Network的思路是用FM预训练好的隐向量来初始化DNN的Embedding层再通过DNN做高阶交叉。这种做法在训练初期效果不错因为Embedding有了一个相对合理的起点但它仍然没有把“特征交叉”作为显式操作放入网络中交叉还是要靠DNN自己慢慢学。而且FNN依赖FM的预训练整个训练流程相对复杂工业化部署时还要多维护一套模型。Deep Crossing则是完全端到端把所有特征Embedding拼接后交给残差网络或全连接网络。它的优势是不需要预训练但问题同样存在拼接操作本身没有生成任何新的交叉特征信息要一直到后续隐层中才能慢慢组合。我做过一些对比实验在数据量有限的场景下Deep Crossing的表现往往还不如FM人工特征原因就在于DNN没有足够的样本去学习有效的特征交互模式。PNN就是在这个背景下提出来的与其让DNN隐式地、缓慢地学习特征交叉不如在Embedding层和DNN之间加一个专门的Product层先把特征两两之间的交互信号显式地计算出来再把这些信号和原始Embedding一起送入DNN。这种设计把特征交叉从“黑盒摸索”变成了“白盒计算”理论上更高效实践上也确实有效。1.3 PNN的核心思路用product操作来建模特征交叉PNN的“P”就是Product它的核心创新在于对任意两个特征域的Embedding不再只是拼接而是先做一个product操作内积或外积得到一组新的向量/标量作为交叉特征再送入深度网络。这里的思路可以类比成“预处理”拼接相当于把原材料直接扔给厨师DNN自由发挥而Product层相当于先由配菜师傅把食材按特定方式搭配好再交给厨师加工。配菜师傅的搭配逻辑虽然简单就是内积或外积但它保证了交叉信息以显式的形式存在不会被DNN在传递过程中稀释掉。从后来的发展看PNN这种“Embedding Product DNN”的架构也成为了FNN、DeepFM、xDeepFM等一系列模型的共同范式。不同模型的区别本质上就是“用什么方式在什么时候做特征交叉”的差异。2. PNN网络整体架构与核心环节解析2.1 网络整体结构四层一输出PNN的整体结构可以拆成四层加一个输出层从底往上分别是输入层稀疏特征原始特征经过One-Hot或Multi-Hot编码变成高维稀疏向量。例如用户ID、物品ID、类目ID、年龄分段等每条特征对应一个特征域Field。Embedding层每个特征域对应一个Lookup Table嵌入矩阵把稀疏的One-Hot向量映射成稠密的低维Embedding向量。Product层这是PNN的精华。它将所有特征域的Embedding向量两两之间进行product操作输出交叉后的结果向量同时也会保留一份原始Embedding信息相当于“一阶项”。全连接隐层L1、L2等把Product层的输出展平后通过多层全连接网络进行高阶非线性变换。输出层用Sigmoid函数输出点击率/转化率的预估概率。整体流程可以用一句话概括原稀疏特征 → 稠密Embedding → 显式特征交叉 → 深度网络 → 预估概率。我觉得这个结构最聪明的地方在于Product层的位置恰到好处——它没有取代DNN而是“辅助”DNN。如果只有Product层那模型就退化成了类似FM的形式高阶交叉学不了如果取消Product层那就退化成Deep Crossing。PNN是同时把“低阶显式交叉”和“高阶隐式交叉”塞进了同一个网络各司其职。2.2 Embedding层把稀疏特征变成稠密向量Embedding层的概念今天来看已经很普及了但在PNN刚提出的那会儿很多人还没有把它和“特征表达”深度联系起来。PNN中的Embedding层本质上是做了两件事第一降维。原始稀疏特征动辄百万甚至千万维直接喂给DNN是不现实的。Embedding把每个特征映射到一个低维空间通常16~64维相当于把“1-of-N”编码变成了“分布式表达”维度大幅下降同时保留了语义信息。第二为Product层的交叉计算提供基础。不管是内积还是外积都需要向量化的输入。如果特征还是One-Hot形式那两两内积绝大多数情况下都是0计算交叉就失去了意义。只有转成稠密Embedding后两两之间的内积/外积才有信息量。这里有个细节值得注意不同特征的维度不一定非要一样但在PNN中为了让内积/外积操作可行通常会把所有特征的Embedding维度统一。如果有的特征特别稀疏、有的特别稠密可以适当调整初始化方式但维度必须对齐否则代码层面会很麻烦。2.3 Product层PNN的“杀手锏”Product层是PNN的核心也是它和普通“EmbeddingMLP”模型最不一样的地方。它的输入是N个特征域的Embedding向量假设每个向量维度为M输出则分两部分第一部分是线性项z也就是把每个特征域的Embedding向量拼接或求和后保留下来相当于保留了每个特征本身的信息可以理解为一阶特征。第二部分是交叉项p也就是对N个Embedding两两做product操作得到的输出。最终Product层的输出是z和p拼接在一起或者分别处理后相加再喂给DNN。其中交叉项p的计算方式有两种内积IPNN对特征i和j的Embedding做内积得到标量p_ij fi, fj。把所有特征对的标量拼接起来形成p向量。外积OPNN对特征i和j的Embedding做外积得到矩阵p_ij fi * fj^T维度M×M。把所有矩阵展平或压缩后拼接起来。这两种方式各有优劣后面我会详细对比。Product层放在Embedding之后、DNN之前实际上相当于人为地构造了一个“特征交叉池”。在传统LR里特征交叉需要人工设计成本极高在FM里只做二阶内积而PNN把内积/外积的结果作为DNN的输入DNN可以在其基础上继续学习更高阶的非线性交叉。这相当于既给了模型原材料又给了模型一个半成品加工车间效率自然不一样。2.4 内积与外积的数学原理与选择内积和外积听起来都是线性代数的基础操作但在PNN的语境下它们的含义和效果差异非常大。内积的定义很简洁两个同维向量逐元素相乘再求和得到一个标量。它的本质是在度量两个向量的“方向一致性”。在推荐场景下内积越大表示两个特征向量在语义空间中的方向越接近可以解释为“用户特征与物品特征越匹配”。FM用的就是内积所以从数学原理上讲IPNN可以看作FM在深度网络框架下的“增强版”——它不仅做了二阶内积还把内积结果继续交给DNN处理从而获得高阶交叉能力。外积则不同两个向量做外积得到一个M×M的矩阵。这个矩阵包含了两个向量所有维度之间的两两乘积组合信息量远大于标量。比如向量f1 (a1, b1)向量f2 (a2, b2)外积矩阵为[[a1a2, a1b2], [b1a2, b1b2]]矩阵里既有a1和a2的交互也有a1和b2、b1和a2、b1和b2的交互可以说把交叉粒度细化到了向量内部的每个维度。从表达能力上讲外积上限比内积高很多这也是OPNN理论上更吸引人的原因。但在实际工程中我个人的经验是外积虽然信息更丰富却更容易导致过拟合和训练不稳。因为外积矩阵的维度是M×M如果Embedding维度是64那一个特征对就产生4096维的向量N个特征域两两组合后维度会变得非常夸张。而且很多外积矩阵的元素是稀疏的因为Embedding向量中某些维度的值接近0在DNN反向传播时这些稀疏值对应的梯度也容易出现极端情况导致训练不稳定。所以在选择内积还是外积时我的建议是如果数据量不大、特征规模较小优先选IPNN。稳定、收敛快、实现简单。如果数据量很大、且特征交互模式确实很复杂可以尝试OPNN但要做好正则化和梯度裁剪。也可以做融合部分强关联的特征域对内积其他弱关联特征域用外积但这样做实现复杂度会上升需要根据业务情况权衡。3. PNN的两种变体IPNN与OPNN的实现细节3.1 IPNN的公式与实现IPNNInner Product-based Neural Network的核心是对任意两个特征域的Embedding做内积得到标量p_ij然后将所有的p_ij拼接成一个向量与一阶项拼接后送入DNN。假设有N个特征域每个域的Embedding向量维度为M。那么特征对的数量是C(N, 2) N(N-1)/2如果N10特征对数量就是45如果N50特征对数量就是1225。每个特征对内积后是一个标量所以IPNN得到的交叉向量维度就是C(N, 2)维。这个维度其实不算大相比外积动辄M×M的维度所以IPNN在工程上更容易处理。它的公式可以写成p (p_12, p_13, ..., p_(N-1)N)其中p_ij Ei, Ej这里的Ei是第i个特征域的Embedding向量。在实现的时候有一种比较实用的做法把N个Embedding向量堆叠成一个矩阵E维度N×M那么所有两两内积的结果可以直接用矩阵乘法E * E^T一次性算出来得到的是一个N×N的对称矩阵。我们只需要取上三角或下三角的非对角元素加上对角元素或者去掉对角元素作为交叉向量。这里有一个小经验IPNN的交叉向量是否包含“自身内积”ij的项对效果影响不大因为自身内积就是向量L2范数的平方相当于给模型提供了一个特征重要性信息。但在实际实现时通常取非对角元素就够了这样既能减少冗余又能降低计算量。3.2 OPNN的公式与实现OPNNOuter Product-based Neural Network则是把内积换成外积。对任意两个特征域的Embedding做外积得到M×M的矩阵。将所有外积矩阵展平成向量后拼接维度是C(N, 2) * M * M。这个维度通常非常吓人。举个例子N10M64那么外积向量的维度是C(10, 2) * 64 * 64 45 * 4096 184320维接近18万维的向量直接输入DNN第一层全连接的参数数量就是18万×隐层单元数计算量和过拟合风险都极大。所以原始PPN论文以及很多实际实现中对OPNN都会做一个压缩处理把每个外积矩阵通过一个权重矩阵加权求和压缩成一个k维向量k远小于M×M或者将外积矩阵先经过一个卷积层/池化层再来拼接。在动手实现OPNN时我建议把外积矩阵先做一次“全局平均池化”或“单层卷积”将每个M×M矩阵压缩成一个标量或低维向量再进入DNN。这样虽然损失了一部分信息但能控制计算量增加训练稳定性。从我个人经验来看OPNN在数据集比较大、Embedding维度适中比如8或16的时候能获得优于IPNN的AUC。但一旦Embedding维度超过32OPNN的参数量和过拟合风险就会显著上升训练速度和效果都会受到很大影响。所以如果你决定用OPNN建议Embedding维度初始化得小一点并且配合Dropout使用。3.3 完整Keras代码示例理论讲了一大堆直接上代码更直观。这里我写一个基于TensorFlow Keras的简化版PPN实现包含IPNN和OPNN两种Product层。代码不是工业级最优重心在于把核心逻辑讲清楚。import tensorflow as tf from tensorflow.keras import layers, Model class ProductLayer(layers.Layer): def __init__(self, use_innerTrue, use_outerFalse, compress_dim64): super().__init__() self.use_inner use_inner self.use_outer use_outer self.compress_dim compress_dim def build(self, input_shape): # input_shape: (batch_size, num_fields, embed_dim) self.num_fields input_shape[1] self.embed_dim input_shape[2] if self.use_outer: # 外积压缩矩阵将 M*M 压缩到 compress_dim self.outer_w self.add_weight( shape(self.embed_dim * self.embed_dim, self.compress_dim), initializerglorot_uniform, trainableTrue ) def call(self, inputs): # inputs: (batch, num_fields, embed_dim) field_emb inputs batch_size tf.shape(field_emb)[0] inner_outputs [] outer_outputs [] for i in range(self.num_fields): for j in range(i1, self.num_fields): ei field_emb[:, i, :] # (batch, embed_dim) ej field_emb[:, j, :] if self.use_inner: inner_val tf.reduce_sum(ei * ej, axis-1, keepdimsTrue) # (batch, 1) inner_outputs.append(inner_val) if self.use_outer: outer_mat tf.einsum(bi,bj-bij, ei, ej) # (batch, embed_dim, embed_dim) outer_flat tf.reshape(outer_mat, (batch_size, -1)) # (batch, embed_dim*embed_dim) outer_val tf.matmul(outer_flat, self.outer_w) # (batch, compress_dim) outer_outputs.append(outer_val) if self.use_inner: inner_concat tf.concat(inner_outputs, axis-1) # (batch, num_pairs) if self.use_outer: outer_concat tf.concat(outer_outputs, axis-1) # (batch, num_pairs * compress_dim) # 还要保留一份原始 embedding 作为一阶项 flatten_emb tf.reshape(field_emb, (batch_size, -1)) # (batch, num_fields*embed_dim) result [flatten_emb] if self.use_inner: result.append(inner_concat) if self.use_outer: result.append(outer_concat) return tf.concat(result, axis-1) def build_pnn(item_num, cate_num, embed_dim8, num_fields3, use_innerTrue, use_outerFalse): # 假设三个特征域item_id, cate_id, user_behavior_avg item_input layers.Input(shape(1,), nameitem_id) cate_input layers.Input(shape(1,), namecate_id) user_input layers.Input(shape(1,), nameuser_feat) item_emb layers.Embedding(item_num, embed_dim, nameitem_emb)(item_input) cate_emb layers.Embedding(cate_num, embed_dim, namecate_emb)(cate_input) user_emb layers.Embedding(100, embed_dim, nameuser_emb)(user_input) # 将不同特征域的 embedding 合并成一个 tensor field_embeddings tf.concat([item_emb, cate_emb, user_emb], axis1) # (batch, 3, embed_dim) prod_out ProductLayer(use_inneruse_inner, use_outeruse_outer)(field_embeddings) x layers.Dense(64, activationrelu)(prod_out) x layers.Dropout(0.3)(x) x layers.Dense(32, activationrelu)(x) x layers.Dropout(0.3)(x) output layers.Dense(1, activationsigmoid)(x) model Model(inputs[item_input, cate_input, user_input], outputsoutput) return model model build_pnn(item_num10000, cate_num100, embed_dim8, use_innerTrue, use_outerFalse) model.compile(optimizeradam, lossbinary_crossentropy, metrics[AUC]) model.summary()上面这段代码里我特意用了for循环来计算特征对这样逻辑直观。实际工程中如果特征域数量很多比如超过20个纯for循环的效率会比较低建议把Embedding矩阵整理成一个大矩阵用矩阵乘法一次性计算内积矩阵或者用tf.vectorized_map来做batch维度上的并行。另外要注意这里的user_feat我用Embedding来表示实际业务里用户侧的连续特征如活跃天数、近7天消费金额不需要Embedding可以直接作为数值特征拼接到DNN层之前。这类特征不需要参与Product层的交叉直接保留下来即可否则会让模型参数膨胀不少。4. 我踩过的坑PNN训练中的常见问题与排查技巧4.1 外积特征稀疏导致梯度爆炸我第一次跑OPNN的时候训练没几步就出现了loss变成NaN的情况。排查了半天最后定位到是外积矩阵的数值范围问题某些Embedding向量的初始值如果过大外积矩阵的元素就会变得非常大进而导致梯度爆炸。外积的数学本质是向量元素两两相乘它会把数值范围“放大”。如果两个向量中的元素值都在0.5左右外积后矩阵元素可能在0.25左右但如果元素值在2左右外积矩阵就可能变成几十甚至上百继续经过多层网络后极容易溢出。解决办法有几种Embedding初始化用小方差比如用标准差为0.01的正态分布而不是默认的0.1。对Embedding向量做L2归一化让它的模长固定为1这样内积有界、外积矩阵元素也有界。在Product层之后加BatchNormalization强制把数据拉回正常范围。使用梯度裁剪clipnorm1.0或5.0。我后来在线上稳定训练时通常的组合是Embedding初始化标准差0.01 BatchNormalization 梯度裁剪。三者配合基本上可以杜绝外积导致的数值爆炸问题。4.2 维度爆炸与计算开销这是PPN尤其是OPNN的“老毛病”。前面算过N10、M64时OPNN的输出维度可以到18万维。这种情况下即使模型能训练线上推理的开销也无法接受。我一开始在业务中直接用标准OPNN结构结果单条样本的推理耗时从原来的1.2ms飙升到23ms性能完全不可接受。解决方案有三个方向第一限制参与Product层的特征域数量。不是所有特征都值得做交叉像“用户ID”和“物品ID”这种高基数特征交叉后虽然有信息量但没必要和“小时段”“星期几”这些低阶特征做外积。可以手动筛选重要的特征域参与Product其他特征只保留一阶Embedding。第二用压缩矩阵降维。就像前面代码示例里的outer_w把M×M的外积矩阵压缩到低维空间维度可以从M×M降低到64甚至32。代价是模型表达能力的损失但换来的是训练和推理速度数量级的提升。第三用内积替代外积。IPNN在大多数情况下已经能取得不错的效果而且计算量小很多。如果业务迭代节奏快、需要频繁实验先用IPNN验证思路再决定是否升级到OPNN是比较务实的路线。4.3 一阶项的重要性在调试PPN的过程中我发现一个容易被忽视的细节Product层输出的交叉项虽然重要但一阶项原始Embedding的拼接或求和同样不可或缺。如果没有一阶项网络就只能依赖交叉特征去预测而交叉特征在很多情况下是稀疏的会导致模型对高频特征过度拟合对低频特征则几乎无法学习。举个实际例子一个物品在训练集里只出现过几十次它的ID Embedding本身就学得不太好。这时如果只保留它与其他特征的交叉项噪声会被放大。而如果有一阶项作为“兜底”模型至少能直接从该物品的Embedding本身获取预测信号效果会稳定很多。我在代码实现里始终保留了flatten_emb作为一阶项也推荐大家这么做。有些开源实现会把一阶项和二阶项融合到同一个DNN输入里有些则会把一阶项单独用一个线性模型并行输出两种方式都可以。但千万不要去掉一阶项这是我在多次消融实验里验证过的结论去掉一阶项AUC平均下降0.3~0.5个百分点这个幅度在CTR场景中已经算非常显著了。4.4 特征域顺序与Embedding维度对齐PPN对输入特征域的排列顺序及其Embedding维度有一个“隐性要求”所有参与Product的特征域其Embedding维度必须一致否则内积/外积操作无法进行。这一点在代码实现中一定要写断言来检查否则维度不匹配的报错信息会很绕。另外特征域的排列顺序会影响内积矩阵的结构但理论上不影响最终效果因为DNN可以自行学到不同特征对的重要性。不过在调试时固定顺序会更方便排查。我个人习惯在数据管道中先定义好field的顺序并在训练和预测阶段保持一致。这里有一个容易踩的坑如果某个特征域是Multi-Hot比如用户历史点击的多个物品ID它的Embedding输出是一个(batch, seq_len, embed_dim)的序列不能直接和普通特征域的(batch, embed_dim)向量做内积。遇到这种情况通常需要对序列Embedding做池化sum pooling或attention pooling先压缩成一个向量再参与Product层计算。5. 性能评估与建模经验PNN到底好不好用以及与后续模型的比较5.1 离线评估指标与我的习惯评估PPN模型效果时离线阶段我一般优先看AUC其次看GAUCGroup AUC。AUC反映整体排序能力但CTR场景中用户群体差异很大GAUC按用户分组计算AUC再按曝光加权平均更能反映线上实际的排序质量。在实际对比测试中IPNN相比Deep CrossingEmbeddingMLP通常能带来0.5~1.5个百分点的AUC提升这个幅度相当可观。OPNN在数据量大的场景下相比IPNN还能再提升0.1~0.3个百分点但代价是参数量和训练时间的显著增加。所以我的建议是先做IPNN把它调优到位再考虑是否升级到OPNN。除了AUC我还习惯同时看RIGRelative Information Gain或LogLoss的变化。这两个指标在数据分布变化时会比AUC更敏感有助于发现过拟合问题。特别是使用OPNN时如果训练集RIG持续上升但验证集RIG开始下降那就说明过拟合了需要增加Dropout比例或降低Embedding维度。5.2 线上A/B测试经验离线效果好线上不一定好这是做推荐模型的人都懂的“鬼故事”。PPN上线的过程中我遇到过两个典型的线上问题。第一是特征覆盖度不足导致的“冷启动”现象。PPN对特征交叉的表达依赖Embedding质量如果某些新物品的Embedding没有充分训练交叉项的贡献会变成噪声甚至拉低线上指标。解决方法是给这类稀疏特征加一个“置信度”权重或者在特征侧增加统计特征如点击率、曝光量来辅助预测。第二是推理性能。OPPNN在离线测试时P99耗时勉强达标上到生产环境后因为并发量的增加系统CPU直接被打满。后来做了两个优化一是把外积矩阵的压缩层提前到Embedding层之后利用该层权重矩阵的低秩分解来近似计算外积大幅减少乘法次数二是把模型切分成两段第一段EmbeddingProduct在线下预计算好结果存入缓存线上只计算后续DNN部分。这两个优化把P99耗时降回了3ms以内线上指标也稳定住了。5.3 PNN和DeepFM、DCN、xDeepFM等模型的关系PNN出现之后特征交叉方向又涌现了不少模型了解它们之间的差异能帮你更好地理解PPN的定位。DeepFM可以看作是“FM Deep”的并行结构它的FM部分专门负责二阶特征交叉Deep部分负责高阶隐式交叉。与PPN相比DeepFM更强调低阶项和高阶项的解耦而且它的FM部分天然支持在稀疏特征上直接做交叉实现上更加简洁。从实验结果看DeepFM在大多数公开数据集上与IPNN效果相当但实现难度更低所以目前工业界的应用更广泛。DCNDeep Cross Network的核心是设计了Cross Network用多层交叉进行高阶特征交叉。它和PPN的区别在于PPN只做了一次显式二阶交叉后续高阶交叉交给DNN而DCN是每一层都在做特征交叉交叉的阶数逐层递增。DCN对高阶交叉的表达能力更强在特征间关系复杂的场景下效果往往更好。xDeepFM则是在DCN基础上用向量级的外积替代了标量级的交叉同时引入了CINCompressed Interaction Network来显式学习高阶特征交互。从表达力上讲xDeepFM和OPNN有些类似但xDeepFM用压缩交互的方式让高阶交叉的计算变得更加可控。如果你是在做工程落地我的建议是用IPNN或DeepFM作为基线模型快速验证特征交叉带来的增益如果业务对高阶交叉的需求很明确比如用户行为序列很长、特征分布很复杂再考虑DCN或xDeepFM这类更复杂的模型。PNN最大的价值在于它帮你理解了“显式特征交叉”为什么重要以及“内积/外积”这种基础操作在特征交互建模中的意义。从我个人这些年的实践经验来看PPN最大的贡献不是它本身的线上效果有多极致而是它把“特征交叉”这件事从人工设计变成了网络结构设计为后来各种深度CTR模型打下了方法论基础。如果你正在做推荐系统、广告排序或搜索排序花时间把PPN的结构、内积/外积的取舍、一阶项的作用彻底搞明白绝对不亏。而且按这个思路去理解和调试DeepFM、xDeepFM这些后续模型也会顺手很多。
返回列表