发布时间:2026/7/25 18:07:43
ESMM学习笔记:如何解决CVR预估中的样本选择偏差与数据稀疏难题 ESMM学习笔记如何解决CVR预估中的样本选择偏差与数据稀疏难题引言CVR预估的两大挑战在推荐系统和广告点击率预估领域CVRConversion Rate转化率预估是一个核心任务。与CTRClick-Through Rate点击率预估不同CVR预估面临两个特殊的难题1.样本选择偏差Sample Selection BiasSSBCVR模型通常只在点击样本上训练但实际预测时需要对所有曝光样本进行预估。点击样本和未点击样本在用户行为模式上存在显著差异导致训练集和预测集的分布不一致模型泛化能力下降。2.数据稀疏Data SparsityDS转化行为远比点击行为稀少导致CVR训练样本数量远少于CTR。在广告场景中点击率可能只有1%-5%而转化率可能只有0.1%-0.5%这意味着CVR模型可用的正样本极其有限容易过拟合。为了解决这两个问题阿里巴巴在2018年提出了ESMMEntire Space Multi-Task Model全空间多任务模型。本文将循序渐进地讲解ESMM的原理与实现。## 基础概念从CTR预估到CVR预估### CTR预估与CVR预估的关系在电商或广告系统中用户行为通常遵循一个漏斗模型曝光Impression → 点击Click → 转化ConversionCTR预估关注的是给定曝光样本用户点击的概率 P(click1|impression)。CVR预估关注的是给定点击样本用户转化的概率 P(conversion1|click1)。传统方法中CVR模型只在点击样本上训练这就导致了样本选择偏差问题——模型从未见过未点击样本的特征分布却在预测时需要对它们进行推断。### 多任务学习的思想ESMM的核心思想是将CVR预估和CTR预估作为两个相关任务联合训练。既然点击和转化是顺序发生的那么我们可以利用CTR任务中丰富的点击样本信息来辅助CVR任务。具体来说ESMM引入了一个辅助任务——CTCVRClick-Then-Conversion Rate点击后转化率即 P(click1, conversion1|impression)。通过全空间所有曝光样本上的CTCVR预估间接学习CVR。## ESMM模型架构详解ESMM的模型架构包含以下几个关键部分1.共享嵌入层Shared Embedding Layer将高维稀疏特征映射到低维稠密向量。2.两个独立的塔Two TowersCTR塔和CVR塔分别用于预估CTR和CVR。3.乘积层Multiplication Layer通过CTR和CVR的乘积得到CTCVR的预估值。关键公式- CTR预估pCTR P(click1|impression)- CVR预估pCVR P(conversion1|click1)- CTCVR预估pCTCVR P(click1, conversion1|impression) pCTR × pCVR训练时我们用全空间样本包括未点击和点击来优化CTCVR损失和CTR损失而CVR损失则通过反向传播间接优化。## 代码实现从零构建ESMM下面我们实现一个简化版的ESMM模型。首先我们使用TensorFlow 2.x来构建模型。### 示例1模型架构定义pythonimport tensorflow as tffrom tensorflow.keras.layers import Dense, Embedding, Flatten, Concatenate, Inputfrom tensorflow.keras import Modelclass ESMM(Model): def __init__(self, feature_columns, embedding_dim8): feature_columns: 字典包含每个特征的类别数 embedding_dim: 嵌入维度 super(ESMM, self).__init__() self.feature_columns feature_columns self.embedding_dim embedding_dim # 共享嵌入层 self.embeddings {} for feat_name, vocab_size in feature_columns.items(): self.embeddings[feat_name] Embedding( input_dimvocab_size, output_dimembedding_dim, namefembedding_{feat_name} ) # CTR塔简单MLP self.ctr_dense1 Dense(64, activationrelu, namectr_dense1) self.ctr_dense2 Dense(32, activationrelu, namectr_dense2) self.ctr_output Dense(1, activationsigmoid, namectr_output) # CVR塔简单MLP self.cvr_dense1 Dense(64, activationrelu, namecvr_dense1) self.cvr_dense2 Dense(32, activationrelu, namecvr_dense2) self.cvr_output Dense(1, activationsigmoid, namecvr_output) def call(self, inputs, trainingFalse): # inputs: 字典每个键对应一个特征值为整数索引 # 共享嵌入 embeddings [] for feat_name in self.feature_columns.keys(): feat_input inputs[feat_name] emb self.embeddings[feat_name](feat_input) embeddings.append(Flatten()(emb)) # 展平为向量 # 拼接所有特征嵌入 concat_emb Concatenate()(embeddings) # CTR塔 ctr_hidden self.ctr_dense1(concat_emb) ctr_hidden self.ctr_dense2(ctr_hidden) ctr_pred self.ctr_output(ctr_hidden) # CVR塔 cvr_hidden self.cvr_dense1(concat_emb) cvr_hidden self.cvr_dense2(cvr_hidden) cvr_pred self.cvr_output(cvr_hidden) # CTCVR CTR * CVR ctcvr_pred ctr_pred * cvr_pred return ctr_pred, cvr_pred, ctcvr_pred# 假设有3个特征用户ID1000个、商品ID500个、广告位ID10个feature_columns { user_id: 1000, item_id: 500, ad_pos: 10}# 创建模型实例model ESMM(feature_columns, embedding_dim8)# 查看模型结构model.build(input_shape({user_id: (None,), item_id: (None,), ad_pos: (None,)}))model.summary()### 示例2训练循环与损失函数在ESMM的训练中我们需要同时优化CTR损失和CTCVR损失。注意CVR损失是基于点击样本的但ESMM巧妙地通过共享嵌入和乘积操作来间接优化。pythonimport numpy as np# 生成模拟数据def generate_synthetic_data(num_samples10000): np.random.seed(42) # 特征用户ID、商品ID、广告位ID data { user_id: np.random.randint(0, 1000, sizenum_samples), item_id: np.random.randint(0, 500, sizenum_samples), ad_pos: np.random.randint(0, 10, sizenum_samples) } # 标签点击5%概率和转化点击后10%概率 click np.random.binomial(1, 0.05, sizenum_samples) conversion np.random.binomial(1, 0.1 * click, sizenum_samples) # 只有点击后才可能转化 return data, click, conversion# 自定义损失函数def ctr_loss(y_true, y_pred): # y_true: [click, conversion] 这里我们只使用click return tf.keras.losses.binary_crossentropy(y_true[:, 0], y_pred[:, 0])def ctcvr_loss(y_true, y_pred): # y_true: [click, conversion] 这里使用conversion因为CTCVRclick conversion return tf.keras.losses.binary_crossentropy(y_true[:, 1], y_pred[:, 0])# 准备数据X, click, conversion generate_synthetic_data(2000)# 构建输入字典input_dict {k: v for k, v in X.items()}# 构建标签第一列是click第二列是conversiony np.stack([click, conversion], axis1)# 编译模型注意TensorFlow需要自定义损失函数optimizer tf.keras.optimizers.Adam(learning_rate0.001)# 训练步骤tf.functiondef train_step(features, labels): with tf.GradientTape() as tape: # 前向传播 ctr_pred, cvr_pred, ctcvr_pred model(features, trainingTrue) # 计算损失 # CTR损失使用点击标签 loss_ctr tf.reduce_mean( tf.keras.losses.binary_crossentropy(labels[:, 0], tf.squeeze(ctr_pred)) ) # CTCVR损失使用转化标签因为转化只发生在点击后 loss_ctcvr tf.reduce_mean( tf.keras.losses.binary_crossentropy(labels[:, 1], tf.squeeze(ctcvr_pred)) ) # 总损失两个损失相加可加权重 total_loss loss_ctr loss_ctcvr # 计算梯度并更新 gradients tape.gradient(total_loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) return total_loss, loss_ctr, loss_ctcvr# 训练10个epochfor epoch in range(10): total_loss, loss_ctr, loss_ctcvr train_step(input_dict, y) print(fEpoch {epoch1}: Total Loss {total_loss:.4f}, CTR Loss {loss_ctr:.4f}, CTCVR Loss {loss_ctcvr:.4f})# 训练完成后预测CVR注意只在点击样本上评估更合理import randomtest_sample { user_id: np.array([random.randint(0, 999)]), item_id: np.array([random.randint(0, 499)]), ad_pos: np.array([random.randint(0, 9)])}_, cvr_pred, _ model(test_sample, trainingFalse)print(f预测CVR: {cvr_pred.numpy()[0][0]:.4f})## 高级用法与优化技巧### 多任务学习的权重平衡在ESMM中CTR损失和CTCVR损失的权重可以调整。如果CVR任务特别稀疏可以适当增加CTCVR损失的权重让模型更关注转化信号。### 特征工程与嵌入维度在实际应用中共享嵌入层的维度选择非常关键。过小的嵌入维度会导致信息丢失过大的维度则会导致过拟合。通常建议在8-64之间调整。### 其他变体ESMM的后续改进包括-ESMMAttention在CVR塔中引入注意力机制让模型更关注与转化相关的特征。-Multi-ESMM处理多步转化如加购、收藏、支付的序列任务。## 总结ESMM通过多任务学习巧妙解决了CVR预估中的两大难题1.样本选择偏差通过在全空间所有曝光样本上训练CTCVR任务避免了只在点击样本上训练导致的分布偏移。即使未点击样本的CVR不可观测模型也能通过CTR和CTCVR的乘积关系学到正确的CVR。2.数据稀疏通过共享嵌入层让CTR任务中丰富的点击数据帮助CVR任务学习更好的特征表示。CTR任务提供了大量的训练信号缓解了CVR正样本不足的问题。ESMM的核心思想可以概括为用辅助任务CTR、CTCVR来间接优化主任务CVR同时利用共享表示来迁移知识。这种范式在推荐系统、广告预估等领域具有广泛的应用价值。理解ESMM不仅有助于解决CVR预估问题也为处理其他存在样本选择偏差或数据稀疏的任务提供了思路——例如在医疗诊断中我们可以用高频率的检查结果来辅助预测罕见疾病。

相关新闻

2026/7/25 18:07:43

AI订阅管家:智能监控与优化你的数字消费

1. 为什么我们总在不知不觉中成为"年费冤大头"前几天整理信用卡账单时,我突然发现自己在过去一年里,竟然为各种用不着的订阅服务支付了将近2000元。从某音乐平台的自动续费,到早已遗忘的云存储会员,再到试用后忘记取消的…

2026/7/25 18:07:42

Docker容器化实战:定制镜像、配置Yum源与部署服务

这次我们来看 Docker 容器化技术中几个非常核心的实战操作:如何定制一个简单的 Docker 镜像、如何在容器内部配置 Yum 软件仓库,以及如何在容器内完成服务的安装与部署。对于需要在隔离环境中快速构建和部署应用的开发者或运维人员来说,掌握这些技能是摆脱“只会用现成镜像”…

2026/7/25 18:02:42

暗黑破坏神2存档编辑器:Web端终极修改工具完整指南

暗黑破坏神2存档编辑器:Web端终极修改工具完整指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 你是否曾经为暗黑破坏神2的角色属性不够理想而烦恼?是否想要快速测试不同的装备组合却苦于重新练级&…

2026/7/25 19:27:47

风电功率预测:GMM与深度学习的融合实践

1. 项目背景与核心价值 风电功率预测是新能源并网调度中的关键技术痛点。我在某省级电网调度中心参与风电功率预测系统建设时,曾亲眼目睹因预测偏差导致的全网频率波动事件——那天风电场实际出力比预测值低了23%,调度员不得不紧急启动备用机组。这种场景…

2026/7/25 19:27:47

YOLOv10在工地车辆检测中的实践与优化

1. 项目背景与核心价值 工地运输车识别检测系统是智慧工地建设中的关键环节。传统的人工监管方式存在效率低下、容易遗漏等问题,特别是在大型施工现场,运输车辆的频繁进出给安全管理带来巨大挑战。我们开发的这套系统采用最新的YOLOv10算法,结…

2026/7/25 19:27:47

多层感知机(MLP)在工业预测中的应用与优化

1. 从流水线到神经网络:多层感知机的工业隐喻想象一下现代化汽车工厂的装配流水线:传送带将零件有序输送,每个工位上的工人只专注处理特定工序,经过多道专业工序后,原材料最终变成完整产品。多层感知机(MLP)的工作机制…

2026/7/25 19:22:47

易语言RC4算法实现详解:从原理到实战应用

1. 项目概述:为什么要在易语言里折腾RC4?如果你用易语言做过一些需要处理敏感数据的小工具,比如本地配置加密、网络通信简单混淆,或者只是想给文件加个锁,那你大概率会碰到一个选择:用哪种加密算法&#xf…

2026/7/25 12:13:16

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/25 0:00:15

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:00:15

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:00:15

VHF 甚高频语音喊话系统(桥梁智能防撞场景)核心优势

一、直达船员,预警链路最短营运船舶强制标配 VHF 船载电台,属于驾驶室常态化值守设备;预警语音直接传递至驾驶人员,区别于岸上声光报警(船员经常听不到)、短信 / 小程序(船员极少主动查看&#…

2026/7/25 0:59:36

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…