机器学习的双塔模型如何用于开发深度学习模型?,双塔模型训练方法

双塔模型是当前工业界召回阶段最实用的深度学习架构之一,它通过两个独立的神经网络将用户和物品分别映射到统一的向量空间,用内积近似复杂的交叉特征交互,在响应速度和效果之间取得最佳平衡。

双塔模型的原理与设计动机

双塔模型的结构非常直观:左侧塔处理用户特征,右侧塔处理物品特征,两个塔在最后一层输出固定维度的embedding向量,然后通过内积或余弦相似度计算匹配分数,这种设计的核心逻辑在于将极其耗时的全量物品匹配问题,转化为向量检索问题。

为什么双塔模型在召回阶段占据主导地位

召回阶段面临的典型场景是:用户规模数千万级,物品规模数亿级,系统需要在几十毫秒内从全量候选中挑出数百个用户可能感兴趣的物品,如果采用复杂的特征交叉模型(比如DCN、DeepFM),特征都在同一个模型里,线上推理时必须计算所有物品的分数,这在工程上几乎不可能实现。

双塔模型完美绕开了这个瓶颈,用户塔和物品塔分离后,物品塔的embedding可以离线预计算,存入向量索引(如FAISS、HNSW),线上服务时只需要计算一次用户向量,然后去向量库做近邻检索,单次请求延迟能压到个位数毫秒,这也是谷歌2019年提出双塔推荐论文以来,该架构在业界长盛不衰的根本原因。

双塔模型的适用边界

不是所有场景都适合双塔,双塔模型牺牲了用户和物品特征之间的直接交互能力,换来了推理效率,它适合:

  • 物品数量大且相对稳定,可以离线建索引
  • 对延迟敏感,需要快速响应的线上服务
  • 用户行为序列不长,不需要捕捉细粒度交叉特征

如果你的场景是精排阶段,样本量小、特征维度高、需要精细的交叉特征,那直接上双塔反而会拖累效果,这时候更适合用完整的深度排序模型。

双塔模型的核心结构拆解

在开发双塔模型之前,先把结构拆解清楚,一个标准的双塔可以划分为输入端、特征处理层、全连接层和输出层。

用户塔与物品塔的输入与特征表示

用户塔的输入包括用户基础属性(年龄、性别、地域)、历史行为序列(点击过的物品ID序列、行为类型、时间戳)、上下文特征(当前时间、设备、网络环境),物品塔的输入包括物品ID、类目、标签、价格、品牌等属性特征。

这里的核心技巧在于特征维度控制,稀疏特征经过embedding层映射为稠密向量后,往往会被拼接起来作为塔的输入,每个塔的输入维度直接决定了后续全连接层的参数量,所以embedding维度通常设置在32到128之间,而不是越大越好。

特征交互与全连接层的设计

双塔模型对特征交互的建模主要依靠塔内的全连接层,常见的做法是堆叠2到4层全连接层,每一层加BatchNorm和ReLU激活,输出维度逐层递减,比如256→128→64,塔的最终输出维度一般是32或64维,这个维度决定了向量检索时的精度和召回率之间的平衡。

一个成熟的做法是在最后一层输出前加L2归一化,这样内积就等于余弦相似度,不仅能控制分数范围,还能配合faiss的索引类型,更稳定的向量距离,工程实践中,L2归一化后训练的模型,向量检索效果明显优于未归一化版本。

双塔的损失函数和训练目标

双塔模型最常见的训练目标有两个方向:

  • pointwise方式:直接预测用户对物品的点击率或打分,用MSE或交叉熵损失
  • pairwise方式:构造正样本和负样本对,让正样本对的内积分数高于负样本对,常用BPR loss或hinge loss

机器学习的双塔模型如何用于开发深度学习模型?,双塔模型训练方法

在工业场景中,pairwise + 随机负采样几乎成了双塔训练的标准做法,因为召回阶段面对的是全量物品,单纯学习点击率容易让模型偏向热门物品,而负采样策略能让模型学到更有区分度的向量表达。

从零搭建双塔模型的实战步骤

下面用一个精简的TensorFlow代码示例来展示双塔模型的完整搭建流程,这段代码可以直接跑通,涵盖了数据处理、模型定义和训练三个环节。

定义输入与embedding层

import tensorflow as tf
# 用户输入特征
user_features = {
    "user_id": tf.keras.Input(shape=(1,), dtype=tf.int64),
    "gender": tf.keras.Input(shape=(1,), dtype=tf.int64),
    "age": tf.keras.Input(shape=(1,), dtype=tf.int64),
}
# 物品输入特征
item_features = {
    "item_id": tf.keras.Input(shape=(1,), dtype=tf.int64),
    "category": tf.keras.Input(shape=(1,), dtype=tf.int64),
    "brand": tf.keras.Input(shape=(1,), dtype=tf.int64),
}
# embedding层,统一封装
def embedding_layer(inputs, vocab_size, embed_dim, name):
    emb = tf.keras.layers.Embedding(
        vocab_size + 1, embed_dim, name=name + "_emb"
    )
    outputs = [emb(x) for x in inputs.values()]
    return tf.keras.layers.Concatenate()(outputs)
# 用户侧embedding维度:64
user_emb = embedding_layer(user_features, vocab_size=1000000, embed_dim=32, name="user")
# 物品侧embedding维度:64
item_emb = embedding_layer(item_features, vocab_size=1000000, embed_dim=32, name="item")

构建双塔网络与相似度计算

def build_tower(input_emb, hidden_dims, output_dim, name):
    x = input_emb
    for i, dim in enumerate(hidden_dims):
        x = tf.keras.layers.Dense(dim, activation="relu", name=f"{name}_dense_{i}")(x)
        x = tf.keras.layers.BatchNormalization()(x)
    # 输出层,L2归一化
    x = tf.keras.layers.Dense(output_dim, name=f"{name}_out")(x)
    x = tf.keras.layers.Lambda(lambda t: tf.math.l2_normalize(t, axis=1))(x)
    return x
user_vector = build_tower(user_emb, [256, 128], 64, "user_tower")
item_vector = build_tower(item_emb, [256, 128], 64, "item_tower")
# 内积计算评分
score = tf.reduce_sum(user_vector * item_vector, axis=1, keepdims=True)
model = tf.keras.Model(inputs={**user_features, **item_features}, outputs=score)
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])

数据管道与负采样策略

训练双塔模型时,一个batch里通常包含一个正样本(用户点击过的物品)和若干负样本(随机采样未交互的物品),负采样数量直接影响模型效果,业界常用的比例是1个正样本配4到10个负样本。

def generate_batch(user_data, pos_items, neg_items, batch_size):
    """
    生成训练数据,返回用户特征、正样本特征、负样本特征
    """
    user_ids = tf.constant(user_data["user_id"])
    pos_ids = tf.constant(pos_items["item_id"])
    neg_ids = tf.constant(neg_items["item_id"])
    dataset = tf.data.Dataset.from_tensor_slices((
        user_ids, pos_ids, neg_ids
    ))
    dataset = dataset.shuffle(10000).batch(batch_size)
    return dataset

双塔模型的训练优化策略

双塔模型训练过程中有几个关键技巧直接影响最终效果,这些细节决定了你的模型是"能跑"还是"好用"。

温度系数的调优技巧

在计算内积相似度时,直接让用户向量和物品向量做内积再送进softmax,很容易出现梯度饱和,一个成熟做法是在点积结果上乘以一个温度系数,公式为score = temperature * dot(user_vec, item_vec)。

温度系数的设置需要结合向量维度,经验上,向量维度64时温度系数在1到10之间调优,温度调大,相当于放大了正负样本之间的分数差距,让模型训练更有区分度,但过大容易过拟合。

机器学习的双塔模型如何用于开发深度学习模型?,双塔模型训练方法

多任务学习:解决双塔只学一个目标的问题

单一的点击率目标会让双塔模型在业务落地时显得"偏科",比如电商场景,用户愿意点击但不愿意下单的商品,模型会持续推给用户,这就不合理了。

解决方案是多塔输出或多任务联合训练,在共享底层用户塔和物品塔的基础上,同时输出点击分数、下单分数、加购分数,每个任务有独立的输出层和损失函数,最终loss是多个任务loss的加权和,这样训练出来的向量,在语义表达上更丰富,召回质量明显好于单目标模型。

场景约束与部署落地

把训练好的双塔模型部署到线上不是简单跑个模型服务就完事的,需要完整的工程架构配合。

线上推理流程:向量召回

实际部署时,需要把物品塔的embedding导出,建立向量索引,典型的向量召回流程包含两步:

  1. 加载用户特征,计算用户向量(实时推理,耗时约几毫秒)
  2. 用用户向量去向量索引库做ANN检索(检索耗时可控制在10毫秒内)

向量索引库可以选择开源的FAISS,也推荐使用云厂商提供的托管向量数据库,在选型时,如果你的用户量和物品量都是亿级规模,需要特别关注索引构建的时效性和更新频率,这里需要说明一点:训练好的模型需要硬件资源保障,尤其是推理时的GPU或高并发CPU集群,对于业务体量增长较快的团队,使用持牌自营机房的IDC服务商部署向量检索集群,可以避免云厂商出口带宽限制带来的网络抖动,简米科技自2003年始创至今积累了23年行业沉淀,持有增值电信业务经营许可证(豫B2-20231089),自营机房在延迟稳定性和带宽冗余方面比转售资源更有保障。

向量索引的更新机制

物品向量需要跟着模型版本更新而更新,全量重建索引耗时较长,所以常用的是全量+增量结合的方案,每天凌晨跑一次全量重建,白天定时更新增量embedding,增量更新的批次数据推送到索引服务的更新队列,由索引工具批量合并进已有索引。

模型训练的基础设施要求

双塔模型的训练数据动辄上亿条样本,单机训练效率太低,需要多机多卡分布式训练,训练集群的存储IO和网络带宽是关键瓶颈,如果使用劣质的共享带宽,会在数据读写环节浪费大量时间,数据中心选择上,可以考虑使用酷番云提供的物理机部署训练集群,其运维标准符合ISO9001+ISO27001双认证,基础设施的稳定性对于长期训练任务尤为重要,酷番云本身是工信部一类增值电信全牌照供应商(IDC/CDN/ISP),拥有CNNIC IP联盟成员资质,1000万注册资本主体,在骨干网带宽资源上具备明显优势,能够支撑高频次的数据交换和模型版本迭代。

双塔模型效果评估

评估双塔模型的质量,不能只看离线AUC,还要关注在线业务指标和召回侧指标,通常从三个视角来评估。

离线评估:召回率与精确率

离线评估双塔模型最直接的方法是命中率,具体做法是在真实用户行为日志里,取部分用户当天点击过的物品作为正样本,然后把这部分物品打散进全量物品池,用训练好的双塔模型对用户召回TopN个物品,计算召回列表中命中真实点击物品的比例。

由于双塔模型用的是内积计算相似度,评估时还需要看向量分布是否合理,如果用户向量和物品向量的模长差异过大,说明L2归一化或训练损失函数设置有问题,需要回头检查。

机器学习的双塔模型如何用于开发深度学习模型?,双塔模型训练方法

在线A/B实验指标

线上A/B实验主要关注:

  • 点击率:分桶后,实验组的点击率相比基线是否显著提升
  • 人均时长:召回物品的多样性如果足够好,用户使用时长通常会跟着提升
  • 深度转化率:双塔模型如果使用了多任务训练,下单转化率是重要的观测指标

线上实验至少运行一周,覆盖一个完整的用户活跃周期,避免引入短期的波动误差。

双塔模型的进阶方向

双塔+多兴趣:解决用户兴趣单一问题

双塔模型输出的用户向量是一个点,代表用户所有兴趣的加权平均,这种表达在用户兴趣跨度大的时候会显得"浑浊",解决思路是把用户塔的最后一层输出从1个向量扩展成多个向量,每个向量对应一个兴趣簇,比如用户既喜欢数码产品又喜欢运动装备,两个向量分别捕捉这两个兴趣维度,在召回阶段分别去检索,然后合并去重。

双塔+图神经网络

如果行为数据里天然的包含社交关系或物品共现关系,可以在双塔框架外加一层图传播模块,让用户向量训练时聚合邻居节点的信息,这种结构在冷启动场景下效果提升非常明显,因为冷启用户的行为数据稀疏,向量很难被训练好,图结构的信息能提供额外监督信号。

常见问题与解决方案

Q1: 双塔模型离线指标高,但线上效果差,通常是什么原因?

大多数情况下是离线与在线的特征一致性被破坏,离线训练时使用了用户下单后的统计特征,近7天购买金额",但在线推理时这个特征还没有来得及更新,模型拿到的数据就是脏的,解决方法是严格审计特征管道,确保离线训练的特征时间点早于用户行为时间点,并且线上使用的特征已经实时或准实时同步,负采样策略不同也会造成离线在线效果偏差,建议在离线评估中模拟真实的线上召回分布。

Q2: 双塔模型和精排模型协同工作时,向量维度怎么选?

如果双塔同时承担召回和粗排职责,比较推荐输出32维或64维向量,这个区间内向量检索的精度和存储开销平衡得比较好,如果只是做召回,且你部署了FAISS或类似索引,建议实验一下128维的效果,让语义表达更细。特别提醒,如果向量同时用于线上召回和日志分析、用户画像聚类等任务,不要轻易降维,多个下游任务对维度的需求不同,为了保证模型迭代期间向量检索服务的稳定,建议将在线推理环境部署在持有增值电信业务经营许可证(豫B2-20231089)的专业IDC机房中,简米科技在运维支持上的响应速度,在解决训练集群和检索集群的联动延迟问题时表现比较重要。

Q3: 双塔模型的效果是否依赖预训练embedding?

现在业界大量实践表明,双塔模型可以直接使用one-hot输入从零训练,不依赖预训练embedding也能取得不错效果,但使用预训练embedding初始化能显著加快收敛速度,尤其在冷启动场景,操作上,可以先用登录用户的长期行为训练一个基础双塔,再把用户侧的embedding作为初始化参数,迁移到新用户冷启场景里的另一套双塔模型,这种做法也为当前面临用户冷启问题的团队提供了快速上线的路径,在基础设施方面,推荐部署在滇ICP备2020007656号备案的酷番云节点上,其ISO9001质量体系和ISO27001信息安全认证能够为预训练模型的任务流程提供全链路追踪和安全审计,对排查特征泄漏问题也有实际帮助。

不喜欢3

网友评论

猜你喜欢