新闻详情

新闻详情

首页 / 资讯中心 / 详情

CNN+LSTM混合模型实战:搜索广告CTR预估与排序落地

发布时间:2026/9/30 5:42:30来源:尧图网络
CNN+LSTM混合模型实战:搜索广告CTR预估与排序落地
简介这份PDF文献聚焦深度学习在搜索广告排序中的落地应用面向广告算法工程师、推荐系统学习者及数据研究方向的师生帮助理解点击率CTR预估这一广告业务核心环节的技术演进。全文围绕卷积神经网络与LSTM的混合模型展开先由CNN提取广告数据中的高影响力特征再借助LSTM的时序建模能力完成预测与分类并对比逻辑回归、决策树等传统方法在人工特征工程上的局限同时梳理了百度FNN、谷歌WideDeep与PNN等业界方案。文中还完整介绍了特征提取、模型训练与测试预测的CTR预估流程并给出LSTM层数、隐藏层节点数、学习率等参数对AUC值影响的实验对比便于读者复现调参思路。资源包为1个PDF文件大小约2.73MB结构紧凑、便于检索阅读。目前已有122人学习适合作为广告排序与深度学习交叉方向的参考文献与专业指导材料。1. 从一份论文拆出的搜索广告排序实战CNNLSTM 混合模型到底怎么落地广告排序这件事说白了就是给每次搜索请求里的候选广告排个先后谁排前面谁拿曝光。决定顺序的核心指标是 CTR点击率而 CTR 预估的准确度直接关系到平台的广告收入和用户体验。这份《基于深度学习的搜索广告排序应用》是携程工程师钟小勇写的一篇工程实践论文核心思路不复杂用 CNN 从广告特征里自动抽关键特征再把结果喂给 LSTM 做时序建模和分类最后输出一个 0 到 1 之间的点击概率。相比逻辑回归、FM 这些传统方案它省掉了大量人工特征工程AUC 从 LR 的 0.659 拉到了 0.772。适合谁看正在做 CTR 预估、推荐排序、广告系统或者想找一个能跑通的 CNNLSTM 混合模型参考实现的同学。下面我按“论文讲了什么 → 模型怎么搭 → 参数怎么调 → 坑在哪”的顺序把这份资源拆开讲。2. 广告点击率预测的完整链路从特征提取到排序输出2.1 为什么传统模型在广告排序上越来越吃力广告点击率预测本质上是一个二分类问题给定一条广告曝光请求预测用户会不会点。传统做法里逻辑回归LR是最常见的 baseline它把特征加权求和后过 sigmoid 得到概率。LR 的优点是简单、可解释、训练快但它有个硬伤——依赖人工做特征交叉。比如“用户年龄 × 广告类目”这种组合特征得靠工程师手动构造特征工程的工作量极大而且很难穷举所有有意义的交叉。FM因子分解机在一定程度上缓解了这个问题它通过隐向量内积来自动学习二阶特征交互对高维稀疏数据比较友好。论文里的实验也印证了这一点FM 的 AUC 是 0.696比 LR 的 0.659 高了一截。但 FM 本质上还是浅层模型对高阶非线性关系的表达能力有限。普通神经网络NN虽然比 LR 和 FM 强AUC 到了 0.711但它对输入特征的 spatial 结构没有感知能力。广告数据里有很多类别特征比如广告位 ID、用户设备类型、时间段这些特征之间存在局部相关性NN 的全连接层没法有效捕捉这种局部模式。这就是 CNN 介入的切入点。2.2 CNN 和 LSTM 各自解决什么问题CNN 在图像领域出名但它的核心能力——卷积核在局部感受野上提取特征——同样适用于广告数据。广告特征经过 One-Hot 编码后可以排成一个二维矩阵卷积核在这个矩阵上滑动能自动发现特征之间的局部组合模式。论文里用的卷积核配置是 32 个、大小 5、步长 1卷积之后接 ReLU 激活再做最大池化步长 4。这一套操作下来原始的高维稀疏特征被压缩成了一个 256 维的稠密向量。LSTM 解决的是另一个问题时序依赖。用户的点击行为不是孤立的它跟之前的浏览历史、搜索序列有关系。LSTM 通过输入门、遗忘门、输出门三个机制能够选择性地记住或遗忘历史信息。论文里用了 3 层 LSTM每层 128 个隐藏节点最终输出一个概率值。把两者串起来的好处是CNN 负责“看清楚当前这条广告长什么样”LSTM 负责“结合历史行为判断用户会不会点”。论文的实验结果很直观——CNN 单独用 AUC 是 0.731LSTM 单独用是 0.723合在一起到了 0.772。这不是简单的加法而是特征提取和时序建模的互补。2.3 数据预处理和模型训练的实操步骤论文用的是 Avazu 在 Kaggle 上公开的 2014 年数据集选了 100 万条做训练。每条数据 20 个维度其中 10 个连续特征9 个已脱敏、9 个类别特征标签是 0 或 1。下面是一段可复现的数据预处理和模型搭建代码用 PyTorch 写因为论文里用的 Caffe2 现在生态已经不太活跃了PyTorch 是更现实的选择。import torch import torch.nn as nn import numpy as np from sklearn.preprocessing import LabelEncoder, MinMaxScaler # 假设 df 是已经读入的 Avazu 数据列名按实际调整 # 类别特征做 LabelEncoder连续特征做归一化 cat_cols [C1, banner_pos, site_id, site_domain, device_id, device_model, C14, C17, C21] num_cols [I1, I2, I3, I4, I5, I6, I7, I8, I9, I10] for col in cat_cols: le LabelEncoder() df[col] le.fit_transform(df[col].astype(str)) scaler MinMaxScaler() df[num_cols] scaler.fit_transform(df[num_cols]) # 所有特征拼成一个长向量模拟 One-Hot 后的稠密表示 feature_cols cat_cols num_cols X df[feature_cols].values.astype(np.float32) y df[click].values.astype(np.float32) # 切分训练集和测试集8:1 split int(len(X) * 0.89) X_train, X_test X[:split], X[split:] y_train, y_test y[:split], y[split:] # 转成 TensorCNN 需要 [batch, channel, length] 的形状 X_train_t torch.tensor(X_train).unsqueeze(1) # [N, 1, 19] X_test_t torch.tensor(X_test).unsqueeze(1) y_train_t torch.tensor(y_train).unsqueeze(1) y_test_t torch.tensor(y_test).unsqueeze(1)这段代码做了三件事类别特征编码、连续特征归一化、数据切分。注意unsqueeze(1)那一步CNN 的输入需要有一个 channel 维度这里当成单通道信号处理。实际生产中如果特征更多可以考虑把类别特征和连续特征分开做 embedding但论文里的做法是统一编码后直接送卷积。模型定义部分class CNNLSTM(nn.Module): def __init__(self, input_len19, cnn_out256, lstm_hidden128, lstm_layers3): super(CNNLSTM, self).__init__() # 卷积核 32 个大小 5步长 1 self.conv nn.Conv1d(in_channels1, out_channels32, kernel_size5, stride1) self.relu nn.ReLU() # 最大池化步长 4 self.pool nn.MaxPool1d(kernel_size4, stride4) # 计算池化后的长度((19-5)/11 - 4)/4 1 3 self.fc nn.Linear(32 * 3, cnn_out) self.lstm nn.LSTM(input_sizecnn_out, hidden_sizelstm_hidden, num_layerslstm_layers, batch_firstTrue) self.sigmoid nn.Sigmoid() self.out nn.Linear(lstm_hidden, 1) def forward(self, x): # x: [batch, 1, 19] x self.relu(self.conv(x)) # [batch, 32, 15] x self.pool(x) # [batch, 32, 3] x x.view(x.size(0), -1) # [batch, 96] x self.fc(x) # [batch, 256] x x.unsqueeze(1) # [batch, 1, 256] 作为 LSTM 输入 x, _ self.lstm(x) # [batch, 1, 128] x self.out(x[:, -1, :]) # [batch, 1] return self.sigmoid(x)这里有几个参数需要说明。kernel_size5对应论文里的卷积核大小out_channels32是卷积核个数。池化层kernel_size4, stride4是论文里明确写的移动步长。cnn_out256是 CNN 输出向量的维度这个值在论文的参数对比实验里被验证为最优。LSTM 的num_layers3和hidden_size128也是论文表 2 里的配置。训练循环用 RMSProp 优化器学习率 0.002损失函数用 BCEWithLogitsLoss 或者 BCELossmodel CNNLSTM() optimizer torch.optim.RMSprop(model.parameters(), lr0.002) criterion nn.BCELoss() for epoch in range(30): model.train() optimizer.zero_grad() pred model(X_train_t) loss criterion(pred, y_train_t) loss.backward() optimizer.step() if epoch % 5 0: model.eval() with torch.no_grad(): test_pred model(X_test_t) test_loss criterion(test_pred, y_test_t) print(fEpoch {epoch}, train_loss{loss.item():.4f}, test_loss{test_loss.item():.4f})论文里迭代了 30 次取最优 AUC这个训练轮数可以作为起点。如果 loss 还在降就继续加如果 test_loss 开始上升就是过拟合了需要加 dropout 或者减层数。3. 参数调优的边界LSTM 层数、隐藏节点和学习率怎么选3.1 论文里的参数对比实验说明了什么论文图 4 给了三组参数对比曲线信息量很大。第一组是 LSTM 层数从 1 到 3 的变化AUC 在 3 层时达到最高。但注意层数继续增加论文没有给数据从工程经验看超过 3 层之后收益递减很快而且训练时间线性增长。第二组是 LSTM 隐藏层节点数从 32 到 256 的变化128 时 AUC 最高256 反而略有下降。这说明隐藏层不是越大越好节点太多会过拟合尤其在训练数据只有 100 万条的情况下。第三组是学习率从 0.01 到 0.0001 的对比0.002 附近表现最好。学习率太大0.01会震荡不收敛太小0.0001收敛太慢30 轮迭代根本不够。这些参数不是拍脑袋定的论文作者做了相当多的反复迭代。我一般会建议先用论文的配置跑一遍 baseline然后按“先调学习率、再调层数、最后调隐藏节点”的顺序做网格搜索。学习率对结果的影响最直接优先确定。3.2 优化方法的选择RMSProp vs Adam论文表 2 里组合模型用的是 RMSProp学习率 0.002表 3 里单一 CNN 模型用的是 Adam学习率 0.001。为什么不一样RMSProp 对非平稳目标和循环神经网络比较友好它通过指数加权平均来调整每个参数的学习率适合 LSTM 这种有时序依赖的结构。Adam 本质上是 RMSProp 加动量收敛更快但在某些 CTR 任务上容易过早收敛到局部最优。论文的实验结果也支持这个判断组合模型用 RMSProp 达到了 0.772 的 AUC如果换成 Adam 未必有这个效果。实际用的时候我建议两个都试。先跑 RMSProp如果 loss 曲线震荡厉害就换 Adam 并把学习率降到 0.001。如果 Adam 收敛太快但 AUC 不理想再换回 RMSProp 并适当增大学习率。3.3 模型评估AUC 和对数损失怎么配合看论文用了两个指标AUC 和对数损失log loss。AUC 衡量的是模型的排序能力值越大越好0.5 是随机猜1.0 是完美排序。log loss 衡量的是概率预测的准确度值越小越好。这两个指标要配合看不能只看一个。举个例子CNN 的 AUC 是 0.731log loss 是 0.395LSTM 的 AUC 是 0.723log loss 是 0.382。CNN 排序能力更强但 LSTM 的概率校准更好。组合模型 AUC 0.772、log loss 0.371两个指标都最优。如果只盯 AUC可能会选出一个概率预测偏差很大的模型在实际竞价场景里出价会不准。from sklearn.metrics import roc_auc_score, log_loss model.eval() with torch.no_grad(): pred_prob model(X_test_t).numpy().flatten() auc roc_auc_score(y_test, pred_prob) ll log_loss(y_test, pred_prob) print(fAUC{auc:.4f}, LogLoss{ll:.4f})这段评估代码可以直接用。注意pred_prob是 sigmoid 之后的概率值不要用 logits。4. 避坑与排查训练 CNNLSTM 时最容易翻车的五个地方4.1 现象loss 不下降AUC 一直在 0.5 附近原因最常见的是输入数据没有归一化或者类别特征编码后数值范围差异太大。CNN 的卷积核对输入尺度很敏感如果某些特征值在 0 到 1 之间、另一些在 0 到 10000 之间卷积核的权重更新会非常不稳定。解决所有连续特征必须做 MinMax 或 Standard 归一化类别特征做 LabelEncoder 后也建议除以类别总数缩放到 0 到 1 之间。检查一遍X_train的每一列最大值和最小值确保没有异常值。4.2 现象训练集 loss 很低测试集 loss 很高原因过拟合。论文里的模型有 3 层 LSTM、128 个隐藏节点参数量不小而训练数据只有 100 万条。如果特征维度再高一些过拟合几乎必然发生。解决加 Dropout一般在 LSTM 层之间加nn.Dropout(0.3)到0.5。另外可以减小 LSTM 隐藏节点数从 128 降到 64 试试。论文里 128 是最优但那是在特定数据量下的结论数据量更小的时候要往下调。4.3 现象CNN 卷积层报错提示维度不匹配原因Conv1d 的输入要求是[batch, channel, length]很多人直接把[batch, length]喂进去少了一个维度。或者池化层的 kernel_size 大于卷积后的长度导致输出为负。解决用unsqueeze(1)补 channel 维度。池化前先算一下长度(input_len - kernel_size) / stride 1确保池化 kernel 不超过这个值。论文里输入长度 19、卷积核 5、池化 4算下来是 3刚好够。4.4 现象LSTM 训练速度极慢一个 epoch 要跑几个小时原因LSTM 是串行计算的没法像 CNN 那样大规模并行。如果batch_size设得太小比如 32GPU 利用率会很低。另外num_layers3的 LSTM 本身就比单层慢很多。解决把batch_size加到 256 或 512只要显存够。论文里用的是 NVIDIA 1080Ti12GB 显存跑 100 万条数据 batch_size 可以到 512。如果还是慢考虑把 LSTM 层数降到 2AUC 可能掉 0.5 个点左右但训练时间能省一半。4.5 现象AUC 在 0.75 左右上不去了怎么调都没用原因特征工程到顶了。论文里只用了 19 个特征Avazu 数据集本身有 20 多个字段还有用户历史行为、广告创意内容等没被利用。CNNLSTM 再强输入信息不够也白搭。解决往特征里加交叉项比如用户 ID 和广告类目的组合、时间段和设备类型的组合。或者引入预训练的 embedding把广告标题、描述文本用词向量表示后拼进去。论文结尾也提到了“接下来将继续围绕特征、模型从工程化方向做迭代”说明作者自己也意识到特征还有挖掘空间。5. 进阶技巧用早停和模型集成把 AUC 再往上推一推论文里的训练方式是固定迭代 30 次取最优 AUC这在工程上其实有点浪费。更实用的做法是加早停early stopping每跑完一个 epoch 就评估一次验证集的 AUC如果连续 5 个 epoch 没有提升就停同时保存验证集 AUC 最高的那个模型权重。这样既能防止过拟合又能省训练时间。best_auc 0.0 patience 5 wait 0 for epoch in range(100): model.train() optimizer.zero_grad() pred model(X_train_t) loss criterion(pred, y_train_t) loss.backward() optimizer.step() model.eval() with torch.no_grad(): val_pred model(X_test_t).numpy().flatten() val_auc roc_auc_score(y_test, val_pred) if val_auc best_auc: best_auc val_auc torch.save(model.state_dict(), best_model.pth) wait 0 else: wait 1 if wait patience: print(fEarly stop at epoch {epoch}, best AUC{best_auc:.4f}) break另一个提升方向是模型集成。论文里 CNNLSTM 的 AUC 是 0.772如果把 CNNLSTM、纯 CNN、纯 LSTM 三个模型的预测概率做加权平均通常还能再涨 0.5 到 1 个点。权重可以用验证集上的 AUC 来定AUC 高的模型权重大一些。这种做法在 Kaggle 比赛里很常见工程上也不算复杂推理时多跑几个模型就行延迟增加可控。还有一个容易被忽略的点负采样比例。论文里提到“正样本比例与抽取数据中正样本比例较为接近”这是对的。但实际广告场景里正样本极其稀疏点击率可能只有百分之几。如果直接拿全量数据训练模型会倾向于预测所有样本都是负的AUC 看起来还行但 log loss 会很难看。常见做法是保持正负样本比例在 1:1 到 1:10 之间训练完后再做概率校准Platt scaling 或 isotonic regression把预测概率映射回真实分布。我自己的习惯是每次跑完训练先把验证集的预测概率分布画出来看看是不是集中在 0 附近。如果是说明负采样比例或者损失函数权重有问题得回头调。这个检查花不了两分钟但能避免很多“AUC 看着不错、上线效果拉胯”的情况。从那以后我每次训练 CTR 模型都强制走一遍概率分布检查希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

简电云 | OCPP 1.6 充电桩平台基于 OCPI 2.3.0 实现 POS 云端对接方案 2026/9/30 6:38:29

简电云 | OCPP 1.6 充电桩平台基于 OCPI 2.3.0 实现 POS 云端对接方案

一、为什么需要 POS 云端对接 公共充电站越来越需要支持银行卡、非接触式信用卡和手机钱包。传统方案通常把 POS 与充电桩通过串口或局域网直连,这种方式在单一设备上容易落地,但也带来几个问题: POS、桩控板和固件强耦合,换一个…

阅读更多 →
鸿蒙高级——内存专用之linux-reserve-memory 方案小结(二) 2026/9/30 6:38:28

鸿蒙高级——内存专用之linux-reserve-memory 方案小结(二)

文章大纲 引言 一、普通进程访问使用预留内存 1、先mmap映射到用户空间后再访问 2、使用 /dev/mem 直接访问物理内存 2.1、启用 /dev/mem 2.2、映射物理地址 2.3、用户空间通过dev/mem访问 3、通过 UIO(Userspace I/O)框架 3.1、UIO 的主要功能 3.1.1、内存映射 3.1.2、中断处…

阅读更多 →
AI代码审查:security-audit-skill 2026/9/30 6:38:22

AI代码审查:security-audit-skill

github地址: https://github.com/cloudflare/security-audit-skill 一、使用场景 1、 使用场景 核心一句话:你手上有一堆代码,想知道"哪里可能被﨤"。凡是满足这个的,都适用。场景典型诉求用哪个模式上线前安全评审“这…

阅读更多 →
正点原子 rk3588烧写镜像ubuntu,扩容,安装 xrdp 远程桌面 2026/9/30 6:38:09

正点原子 rk3588烧写镜像ubuntu,扩容,安装 xrdp 远程桌面

由于正点官方最近不知道为啥没有提供ubunut了,因此这里提供下我之前下载的网盘资料 通过网盘分享的文件:正点-开发板光盘A盘-基础资料 链接: https://pan.baidu.com/s/13Jw6IQ8dMZkRHkTt_6Y6iw?pwdac3b 提取码: ac3b扩容 原装出厂root分区 大小被限制在…

阅读更多 →
Node.js 最佳实践:用 APM 产品主动发现错误与停机(nodebestpractices 实践指南) 2026/9/30 6:38:09

Node.js 最佳实践:用 APM 产品主动发现错误与停机(nodebestpractices 实践指南)

文档教程后端 【免费下载链接】nodebestpractices ✅ The Node.js best practices list (July 2026) 项目地址: https://gitcode.com/GitHub_Trending/no/nodebestpractices 点击查看 免费下载 应用进入生产环境后,传统"捕获异常"式的错误处理…

阅读更多 →
Netty 官方 Docker 构建环境完全指南:多 JDK 构建矩阵与 aarch64/riscv64 原生库交叉编译 2026/9/30 6:38:09

Netty 官方 Docker 构建环境完全指南:多 JDK 构建矩阵与 aarch64/riscv64 原生库交叉编译

后端通信网络异步编程 【免费下载链接】netty Netty project - an event-driven asynchronous network application framework 项目地址: https://gitcode.com/gh_mirrors/ne/netty 点击查看 免费下载 本文围绕 Netty 仓库 docker/ 目录下的官方容器化构建体系展开…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉