☰
DeepCTR 之 PNN(Product-based Neural Network)模型:源码级原理剖析与完整参数实战指南
2026/9/27 7:51:09 网站建设 项目流程
  • 人工智能
  • 深度学习
  • 机器学习

【免费下载链接】DeepCTR

Easy-to-use,Modular and Extendible package of deep-learning based CTR models .

项目地址:https://gitcode.com/gh_mirrors/de/DeepCTR
点击查看免费下载

导读

本文以 DeepCTR 官方 API 文档中 deepctr.models.pnn 模块 为核心,系统讲解基于乘积的神经网络 PNN(Product-based Neural Network)在 DeepCTR 中的实现与使用。你将掌握 PNN 的完整构造参数与默认值、内积/外积两种特征交互层(IPNN / OPNN)的底层实现原理、四种产品层组合模式,以及基于 Keras 与 TensorFlow Estimator 两种接口的建模、训练、评估与模型持久化全流程。文末还会结合仓库测试用例说明如何快速验证模型可用性。

PNN 模型是什么:从论文到 DeepCTR 实现

PNN(Product-based Neural Network)由 Qu 等人提出("Product-based neural networks for user response prediction",ICDM 2016),其核心思想是在传统 DNN 之前显式建模特征域之间的乘积交互。与仅仅拼接 embedding 向量的 FNN、DeepFM 不同,PNN 在 embedding 层之上增加了一个Product Layer,对任意两两特征域计算内积(inner product)或外积(outer product),把高阶特征交互信号注入深度网络。

在 DeepCTR 中,PNN 由三部分协作完成:

  • 模型入口函数 deepctr/models/pnn.py 中的PNN(),负责组装整个网络;
  • 乘积交互层 deepctr/layers/interaction.py 中的InnerProductLayer与OutterProductLayer;
  • DNN 与输出层 deepctr/layers/core.py 中的DNN与PredictionLayer。

该模块在官方模型索引 Models.rst 中被列为 DeepCTR 的核心模型之一(IPNN 与 OPNN 两种变体可通过参数切换)。

PNN API 与完整参数详解

PNN是典型的 Keras 函数式 API 构造器,函数签名(见 deepctr/models/pnn.py)如下:

def PNN(dnn_feature_columns, dnn_hidden_units=(256, 128, 64), l2_reg_embedding=0.00001, l2_reg_dnn=0, seed=1024, dnn_dropout=0, dnn_activation='relu', use_inner=True, use_outter=False, kernel_type='mat', task='binary'): ... return model

调用后返回一个tensorflow.keras.models.Model实例。下表逐参数说明其含义、默认值与取值范围:

参数类型默认值说明
dnn_feature_columnsiterable无(必填)供深度部分使用的全部特征列(SparseFeat/DenseFeat等),由deepctr.feature_column构造
dnn_hidden_unitslist(256, 128, 64)DNN 隐层神经元数量列表,[]表示去掉 DNN,只保留产品层输出
l2_reg_embeddingfloat0.00001施加在 embedding 向量上的 L2 正则强度
l2_reg_dnnfloat0施加在 DNN 权重上的 L2 正则强度
seedint1024随机种子,用于权重初始化、Dropout 等随机过程复现
dnn_dropoutfloat0DNN 神经元丢弃概率,取值范围[0, 1)
dnn_activationstr'relu'DNN 激活函数,如'relu'、'tanh'、'sigmoid'等
use_innerboolTrue是否启用内积(Inner Product)交互
use_outterboolFalse是否启用外积(Outer Product)交互
kernel_typestr'mat'外积核矩阵类型,只能是'mat'、'vec'或'num'
taskstr'binary''binary'使用二分类 logloss,'regression'使用回归损失

两个值得注意的实现细节:

  1. 非法参数会直接抛错。PNN入口处对kernel_type做了白名单校验(deepctr/models/pnn.py),OutterProductLayer构造时同样校验(deepctr/layers/interaction.py),传入kernel_type之外的字符串会抛出ValueError("kernel_type must be mat,vec or num")。

  2. 默认组合是 IPNN:use_inner=True, use_outter=False,这也是论文中最常用的配置。

模型结构与数据流:源码级解析

PNN的完整数据流可以拆成六个步骤(对应 deepctr/models/pnn.py):

第 1 步:构建输入层。build_input_features(dnn_feature_columns)把特征列转换为 KerasInput字典,inputs_list = list(features.values())作为最终Model(inputs=..., outputs=...)的输入列表。

第 2 步:生成 embedding 与稠密值。input_from_feature_columns(features, dnn_feature_columns, l2_reg_embedding, seed)返回sparse_embedding_list(每个稀疏域一个(batch, 1, embedding_size)的 3D 张量列表)和dense_value_list。

第 3 步:计算乘积特征。两个分支并行:

inner_product = Flatten()(InnerProductLayer()(sparse_embedding_list)) outter_product = OutterProductLayer(kernel_type)(sparse_embedding_list)

第 4 步:拼接线性信号。把所有域的 embedding 首尾相接并Reshape成一维向量:

linear_signal = Reshape( [sum(map(lambda x: int(x.shape[-1]), sparse_embedding_list))])(concat_func(sparse_embedding_list))

第 5 步:按开关组合深度输入。use_inner/use_outter的四种组合决定deep_input的内容(详见下一节),随后combined_dnn_input([deep_input], dense_value_list)把产品层输出与稠密原始特征拼在一起喂给 DNN。

第 6 步:DNN + 输出层。DNN(dnn_hidden_units, dnn_activation, l2_reg_dnn, dnn_dropout, False, seed=seed)得到dnn_out,经Dense(1, use_bias=False)映射为 logit,最后由PredictionLayer(task)输出:

  • task='binary'时输出 sigmoid 概率;
  • task='regression'时输出线性 logit。

内积与外积交互层:两个关键算子的实现原理

InnerProductLayer(IPNN 核心)

InnerProductLayer(deepctr/layers/interaction.py)接收 N 个(batch, 1, embedding_size)的 embedding 张量,对全部N*(N-1)/2个特征域两两组合:

  • row/col通过双重循环生成所有i < j的下标对;
  • 按行、列分组拼接后逐元素相乘得到p * q;
  • 默认reduce_sum=True,沿 embedding 维度求和,输出形状为(batch_size, N*(N-1)/2, 1);
  • 若reduce_sum=False,则输出逐元素乘积(batch_size, N*(N-1)/2, embedding_size)。

在PNN中该层输出随后被Flatten()展开成一维向量,即 IPNN 论文中"内积池化"的结果。层构建时还会校验所有输入形状必须一致且为(None, 1, embedding_size)形态,否则抛ValueError。

OutterProductLayer(OPNN 核心)

OutterProductLayer(deepctr/layers/interaction.py)的输出形状固定为(batch_size, N*(N-1)/2),其实现参考了论文作者发布的 product-nets 开源代码。关键在于kernel 权重的三种参数化方式,这也是kernel_type参数的本源:

kernel_typekernel 形状计算方式
'mat'(embed_size, num_pairs, embed_size)对每对特征用一个完整的k×k矩阵做双线性变换:p^T · W · q,最强大但参数量最大
'vec'(num_pairs, embed_size)每对特征共用一个向量做加权求和:sum(p * q * k)
'num'(num_pairs, 1)每对特征仅用一个标量做加权:sum(p * q * k),参数量最小

'mat'分支在call中通过p扩维后与 kernel 逐元素相乘、两次归约与转置实现p^T W q(见 deepctr/layers/interaction.py);'vec'与'num'分支则统一走kp = reduce_sum(p * q * k, -1)的简洁路径(deepctr/layers/interaction.py)。

四种产品层组合模式

use_inner与use_outter的组合决定了送入 DNN 的deep_input(deepctr/models/pnn.py):

use_inneruse_outterdeep_input 内容对应模型
TrueFalselinear_signal + inner_productIPNN(默认)
FalseTruelinear_signal + outter_productOPNN
TrueTruelinear_signal + inner_product + outter_productIPNN+OPNN 混合
FalseFalse仅linear_signal退化为纯 embedding 拼接 + DNN

注意linear_signal始终保留:即使关闭全部乘积,embedding 拼接信号依然作为 DNN 的输入,保证特征信息不丢失。

实战:用 PNN 完成一次完整的训练与评估

DeepCTR 各模型共享统一的使用范式:先构造特征列,再实例化模型,最后compile+fit。仓库测试工具 tests/utils.py 中的check_model展示了标准流程(tests/utils.py):

import numpy as np from deepctr.models import PNN from deepctr.feature_column import SparseFeat, DenseFeat # 1. 构造特征列(稀疏域 + 稠密域) feature_columns = [ SparseFeat('sparse_feature_0', vocabulary_size=4, embedding_dim=4), SparseFeat('sparse_feature_1', vocabulary_size=4, embedding_dim=4), DenseFeat('dense_feature_0', 1), ] # 2. 实例化模型(IPNN 默认配置) model = PNN(feature_columns, dnn_hidden_units=(256, 128, 64), dnn_dropout=0.5, use_inner=True, use_outter=False) # 3. 编译并训练 model.compile('adam', 'binary_crossentropy', metrics=['binary_crossentropy']) x = { 'sparse_feature_0': np.random.randint(0, 4, 8), 'sparse_feature_1': np.random.randint(0, 4, 8), 'dense_feature_0': np.random.random(8), } y = np.random.randint(0, 2, 8) model.fit(x, y, batch_size=100, epochs=1, validation_split=0.5) # 4. 权重与整模型持久化 model.save_weights('pnn_weights.h5') model.load_weights('pnn_weights.h5') model.save('pnn.h5')

关于持久化有两点补充:

  • 重载完整模型时需要使用 DeepCTR 提供的custom_objects(from deepctr.layers import custom_objects),以保证InnerProductLayer、OutterProductLayer等自定义层能被正确反序列化;
  • PNN_test用例正是依次验证了 "train/valid 通过 → save/load weights → save/load 整模型" 的完整闭环(tests/utils.py)。

PNNEstimator:TensorFlow Estimator 接口版本

除 Keras 版外,仓库还提供deepctr.estimator.models.pnn模块下的PNNEstimator(deepctr/estimator/models/pnn.py),面向 TensorFlow Estimator 生态。其核心参数与PNN完全一致(dnn_hidden_units、l2_reg_embedding、use_inner、use_outter、kernel_type、task等),额外扩展了训练运行时配置:

新增参数默认值说明
model_dirNone模型参数、计算图与 checkpoint 的保存目录,也用于断点续训
configNonetf.RunConfig运行时配置
linear_optimizer'Ftrl'线性部分使用的优化器
dnn_optimizer'Adagrad'深度部分使用的优化器
training_chief_hooksNone训练时在 chief worker 上运行的SessionRunHook列表

结构上的差异(deepctr/estimator/models/pnn.py):内部_model_fn中,稀疏/稠密特征通过input_from_feature_columns得到 embedding,内积/外积与linear_signal的拼接逻辑与 Keras 版逐行对应;get_linear_logit(features, [], ...)以空线性特征列表构造线性 logit(即默认不叠加线性项);最后deepctr_model_fn统一封装训练、评估与预测。使用方式遵循 Estimator 惯例:model.train(input_fn)/model.evaluate(input_fn),见 tests/models/PNN_test.py 中的PNNEstimator用例。

需要留意:Estimator 接口的可用性依赖 TensorFlow 版本(测试工具中仅对<2.0或[2.0, 2.6)区间启用,见 tests/utils.py),选用前请确认运行环境。

测试与验证:仓库如何保障 PNN 可用

PNN_test.py 使用 pytest 参数化覆盖两类关键配置(tests/models/PNN_test.py):

  • (use_inner=True, use_outter=True, sparse_feature_num=3):双乘积混合模式;
  • (use_inner=False, use_outter=False, sparse_feature_num=1):关闭全部乘积的退化模式。

测试数据由get_test_data随机生成(SAMPLE_SIZE=8,embedding 维度 4),每个用例均以dnn_hidden_units=[4, 4], dnn_dropout=0.5构造模型并跑通check_model全流程。这从侧面印证了:任何use_inner/use_outter组合与稀疏特征数量下,PNN 都能完成编译、训练、评估与序列化,可作为自定义实验的参照模板。

小结

PNN 通过产品层把"特征域两两交互"显式注入深度网络,在 DeepCTR 中落地为PNN/PNNEstimator两个入口,配合InnerProductLayer、OutterProductLayer两个可复用算子,可一键切换 IPNN、OPNN 及混合模式。想要进一步了解与其他深度 CTR 模型的差异,可对照同目录下的 FNN、DeepFM、NFM 等模型文档;若需在实验中验证梯度流与训练行为,可从 tests/models/PNN_test.py 出发快速搭建回归用例。

  • 人工智能
  • 深度学习
  • 机器学习

【免费下载链接】DeepCTR

Easy-to-use,Modular and Extendible package of deep-learning based CTR models .

项目地址:https://gitcode.com/gh_mirrors/de/DeepCTR
点击查看免费下载
上一篇:终极workerd兼容性指南:掌握兼容性日期的高效管理技巧
下一篇:从崩溃到稳定:Portkey-AI网关Anthropic消息流事件全解析与修复指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询