从公式到代码手把手复现阿里ESMM模型PaddlePaddle/PyTorch版在推荐系统的技术演进中多任务学习已成为提升模型效果的关键策略。阿里妈妈团队提出的ESMMEntire Space Multi-Task Model通过创新的概率分解思想有效解决了转化率预估中的样本选择偏差和数据稀疏问题。本文将带您深入理解这一经典模型的数学原理并分别用PaddlePaddle和PyTorch框架实现完整解决方案。1. ESMM核心原理与技术突破1.1 概率图视角下的转化链路建模电商场景的用户行为遵循严格的曝光→点击→转化顺序。设$x$用户特征和上下文特征$y$点击行为0/1$z$转化行为0/1ESMM的核心公式揭示了三个关键概率的关系 $$ pCTCVR pCTR \times pCVR $$ 其中$pCTR p(y1|x)$$pCVR p(z1|y1,x)$$pCTCVR p(y1,z1|x)$这种分解带来两个重要优势全空间建模CTR和CTCVR任务可以使用全部曝光样本训练隐式学习CVR参数通过乘积关系间接优化1.2 网络架构设计精要ESMM的模型结构包含三个核心组件组件输入输出训练样本共享Embedding层原始特征特征嵌入全量曝光样本CTR塔特征嵌入pCTR全量曝光样本CVR塔特征嵌入pCVR仅点击样本注意虽然CVR塔理论上只处理点击样本但其参数通过CTCVR的联合损失进行更新2. PaddlePaddle实现详解2.1 环境配置与数据准备首先安装必要依赖pip install paddlepaddle2.4.0 pip install pandas sklearn准备示例数据格式user_iditem_idcate_idclickconversion1234567891023456789000特征处理关键代码import paddle from paddle.io import Dataset class ESMNDataset(Dataset): def __init__(self, data): self.data data def __getitem__(self, idx): sample self.data.iloc[idx] return { user_id: sample[user_id], item_id: sample[item_id], cate_id: sample[cate_id], click: sample[click], conversion: sample[conversion] sample[click] }2.2 模型构建完整模型实现class ESMM(paddle.nn.Layer): def __init__(self, user_num, item_num, cate_num, embed_dim64): super().__init__() # 共享特征嵌入 self.user_emb paddle.nn.Embedding(user_num, embed_dim) self.item_emb paddle.nn.Embedding(item_num, embed_dim) self.cate_emb paddle.nn.Embedding(cate_num, embed_dim) # CTR塔 self.ctr_mlp paddle.nn.Sequential( paddle.nn.Linear(embed_dim*3, 128), paddle.nn.ReLU(), paddle.nn.Linear(128, 64), paddle.nn.ReLU(), paddle.nn.Linear(64, 2) ) # CVR塔 self.cvr_mlp paddle.nn.Sequential( paddle.nn.Linear(embed_dim*3, 128), paddle.nn.ReLU(), paddle.nn.Linear(128, 64), paddle.nn.ReLU(), paddle.nn.Linear(64, 2) ) def forward(self, inputs): # 特征嵌入 user_emb self.user_emb(inputs[user_id]) item_emb self.item_emb(inputs[item_id]) cate_emb self.cate_emb(inputs[cate_id]) concat_emb paddle.concat([user_emb, item_emb, cate_emb], axis1) # CTR预测 ctr_logits self.ctr_mlp(concat_emb) ctr_pred paddle.nn.functional.softmax(ctr_logits)[:, 1] # CVR预测 cvr_logits self.cvr_mlp(concat_emb) cvr_pred paddle.nn.functional.softmax(cvr_logits)[:, 1] # CTCVR计算 ctcvr_pred ctr_pred * cvr_pred return ctr_pred, cvr_pred, ctcvr_pred2.3 自定义损失函数实现论文中的联合损失class ESMNLoss(paddle.nn.Layer): def __init__(self): super().__init__() self.ctr_loss paddle.nn.BCELoss() self.ctcvr_loss paddle.nn.BCELoss() def forward(self, preds, labels): ctr_pred, _, ctcvr_pred preds click_label labels[click] conversion_label labels[conversion] ctr_loss self.ctr_loss(ctr_pred, click_label) ctcvr_loss self.ctcvr_loss(ctcvr_pred, conversion_label) return ctr_loss ctcvr_loss3. PyTorch实现方案3.1 模型结构迁移PyTorch版本的核心差异import torch import torch.nn as nn class ESMMTorch(nn.Module): def __init__(self, user_num, item_num, cate_num, embed_dim64): super().__init__() # 共享嵌入层 self.user_emb nn.Embedding(user_num, embed_dim) self.item_emb nn.Embedding(item_num, embed_dim) self.cate_emb nn.Embedding(cate_num, embed_dim) # 网络塔结构 self.ctr_tower nn.Sequential( nn.Linear(embed_dim*3, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid() ) self.cvr_tower nn.Sequential( nn.Linear(embed_dim*3, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid() ) def forward(self, x): user_emb self.user_emb(x[user_id]) item_emb self.item_emb(x[item_id]) cate_emb self.cate_emb(x[cate_id]) concat_emb torch.cat([user_emb, item_emb, cate_emb], dim1) pctr self.ctr_tower(concat_emb) pcvr self.cvr_tower(concat_emb) pctcvr pctr * pcvr return pctr.squeeze(), pcvr.squeeze(), pctcvr.squeeze()3.2 训练流程优化PyTorch训练循环示例def train_epoch(model, dataloader, optimizer, device): model.train() total_loss 0 for batch in dataloader: optimizer.zero_grad() # 数据转移到设备 inputs {k: v.to(device) for k,v in batch.items()} labels { click: inputs[click].float(), conversion: (inputs[click] * inputs[conversion]).float() } # 前向计算 ctr_pred, cvr_pred, ctcvr_pred model(inputs) # 损失计算 ctr_loss F.binary_cross_entropy(ctr_pred, labels[click]) ctcvr_loss F.binary_cross_entropy(ctcvr_pred, labels[conversion]) loss ctr_loss ctcvr_loss # 反向传播 loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(dataloader)4. 实战技巧与调优策略4.1 特征工程最佳实践用户侧特征历史点击/转化统计兴趣标签活跃时段物品侧特征类目属性价格分段销量统计上下文特征曝光位置时间周期设备类型4.2 模型调优关键点Embedding维度选择高基数特征16-64维低基数特征8-16维塔结构设计# 更深的网络结构示例 self.ctr_tower nn.Sequential( nn.Linear(embed_dim*3, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(0.3), nn.Linear(256, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Linear(128, 1), nn.Sigmoid() )损失函数加权# 根据任务重要性调整权重 loss alpha * ctr_loss beta * ctcvr_loss4.3 线上部署考量性能优化使用TensorRT加速推理实现Embedding缓存机制效果监控建立CTR/CVR漂移检测设计A/B测试分层策略在电商推荐系统中ESMM的落地需要与召回模块、排序模块协同工作。实际部署时我们发现将CVR预测结果与CTR预测进行动态加权如score CTR^α * CVR^β能够更好地平衡点击率和转化率的目标。
从公式到代码:手把手复现阿里ESMM模型(PaddlePaddle/PyTorch版)
从公式到代码手把手复现阿里ESMM模型PaddlePaddle/PyTorch版在推荐系统的技术演进中多任务学习已成为提升模型效果的关键策略。阿里妈妈团队提出的ESMMEntire Space Multi-Task Model通过创新的概率分解思想有效解决了转化率预估中的样本选择偏差和数据稀疏问题。本文将带您深入理解这一经典模型的数学原理并分别用PaddlePaddle和PyTorch框架实现完整解决方案。1. ESMM核心原理与技术突破1.1 概率图视角下的转化链路建模电商场景的用户行为遵循严格的曝光→点击→转化顺序。设$x$用户特征和上下文特征$y$点击行为0/1$z$转化行为0/1ESMM的核心公式揭示了三个关键概率的关系 $$ pCTCVR pCTR \times pCVR $$ 其中$pCTR p(y1|x)$$pCVR p(z1|y1,x)$$pCTCVR p(y1,z1|x)$这种分解带来两个重要优势全空间建模CTR和CTCVR任务可以使用全部曝光样本训练隐式学习CVR参数通过乘积关系间接优化1.2 网络架构设计精要ESMM的模型结构包含三个核心组件组件输入输出训练样本共享Embedding层原始特征特征嵌入全量曝光样本CTR塔特征嵌入pCTR全量曝光样本CVR塔特征嵌入pCVR仅点击样本注意虽然CVR塔理论上只处理点击样本但其参数通过CTCVR的联合损失进行更新2. PaddlePaddle实现详解2.1 环境配置与数据准备首先安装必要依赖pip install paddlepaddle2.4.0 pip install pandas sklearn准备示例数据格式user_iditem_idcate_idclickconversion1234567891023456789000特征处理关键代码import paddle from paddle.io import Dataset class ESMNDataset(Dataset): def __init__(self, data): self.data data def __getitem__(self, idx): sample self.data.iloc[idx] return { user_id: sample[user_id], item_id: sample[item_id], cate_id: sample[cate_id], click: sample[click], conversion: sample[conversion] sample[click] }2.2 模型构建完整模型实现class ESMM(paddle.nn.Layer): def __init__(self, user_num, item_num, cate_num, embed_dim64): super().__init__() # 共享特征嵌入 self.user_emb paddle.nn.Embedding(user_num, embed_dim) self.item_emb paddle.nn.Embedding(item_num, embed_dim) self.cate_emb paddle.nn.Embedding(cate_num, embed_dim) # CTR塔 self.ctr_mlp paddle.nn.Sequential( paddle.nn.Linear(embed_dim*3, 128), paddle.nn.ReLU(), paddle.nn.Linear(128, 64), paddle.nn.ReLU(), paddle.nn.Linear(64, 2) ) # CVR塔 self.cvr_mlp paddle.nn.Sequential( paddle.nn.Linear(embed_dim*3, 128), paddle.nn.ReLU(), paddle.nn.Linear(128, 64), paddle.nn.ReLU(), paddle.nn.Linear(64, 2) ) def forward(self, inputs): # 特征嵌入 user_emb self.user_emb(inputs[user_id]) item_emb self.item_emb(inputs[item_id]) cate_emb self.cate_emb(inputs[cate_id]) concat_emb paddle.concat([user_emb, item_emb, cate_emb], axis1) # CTR预测 ctr_logits self.ctr_mlp(concat_emb) ctr_pred paddle.nn.functional.softmax(ctr_logits)[:, 1] # CVR预测 cvr_logits self.cvr_mlp(concat_emb) cvr_pred paddle.nn.functional.softmax(cvr_logits)[:, 1] # CTCVR计算 ctcvr_pred ctr_pred * cvr_pred return ctr_pred, cvr_pred, ctcvr_pred2.3 自定义损失函数实现论文中的联合损失class ESMNLoss(paddle.nn.Layer): def __init__(self): super().__init__() self.ctr_loss paddle.nn.BCELoss() self.ctcvr_loss paddle.nn.BCELoss() def forward(self, preds, labels): ctr_pred, _, ctcvr_pred preds click_label labels[click] conversion_label labels[conversion] ctr_loss self.ctr_loss(ctr_pred, click_label) ctcvr_loss self.ctcvr_loss(ctcvr_pred, conversion_label) return ctr_loss ctcvr_loss3. PyTorch实现方案3.1 模型结构迁移PyTorch版本的核心差异import torch import torch.nn as nn class ESMMTorch(nn.Module): def __init__(self, user_num, item_num, cate_num, embed_dim64): super().__init__() # 共享嵌入层 self.user_emb nn.Embedding(user_num, embed_dim) self.item_emb nn.Embedding(item_num, embed_dim) self.cate_emb nn.Embedding(cate_num, embed_dim) # 网络塔结构 self.ctr_tower nn.Sequential( nn.Linear(embed_dim*3, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid() ) self.cvr_tower nn.Sequential( nn.Linear(embed_dim*3, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid() ) def forward(self, x): user_emb self.user_emb(x[user_id]) item_emb self.item_emb(x[item_id]) cate_emb self.cate_emb(x[cate_id]) concat_emb torch.cat([user_emb, item_emb, cate_emb], dim1) pctr self.ctr_tower(concat_emb) pcvr self.cvr_tower(concat_emb) pctcvr pctr * pcvr return pctr.squeeze(), pcvr.squeeze(), pctcvr.squeeze()3.2 训练流程优化PyTorch训练循环示例def train_epoch(model, dataloader, optimizer, device): model.train() total_loss 0 for batch in dataloader: optimizer.zero_grad() # 数据转移到设备 inputs {k: v.to(device) for k,v in batch.items()} labels { click: inputs[click].float(), conversion: (inputs[click] * inputs[conversion]).float() } # 前向计算 ctr_pred, cvr_pred, ctcvr_pred model(inputs) # 损失计算 ctr_loss F.binary_cross_entropy(ctr_pred, labels[click]) ctcvr_loss F.binary_cross_entropy(ctcvr_pred, labels[conversion]) loss ctr_loss ctcvr_loss # 反向传播 loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(dataloader)4. 实战技巧与调优策略4.1 特征工程最佳实践用户侧特征历史点击/转化统计兴趣标签活跃时段物品侧特征类目属性价格分段销量统计上下文特征曝光位置时间周期设备类型4.2 模型调优关键点Embedding维度选择高基数特征16-64维低基数特征8-16维塔结构设计# 更深的网络结构示例 self.ctr_tower nn.Sequential( nn.Linear(embed_dim*3, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(0.3), nn.Linear(256, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Linear(128, 1), nn.Sigmoid() )损失函数加权# 根据任务重要性调整权重 loss alpha * ctr_loss beta * ctcvr_loss4.3 线上部署考量性能优化使用TensorRT加速推理实现Embedding缓存机制效果监控建立CTR/CVR漂移检测设计A/B测试分层策略在电商推荐系统中ESMM的落地需要与召回模块、排序模块协同工作。实际部署时我们发现将CVR预测结果与CTR预测进行动态加权如score CTR^α * CVR^β能够更好地平衡点击率和转化率的目标。