普通视图

发现新文章,点击刷新页面。
昨天 — 2025年5月20日掘金专栏-百度Geek说

PD 分离推理的加速大招,百度智能云网络基础设施和通信组件的优化实践

作者 百度Geek说
2025年5月20日 15:13

为了适应 PD 分离式推理部署架构,百度智能云从物理网络层面的「4us 端到端低时延」HPN 集群建设,到网络流量层面的设备配置和管理,再到通信组件和算子层面的优化,显著提升了上层推理服务的整体性能。

百度智能云在大规模 PD 分离式推理基础设施优化的实践中,充分展现了网络基础设施、通信组件与上层业务特征深度融合的重要性。


01 PD分离式推理服务对网络的需求

传统的推理服务均是集中式,大多是单机部署。即使是多机部署,机器规模也非常小,对网络的带宽和时延需求都不大。当前大规模 PD 分离式推理系统来说,对网络通信的需求则发生了变化:

  • 引入大规模的 EP 专家并行。EP 会从单机和双机的小规模,变成更大规模,因此 EP 之间的「 Alltoall 通信域」成倍增长。这对于网络基础设施、Alltoall 算子等的通信效率都提出了更高的要求,它们会直接影响 OTPS、TPOT 等指标,从而影响最终的用户体验。

  • PD 分离式部署,Prefill 和 Decode 之间会有 KV Cache 流量的传输,KV Cache 通信的时延直接影响推理服务整体的性能。

为了提升大规模 PD 分离式推理系统的效率,百度智能云针对性地优化了网络基础设施和通信组件:

  • 物理网络层面:为适配 Alltoall 流量专门建设了「4us 端到端低时延」 HPN 集群,支持自适应路由功能彻底解决网络哈希冲突,保证稳定的低时延。

  • 流量管理层面:优化 Alltoall 多打一 incast 流量导致的降速问题。对 HPN 网络中训练、推理等不同类型流量进行队列管理,实现训推任务的互不干扰。通过自研高性能 KV Cache 传输库实现 DCN 弹性 RDMA 满带宽传输。

  • 通信组件层面:Alltoall 算子优化,相比开源的方案,大幅提升 Prefill 和 Decode 的 Alltoall 通信性能。针对 batch size 级别的动态冗余专家编排,将专家均衡度控制在了 1.2 以下,确保集群中所有 GPU 通信时间大致相同。优化双流,实现最大程度的计算和通信 overlap,整体提升 20% 吞吐。

下面我们逐一介绍百度智能云在以上几个层面的优化实践。

02 解决方案和最佳实践

2.1 建设适配的 HPN 网络设施

百度智能云在训练场景下的 HPN 网络架构设计已经有着丰富的经验,AIPod 使用多导轨网络架构,GPU 服务器配有 8 张网卡,然后每张网卡分别连到一个汇聚组的不同 LEAF 上。在 LEAF 和 SPINE 层面,通过 Full Mesh 的方式进行互联。

以下图为例,考虑一个训练场景下的 3 层架构 HPN 网络:

图片

2.1.1 训练和推理任务的流量特征

  • 非 MoE 训练任务的流量特征

在传统非 MoE 的训练场景下,跨机通信产生的流量大多数都是同号卡流量。例如在梯度同步时候产生的 AllReduce 或者 ReduceScatter 或者 AllGather,PP 之间的 SendRecv 等。同号卡通信最佳情况可以只经过一跳,以上图为例,每个 LEAF 交换机有 64 个下联口,因此 64 台服务器规模同号卡通信理论上可以做到一跳可达。

规模再大,就只能经过 SPINE 或者最差经过 SUPER SPINE 来进行通信。为了减少流量上送 SPINE,百度百舸在任务调度的时候会自动进行服务器的亲和性调度。在创建任务的时候,尽量把同一通信组下的 Rank 排布在同一 LEAF 交换机下的服务器内,那么理论上大部分流量都可以收敛在 LEAF 下。

  • MoE 推理流量特征

对于推理服务来说,MoE EP 之间的 Alltoall 通信流量模式与 AllReduce 等不同,会产生大量的跨导轨流量。虽然对于 Prefill 阶段来说,可以通过软件实现层面规避掉跨导轨的流量,但是 Decode 阶段仍然无法避免跨导轨,这会导致多机之间的通信不只是同号卡通信,跨机流量大部分并不能一跳可达,会有大量的流量上到 SPINE 或者 SUPER SPINE,从而导致时延增加。

  • MoE 训练流量特征

对于 MoE 训练的流量会更加复杂,综合了训练和推理的流量特征,既存在传统的梯度同步产生的 AllReduce 或者 ReduceScatter 或者 AllGather,PP 之间的 SendRecv,也存在 EP 之间的 Alltoall 流量。这些流量不但会出现跨导轨传输的问题,他们之间可能会存在 overlap 导致互相干扰。

2.1.2 面向 EP 的 HPN 架构优化

鉴于 Alltoall 通信的特点,我们在设计 HPN 网络的时候,会考虑优先保证跨导轨流量至多 2 跳可达,让 Alltoall 流量收敛到 SPINE 层,以这种方式尽量减少跨导轨的通信时延。如下图所示:

图片

LEAF 层所有设备全部有一根线接入同一台 SPINE 交换机,这样可以让集群内 Alltoall 跨导轨流量全部收敛到 SPINE 层,跨导轨通信时延可以进一步从 5us+ 缩小为 4us。

这种经过优化后的 HPN 网络架构,能接入的卡数主要取决于交换机芯片支持的最大的下联口有多少。虽然对于超大模型的训练任务来说,这个集群规模可能不够,但是对于推理来说,通常不需要那么大规模的机器,是可以满足需求的。

2.1.3 自适应路由彻底消除 hash 冲突

同时,由于 Alltoall 通信流量的特征,LEAF 到 SPINE 之间的通信流量会成为常态。当流量需要通过 SPINE 传输的时候,会由 hash 选择 SPINE 出口的过程,这时候有可能会产生 hash 冲突,导致网络抖动。因此为了避免 hash 冲突,百度智能云基于自研交换机实现自适应路由。如下图所示:

图片

假设 A 和 C 进行 Alltoall 跨导轨通信,A 发出的流量必然要经过 SPINE,那么流量在到达 LEAF 的时候,会基于 packet 做 hash,并结合链路的负载情况动态选择最优的出口,将报文发送到多个 SPINE 上。

基于报文 hash 到不同的物理路径,百度智能云实现了链路负载均衡,消除因 hash 冲突时延增加导致的性能抖动,实现稳定的低时延网络。

详情可参考:彻底解决网络哈希冲突,百度百舸的高性能网络 HPN 落地实践

2.2 流量的管理和优化

2.2.1 避免 incast 造成降速,不同类型流量的分队列管理

  • Alltoall 多打一,不合理的配置造成降速

在推理服务中,EP 间的 Alltoall 通信流量特性与传统训练中的 AllReduce 完全不同,网络上多打一造成的 incast 流量非常常见。这种 incast 的严重程度会随着规模的增大而增大。incast 流量的突发,可能会造成接收侧网卡上联的交换机端口向发送侧反压 PFC,导致网络降速。

传统 Alltoall 流量多打一的示意图如下,假设机器 A 和机器 C 的 GPU0、GPU2、GPU4、GPU6 都需要给机器 B 的 GPU0 发送数据,那么在网络上就会出现 8 打 1 的情况。

图片

传统的 Alltoall 实现,例如 PyTorch 内部调用的 Alltoall,是使用 send recv 去实现的,如果使用 PXN 可以缩小网络上的发生多打一的规模,但是多打一依然存在,如下图所示:

图片

因此无论 Alltoall 的算子实现方式如何,网络上的多打一都无法避免。此时如果网络侧的拥塞控制算法的配置不合理,对拥塞过于敏感,就会产生降速,进而对整体吞吐造成影响。

  • 推理训练任务中非 Alltoall 流量的干扰

除此之外,如果集群内还存在其他流量,例如训练任务 DP(数据并行)之间的 AllReduce 或者 ReduceScatter 或者 AllGather,或者 PD(Prefill-Decode)之间的 KV Cache 传输,也会对 Alltoall 的流量造成影响,从而进一步降低推理引擎的整体吞吐。

因此无论是端侧网卡的配置,或者是交换机的配置,都需要针对 Alltoall 这种多打一 incast 流量做针对性优化,同时尽量避免集群内其他流量对 Alltoall 流量造成影响。

针对这种情况,我们给出的解决方案如下:

  • 在队列管理层面,通过端侧网卡将 EP 的流量做专门的优先级配置,将 Alltoall 流量导入到高优先级队列。其他训练的流量,比如 AllReduce 等使用低优先级队列。

  • 在资源层面,在端侧网卡和交换机的高优先级队列上,预留更多的 buffer,分配更高比例的带宽,优先的保证高优先级队列的流量。

  • 在拥塞控制算法配置层面,高优先级队列关闭 ECN 标记功能,让 DCQCN 算法对 Alltoall 流量微突发造成的拥塞不做出反应,从而解决 incast 问题造成的降速。

在经过端侧网卡和网侧交换机配合调整后,可以保障 Alltoall 通信流量的通信带宽和传输时延,实现训推任务的互不干扰,并有效的缓解 incast 流量带来的非预期的降速而造成的性能抖动。

经过测试,在我们部署的推理服务中,Alltoall 过程的整体通信时延有 5% 的降低。

2.2.2 DCN 支持弹性 RDMA 实现 KV Cache 满带宽传输

在 PD 分离式推理系统中,还存在 PD 之间 KV Cache 传输的流量。相比 Alltoall 虽然他的带宽需求不算大,但为了避免二者的流量互相干扰,通常我们会让 KV Cache 的传输流量单独走 DCN 网络,使其与 Alltoall 的流量完全隔离开。

图片

在 DCN 网络的设计上,为了保证 KV Cache 流量的传输带宽,其网络架构收敛比采用 1:1。端侧网卡支持弹性 RDMA,使用 RDMA 协议保证 KV Cache 的高性能传输。

在传输库层面,百度智能云使用自研的高性能 KV Cache RDMA 传输库,其接口设计与框架层深度定制,支持上层框架分层传输,也支持多层 KV Cache 的批量传输,便于在框架层做计算与传输的 overlap。

通过以上设计优化,KV Cache 传输在主网卡可以用满带宽传输时间可以完全被计算 overlap 住,不成为推理系统的瓶颈。

2.3 提高推理服务组件的网络通信效率

在有了高带宽低时延的网络基础设施的基础上,如何用好网络基础设施,是推理服务软件层面需要重点考虑的事情。

在我们对 PD 分离推理服务的 profile 分析当中,发现了一些影响网络通信效率的关键因素。

2.3.1 Alltoall 算子的通信效率

目前社区开源的 DeepEP 已经给出了推理系统中 dispatch 和 combine 过程的 Alltoall 高性能的算子的实现,且性能表现优异。

对于 Prefill 来说,由于输入的 batch size 较大,Alltoall 通信算子的同号卡传输阶段为了平衡显存资源和性能,采用分 chunk 传输的方式,发送和接收会循环使用一小块显存,并对每次 RDMA 发送以及机内 NVLink 传输的 token 数做了限制。

通过实际观测网卡的传输带宽,发现其并没有被打满。在此基础上,我们对网络传输的显存的大小,以及每一轮发送接收的最大 token 数等配置,针对不同的 GPU 芯片,做了一些精细化的调整,使之在性能上有进一步的提升。通过优化,DeepEP 的传输性能有大概 20% 的性能提升,网络带宽已经基本被打满。

对于 Decode 来说,DeepEP 的实现是多机之间的 EP 通信,不区分机内和机间,一律采用网络发送。这样做的考虑是为了机内传输也不消耗 GPU 的 SM 资源,完成网络发送后算子即可退出。在网络传输的时间内做计算,完成后再调用 Alltoall 的接收算子,以此来实现计算和通信的 overlap。但这样做的缺点是机内的 NVLink 的带宽并没有被高效的利用起来,网络传输的数据量会变大。

因此,百度智能云通过在 GPU 算子内使用 CE 引擎做异步拷贝,在不占用 GPU SM 资源的情况下,也能实现机内 NVLink 带宽的高效利用,同时不影响计算和通信的 overlap。

2.3.2 动态冗余专家编码,保证 EP 负载均衡

EP 专家之间如果出现处理 token 不均衡的情况,将会导致 Alltoall 通信算子的不同 SM 之间,以及不同 GPU 的通信算子之间,出现负载不均的情况,导致的结果就是整体通信时间会被拉长。

由于 EP 专家之间的负载均衡是推理服务引擎提升吞吐的非常重要的一环,经过百度智能云的大规模的线上实践的经验来看,静态冗余专家并不能很好的保证专家均衡。因此我们专门适配了针对 batch size 级别的动态冗余专家,把专家均衡度(max token/avg token)基本控制在了 1.2 以下,不会出现明显的「快慢卡」的情况

2.3.3 极致优化双流效果,整体吞吐进一步提升

通信和计算 overlap,隐藏通信的开销,一直都是推理服务,或者大模型训练中,非常重要的课题。

在百度智能云的实践中,我们在线上大规模的推理服务中开启了双流。为了尽量隐藏掉通信的开销,达到最好的 overlap 的效果,除了做 EP 之间的专家均衡以外,对计算算子也做了针对性的优化,例如对计算算子和通信算子 kernel launch 的顺序做合理排布,对二者所需的 SM 资源做合理的分配,避免出现计算算子占满 SM 导致通信算子 launch 不进去的情况,尽可能的消灭掉 GPU 间隙的资源浪费。通过这些优化,整体的吞吐可以提升 20% 以上。

03 总结

百度智能云在大规模 PD 分离式推理基础设施优化的实践中,充分展现了网络基础设施、通信组件与上层业务特征深度融合的重要性。这种融合不仅是技术层面的创新,更是对实际业务需求的深刻理解和响应。

昨天以前掘金专栏-百度Geek说

打破算力瓶颈!起底百度智能云高性能存储加速系统如何让昆仑芯3万卡集群火力全开

作者 百度Geek说
2025年5月15日 15:36

01 引言

大模型的训练和推理任务,本质就是海量数据处理的过程。强大的算力集群,不仅需要高性能的AI加速卡和高性能的RDMA网络,还离不开高性能存储系统的支持。

当前,在大模型训练任务的数据读取、Checkpoint加载,推理任务的快速分发和镜像加载等场景,数据的大小少则几十GiB,多则几百TiB甚至至多达到数PiB。存储速度越快,算力空闲时间越短。这需要一套能够支持大规模算力集群、海量数据场景的高性能存储加速系统。

02 RapidFS存储加速集群

在Create 2025大会,昆仑芯3万卡集群正式发布。为此,我们为RapidFS存储加速服务部署了数百台国产CPU服务器,集群设计总吞吐接近10 TiB/s,以满足3万卡昆仑芯集群大规模数据读写需求。

我们使用部分资源进行了RapidFS性能测试(更多测试细节见后文)。

测试结果显示,20个RapidFS存储节点稳定提供了302 GiB/s吞吐,70个RapidFS存储节点稳定提供了1.03 TiB/s吞吐。单台RapidFS存储节点可提供15 GiB/s吞吐,折合单TiB(裸容量)300 MiB/s。

这些数据表明RapidFS存储加速集群的吞吐性能,随着集群规模线性增长。单台RapidFS存储节点经过软硬一体的协同优化,充分发挥出国产CPU的性能和软件加速效果。

同时,这也意味着在70个RapidFS存储节点提供加速的情况下,100个计算节点并发加载10 GiB的文件仅需1秒,让数据随叫随到。

03 RapidFS产品简介

RapidFS是一款近计算存储加速工具。依托对象存储BOS作为数据湖存储底座,构建容量与性能解耦、冷热分层、透明流转的高性能存储方案。以POSIX挂载和HDFS协议,为上层计算应用提供统一文件访问入口,加速AI训练与推理、海量数据处理与分析、数据分发等业务场景下的存储访问。

图片

04 性能测试详细说明

4.1 服务器配置

在本次测试的昆仑芯3万卡集群中,百度智能云RapidFS以全托管集群方式部署于国产CPU服务器,作为近计算存储加速服务使用。详细配置如下:

图片

4.2 测试规模

我们分别对20个存储节点和70个存储节点规模的RapidFS集群进行了性能测试。

4.3 测试方法

按照DeepSeek V3模型文件构造160个4.3 GiB文件,总计688 GiB。将这些文件导入对象存储BOS并加载至RapidFS存储加速集群中。每个计算节点开启8进程从RapidFS存储加速集群中读取模型文件,持续压测600秒。

4.4 测试结果

测试集群A:20个RapidFS存储节点

图片

测试集群B:70个RapidFS存储节点

图片

百度智能云RapidFS存储加速集群用数据证明了国产算力基础设施的突破潜力。存储性能与算力需求实现「同频共振」,成为大模型训练与推理的效率助推器。

Qwen3 系列全家桶,百度百舸一键部署

作者 百度Geek说
2025年5月13日 14:53

Qwen3 系列全家桶包含了 8 款不同尺寸的模型,覆盖了从 6 亿到 2350 亿的参数规模。其中 2 款混合专家(MoE)模型和 6 款稠密(Dense)模型,均支持「混合推理」机制。

目前,百度百舸平台已经同步支持 Qwen3 系列全家桶的一键部署,为企业提供一站式 AI 服务,实现大模型落地「快稳省」的要求。

一键部署流程

登录百度百舸·AI 异构计算平台,在「**快速开始」**找到 Qwen3 系列模型。

图片

点击模型卡片的「一键部署」开始部署模型。目前 Qwen3 系列模型支持 SGLang、vLLM 推理加速方式。

百度百舸平台已推荐部署不同模型的最低配置资源,您可以按需修改。(注意:需要提前购买算力资源,并在百度百舸平台创建自运维或全托管资源池)

图片

部署成功后,通过「在线服务」列表中查看服务调用信息,获取调用地址和 Token 调用服务。

图片

百度百舸·AI 异构计算平台,是面向大模型训推一体化的基础设施,提供领先的 AI 工程加速能力,从资源准备、模型开发、模型训练到模型部署,为 AI 工程全周期提供丰富特性和极致易用体验。

针对大模型 PD 分离式推理部署方案,百度百舸平台支持自适应 PD 任意配比、细粒度 PD 负载均衡、自适应最优混合并行策略、动态冗余专家编排等,降低 40% TPOT 和 95% 推理成本,实现了极致的推理加速优化。

这套方案正在支撑百度智能云千帆平台,为 40 万客户提供服务。上线以来,推理吞吐提升了 20 倍,速度提升了 50% 以上。

中国自动驾驶研发解决方案,第一!

作者 百度Geek说
2025年5月8日 16:07

4月28日,IDC《中国汽车云市场(2024下半年)跟踪》报告发布,2024下半年中国汽车云市场整体规模达到65.1亿元人民币,同比增长27.4%。IDC认为,自动驾驶技术深化与生成式AI的发展将为汽车云打开新的成长天花板,推动云计算在汽车行业的持续渗透。

IDC报告显示,2024年全年自动驾驶研发解决方案市场规模达16.34亿元人民币,同比增长18.42%,百度智能云以5.64亿元人民币的市场份额排名第一,份额占比达34.51%。

IDC中国企业级研究部分析师陈启今表示:“自动驾驶研发解决方案市场竞争激烈,百度智能云凭借自动驾驶领域的深厚行业积累和企业解决方案优势,重点关注头部车企和Tier1,市场份额重回至行业第一。”

智能驾驶进入AI时代,智算基础设施与算法、数据三者协同发展,端到端智驾正成为业内共识,车企和供应商不断加码算力集群采购、新算法架构搭建、仿真测试等资本支出,头部客户算力花销和算力规模正朝着亿级、10EFlops级别演进。

陈启今表示,智驾领域技术持续迭代、竞争白热化,客户对自动驾驶解决方案的需求不断增加,而新车网联化进程全面加速及车联网场景创新也驱动客户加大相关投入,这些因素共同为汽车云长期发展积累增长势能。

在这样的趋势下,百度智能云快速完成迭代,将汽车云解决方案已经升级到了3.0版,为车企提供了强大的算力支撑、精准的算法适配、高质量仿真场景及车路协同等核心技术,针对端到端智能驾驶进行了重点的适配,有力推动了自动驾驶的量产落地。

目前,百度智能云正加速对头部车企的覆盖,中国市场TOP15销量品牌、TOP10新能源车企中合作客户均已经实现全覆盖、在主流车企中渗透率达到95%。

图片

百度沈抖:智能基础设施,为应用而生

千亿级打点PV的成本治理实践

作者 百度Geek说
2025年4月29日 11:06

导读

打点是指在网站或者APP中加入一些统计代码,通过日志记录用户在 APP 内触发的一系列行为,包括点击、滑动等。打点上报后汇聚成用户行为日志,用户行为日志可用于报表统计、AB Testing、个性化推荐等,是分析用户、调整策略、迭代产品的重要依据。

日志中台做为百度内一站式打点解决方案,覆盖了厂内以百度APP为代表的大多产品,每天产生千亿级的打点日志PV。这些日志经过格式化之后,满足用户的各种数据消费需求,光是占用的存储资源每天达上百P。为了满足业务长周期的数据统计、分析、回溯等需求,需要大量的计算和存储成本,部分核心数据甚至需要永久存储。

但是,随着业务快速迭代发展,线上打点只增不减,单条日志越来越长,上报量越来越大,规模日渐膨胀。打点日志的无序增长,既影响打点服务的稳定,也带来计算和存储资源的增长。为了在资源有限的前提下,最大化打点日志的价值,需要对打点日志进行持续的治理,提升打点收益。治理手段包括无用点位的定位和下线、异常打点的发现和修复、已有打点的字段裁剪和上报机制优化、新feature放量或运营活动期间打点服务的稳定性保障等。

图片

△点位全生命周期治理

通过点位治理措施,对于正常需求导致pv上涨的点位,中台能够提前扩充资源,保障业务的高效发展;对于异常问题引起的pv上涨的点位,中台能够协助业务方排查潜在风险,减少业务隐患;对于无用打点,及时发现并完成点位下线,节省后续计算和存储资源;对于冗余打点引起pv上涨的点位,中台协助优化打点上报逻辑,实现高质量打点,推动业务方和日志中台的降本增效。因此,点位治理实践能够助力日志中台感知点位波动预先为正常流量的增幅留足空间,保证打点符合用户预期限制低质量有问题流量无序发展,为用户提高更优质量的打点体验,高效率高质量支持业务蓬勃发展。

图片

△全生命周期打点管理

01 要治理的问题和方案

图片

日志中台的成本治理实践主要分三个阶段:人工治理、半自动化治理、点位全生命周期标准化治理。在最开始的阶段,首要目标为与用户沟通,制止打点流量无序增长。因此采取人工治理的方式:由中台同学和点位相关业务同学沟通来推进点位治理,人工治理能够充分了解用户治理诉求,分析点位pv增长原因,在支持业务正常推进的基础上采取定制化的治理措施。通过人工治理的方式,在治理前期取得了一定的治理收益,但随着成本治理的不断推进,治理覆盖的点位、业务线和业务方不断增加,治理变得越来越复杂且难以持续跟进。参照人工治理阶段积累的经验,采用技术化的手段,升级到了半自动平台化治理,从治理实施的角度出发,实现流程化治理,推进了治理前发现异常点位、治理中介入点位治理和治理后成果展示与分析的状态流转,大大提高了治理效率。然而,点位治理不是一劳永逸的事情,为了更好的完成点位可持续治理,日志中台从点位全生命周期的角度出发,实现了点位全生命周期标准化治理,能够修复异常打点、优化冗余打点、下线无用点位,并总结点位相关特性,实现了依据点位特性的长期治理,在对打点的健壮性优化的同时提升了重复治理的效率。

1.1阶段一 人工治理

1.1.1 问题分析

打点用户作为日志中台的核心用户群体,是打点的发起者、使用者,因此是点位治理的主要执行者。打点用户只要有两个核心特点:打点目的多样,点位治理措施多样打点目的多样是指用户会根据实际业务要求进行打点,例如节日/活动流量打点、实验分析打点、实际需求打点等等。同时打点用户在实现点位治理时,也会有不同的实际操作,例如会选择优化打点代码、对打点实验进行固化或者打点下线、对实际需求打点进行缴费以保证计算和存储资源充足。人工治理阶段依靠着中台同学和业务同学的沟通合作能够在充分满足用户打点目的多样性的同时尽可能提供灵活、丰富的打点治理策略

图片

△问题分析

点位波动的原因能够从三个维度进行解析说明,分别是业务线、内部因素和外界因素。从业务线角度而言,不同业务线之间因其承担着不同的业务定位,因此其点位波动会受到业务整体的决策而波动,因此点位治理策略应当面向业务线特色而展开。对于较大的业务线,例如手百,需要明确到点位的波动是否与某个细节打点相关。而对于较为独立的业务线,例如贴吧,网盘等,中台更关注业务线整体pv的波动。对于内部因素而言,影响点位pv波动的因素是各种各样的,主要分为三大类,即需求上线导致的打点pv增幅,这其中有因为直接需求、级联需求或需求同步导致的pv涨幅(例如极速版同步手百主版)。有异常打点导致的pv增幅,其中主要包括代码本身异常、流量异常和打点时机异常。在外界因素方面,导致打点pv增幅的原因主要分为三部分:节假日、双十一等商业活动或热点直播导致的pv涨幅,以及实验变更的微观涨幅和APP大盘增长导致的宏观涨幅。综上所述,点位pv波动的因素是较为复杂的,因此点位治理的核心目标是针对各种复杂诱因导致的点位pv波动采取面向用户个性化的点位治理措施,实现高效率灵活的点位治理。

图片

1.1.2 解决方案

阶段一主要依靠人工治理,其步骤可以用以下DAG图说明,支持四大类点位治理模式**【需求普涨、异常修复、活动流量和打点优化】**,模版化的处理步骤能覆盖绝大部分点位治理场景。

图片

1.2 阶段二 半自动治理平台化

1.2.1 问题分析

图片

随着成本治理的不断推进,治理覆盖的点位、业务线和业务方不断增加,治理变得越来越复杂且难以仅靠人力沟通持续跟进,而点位治理方作为打点治理的主要发起方和跟进方,需要频繁的与业务方进行交流,以便于针对点位实际和业务现状发起点位治理。同时点位治理过程需要全过程记录,依靠人工治理架构的点位治理过程使用文档记录全过程,同时点位治理流程中产生的点位治理时间轴、点位治理总览、点位治理成果均以文档的形式记录会有展现效果差、依赖人力更新的问题。同时点位治理流程较为复杂,如果使用人力治理+文档记录的措施缺乏标准的状态流转,无法保证打点治理的高效和质量。

图片

△半自动化平台治理

1.2.2 解决方案

打点治理的涉及的方方面面非常多,按照时间顺序而言,主要分为异常点位的发现和挖掘、面向异常点位的治理实施、以及治理后成果的总结和治理全局分析。对于涉及的主体而言,打点治理主要涉及的被动主体为点位用户以及点位信息,主动主体为点位治理方,对点位本身而言,打点治理流程需要感知点位异常波动、整理点位相关基础信息【业务线、负责人、历史相关需求】等、最终整理完成点位自身特色信息【点位属性是活动点位、基础框架点位等】。对于点位治理方而言,需要针对异常点位发起点位治理【通过如流群内部消息面向业务同学】、需要根据点位自身情况选取点位治理策略【打点优化、异常治理、成本追缴】等,同时在点位治理流程中,点位治理负责人需要及时跟进点位治理情况,推进点位治理信息,在治理完成后需要总结点位治理结果报表,并完成阶段性总结。对于业务方而言,用户需要感知点位pv波动信息、点位治理需求并给出点位治理及时反馈。因此在打点治理的重要场景上,主要的难题为:需要形成点位治理【前期、中期和后期】的规范化治理流程,有效推进点位治理状态的流转【发现异常、介入治理、推进治理、完成治理】;由于点位治理是面向用户导向的,其中涉及到大量的沟通成本,为了加速办公效率,针对IM沟通需要做专门的优化。针对上述问题,日志中台推进了打点半自动化治理平台的建设,实现了治理标准流程化、办公沟通智能化、点位治理高效化

图片

△一站式成本治理平台

成本治理平台将打点治理分为三个阶段**【治理前-异常波动点位挖掘阶段】,【治理中-目标点位介入治理阶段】,【治理后-治理成果展示&分析阶段】**。

在治理前期【异常波动点位挖掘阶段】,该阶段核心为实现一个定时例行任务,该任务定时获取所有点位的天级pv,并根据异常波动识别算法判别出异常点位,并组装该点位的其他相关信息(业务线、是否是实时流点位等),最终完成异常点位信息的下发和邮件通告。异常点位挖掘任务依托定时任务调度系统完成开发,实现算子高效配置,任务定时准确执行,能够有效挖掘出异常点位信息。

在治理实施中期【目标点位介入治理阶段】,按照点位治理状态的不同,分为三个核心页面进行综合治理,即待治理页面,正在治理页面和治理完成页面。其中待治理页面主要展示由【异常波动点位挖掘阶段】所得到的异常点位列表,在点位负责人甄别该点位确实符合点位治理要求后,即可一键建群触发点位治理流程。触发后,该点位即可展示在正在点位治理页面,针对目标点位治理,点位治理负责人即可按照【点位治理默认状态流转图】或【自定义算子点位治理状态图】完成点位治理,在治理过程中,平台使用企业办公IM企业机器人来实时推送点位治理模版信息【点位治理背景、点位治理缴费文档等】,进而加速点位治理过程。同时在点位治理过程中,数据库会记录点位状态变更时间轴,实时记录点位治理状态。当点位流程治理完成后,点位会移入已经治理完成的点位页面。已经治理完成点位页面会同步至指定MySQL数据库中,智能报表平台会针对该数据库做实时数据分析和可视化报表生成。

在治理后期【理成果展示&分析阶段】该阶段核心是展示指定时间范围内的治理效果【已经治理pv、已治理的点位个数】,以及分析相关指标【各个治理种类的点位数目、已经追缴的成本金额】。治理平台采取可视化智能报表平台完成对点位治理的趋势分析,按照时间顺序对已经治理的pv数和点位个数完成了对点位治理的分析

图片

△办公IM成本治理机器人

在点位治理过程中,点位治理负责同学需要和点位负责同学、点位相关RD有频繁且密集的沟通,为了提高业务沟通效率,点位治理平台接入 办公IM企业级开发机器人【成本治理机器人】,成本治理机器人实现了全流程的治理加速,在治理发起时,点位负责人能够针对异常目标点位一键发起群聊,该群聊名为【点位监控】(相关)点位流量上涨。在治理发起后第一时间,成本治理机器人会同步点位基本信息、点位涨幅pv等,通报使用自动化通报模版。在点位治理推进中,如流机器人支持发送自定义信息并@相关业务人员完成治理状态推进。

1.3 阶段三 点位全生命周期标准化治理

1.3.1 问题分析

图片

△打点全生命周期

点位治理不是一劳永逸的事情,为了更好的完成点位可持续治理,日志中台从点位角度出发实现了点位全生命周期标准化治理架构。打点本身是点位治理的重要对象,同时打点本身自身也有着足够的信息量,例如,点位本身会因为业务下线或业务场景的迭代而成为无用点位;点位本身会因为打点开发代码 BUG而成为异常点位或是冗余点位;同时点位自身因为其长期存在,进而会在一定时间内长期波动,导致需要点位治理频繁介入。因此点位治理问题需要在点位生命周期维度完成对无用点位的下线;对有异常问题的点位完成修复、对于冗余点位的优化;在点位长期波动角度,完成基于点位特性的高效治理,而非是机械重复的全流程点位治理。

图片

1.3.2 解决方案

1.3.2.1  基于点位特性持续治理

基于点位特性持续治理,图中是某运营活动相关点位pv波动图,图中可以清晰看到,该点位在所示周期内出现了三次点位波动,因为该点位属于活动运营性质点位,因此在春节期间、618活动期间以及暑假活动运营期间,出现了多次波动,如果按照常规治理手段,需要多次频繁介入,为了在持续性治理中提高治理效率,应当结合点位业务属性,构建出治理经验总结,在后续多次治理中不断完善治理属性,即可根据历史治理经验实现既定治理措施。我们将点位根据业务属性而形成的分类称之为“点位特性”,而根据点位特性的操作化治理称之为“基于点位特性的持续治理”,实践表明,基于点位特性的持续治理流程针对点位多次治理,大大加速效率。例子中的运营活动点位,在得知其活动属性的基础上,仅需关注涨幅与活动映射关系以及预估流量是否与预期相符合即可,无须重复治理流程。

图片

△基于点位特性持续治理

打点治理是一个长期持续性的操作,单个点位存在多次介入治理的可能性,因此考虑到点位的持续性治理是非常重要的。在长期的点位治理中,点位因其个性化特色,具有自身属性。结合点位自身特色与规则介入,能够在持续性治理操作中实现基于点位特性的治理。从点位特色出发,常见的点位种类有如下六种,分别为单需求类型点位、复合需求类型点位、活动属性类型点位、级联需求类型点位、实验类型点位、框架性质类型点位。其中不同点位种类具有自身的相应的特征,因此应当采取相关的治理策略,进而大大降低了二次治理的难度和工作量。

下面是常见点位特性的说明及相应的再次治理策略:

  • 单需求类型点位,该类点位上下游关系较为简单,点位定位明确,主要完成单一或固定类型的需求,因此其涨幅与需求之间关联,对于二次治理时,重点关注点位所对应的需求方即可,治理策略较为简单。

  • 复合需求类型点位,该类点位往往是多业务方共用打点,执行不同类型的需求,因此再次治理时,需要补充记录点位使用拓扑关系,完善点位下游关系

  • 活动类型点位,该类打点往往与节假日/运营活动强关联,例如小说相关打点往往和寒暑假密不可分,手百皮肤活动往往与运营活动强相关,对于此类打点,需要核实对应的活动,并保证容量充足即可。

  • 级联需求类型点位,该类打点往往提供一个基础性的功能,例如工具性质打点,这类打点并不直接作用于业务方,而是为业务方提供第三方能力,因此其上涨与自身无关,此类打点需要核实符合预期即可。

  • 实验类型点位,该类打点往往与策略实验放量相关,具有一定的活动周期属性,但是与活动属性点位不同的是,实验复合预期后可能会固化,需要核实长期上涨带来的费用。

  • **框架性质类型打点,**该类打点作为手百等APP的基础打点,承载着多项核心功能,往往打点量级较大(单点位可达百亿)正常涨幅波动也较大(天级波动可达10亿上下),其波动需要结合DAU大盘涨幅进行分析,往往无法与某些需求直接关联。

    图片

    △治理角度的常见点位分类

    1.3.2.2  推进无用点位下线

    随着业务的持续迭代与推进,点位的状态也在不断更新,一些点位会逐渐成为无用点位。无用点位因其自身属性分为两大类:无流量点位和有流量无使用点位,其中无流量点位往往因为实验的下线或业务线的变更导致点位无流量,而有流量无使用点位往往因为业务的优化升级或是日常迭代导致点位依然有上报,但是不再有下游使用,上报的数据内容也不再有访问记录。其中无流量点位会消耗一定的数据分析和维护成本,并对相关分析带来一定影响,而有流量无使用的点位则会占用一定的计算和存储资源。因此,推进无用点位下线是点位全生命周期治理的重要一环,日志中台及相关数据存储团队形成了完善的无用点位下线流程。

图片

△无用点位下线流程图

在点位负责人完成上线后,中台及相关数据存储团队会进行例行的无用点位识别任务,当识别出无用点位后,会通知相关点位负责人,若点位负责人支持点位下线,则点位会进入预下线状态,当点位在一定时间段内仍无相关业务反馈,则该点位会完成下线。若点位负责人因业务特殊需求,则能够继续保留该点位,若该点位超过三次被识别为无用点位则会报备总监确认,结合业务实际则可以录入白名单。

图片

△基于鉴权信息访问判别来源

无用点位识别任务的核心在于识别出有流量但是没有下游使用的点位,识别任务会根据相关业务的若干数据表的鉴权信息筛选出相关的下游访问来源,这些下游访问来源包括但不限于实验分析平台、数据分析平台、报表平台,相关业务使用和一些定时例行任务。当筛选出相关点位的具体下游访问来源之后,即可联合下游访问来源的具体业务信息识别出该点位是否确实无人使用,进而判断出无用点位。

1.3.2.3  异常点位修复&冗余点位优化

图片

△异常点位修复&冗余点位优化

为了更好的完成点位治理,需要对打点潜在问题进行分析,进而能够根据潜在问题制定相应的解决方案。结合打点实际,业务实际和中台业务逻辑可以发现,打点存在有几类问题:冗余打点浪费了一定的资源,多条打点公共参数相同,仅仅业务参数有差异,但是依然分开若干条上报;对于比值类实验指标,不同的打点量级的实验效果是一致的,但依然打了较大量级的日志条数;异常打点不符合业务预期,异常上报了一定量级的日志,点位缺乏分级别处理无法做到重要点位高优先级处理。为了解决上述问题,我们进行了针对性的方案优化,针对冗余打点采取合并上报、打点采样等打点优化措施,针对异常打点采取【发现异常、确认异常,最终修复异常】的工作流程。

02 项目收益&业务反馈

日志中台点位治理实践项目对点位实现各种灵活治理措施,包括但不限于打点优化、异常修复、成本追缴和活动流量观察。在点位治理项目上线后,助力业务方发现10+潜在风险点,手百每人每天上报日志减少上百条。治理项目每年治理上千亿pv,节省数百万的用于计算、存储的年化成本费用

图片

在治理过程中,我们坚持用户导向,点位治理流程协助用户方发现很多问题,排查了潜在异常,节约了很多资源,也收到很多高质量的业务方真实反馈。

图片

△业务高质量反馈

03 总结与展望

图片

△总结与展望

日志中台打点治理实践方案已经取得了一定的项目收益,协助用户优化了了打点体验,提升了打点质量,升级了业务性能,同时也助力了手百等业务的稳健、高质量发展,在未来日志中台会持续打造业界领先的打点治理方案,进一步优化用户体验,帮助用户精细化排查点位波动的原因,更为精准化的定位问题原因,精密化提升打点收益与产出,切切实实使每一次打点都取得超出预期的收益。同时进一步助力业务发展,降低手百每人每天上报的日志数目,在有限的打点资源内尽可能创造更高规模的收益。同时随着日志中台对于事件的支持,打点治理方案会探索基于事件的pv治理策略,支持更细粒度的打点治理。

-----END------

推荐阅读

从数字化到智能化,百度 SRE 数智免疫系统的演进和实践

走!Ké武汉,看百度智能云生态大会

名列前茅!百度文心大模型4.5及X1在中国信通院“方升”大模型基准测试中表现优异

飞桨新一代框架3.0正式发布:加速大模型时代的技术创新与产业应用

名列前茅!百度文心大模型4.5及X1在中国信通院“方升”大模型基准测试中表现优异

作者 百度Geek说
2025年4月17日 09:53

中国人工智能产业发展联盟(以下简称“AIIA”)紧密跟踪大模型和智能体的技术发展与行业应用动态,构建并发布了“方升”(FactTesting)大模型基准测试体系,自2024年以来已对国内外开源与闭源大模型开展了6轮能力监测,累计测试了200余个大模型,持续跟踪其技术演进与表现,为行业技术选型与能力评估提供了重要依据。2025年,评测范围进一步扩展至多模态理解、文生图、文生视频等领域,并率先开展智能体测试的研究与实践,初步构建了智能体测试验证平台,为产业界提供全面的技术评估参考。

2025年4月9日,在南京召开的中国人工智能产业发展联盟第十四次全体会议上,中国人工智能产业发展联盟正式发布“方升”大模型基准测试结果(2025年1季度)。 图片

“方升”大模型基准测试结果发布现场

在权威发布环节,AIIA 总体组组长、中国信通院人工智能研究所所长魏凯发布了“方升”人工智能基准测试结果及测试观察。在大语言模型测试结果中,文心大模型4.5在基础能力结果、文心大模型X1在推理能力结果中均名列前茅。

图片

大语言模型-基础能力测试结果

图片

大语言模型-推理能力测试结果

3月16日,百度正式发布文心大模型4.5和文心大模型X1。

文心大模型4.5是百度自主研发的新一代原生多模态基础大模型,通过多个模态联合建模实现协同优化,多模态理解能力优秀;具备更精进的语言能力,理解、生成、逻辑、记忆能力全面提升,去幻觉、逻辑推理、代码能力显著提升。

文心大模型X1具备更强的理解、规划、反思、进化能力,并支持多模态,**是首个自主运用工具的深度思考模型。**作为能力更全面的深度思考模型,文心大模型X1兼备准确、创意和文采,在中文知识问答、文学创作、文稿写作、日常对话、逻辑推理、复杂计算及工具调用等方面表现尤为出色。

图片

文心一言官网

目前,两款模型已在文心一言官网上线,免费向用户开放。(yiyan.baidu.com

2025是大模型技术全面迭代的一年,百度将在人工智能、数据中心、云基础设施上更大胆地投入,打造更好、更智能的下一代模型。

----------END----------

推荐阅读

飞桨新一代框架3.0正式发布:加速大模型时代的技术创新与产业应用

即刻体验!文心大模型X1现面向企业用户全面开放!

一篇论文,看见百度广告推荐系统在大模型时代的革新

前沿多模态模型开发与应用实战3:DeepSeek-VL2多模态理解大模型算法解析与功能抢先体验

秒哒首发即爆发!上线首日吸引2万用户,打造3万应用!

飞桨新一代框架3.0正式发布:加速大模型时代的技术创新与产业应用

作者 百度Geek说
2025年4月15日 10:20

人工智能技术日新月异,深度学习框架作为技术底座深刻影响着算法创新的速度与产业落地的深度。飞桨框架以五大核心突破回应时代命题,正式发布3.0版本。飞桨框架3.0实现了从底层硬件适配到顶层开发体验的全面进化,在训练效率、性能、兼容性等关键指标上建立新标杆,作为支撑千行百业智能化转型的“AI 操作系统”,此次升级不仅是技术参数的迭代,更是面向大模型工业化生产范式的革命性突破。无论是前沿算法研究还是产业级大模型落地,飞桨框架3.0都将成为开发者的首选利器。

作为中国首个自主研发的产业级深度学习平台,飞桨一直坚持开源路线,支撑产业智能化升级。2025年4月1日,飞桨框架迎来重大更新,发布飞桨框架3.0正式版。飞桨框架3.0版本不仅延续了飞桨框架2.0系列动静统一、训推一体的特性,更在自动并行、神经网络编译器、高阶自动微分等方面取得突破,为大模型时代的技术创新与产业应用提供了强大支撑,为开发者打造了一站式、高性能的深度学习开发体验。

飞桨框架3.0具备以下五大新特性:

1)动静统一自动并行:通过少量的张量切分标记,即可自动完成分布式切分信息的推导,Llama 预训练场景减少80%的分布式相关代码开发。

2)大模型训推一体:依托高扩展性的中间表示(PIR)从模型压缩、推理计算、服务部署、多硬件推理全方位深度优化,支持文心4.5、文心X1等多款主流大模型,DeepSeek-R1满血版单机部署吞吐提升一倍。

3)科学计算高阶微分:通过高阶自动微分和神经网络编译器技术,微分方程求解速度比 PyTorch 快115%。

4)神经网络编译器:通过自动算子自动融合技术,无需手写 CUDA 等底层代码,部分算子执行速度提升4倍,模型端到端训练速度提升27.4%

5)异构多芯适配:通过对硬件接入模块进行抽象,降低异构芯片与框架适配的复杂度,兼容硬件差异,初次跑通所需适配接口数比 PyTorch 减少56%,代码量减少80%

01 背景概述

在大模型时代,深度学习框架的重要性愈发凸显,成为推动人工智能技术发展的核心引擎。算法、算力、数据作为人工智能技术的三大要素,其相互作用与协同发展不断催生着新的突破。越来越多的实例证明,算法创新能够发挥出更为显著的威力。DeepMind 的 AlphaFold3通过动态扩散算法突破蛋白质结构预测精度,已成功应用于抗疟疾等药物分子设计;DeepSeek 通过算法创新,成功提升了 DeepSeek V3模型的性价比,大幅降低了训练成本。这些突破性进展表明,算法创新正在重构技术发展的成本曲线

然而,算法创新并非易事,当前算法工程师和科研人员在使用现有深度学习框架进行算法创新时,仍面临诸多挑战。

1)大模型分布式开发门槛高:大模型参数规模庞大,其分布式训练需使用复杂的并行策略,包括数据并行、张量并行、参数分片并行、流水线并行、序列并行、专家并行等。大模型开发中,如何实现多种并行策略的高效协同已成为关键瓶颈。

2)模型推理部署困难重重:由于算法训练和推理任务的计算、通信存在较大差别,算法工程师在完成模型算法创新后,往往难以直接应用于推理部署,需要大量的工程开发工作。

3)前沿模型架构灵活多变:科学智能(AI for Science)等新兴领域的快速发展,对深度学习框架提出了新的要求,包括求解复杂微分方程所需的高阶自动微分、傅里叶变换等科学计算操作、复数的高效运算等。

4)模型极致性能优化难度大:以大模型为代表的很多场景对训练推理速度有严苛要求,为突破计算瓶颈,工程实践中常需通过手写 CUDA 内核代码进行性能优化,这对算法工程师的底层编程能力提出了极高要求。

5)异构芯片适配成本高:AI 应用场景丰富多样、算力需求巨大,单一芯片难以满足业务需求。而不同芯片之间的硬件架构、软件栈成熟度、开发接口差异大,业务适配成本高、软硬协同优化难。

为此,飞桨新一代框架3.0应运而生:该版本提供了丰富的深度学习相关的各种开发接口表示层专注于计算图的表达与转换,通过高可扩展中间表示 PIR,实现动转静、自动微分、自动并行、算子组合以及计算图优化等核心功能;调度层负责对代码或计算图进行智能编排与高效调度,支持动态图和静态图两种不同的执行模式;算子层由神经网络编译器 CINN 和算子库 PHI 共同构成,涵盖了张量定义、算子定义、算子自动融合和算子内核实现等关键功能;适配层则用于实现与底层芯片适配,包括设备管理、算子适配、通信适配以及编译接入等功能。

图片

飞桨框架3.0架构图

飞桨框架3.0凭借强大的功能和优化的设计,帮助算法工程师和科研人员以更低的成本进行算法创新,并实现产业应用。以百度文心大模型为例,飞桨框架3.0在训练、推理等方面为文心大模型提供端到端优化,训练方面重点提升训练吞吐、训练有效率和收敛效率,集群训练有效率超过98%;推理部署方面通过注意力机制量化推理、通用投机解码等技术提升推理吞吐和效率;全面支持文心4.5、文心X1等大模型的技术创新和产业应用。

02 全面支持自动并行训练

降低大模型开发训练门槛

在大模型时代,随着模型规模和训练数据量的不断增长,传统的单机单卡训练已无法满足需求,分布式并行训练成为加速大模型迭代的关键。然而,无论是动态图还是静态图,当前市场上的并行训练框架普遍存在使用成本高的问题。开发者既要熟知模型结构,还要深入了解并行策略和框架调度逻辑,使得大模型的开发和性能优化门槛非常高,制约了大模型的开发和训练效率。

针对这一痛点,飞桨提出了动静统一自动并行方案。该技术通过原生动态图的编程界面与自动并行能力,同时保障了灵活性和易用性,大幅降低了大模型并行训练的开发成本;同时,利用框架动静统一的优势,一键转静使用静态优化能力,提供极致的大模型并行训练性能。开发者仅需少量的张量切分标记,框架便能自动推导出所有张量和算子的分布式切分状态,并添加合适的通信算子,保证结果正确性。具体工作流程如下图所示:

图片

动静统一自动并行流程图

飞桨框架3.0动静统一自动并行技术的具体特点如下:

1)简单易用,大幅降低大模型并行训练开发成本。飞桨自动并行功能允许用户在不考虑复杂分布式通信的情况下完成算法实现。仅需借助少量 API 调用,即可将算法转换为并行训练程序,显著简化开发过程。以 Llama2的预训练为例,传统实现方式需要开发者精细调整通信策略,以确保正确高效执行,而自动并行实现方式相比传统方式减少80%的分布式核心代码,极大降低了开发复杂度。

2)全面可用,适用于众多大模型训练场景。**基于飞桨大模型开发套件(PaddleNLP、PaddleMIX),飞桨框架已全面验证 Llama、QwenVL 等从大语言模型到多模态模型的预训练、精调阶段的自动并行训练。

3)轻松加速,一键动转静提供极致性能优化。**得益于飞桨框架独特的动静统一设计,用户仅需简单添加一行代码,即可轻松实现从动态到静态的转换。这一转换使得我们能够充分利用多种静态优化技术,匹敌甚至超越经过极致优化的动态图训练效率。

4)协同文心,开源多项大模型独创优化策略。**飞桨协同文心创新实现精细化重计算、稀疏注意力计算优化、灵活批次的流水线均衡优化等,这些优化技术在飞桨框架3.0中开源,助力开发者进行极致的大模型训练性能优化。

未来,我们将进一步探索无需使用张量切分标记的全自动并行,让开发者可以像写单机代码一样写分布式代码,进一步提升大模型的开发体验。

图片

动静统一自动并行训练速度对比

03 大模型训推一体

提升推理部署效率

在完成模型的开发和训练后,我们需要面对推理部署场景的挑战:如何低门槛、低开发成本、快速地将模型部署到业务场景,并提供低时延、高吞吐、低算力成本的推理服务。**自2.0版本起,飞桨便采用了“动静统一、训推一体”的设计理念,3.0版本也继续秉持这一理念,并在大模型场景下持续优化,发挥更大作用。

在推理部署方面,相较于动态图,静态图不仅可部署范围更为广泛,它能够通过整图导出的方式,摆脱对 Python 源代码和执行环境的依赖;而且更适合进行全局调优,可通过手写或者借助编译器自动实现算子融合等方式来加速推理过程。

得益于动静统一的架构和接口设计,飞桨能够完整支持动态图和静态图这两种不同的运行模式,并且具备出色的整图导出能力。飞桨的动转静整图导出成功率高达95%,高于 PyTorch 62%。“训推一体”意味着能够在同一套框架下,尽可能复用训练和推理的代码,特别是复用模型组网代码。**在完成模型的开发训练后,只需进行少量的开发工作,即可实现快速推理部署。**与业界当前先使用 PyTorch 和 DeepSpeed 进行训练,再采用 vLLM、SGLang、ONNXRuntime 等推理引擎进行推理部署的方案相比,飞桨采用训练和推理使用同一套框架的方式,能够有效避免不同框架之间可能出现的版本兼容性问题,以及因模型结构变化、中间表示差异、算子实现差异等带来的困扰。

图片

飞桨训推一体架构设计

大模型的推理部署需要更好地平衡成本、性能和效果,飞桨框架3.0全面升级了大模型推理能力,依托高扩展性的中间表示(PIR)从模型压缩、推理计算、服务部署、多硬件推理全方位深度优化,能够支持众多开源大模型进行高性能推理,并在 DeepSeek V3/R1上取得了突出的性能表现。飞桨框架3.0支持了 DeepSeek V3/R1满血版及其系列蒸馏版模型的 FP8推理,并且提供 INT8量化功能,破除了 Hopper 架构的限制。此外,还引入了4比特量化推理,使得用户可以单机部署,降低成本的同时显著提升系统吞吐一倍,提供了更为高效、经济的部署方案。在性能优化方面,我们对 MLA 算子进行多级流水线编排、精细的寄存器及共享内存分配优化,性能相比 FlashMLA 最高可提升23%。综合 FP8矩阵计算调优及动态量化算子优化等基于飞桨框架3.0的 DeepSeek R1 FP8推理,单机每秒输出 token 数超1000;若采用**4比特单机部署方案,每秒输出 token 数可达2000以上,推理性能显著领先其他开源方案。**此外,还支持了 MTP 投机解码,突破大批次推理加速,在解码速度保持不变的情况下,吞吐提升144%;吞吐接近的情况下,解码速度提升42%。针对长序列 Prefill 阶段,通过注意力计算动态量化,首 token 推理速度提升37%

图片

DeepSeek 模型单机推理速度对比(H800上256并发不含 MTP 测试)

04 助力科学前沿探索

提升微分方程求解速度

人工智能正以前所未有的方式重塑科学研究范式,成为推动科学发现与技术创新的“超级加速器”。例如,布朗大学团队首次提出物理信息神经网络(PINNs),通过自动微分实现物理约束与数据驱动的结合;NVIDIA 实验室提出全球高分辨率气象预报模型 FourCastNet,预报时长从几个小时缩短到几秒钟;2025年1月,Baker 团队在《Nature》发表研究,利用 RFdiffusion 算法从头设计出能够高效中和眼镜蛇蛇毒中三指毒素的蛋白质。**科学智能(AI for Science)为解决科学问题带来新方法的同时,也对深度学习框架带来诸多新挑战。**对科学问题机理化的探索,需要深度学习框架能够具备更加丰富的各类计算表达能力,如高阶自动微分、傅里叶变换、复数运算、高阶优化器等等;此外,如何实现深度学习框架与传统科学计算工具链的协同,也是需要思考的问题。

为了解决这些挑战,飞桨框架3.0提出了基于组合算子的高阶自动微分技术,如下图所示,该技术的核心思想是将复杂算子(如 log_softmax)拆解为多个基础算子的组合,然后对这些基础算子进行一阶自动微分变换。重要的是,基础算子经过一阶自动微分变换后,其所得的计算图仍然由基础算子构成。通过反复应用一阶自动微分规则,我们可以轻松地获得高阶自动微分的结果。这一机制不仅完美兼容动态图模式和静态图模式,而且在动态图模式下支持 N+1阶微分的灵活拆分,同时在静态图模式下能够进行高效的编译器融合优化。

图片

基于组合算子的高阶自动微分技术

基于飞桨框架的高阶自动微分和编译优化技术,实现了方程求解类模型性能的大幅提升,英伟达 Modulus 的41个不同方程实验显示,飞桨的微分方程求解速度比 PyTorch 开启编译器优化后的2.6版本平均快 115%。此外,飞桨还实现了傅里叶变换、复数运算、高阶优化器等功能,这些方法在航空航天、汽车船舶、气象海洋、生命科学等多个领域都具有广泛的应用潜力,为科学研究和工程实践提供了有力的支持。在模型层面,我们成功研发了赛桨(PaddleScience)、螺旋桨(PaddleHelix)等系列开发套件,为科学计算提供了更为便捷、高效的解决方案。飞桨对 DeepXDE、Modulus 等主流开源科学计算工具进行了广泛适配,并成为 DeepXDE 的默认推荐后端。

图片

飞桨 AI for Science 全景图

05 神经网络编译器技术

实现框架通用性能提升

在众多深度学习的应用场景中,如大模型训练、自动驾驶等,对模型的训练与推理速度均提出了极高的要求。然而,**要实现训练与推理速度的提升并非易事,这需要我们紧密结合模型结构与硬件特性,开展大量的工程实现与优化工作。**在模型结构层面,模型结构正日益呈现出多样化的趋势,从基础的全连接网络,到复杂的卷积神经网络、循环神经网络、Attention 网络、状态空间模型、图神经网络等,每一种模型结构都拥有其独特的计算模式与优化需求。在硬件特性方面,算力的增长速度远远超过了访存性能的提升,访存性能的瓶颈限制了访存密集型算子(如归一化层、激活函数等)的执行效率。特别是,当前市场上硬件平台种类繁多,我们需要投入大量的人力物力,进行针对性的优化工作,这将严重拖慢算法创新和产业应用的速度

让我们通过一个实例来阐释这一点。我们以 Llama 模型中经常使用的 RMS Normalization(Root Mean Square Layer Normalization)为例,其计算公式相对简单明了。

图片

假设我们需要实现 RMS Normalization 的计算,最简单的办法是,我们可以使用飞桨框架提供的张量运算开发接口,调用平方、求和、除法、开根号等操作来完成,代码如下:

class RMSNorm(paddle.nn.Layer):
    def __init__(self):
        super().__init__()
        self.variance_epsilon = 1e-6
        self.weight = paddle.create_parameter(shape=[768], ...)
        
    def forward(self, x):
        variance = x.pow(2).mean(-1, keepdim=True)
        x = paddle.rsqrt(variance + self.variance_epsilon) * x
        return x * self.weight

上述代码开发简单,但是由于存在大量的访存操作导致性能很差,且显存占比较多;为了突破访存瓶颈,开发者可以选择通过手写 CUDA 代码的方式实现一个融合的 FusedRMSNorm 算子,但是对于开发者要求更高,开发成本也更高,更重要的是这种方式极大降低了可维护性和灵活性。

为此,飞桨框架3.0研制了神经网络编译器 CINN(Compiler Infrastructure for Neural Networks),相比于 PyTorch 2.0的 Inductor 加 Triton 的两阶段编译方案,CINN 支持直接从神经网络中间表述编译生成 CUDA C 代码,通过一阶段的编译方案,CINN 避免了两阶段编译由于中间表示信息传递和表达能力限制所造成的信息损失,具备更通用的融合能力和更好的性能表现。具体一些技术创新如下:

1)以 Reduce 为核心的算子融合技术。摒弃传统的粗粒度 pattern 匹配模式,支持维度轴自动变换对齐融合,在保证计算正确性的同时,具有更强的算子融合能力,带来更大的性能优化潜力。

2)动静态维度的高效后端 Kernel 调优技术。算子全面支持 reduce、broadcast、transpose 等多种算子的不同组合方式,针对各类算子组合和数据类型,自适应不同维度大小与不同硬件配置,进行全场景高效调优。通过自动向量化提高 BF16、FP16等小数据类型的访存效率。通过分析与分桶机制,实现动静态运行时配置生成,根据运行时的硬件配置,在无需 profiling 的情况下生成高效的 kernel。

3)动态维度的复杂表达式化简技术。建立了分层化简体系,Lower、Schedule、CodeGen 阶段执行不同等级化简方法,解决传统化简方法中多场景叠加后化简困难、化简不彻底问题。实现了复杂表达式结构化简,抽取融合算子经过编译、调优后的固定子结构进行专项化简,且灵活支持自定义化简方法。

图片

神经网络编译器 CINN 流程图

借助神经网络编译器技术,我们能够在维持高度灵活性和易用性的基础上,实现性能的显著提升。以下为 A100平台上 RMSNorm 算子的性能测试结果:相较于采用 Python 开发接口组合实现的方式,经过编译优化后的算子运行速度提升了4倍;即便与手动算子融合的方式相比,也实现了14%的性能提升,在灵活性与高性能之间寻找到了较为理想平衡点。我们在 PaddleX 开发套件里选取了超过60模型进行实验,使用 CINN 编译器后超60%模型有显著性能提升,平均提升达27.4%。重点模型相比 PyTorch 开启编译优化后的版本平均快18.4%

图片

神经网络编译器 CINN 训练速度对比

06 标准化统一硬件适配

加速软硬协同优化

在深度学习的创新探索与产业落地进程中,单一芯片往往难以满足复杂多变的业务需求,因此通常需要融合运用多种芯片来构建解决方案。大模型应用对于算力的需求极为庞大,而单一芯片的供应数量有限,远不足以支撑大模型的高效运行。不仅如此,不同场景对芯片性能有着差异化的严苛要求,单一芯片更是难以全面满足。例如,在大模型训练场景中,需要芯片具备大显存、高带宽以及高可靠性的特性;自动驾驶场景则强调低时延与高可靠性,以保障行车安全;端侧场景则聚焦于低功耗,以延长设备的续航时间。

飞桨框架自发布之初就考虑了多硬件适配的需求,历经持续迭代与演进,3.0版本构建了一套成熟且完善的多硬件统一适配方案:

1)飞桨聚焦于硬件接口的抽象。飞桨将硬件接口细分为设备管理、计算执行、分布式通信等多个类别,通过标准化的硬件接口成功屏蔽了不同芯片软件栈开发接口之间的差异。通过合理的抽象,减少了适配所需的接口数量,以昇腾芯片适配为例,初步跑通所需适配接口数比 PyTorch 方案减少56%,适配代码量减少80%

2)基于标准化适配接口的定义,飞桨实现了松耦合、可插拔的架构。在此架构下,每类芯片仅需提供标准化适配接口的具体实现,便能轻松融入飞桨后端,极大地简化了芯片接入的流程。

3)考虑到不同芯片软件栈成熟度的差异,飞桨提供了丰富多样的接入方式,涵盖算子开发、算子映射、图接入、编译器接入等。针对大模型训练与推理需求,飞桨还具备全栈优化能力,如支持动静统一编程范式、超大规模分布式训练技术,提高了模型开发与部署效率。

4)飞桨与芯片厂商携手合作,共同构建了官方代码合入机制、例行发版机制和持续集成测试等研发基础设施,还建立了日级别例行功能与精度监测,保障开发者使用体验。

这些举措提升了研发效率,确保飞桨与各类芯片的适配工作高效、稳定推进。

图片

多硬件统一适配方案

基于前述技术,飞桨与芯片厂商紧密合作,**携手共建蓬勃发展的硬件生态,当前飞桨已与超过40家成员单位开展合作,适配超过60个芯片系列。**飞桨已与24家硬件厂商伙伴达成深度合作,共同推出了飞桨生态发行版。飞桨能够有效屏蔽底层硬件之间复杂多样的差异,为开发者提供简洁易用的开发接口。**开发者只需编写一份代码,就可以让程序在不同芯片上顺畅运行,轻松实现业务的跨芯片迁移。**飞桨的跨平台能力为业务在芯片选择方面带来了前所未有的灵活性,使开发者能够根据实际需求,更加自由、高效地规划业务部署。

07 总结

飞桨框架3.0面向大模型、异构多芯进行专属设计,向下适配异构多芯,充分释放硬件潜能;向上一体化支撑大模型的开发、训练、压缩、推理、部署全流程,并助力科学前沿探索。具备动静统一自动并行、大模型训推一体、科学计算高阶微分、神经网络编译器、异构多芯适配五大新特性。

1)动静统一自动并行:用户只需在单卡程序上进行少量的张量切分标记,飞桨就能将其自动转换为并行训练程序,大幅度降低了产业开发和训练的成本,使开发者能够更专注于模型和算法的创新。

2)大模型训推一体:同一套框架支持训练和推理,实现训练、推理代码复用和无缝衔接,为大模型的全流程提供了统一的开发体验和极致的训练效率,为产业提供了极致的开发体验。

3)科学计算高阶微分:科学计算提供了高阶自动微分、复数运算、傅里叶变换、编译优化、分布式训练等能力支撑,支持数学、力学、材料、气象、生物等领域科学探索,微分方程求解速度比 PyTorch 开启编译器优化后的2.6版本平均快115%。

4)神经网络编译器:采用与框架一体化的设计,能够支持生成式模型、科学计算模型等多种模型的高效训练与可变形状推理,在计算灵活性与高性能之间提供了良好的平衡点,显著降低了性能优化的成本。

5)异构多芯适配:构建了一套成熟且完善的多硬件统一适配方案,通过标准化接口屏蔽了不同芯片软件栈开发接口差异,实现可插拔架构,提供多种接入方式和基础设施,支撑硬件厂商合入4001个 PR,包括26584个 commits。

飞桨框架3.0将为开发者提供一个“动静统一、训推一体、自动并行、自动优化、广泛硬件适配”的深度学习框架,开发者可以像写单机代码一样写分布式代码,无需感知复杂的通信和调度逻辑,即可实现大模型的开发;可以像写数学公式一样用 Python 语言写神经网络,无需使用硬件开发语言编写复杂的算子内核代码,即可实现高效运行。目前3.0正式版本已面向开发者开放,并且兼容2.0版本的开发接口,非常欢迎广大开发者使用和反馈。

---------- END----------

推荐阅读

即刻体验!文心大模型X1现面向企业用户全面开放!

一篇论文,看见百度广告推荐系统在大模型时代的革新

前沿多模态模型开发与应用实战3:DeepSeek-VL2多模态理解大模型算法解析与功能抢先体验

秒哒首发即爆发!上线首日吸引2万用户,打造3万应用!

秒哒,全面开放!

即刻体验!文心大模型X1现面向企业用户全面开放!

作者 百度Geek说
2025年4月10日 11:24

4月2日,文心大模型X1正式上线百度智能云千帆大模型平台,企业用户和开发者登录即可调用API。

文心大模型X1具备更强的理解、规划、反思、进化能力,并支持多模态,是能力更全面的深度思考模型。模型兼备准确、创意和文采,在中文知识问答、文学创作、文稿写作、日常对话、逻辑推理、复杂计算及工具调用等方面表现尤为出色。

据权威测试,在多个公开数据集测评中,文心大模型X1在数学、代码、知识推理等能力上表现优异,超越升级后的DeepSeek-V3-0324。在数学场景中,GSM8K数据集测试后结果显示,文心X1得分95.6,DeepSeek-V3-0324得分93.6;代码生成层面,MBPP数据集测试后结果显示,文心X1得分83.3,DeepSeek-V3-0324得分81.2;在知识推理层面,C-Eval数据集测试后结果显示,文心X1得分88.6,DeepSeek-V3-0324得分85.1;在数学推理层面,Aime2024数据集测试后结果显示,文心X1得分78.6,DeepSeek-V3-0324得分57.1。

图片

在模型服务方面,现可直接通过千帆ModelBuilder调用文心大模型X1 API服务,输入价格低至0.002元/千tokens,输出价格低至0.008元/千tokens,同时支持批量推理场景,满足更多元业务需求。

在模型开发方面,千帆ModelBuilder模型蒸馏支持文心大模型X1作为教师模型,一键实现从“思考模型”到“轻量模型”的知识蒸馏。

在应用开发方面,千帆AppBuilder支持用户基于文心大模型X1,快速搭建具有深思考能力的RAG、Agent、AI搜索、工作流,实现更充分的思考规划、更准确的工具调用、更全面的生成效果,助力企业级大模型应用在千行百业落地。

百度智能云千帆大模型平台始终致力于为用户提供全流程、一站式的AI服务,以开放性、易用性、低成本的平台理念,企业用户和开发者能够更高效地探索大模型应用,提升创新效率,加速各类AI应用从概念到落地的转化,为AI技术在更多领域的拓展与应用注入强大动力。

------END------

推荐阅读

一篇论文,看见百度广告推荐系统在大模型时代的革新

前沿多模态模型开发与应用实战3:DeepSeek-VL2多模态理解大模型算法解析与功能抢先体验

秒哒首发即爆发!上线首日吸引2万用户,打造3万应用!

秒哒,全面开放!

图灵数据洞察平台-TDF(Turing Data Finder)

一篇论文,看见百度广告推荐系统在大模型时代的革新

作者 百度Geek说
2025年4月8日 10:29

我们见证了 DeepSeek R1,用强大的推理能力再次点燃 AI 智力增长的火箭。

在上个星期,OpenAI 给 GPT-4o 的一波图像生成更新又让全网陷入了梗图、甚至玩梗视频制造的火热氛围中。

用 GPT-4o 渲染过的《星际穿越》电影片段。

AI 的「想象力」一次又一次震撼着我们,基于先进大模型的应用正在越来越多的领域引发革命,被改变的也包括科技领域本身。

比如,生成式 AI 正在改变人们获取信息的方式。很多人认为,大型语言模型(LLM)既然强于生成和推理,那么应该也能从用户的历史行为中洞察出深层次的兴趣,进而为推荐系统找到全新的可能性。

既然生成式 AI 能通过已知上下文预测生成新内容,那么已知一些人们感兴趣的内容,AI 应该也可以预测出他们的下一个兴趣点。这个预测的内容可以是一篇文章、一段视频、某个品牌的商品或是 App 上的服务。

近日,百度推荐广告团队在广告生成式推荐取得了新成果,其构建的生成式 AI 推荐系统实现了前所未有的效果。

图片

  • 论文标题:Sparse Meets Dense: Unified Generative Recommendations with Cascaded Sparse-Dense Representations

  • 论文 ArXiv:arxiv.org/pdf/2503.02…

在科技行业中,推荐系统虽不如图像生成、代码生成那样具有极高的讨论度,但一直是数字生态举足轻重的一部分。它在电商平台、视频 App 和社交网络上广泛出现,是提供符合用户偏好个性化内容的核心技术。

ChatGPT 推出以来,生成式检索(Generative Retrieval)逐渐成为了推荐系统领域最热门的研究方向。与传统的序列推荐方法不同的是,生成式模型可以根据用户的行为更加直接的进行预测,由 AI 模型处理复杂的用户 - 商品交互,可以提供推理和小样本学习等新能力,大幅提高推荐准确性和多样性。

尽管把生成式 AI 引入推荐系统的创新已有不少,但与序列密集检索方法相比,生成式检索方法仍然面临一些挑战,比如它们往往难以进行细粒度相似性建模。

谷歌的 TIGER 是推荐系统生成检索的知名方法,如图 1(左下)所示;百度则新提出了级联组织双表征生成式检索(Cascaded Organized Bi-Represented generAtive Retrieval,COBRA),这是一个将生成式和密集检索高效融合的框架。图 1(右)展示了 COBRA 的推理范式。

图片

COBRA 研究的主要贡献如下:

  • 级联双表示的检索框架:COBRA 作为一种新型生成式推荐框架,可在生成稀疏 ID 和稠密向量之间交替。通过将稠密表示合并到 ID 序列中,COBRA 弥补了基于 ID 的方法固有的信息损失。使用稀疏 ID 作为生成稠密向量的条件可以降低稠密表示的学习难度。

  • 端到端训练可学习的稠密表示:COBRA 利用原始特征数据作为输入,通过端到端训练生成稠密表示。与静态嵌入不同,COBRA 的稠密向量是动态学习的,可捕获语义信息和细粒度细节。

  • 生成过程由粗到细:在推理过程中,COBRA 首先生成稀疏 ID,然后将其反馈到模型中以生成精细的稠密表示,从而提取细粒度兴趣表征。此外,该研究还提出了 BeamFusion 来实现推荐多样性和精度的灵活可控。

  • 全面的实证验证:通过对多个基准数据集的大量实验,研究证明了 COBRA 在推荐准确率方面的表现优于现有的 SOTA 方法,验证了 COBRA 在推荐任务中真实有效性。

01 生成式检索 几波技术演进

其实,在形成如今 COBRA 方案之前,百度研究团队针对广告场景中的生成式推荐任务,经历了多个阶段的技术探索,并针对暴露出来的技术缺陷持续优化与完善。

在生成式推荐任务中,大模型要预测的 item 是综合体(如广告标题、品牌、多模信息等)⽽并⾮简单的 token。因此,1)如何对 item 进行表征,2)基于表征进行序列建模是生成式推荐的两个核心问题。

最开始,百度采用了「纯⽂本表征 + LLM 建模」的方案,直接利用 LLM 进行推荐。通过标题、落地页等文本来表征 item,虽然可以辅助理解用户意图、提升可解释性,但超长的输入导致了巨大的资源和性能开销,运行成本较高。随后尝试通过短语来表征 item,但短语很容易出现信息压缩过度、表达不全的情况,难以全面描述 item 的各种属性。此外,item 之间的序列关系偏重兴趣协同而并非单纯的语义关系,与 LLM 建模的语义关系存在着鸿沟。

在意识到无法简单的直接使用现有方法后,研究团队开始考虑对 item 进行压缩表达,全面满足性能、信息完备、item 关系建模的要求。

因此,研究团队形成了「稠密表征 + 对⽐学习度量」的方案,核心在于将 item 表征为稠密向量。为此,他们引入了一个编码器逐个对 item 内容进行编码,使得 item 序列转变为一组向量序列并输入到一个 Causal Decoder 中;接着通过 Next Item Prediction 的方式完成模型训练,在训练中引入对比学习,使得编码器、解码器能够同步更新。在推理阶段,算法通过编码器输出 item 向量来构建索引,并通过向量序列输入到解码器中获取用户表征,最终完成 ANN 召回。

这一方案的优势在于表达能力强,可以完整利用 item 原始信息,对比学习保证了端到端训练,进一步建模序列中隐含的协同信息。虽然 item 信息利用和序列关系建模两大关键问题得到了有效解决,但仍然是在较大稠密空间上建模,缺少了兴趣探索过程,建模复杂度并未降低。

图片

「稠密表征 + 对⽐学习度量」方案概览。

接下来,研究团队受到谷歌 TIGER 的启发,尝试了「稀疏表征 + 稀疏 ID ⽣成」的方案,通过稀疏 ID 来表征 item。

完整的实现过程是这样的:首先通过商业预训练模型对广告特征进行嵌入,然后使用残差量化变分自编码器(RQ-VAE)将嵌入向量量化为带层次结构的 ID Tuple(如 L1、L2、L3),最后将 ID 序列输入到 Causal Transformer 并通过下一个 ID 预测来建模序列。在推理阶段,在给定行为序列的情况下,模型可以通过自回归方式来生成下一个可能的广告 ID。

稀疏表征的引入充分发挥出了「嵌入 + 量化」的作用,将 item 转化为 ID,使模型在压缩空间中学习用户兴趣转移,尤其适合高度个性化推荐场景中的「千人千面广告推送」。然而,受限于相互隔离的「嵌入、量化、序列建模」,不可避免地出现了信息损失,导致对用户偏好的精细变化捕捉效果较弱。

在尝试了以上技术方案之后,研究团队认识到了单一表征方式难以同时兼顾粗粒度类别信息和细粒度特征信息的局限性,提出了 COBRA 框架,通过级联方式融合稀疏 ID 和稠密向量表征,形成了「稀疏 - 稠密级联表征 + ⽣成度量⼀体化」方案,大大增强了模型的灵活性和适应性。

02 COBRA 框架的四大创新

下图为 COBRA 的整体框架,在集成了级联稀疏 - 稠密表征和由粗到细生成之后,实现了当前 SOTA 级别的推荐性能。

图片

一是级联稀疏 - 稠密表征。

过程中,级联表征将稀疏 ID 和稠密向量集成在一个统一的生成式模型中。对于每个 item,它的稀疏 ID 和稠密向量组合起来以形成级联表征。这样做可以兼顾稀疏与稠密表征的优点,获得更全面的 item 特征,其中稀疏 ID 通过离散约束提供稳定的类别基础信息,稠密向量确保模型捕获高级语义和细粒度细节。

二是交替学习的序列建模。

得益于级联表征的方式,方案中将目标 item 的概率分布建模分为两个阶段,以利用稀疏与稠密表征的互补优势。COBRA 没有选择基于历史交互序列来直接预测下一个 item,而是转为交替预测稀疏 ID 和稠密向量。具体来说,采用 Causal Transformer 统一生成式模型接收级联表征作为输入,从而捕获序列依赖关系。

三是端到端训练。

COBRA 的端到端训练过程旨在同时优化稀疏和稠密表征预测。训练过程由一个复合损失函数控制,该函数结合了稀疏 ID 预测和稠密向量预测的损失。稀疏 ID 预测损失在基于历史序列预测下一个稀疏 ID 的过程中,保证了模型的效率;稠密向量预测损失用于细化稠密向量。同时,该稠密向量由端到端的可训练编码器生成,并在训练过程中进行优化,从而适应不同推荐任务的特定需求。

这种双目标的损失函数可以实现均衡的优化过程,使模型在稀疏 ID 的指导下动态地细化稠密向量,同时端到端的训练方法可以捕获高级语义和协同信息。

最后是由粗到细生成。

作为一种高效的策略,这有助于模型解耦与模块优化,并在保证候选多样化与覆盖性的同时进一步提高精度。在推理阶段,COBRA 采用由粗到细的生成过程,先生成稀疏 ID,后细化稠密向量,如下图 3 所示。

具体地,首先基于⽤户历史交互序列,使用 Transformer 解码器建模的 ID 概率分布,并利用 BeamSearch 算法生成下一个 item 的稀疏 ID。然后,将⽣成的稀疏 ID 追加到输⼊序列中,作为条件进⼀步⽣成对应的稠密向量,捕获 item 的细粒度特征。同时引⼊ BeamFusion 机制,并结合 BeamSearch 和近邻检索分数,在确保推荐精度的同时保证召回⼴告候选的多样性。

图片

由粗到细的生成过程。

COBRA 框架为生成式推荐领域提供了一个的新范式。

03 多场景性能提升 已实际应用

实测效果如何?研究团队使用公开和工业数据集对 COBRA 框架进行了全面评估,并重点展示了 COBRA 提升推荐准确率和多样性的能力,并通过离线和在线评估来验证实际效果。大量实验表明,COBRA 优于目前业内最先进的方法。

在公开数据集上,研究团队使用了 Amazon Product Reviews 数据集,并重点分析了「Beauty」、「Sports and Outdoors」以及「Toys and Games」三个子集。

实现结果如下表 2 所示,其中在「Beauty」数据集上,COBRA 的 Recall@5 和 Recall@10 相比之前的最佳模型 TIGER 分别提升了 18.3% 和 11.9%;在「Sports and Outdoors」数据集上,COBRA 的 Recall@5 和 NDCG@10 相比 TIGER 分别提升了 15.5% 和 18.8%;在「Toys and Games」数据集上,COBRA 的 Recall@10 和 NDCG@10 相比 TIGER 分别提升了 24.5% 和 19.2%。

图片

对于行业数据集,研究团队采用了 Baidu Industrial 数据集,它基于百度广告平台上的用户交互日志构建,涵盖了列表页、双栏、短视频等多种推荐场景,包含了 500 万用户和 200 万条广告,全面展现了真实用户行为和广告内容。

为了验证本文策略的有效性,研究团队对 COBRA 以及移除稀疏 ID 的变体 COBRA w/o ID、移除稠密向量的变体 COBRA w/o Dense 以及移除 BeamFusion 的变体 COBRA w/o BeamFusion 进行了比较。结果如下表 3 所示,相较于三种变体,COBRA 均体现出了优势,从而验证了该框架中各个组件的有效性。

在 K=800 时,COBRA 的召回率为 0.4466,相较没有稀疏 ID 的变体提升了 43.6%, 相较没有 BeamFusion 的变体提升了 36.1%。

图片

为了评估 COBRA 的表征学习能力,研究团队对广告稠密嵌入展开相似度矩阵分析,如下图 4 所示,展现了 COBRA 模型的类别内聚性和类别间分离性。相反,没有稀疏 ID 的模型变体显示出较弱的类别间分离性(图 4b),加入稀疏 ID 则可以增强内聚性和分离性(图 4c 差异矩阵定量分析)

这意味着 COBRA 不仅能够将同⼀类别的项目紧密地聚集在⼀起,还能将不同类别的项⽬有效地区分开来,从而在推荐时能够更精准地捕捉⽤户的兴趣点。

图片

进一步的可视化广告嵌入分布验证了 COBRA 的嵌入能力。通过随机抽取一万个广告,研究团队观察到了不同广告嵌入形成了明显的聚类中心,如下图 5 所示。我们可以看到,紫色、青色、浅绿色和深绿色聚类主要分别对应小说、游戏、法律服务和衣物广告。

图片

由于与大量业务直接相关,推荐系统是一个很「卷」的领域,在百度的研究中,工程师们把 COBRA 最终策略投放到真实生产环境上跑了一圈,在 A/B 测试中实现了转化率增加 3.6%,ARPU(平均每用户收入)增加 4.15% 的好成绩。

这些业务指标提升表明,COBRA 不仅在离线评估中表现出色,还能够在实际生产环境中带来可衡量的商业价值,目前该方法在百度广告推荐业务中已经全量上线。

04 结语

经过一系列提升和改进,生成式 AI 已经可以做到表达清晰、预测准确,并在百度的广告推荐系统中实现了应用。与很多领域一样,推荐系统正在向着需求个性化的方向快速发展,而在这个方向上,AI 提供的解决方案已经展现出了独特的优势。

对于普通人来说,在各种 App 上,大模型驱动的推荐系统可以帮助我们获取更多有用的内容,让信息流更加聪明。

对于科技公司而言,或许在几年之内,AI 驱动的业务就可以从目前的局部智能化进化到「需求预测 - 生产调度 - 仓储物流 - 营销交付」的全流程智能化阶段。

未来,AI 应用的深度将决定业务的增长速度。

------END------

推荐阅读

前沿多模态模型开发与应用实战3:DeepSeek-VL2多模态理解大模型算法解析与功能抢先体验

秒哒首发即爆发!上线首日吸引2万用户,打造3万应用!

秒哒,全面开放!

图灵数据洞察平台-TDF(Turing Data Finder)

两连发!文心大模型4.5及X1,上线千帆!

前沿多模态模型开发与应用实战3:DeepSeek-VL2多模态理解大模型算法解析与功能抢先体验

作者 百度Geek说
2025年4月3日 11:03

多模态理解大模型,是一类可以同时处理和理解多种数据形式(如图像、文本、视频等)的人工智能大模型,可以应用于图文理解、视觉问答、文档理解、场景描述等任务。本文将介绍目前热门的 DeepSeek-VL2多模态大模型。DeepSeek-VL2是一款基于混合专家(MoE,Mixture of Experts)架构的多模态大模型,结合了混合专家架构和多模态数据处理能力,通过稀疏计算和专家分工的方式高效处理多种模态(如文本、图像、音频等)的数据,推理时只激活部分网络参数。而前两期课程介绍的 Qwen2.5VL、Janus-Pro 以及 DeepSeek-VL第一代模型,则是经典的 Dense 类的多模态理解大模型,会对所有模型参数进行计算和更新。MoE(Mixture of Experts)混合专家模型的核心思想是将模型划分为多个专家子网络(experts),并通过路由机制(router)动态选择合适的专家来处理输入数据。MoE 的最大优势就是是稀疏激活,只有少数几个专家网络模块会被激活,这意味着计算量可以显著减少,计算效率得到提升,同时精度指标远远超出相同激活参数量的 Dense 类模型。

图片

DeepSeek-VL2在视觉理解上的效果展示

接下来,本篇文章内容将包括模型结构、训练流程、模型能力的展示,并以飞桨多模态开发套件 PaddleMIX 中 DeepSeek-VL2的实现为例,对代码进行逐步解读。

01 模型架构

DeepSeek-VL2的前身是去年发布的 DeepSeek-VL,其模型结构设计是经典的 Dense 模型结构,也就是有参数都会进行计算和更新。DeepSeek-VL 由三个主要模块组成:

  • Hybrid Vision Encoder:**混合视觉编码器,采用 SigLIP-L 作为视觉编码器,结合 SAM-B 和 SigLIP-L 编码器,能够高效处理高分辨率图像(1024×1024),同时保留语义和细节信息。高分辨率特征图经过插值和卷积处理后,与低分辨率特征图连接,生成具有2048个维度的视觉 token。

  • VL Adaptor:**视觉语言适配器,使用两层混合 MLP 桥接视觉编码器和语言模型。高分辨率和低分辨率特征分别经过单层 MLP 处理后沿维度连接,再通过另一层 MLP 转换到语言模型的输入空间。

  • DeepSeek LLM:**语言模型是 DeepSeek-LLM,其设计遵循 LLaMA,采用 Pre-Norm 结构和 SwiGLU 激活函数,使用旋转嵌入进行位置编码。

图片

DeepSeek-VL 架构

而近期发布的 DeepSeek-VL2尽管是 MoE 架构,但它也是由三部分核心模块组成:视觉编码器 Vision Encoder、视觉-语言适配器 VL Adaptor 和 DeepSeek-MoE 语言模型。与其前身 DeepSeek-VL 相比,DeepSeek-VL2在视觉编码器和语言建模部分都有了显著的提升,这主要是因为 DeepSeek-VL2引入了两项重大改进:动态切片策略,以及采用多头隐变量注意力(Multi-head Latent Attention,MLA)机制的 DeepSeek-MoE 语言模型。这些创新使得 DeepSeek-VL2能够更高效地处理高分辨率视觉输入和文本数据。

图片

DeepSeek-VL2架构

  • Vision Encoder:**DeepSeek-VL2采用的也是 SigLIP,同时引入了动态切片策略(Dynamic Tiling Strategy),能够处理不同分辨率和长宽比的高分辨率图像。传统的图像编码方法往往固定分辨率,导致在处理较大或不规则图像时性能下降。动态切片策略通过将高分辨率图像分割成多个小块进行处理,减少了计算成本,同时保留了详细的视觉特征。该方法避免了传统视觉编码器的固定分辨率限制,使得模型在处理复杂图像任务(如视觉引导、文档分析等)时具有更好的性能。

  • VL Adaptor:**DeepSeek-VL2采用两层多层感知器(MLP),然后再使用2×2 pixel shuffle 操作压缩每个图像块的 token 数目,用于视觉特征映射到文本空间。

  • DeepSeek-MoE LLM:**语言模型采用了 DeepSeek-MoE(Mixture of Experts)架构,并结合了多头潜在注意力机制(Multi-head Latent Attention,MLA)。MLA 机制能够有效压缩键值缓存(KV Cache),提升推理效率。MoE 架构则通过稀疏计算进一步提升了效率,使得模型在处理大规模数据时能够实现更高的吞吐量。

在模型尺寸上,DeepSeek-VL2系列目前有以下3个参数版本:DeepSeek-VL2-Tiny、DeepSeek-VL2-Small 和 DeepSeek-VL2,分别拥有1B、2.8B 和4.5B 的激活参数。具体的结构设置如下表所示:

图片

DeepSeek-VL2三种参数量的模型设置

02 创新点

2.1 动态图像切片编码策略

动态切片策略

DeepSeek-VL2将一张高分辨率图像切片,为了适应不同长宽比,首先定义了一组候选分辨率:CR={(m⋅384,n⋅384) ∣ m∈N,n∈N,1≤m,n,mn≤9}, m:n表示宽高比。对于一张(H,W)图像,在保证宽高比不变下调整图像分辨率,计算以长边对其到候选分辨率所需要的填充的区域面积。选择面积最小的分辨率 (mi⋅384,ni⋅384),然后将调整大小后的图像划分成 mi×ni 个384×384分辨率的局部图块以及一个全局缩略图块。出于计算效率和上下文长度管理的考虑,在处理多于2张图像时,禁用动态图块策略。

图片

DeepSeek-VL2中的动态切片策略

在将图片切片后,再使用2×2 pixel shuffle 操作压缩每个图像块的 token 数目,从27×27压缩至14×14=196 tokens 对于全局缩略图像块(14×14),在每一行的末尾添加14个标记,从而总共得到14×15=210个 tokens。当处理 mi×ni 个局部图像块时,在每一行的局部块末尾新增,共新增 mi⋅14个 tokens,完整的 Visual Token 包含210+1+mi⋅14×(ni⋅14+1) 个视觉标记,这些 Tokens 随后使用两层多层感知器(MLP)投影到语言模型的 Embedding 空间中。

2.2 DeepSeek-MoE语言模型

在语言模型部分,DeepSeek-VL2使用了 DeepSeek-MoE 语言模型,该模型结合了混合专家(Mixture of Experts, MoE)架构和多头潜在注意力(Multi-head Latent Attention,MLA)机制。MoE 架构通过选择性激活不同的专家网络,实现了计算资源的高效利用和模型性能的提升。而 MLA 机制 MLA 机制通过将键值缓存压缩为潜在向量,增强了推理效率,从而提升了吞吐量,且能够在处理多模态信息时,更好地捕捉到视觉和语言之间的复杂关系,进而提升模型在图文理解、问答等任务中的表现。

在 MoE 训练过程中,为每个专家引入了一个全局偏置项,以经济高效的方式改善专家之间的负载均衡。现有的 MoE 架构可能存在知识混杂(Knowledge Hybridity)和知识冗余(Knowledge Redundancy)的问题,限制了专家的专业化。在实现思想上,DeepSeek-MoE 采用两个主要策略:

  • Fine-Grained Expert Segmentation-细粒度的专家分割,通过细化 FFN 中间隐藏维度,维持参数数量不变的同时激活更多细粒度的专家,使得激活的专家更加灵活和适应性更强;

  • Shared Expert Isolation-共享专家隔离,将某些专家隔离为共享专家,始终激活,旨在捕捉和巩固不同上下文中的共同知识。

图片

DeepSeek-MOE 的架构

2.3 高校的推理速度与吞吐量

为了提升模型的推理速度,DeepSeek-VL2在语言部分的处理上引入了键值缓存压缩技术。这项技术能够有效减少计算中的冗余操作,从而提高推理过程的效率,尤其在处理大规模数据时表现出色。通过这种优化,DeepSeek-VL2在多个任务上不仅表现出了更高的准确率,也大大提升了计算效率。

03 训练方法

3.1 训练数据

DeepSeek-VL2从多种来源构建了一个综合性的视觉-语言数据集。训练过程分为三个阶段:(1)视觉-语言对齐(VL alignment);(2)视觉-语言预训练(VL pretraining);(3)监督微调(Supervised Fine-Tuning)。

1.VL alignment 数据

对齐阶段专注于训练多层感知机(MLP)VL Adaptor,以桥接预训练的视觉编码器和大型语言模型。这一阶段使用了 ShareGPT4V 数据集,该数据集包含大约120万个描述和对话样本。

2.VL-Pretrain 数据

VL-Pretrain 数据结合了视觉-语言数据和纯文本数据,以保持 VL 能力和纯文本性能之间的平衡。对于 DeepSeek-VL2,作者保持了大约70%的 VL 数据和30%的纯文本数据的比例,后者直接来源于作者基础大型语言模型(LLM)的预训练语料库。

Image-Text 混合数据

数据收集始于几个开源数据集,包括 WIT、WikiHow 和 OBELICS 中的30%随机样本。这一特定的混合比例是通过使用 DeepSeek-VL2-Tiny 进行初步实验确定的。为了增强多语言能力,在主要以英语为主的数据集中补充了从 Wanjuan 中提取的中文内容。此外,DeepSeek-VL2还开发了一个内部数据集,以扩大对一般现实世界知识的覆盖范围。

Image Caption 数据

图像描述是视觉语言模型(VLM)训练中的基础数据,提供了视觉信息和文本信息之间的直接对齐。因为开源数据集质量差异很大,为了解决这些质量不一致的问题,DeepSeek-VL2开发了一个全面的图像描述流程,该流程考虑了:(1)光学字符识别(OCR)提示;(2)元信息(例如位置、相机设置);(3)原始描述作为提示。DeepSeek-VL2使用内部 Captioner,使用 类似于 PixelProse 的提示策略重新为图像添加描述,采用不同的指令来指导 VLM 生成描述。尽管 Catpion 整体质量有所提高,在大规模标注流程中观察到了重复问题。为了缓解这一问题,DeepSeek-VL2采用一个质量控制流程,使用 DeepSeek Chat 仅根据 Caption 的写作质量进行评分。

OCR 数据

LaTex OCR 和12M RenderedText、包括不同文档类型的大规模内部数据集

VQA 数据

  • DeepSeek-VL 通用的 VQA 数据。

  • 表格、图表和文档理解数据。PubTabNet、FinTabNet 和 Docmatix。

  • Web-to-code 和 plot-to-Python 生成。Websight,并遵循 DeepSeek-VL 的方法,使用公开的 Jupyter 笔记本中的 Python 图表。通过使用 DeepSeek V2.5对 Websight 部分数据增强。作者还利用 DeepSeek V2.5生成的 Python 图表代码来减少 plot-to-code 中的噪声。

  • 包括视觉提示的 QA 数据:参考 Vip-llava 构建具有不同视觉提示(箭头、方框、圆圈和涂鸦)的数据。

Visual grounding 数据

基于 Kosmos-2和 Objects365构建 视觉定位数据,并采用以下模版构建

  • Prompt: \texttt{Locate <|ref|><|/ref|> in the given image.}

  • Response: \texttt{<|ref|><|/ref|><|det|>[[x1, y1, x2, y2],\ldots]<|/det|>}

Grounded 对话数据

基于 Kosmos-2构建视觉定位对话数据并采用以下模版构建

  • Prompt: \texttt{<|grounding|>Can you describe the content of the image?}
  • Response: $\texttt{Two <|ref|>dogs<|/ref|><|det|>[[x1, y1, x2, y2],\ldots]<|/det|> are running on the grass.}

3.SFT 数据

DeepSeek-VL2的 SFT 数据结合了多种开源数据集与高质量的内部 QA 对。

General visual question-answering

虽然 VQA 数据集种类繁多,但它们通常存在三大局限:(1)回答简短;(2)光学字符识别(OCR)质量不佳;(3)内容虚幻。为解决这些问题,DeepSeek-VL2综合考虑原始问题、图像和 OCR 信息来重新生成回答。作者的实验表明,这种方法能产生更全面、更准确的结果。在 DeepSeek-VL2的开发过程中早期版本,尤其是 Tiny 变体,偶尔会在中文回答中不恰当地插入英文单词。这一问题在 DeepSeek-VL2大型模型中并不存在,这表明它源于模型容量有限以及视觉-语言预训练阶段中英文数据的不平衡。为解决小型模型中的这一局限,DeepSeek-VL2团队开发了一个包含多样图像描述和单轮/多轮对话的内部中文问答数据集。该数据集有助于缓解语言混合问题。此外还创建了补充现实世界的和文化相关的视觉知识,包括动漫、网络梗、美食和艺术的内部数据集。

OCR and document understanding

得益于 DeepSeek-VL2先进的 Caption Pipeline,DeepSeek-VL2已经展现出比其他最先进的视觉语言模型(VLM)更优越的 OCR 能力。因此,在 SFT 阶段未进一步提升 OCR 性能,而是专注于清理现有的开源数据集,通过移除 OCR 质量不佳的样本。对于文档理解,DeepSeek-VL2团队从内部数据中筛选了一个多样化的文档页面子集。然后针对文档理解生成了多轮对话式问答对。

Table and chart understanding

通过对除 Cauldron(其已展现出高质量)外的所有公共数据集基于其原始问题重新生成回答,从而增强了基于表格的问答数据。与在视觉语言预训练阶段开发的 OCR 能力类似,的模型在图表理解方面也表现出色,且无需额外努力。

Textbook and academic questions

从文档集合中构建了一个专注于教科书的内部数据集。该数据集主要强调多个学科领域的大学水平内容。

Web-to-code and plot-to-Python generation

网页到代码与图表到 Python 代码生成。扩展了内部关于网页代码和 Python 图表代码的数据集,这些数据集超出了预训练期间所使用的范围。对于开源数据集,通过重新生成答案来提高其质量。

纯文本数据

为了保持模型的语言能力,在 SFT 阶段,还使用了纯文本指令调整数据集。

3.2 训练阶段

DeepSeek-VL2通过三阶段的流程进行训练:

  • 初始阶段:使用3.1.1节中详细描述的图文配对数据,训练视觉编码器和视觉-语言适配器 MLP,同时保持语言模型固定。
  • 预训练阶段:使用3.1.2节描述的数据进行视觉-语言预训练。在此阶段,所有模型参数,包括视觉编码器、视觉-语言适配器和语言模型,都会解锁并同时训练。
  • 微调阶段:使用第3.1.3节概述的数据进行有监督的微调,进一步优化模型性能。

在预训练和微调阶段,强调视觉理解能力,并仅在文本标记上计算下一个标记预测损失。

视觉-语言对齐

基于预训练的语言模型(DeepSeekMoE 3B/16B/27B),的主要目标是建立视觉特征和语言特征之间的稳固连接。这种对齐使得预训练的语言模型能够有效地处理视觉输入。与之前的方法不同,这些方法保持预训练的视觉编码器和语言模型固定,调整固定分辨率的视觉编码器以适应动态高分辨率图像。在这个阶段,优化视觉编码器和视觉-语言适配器,同时保持语言模型冻结。

视觉-语言预训练 在嵌入空间中建立视觉-语言对齐之后,将大部分计算资源用于视觉-语言预训练。这个阶段的重点是开发跨多种任务的综合性联合视觉-语言知识。解锁所有参数,包括视觉编码器、视觉-语言适配器和语言模型,并同时进行训练。通过这些阶段的系统训练,DeepSeek-VL2不仅能够处理高分辨率的视觉输入,还能够在多模态任务中表现出色。这种训练方法使得模型在多样化的任务中提高了视觉和语言理解能力。

有监督微调 在最后阶段,通过有监督的微调来增强预训练模型的指令跟随能力和对话能力。利用内部的视觉语言 SFT 数据,优化所有参数,但仅对答案和特殊标记进行监督,同时屏蔽系统和用户提示。为了加强对话理解,将多模态数据与来自 DeepSeek-V2的纯文本对话数据结合使用。这种方法确保了在各种视觉语言任务中具有强大的性能,包括密集图像描述、通用视觉问答(VQA)、光学字符识别(OCR)、表格/图表/文档/图形理解、视觉到代码、视觉推理、视觉定位和语言理解等。

图片

DeepSeek-VL2的训练超参数

3.3 结果评估

DeepSeek-VL2在多个常用的多模态基准数据集上进行了评估,包括 DocVQA、ChartQA、InfoVQA、TextVQA 等。这些基准涵盖了从文档理解到逻辑推理等多种任务,全面评估了 DeepSeek-VL2在不同任务上的表现。

视觉引导能力

DeepSeek-VL2在视觉引导任务上展现了强大的能力,能够根据图像中的描述性信息准确定位物体,并生成相应的回答。

多图像对话能力

DeepSeek-VL2在处理多图像对话任务时表现突出,能够分析多张图片之间的关系,并基于这些信息进行简单的推理。

视觉故事生成能力

在视觉故事生成任务中,DeepSeek-VL2能够根据图片创作出创意十足的故事,并且能够有效结合图像中的细节,如地标识别和 OCR 结果。

图片

DeepSeek-VL2 OCR 相关能力指标结果

图片

DeepSeek-VL2用 VQA 和数学相关能力指标结果

图片

DeepSeek-VL2视觉故事生成能力展示

04 代码解读

下面以 PaddleMIX 中 DeepSeek-VL2的实现为例,对关键创新点的代码实现进行讲解。

PaddleMIX

github.com/PaddlePaddl…

4.1 标动态切片策略

功能

该函数 select_best_resolution 的目的是在给定的候选分辨率列表中找到最适合原始图像大小的分辨率。

步骤实现

DeepSeek-VL2在处理多图像对话任务时表现突出,能够分析多张图片之间的关系,并基于这些信息进行简单的推理。

  • 计算缩放比例:对于每个候选分辨率,计算其相对于原始图像尺寸的缩放比例(取宽度和高度缩放比例中的最小值)。

  • 计算缩放后的尺寸:使用上述缩放比例计算缩放后的图像宽度和高度。

  • 计算有效分辨率:有效分辨率是缩放后的图像分辨率与原始图像分辨率中较小的一个。这是为了确保缩放后的图像不会比原始图像具有更高的分辨率。

  • 计算浪费的分辨率:浪费的分辨率是候选分辨率的面积减去有效分辨率的面积。

  • 选择最佳匹配:遍历所有候选分辨率,找到有效分辨率最大且浪费分辨率最小的那个作为最佳匹配。如果两个候选分辨率的有效分辨率相同,则选择浪费分辨率较小的那个。

输出

返回一个元组,代表最佳匹配的分辨率(宽度和高度)。如果没有找到任何合适的分辨率,理论上应该返回 None(尽管在当前的实现中,如果至少有一个候选分辨率,它总是会返回一个结果)。

def select_best_resolution(image_size, candidate_resolutions):
    original_width, original_height = image_size
    best_fit = None
    max_effective_resolution = 0
    min_wasted_resolution = float("inf")

    for width, height in candidate_resolutions:
        scale = min(width / original_width, height / original_height)
        downscaled_width, downscaled_height = int(original_width * scale), int(original_height * scale)
        effective_resolution = min(downscaled_width * downscaled_height, original_width * original_height)
        wasted_resolution = width * height - effective_resolution

        if (
            effective_resolution > max_effective_resolution
            or effective_resolution == max_effective_resolution
            and wasted_resolution < min_wasted_resolution
        ):
            max_effective_resolution = effective_resolution
            min_wasted_resolution = wasted_resolution
            best_fit = width, height

    return best_fit


4.2 VL Adapter

方法

tokenize_with_images

功能

该函数 tokenize_with_images 的目的是将包含 texttt\\texttt{} 标签的文本对话进行分词处理,并同时处理与文本对话相关联的图像。它将文本和图像转换为适合模型处理的格式,包括图像的分辨率调整、裁剪、以及将文本和图像转换为一系列 tokens。

参数

  • conversation:包含 texttt\\texttt{} 标签的原始文本对话。

  • images:与文本对话中的 texttt\\texttt{} 标签相对应的图像列表。

  • bos:布尔值,指定是否在分词结果的开头添加开始序列(Begin Of Sequence, BOS) token。默认为 True。

  • eos:布尔值,指定是否在分词结果的末尾添加结束序列(End Of Sequence, EOS)token。默认为 True。

  • cropping:布尔值,指定是否对图像进行裁剪以适应特定的分辨率。默认为 True。

步骤实现

  • 断言检查:确保文本对话中的 texttt\\texttt{} 标签数量与提供的图像数量相匹配。

  • 文本分割:使用 texttt\\texttt{} 标签将文本对话分割成多个部分。

  • 初始化列表:用于存储处理后的图像、图像序列掩码、图像空间裁剪信息、图像 token 数量以及分词后的字符串。

  • 遍历文本和图像:对于每个文本部分和对应的图像,执行以下操作:

  • 文本分词:将文本部分分词,但不添加 BOS 和 EOS token。

  • 图像分辨率选择:根据裁剪标志选择最佳图像分辨率。

  • 全局视图处理:将图像调整为固定大小(self.image_size),并填充背景色。

  • 局部视图处理:根据最佳分辨率将图像裁剪成多个小块,并对每个小块进行处理。

  • 记录裁剪信息:记录每个图像在宽度和高度上被裁剪成的小块数量。

  • 添加图像 token:为每个图像(全局和局部视图)生成一系列图像 token,并添加到分词后的字符串中。

  • 更新掩码和 token 数量:更新图像序列掩码和图像 token 数量列表。

  • 处理最后一个文本部分:对最后一个文本部分进行分词处理(但不添加 BOS 和 EOS token),并更新分词后的字符串和图像序列掩码。

  • 添加 BOS 和 EOS token:根据参数设置,在分词结果的开头和末尾添加 BOS 和 EOS token。

  • 断言检查:确保分词后的字符串长度与图像序列掩码的长度相匹配。

输出

返回一个元组,包含以下内容:

  • tokenized_str:分词后的字符串,包含文本和图像 token。

  • images_list:处理后的图像列表,包括全局视图和局部视图。

  • images_seq_mask:图像序列掩码,用于指示哪些 token 是图像 token。

  • images_spatial_crop:图像空间裁剪信息,记录每个图像在宽度和高度上的裁剪小块数量。

  • num_image_tokens:每个图像对应的 token 数量列表。

def tokenize_with_images(
        self, conversation: str, images: List[Image.Image], bos: bool = True, eos: bool = True, cropping: bool = True
    ):
        """Tokenize text with <image> tags."""
        assert conversation.count(self.image_token) == len(images)
        text_splits = conversation.split(self.image_token)
        images_list, images_seq_mask, images_spatial_crop = [], [], []
        num_image_tokens = []
        tokenized_str = []
        for text_sep, image in zip(text_splits, images):
            """encode text_sep"""
            tokenized_sep = self.encode(text_sep, bos=False, eos=False)
            tokenized_str += tokenized_sep
            images_seq_mask += [False] * len(tokenized_sep)
            """select best resolution for anyres"""
            if cropping:
                best_width, best_height = select_best_resolution(image.size, self.candidate_resolutions)
            else:
                best_width, best_height = self.image_size, self.image_size

            """process the global view"""
            global_view = ImageOps.pad(
                image, (self.image_size, self.image_size), color=tuple(int(x * 255for x in self.image_transform.mean)
            )
            images_list.append(self.image_transform(global_view))

            """process the local views"""
            local_view = ImageOps.pad(
                image, (best_width, best_height), color=tuple(int(x * 255for x in self.image_transform.mean)
            )

            for i in range(0, best_height, self.image_size):
                for j in range(0, best_width, self.image_size):
                    images_list.append(
                        self.image_transform(local_view.crop((j, i, j + self.image_size, i + self.image_size)))
                    )

            """record height / width crop num"""
            num_width_tiles, num_height_tiles = (best_width // self.image_size, best_height // self.image_size)
            images_spatial_crop.append([num_width_tiles, num_height_tiles])

            """add image tokens"""
            h = w = math.ceil(self.image_size // self.patch_size / self.downsample_ratio)
            tokenized_image = [self.image_token_id] * h * (w + 1)
            tokenized_image += [self.image_token_id]
            tokenized_image += [self.image_token_id] * (num_height_tiles * h) * (num_width_tiles * w + 1)
            tokenized_str += tokenized_image
            images_seq_mask += [True] * len(tokenized_image)
            num_image_tokens.append(len(tokenized_image))

        """process the last text split"""
        tokenized_sep = self.encode(text_splits[-1], bos=False, eos=False)
        tokenized_str += tokenized_sep
        images_seq_mask += [False] * len(tokenized_sep)

        """add the bos and eos tokens"""
        if bos:
            tokenized_str = [self.bos_id] + tokenized_str
            images_seq_mask = [False] + images_seq_mask
        if eos:
            tokenized_str = tokenized_str + [self.eos_id]
            images_seq_mask = images_seq_mask + [False]
        assert len(tokenized_str) == len(
            images_seq_mask
        ), f"tokenize_with_images func: tokenized_str's length {len(tokenized_str)} is not equal to imags_seq_mask's length {len(images_seq_mask)}"
        return (tokenized_str, images_list, images_seq_mask, images_spatial_crop, num_image_tokens)


4.3 MLA(Multi-head Latent Attention)

类名

DeepseekV2Attention

主要功能

实现多头注意力机制,用于处理序列数据,支持缓存机制和不同的 RoPE(Rotary Position Embedding)缩放策略。

初始化参数 (init)

  • config:DeepseekV2Config 类型的配置对象,包含模型的各种配置参数。

  • layer_idx:可选参数,表示当前层的索引,用于缓存机制。

前向传播参数 (forward)

  • hidden_states:paddle.Tensor 类型的输入张量,表示隐藏状态。

  • attention_mask:可选参数,paddle.Tensor 类型的注意力掩码,用于屏蔽不需要关注的位置。

  • position_ids:可选参数,paddle.Tensor 类型的位置编码,用于 RoPE。

  • past_key_value:可选参数,Tuple[paddle.Tensor] 类型的缓存键值对,用于加速推理。

  • output_attentions:布尔类型,表示是否输出注意力权重。

  • use_cache:布尔类型,表示是否使用缓存机制。

  • kwargs:其他可选参数。

前向传播 (forward)

实现多头注意力机制,用于处理序列数据,支持缓存机制和不同的 RoPE(Rotary Position Embedding)缩放策略。

1.查询投影(Query Projection):

  • 如果 q_lora_rank 为 None,则使用 q_proj 对查询进行投影。

  • 否则,使用基于 LoRA 的投影(q_a_proj、q_a_layernorm 和 q_b_proj)。

2.键值投影(Key-Value Projection):

  • 使用 kv_a_proj_with_mqa 对键和值进行投影。

  • 将结果拆分为 LoRA 和 RoPE 组件。

  • RoPE 应用(RoPE Application)。

  • 计算 RoPE 的余弦和正弦值。

  • 将 RoPE 应用于查询和键。

3.缓存(Caching):

  • 如果 use_cache 为 True,则更新缓存的键和值。

注意力权重(Attention Weights)

实现多头注意力机制,用于处理序列数据,支持缓存机制和不同的 RoPE(Rotary Position Embedding)缩放策略。

  • 使用缩放点积注意力计算注意力分数。

  • 应用注意力掩码和 softmax。

  • 输出投影(Output Projection)。

  • 使用注意力权重和投影后的值计算注意力输出。

  • 应用输出投影(o_proj)。

class DeepseekV2Attention(paddle.nn.Layer):
    """Multi-headed attention from 'Attention Is All You Need' paper"""

    def __init__(self, config: DeepseekV2Config, layer_idx: Optional[int] = None):
        super().__init__()
        self.config = config
        """
        ..............
        """
        if self.q_lora_rank is None:
            self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.q_head_dim, bias_attr=False)
        else:
            self.q_a_proj = nn.Linear(self.hidden_size, config.q_lora_rank, bias_attr=config.attention_bias)
            self.q_a_layernorm = DeepseekV2RMSNorm(config=config, hidden_size=config.q_lora_rank)
            self.q_b_proj = nn.Linear(config.q_lora_rank, self.num_heads * self.q_head_dim, bias_attr=False)

        self.kv_a_proj_with_mqa = nn.Linear(self.hidden_size, config.kv_lora_rank + config.qk_rope_head_dim, bias_attr=config.attention_bias)
        self.kv_a_layernorm = DeepseekV2RMSNorm(config=config, hidden_size=config.kv_lora_rank)
        self.kv_b_proj = nn.Linear(config.kv_lora_rank, self.num_heads * (self.q_head_dim - self.qk_rope_head_dim + self.v_head_dim), bias_attr=False)

        self.o_proj = nn.Linear(self.num_heads * self.v_head_dim, self.hidden_size, bias_attr=config.attention_bias)

        self._init_rope()

        self.softmax_scale = self.q_head_dim**-0.5
        if self.config.rope_scaling is not None:
            mscale_all_dim = self.config.rope_scaling.get("mscale_all_dim"0)
            scaling_factor = self.config.rope_scaling["factor"]
            if mscale_all_dim:
                mscale = yarn_get_mscale(scaling_factor, mscale_all_dim)
                self.softmax_scale = self.softmax_scale * mscale * mscale

    def forward(
        self,
        hidden_states: paddle.Tensor,
        attention_mask: Optional[paddle.Tensor] = None,
        position_ids: Optional[paddle.Tensor] = None,
        past_key_value: Optional[Tuple[paddle.Tensor]] = None,
        output_attentions: bool = False,
        use_cache: bool = False,
        **kwargs,
    ) -> Tuple[paddle.Tensor, Optional[paddle.Tensor], Optional[Tuple[paddle.Tensor]]]:

        bsz, q_len, _ = tuple(hidden_states.shape)
        if self.q_lora_rank is None:
            q = self.q_proj(hidden_states)
        else:
            q = self.q_b_proj(self.q_a_layernorm(self.q_a_proj(hidden_states)))

        q = q.reshape([bsz, q_len, self.num_heads, self.q_head_dim]).transpose(perm=[0213])
        q_nope, q_pe = paddle.split(q, [self.qk_nope_head_dim, self.qk_rope_head_dim], axis=-1)

        compressed_kv = self.kv_a_proj_with_mqa(hidden_states)
        compressed_kv, k_pe = paddle.split(compressed_kv, [self.kv_lora_rank, self.qk_rope_head_dim], axis=-1)
        compressed_kv = self.kv_a_layernorm(compressed_kv)
        k_pe = k_pe.reshape([bsz, q_len, 1, self.qk_rope_head_dim]).transpose(perm=[0213])

        kv_seq_len = tuple(k_pe.shape)[-2]
        if past_key_value is not None:
            kv_seq_len += past_key_value[0].shape[1]
        cos, sin = self.rotary_emb(q_pe, seq_len=kv_seq_len)
        q_pe, k_pe = apply_rotary_pos_emb(q_pe, k_pe, cos, sin, position_ids)

        if use_cache and past_key_value is not None:
            compressed_kv = compressed_kv.unsqueeze(axis=2)
            k_pe = k_pe.transpose(perm=[0213])  # (b h l d) to (b l h d)
            k_pe = paddle.concat([past_key_value[0], k_pe], axis=1)
            compressed_kv = paddle.concat([past_key_value[1], compressed_kv], axis=1)

            past_key_value = (k_pe, compressed_kv)

            k_pe = k_pe.transpose(perm=[0213])  # go back to (b l h d)
            compressed_kv = compressed_kv.squeeze(2)
        elif use_cache:
            past_key_value = (k_pe.transpose([0213]), compressed_kv.unsqueeze(axis=2))
        else:
            past_key_value = None

        # shit tranpose liner weight
        kv_b_proj = self.kv_b_proj.weight.T.reshape([self.num_heads, -1, self.kv_lora_rank])
        q_absorb = kv_b_proj[:, :self.qk_nope_head_dim, :]
        out_absorb = kv_b_proj[:, self.qk_nope_head_dim:, :]

        q_nope = paddle.matmul(q_nope, q_absorb)
        attn_weights = (
            paddle.matmul(q_pe, k_pe.transpose([0132])) # [1, 16, 1304, 64] * [1, 1, 1304, 64]
            + paddle.matmul(q_nope, compressed_kv.unsqueeze(axis=-3).transpose([0132])) #  [1, 16, 1304, 512] * [1, 1, 1304, 512]
        ) * self.softmax_scale

        if tuple(attn_weights.shape) != (bsz, self.num_heads, q_len, kv_seq_len):
            raise ValueError(
                f"Attention weights should be of size {bsz, self.num_heads, q_len, kv_seq_len}, but is {tuple(attn_weights.shape)}"
            )
        assert attention_mask is not None
        if attention_mask is not None:
            if tuple(attention_mask.shape) != (bsz, 1, q_len, kv_seq_len):
                raise ValueError(
                    f"Attention mask should be of size {bsz, 1, q_len, kv_seq_len}, but is {tuple(attention_mask.shape)}"
                )
            attn_weights = attn_weights + attention_mask

        # upcast attention to fp32
        attn_weights = F.softmax(attn_weights, axis=-1, dtype="float32").to(q_pe.dtype)
        attn_weights = F.dropout(attn_weights, self.attention_dropout, training=self.training)
        attn_output = paddle.einsum("bhql,blc->bhqc", attn_weights, compressed_kv)
        attn_output = paddle.matmul(attn_output, out_absorb.transpose([021]))

        if tuple(attn_output.shape) != (bsz, self.num_heads, q_len, self.v_head_dim):
            raise ValueError(
                f"`attn_output` should be of size {bsz, self.num_heads, q_len, self.v_head_dim}, but is {tuple(attn_output.shape)}"
            )
        attn_output = attn_output.transpose([0213])
        attn_output = attn_output.reshape([bsz, q_len, self.num_heads * self.v_head_dim])
        attn_output = self.o_proj(attn_output)
        if not output_attentions:
            attn_weights = None
        return attn_output, attn_weights, past_key_value


4.4 DeepSeekV2-MoE

类名

DeepseekV2MoE

主要功能

实现混合专家机制,通过路由机制将输入分配给多个专家网络,并将结果加权组合。

初始化参数 (init)

config:配置对象,包含模型的各种参数,如专家数量、共享专家数量、中间层大小等。

步骤实现

1.初始化 (init):

  • 从配置对象中读取参数,如专家数量、共享专家数量、中间层大小等。

  • 根据分布式环境(ep_size)分配专家网络到不同的设备上。

  • 初始化专家网络列表(self.experts)和共享专家网络(self.shared_experts)。

  • 初始化门控机制(self.gate)。

2.前向传播 (forward):

  • 保存输入张量的原始形状和值(identity 和 orig_shape)。

  • 使用门控机制(self.gate)计算路由索引(topk_idx)、路由权重(topk_weight)和辅助损失(aux_loss)。

  • 将输入张量展平以便处理。

  • 训练模式:

    ·将输入张量复制多次以匹配每个专家的输入。

    ·根据路由索引将输入分配给对应的专家网络,并计算输出。

    ·对专家输出进行加权求和,并恢复原始形状。

    ·添加辅助损失(AddAuxiliaryLoss.apply)。

  • 推理模式:

    ·调用 moe_infer 方法处理输入,并恢复原始形状。

    ·如果存在共享专家网络,将其输出与专家网络的输出相加。

    ·返回最终的输出张量。

class DeepseekV2MoE(paddle.nn.Layer):
    """
    A mixed expert module containing shared experts.
    """
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.num_experts_per_tok = config.num_experts_per_tok
        if hasattr(config, "ep_size") and config.ep_size > 1:
            assert config.ep_size == dist.get_world_size()
            self.ep_size = config.ep_size
            self.experts_per_rank = config.n_routed_experts // config.ep_size
            self.ep_rank = dist.get_rank()
            self.experts = nn.ModuleList(
                [
                    (
                        DeepseekV2MLP(
                            config, intermediate_size=config.moe_intermediate_size
                        )
                        if i >= self.ep_rank * self.experts_per_rank
                        and i < (self.ep_rank + 1) * self.experts_per_rank
                        else None
                    )
                    for i in range(config.n_routed_experts)
                ]
            )
        else:
            self.ep_size1
            self.experts_per_rank = config.n_routed_experts
            self.ep_rank0
            self.experts = nn.LayerList(
                [
                    DeepseekV2MLP(config, intermediate_size=config.moe_intermediate_size)
                    for i in range(config.n_routed_experts)
                ]
            )
        self.gate = MoEGate(config)
        if config.n_shared_experts is not None:
            intermediate_size = config.moe_intermediate_size * config.n_shared_experts
            self.shared_experts = DeepseekV2MLP(config=config, intermediate_size=intermediate_size)

    def forward(self, hidden_states):
        identity = hidden_states
        orig_shape = hidden_states.shape
        topk_idx, topk_weight, aux_loss = self.gate(hidden_states)
        hidden_states = hidden_states.reshape([-1, hidden_states.shape[-1]])
        flat_topk_idx = topk_idx.reshape([-1])
        # remove the infer method
        if self.training:
            hidden_states = hidden_states.repeat_interleave(self.num_experts_per_tok, axis=0)
            y = paddle.empty_like(hidden_states)
            for i, expert in enumerate(self.experts):
                # y[flat_topk_idx == i] = expert(hidden_states[flat_topk_idx == i])
                if paddle.any(flat_topk_idx == i):
                    y[flat_topk_idx == i] = expert(hidden_states[flat_topk_idx == i])

            y = (y.reshape([*topk_weight.shape, -1]) * topk_weight.unsqueeze(-1)).sum(axis=1)
            y = paddle.cast(y, hidden_states.dtype).reshape([*orig_shape])
            if self.gate.alpha > 0.0:
                y = AddAuxiliaryLoss.apply(y, aux_loss)
        else:
            y = self.moe_infer(hidden_states, topk_idx, topk_weight).reshape([*orig_shape])
        if self.config.n_shared_experts is not None:
            y = y + self.shared_experts(identity)
        return y


4.5 MoEGate

类名

MoEGate

主要功能

实现混合专家机制的门控逻辑,包括路由权重计算、专家选择和辅助损失计算。

初始化参数 (init)

config:配置对象,包含模型的各种参数,如专家数量、路由缩放因子、评分函数等。

步骤实现 1.初始化 (init):

  • 从配置对象中读取参数,如专家数量、路由缩放因子、评分函数等。

  • 初始化门控权重(self.weight)和路由策略相关参数。

  • 如果使用 noaux_tc 路由策略,初始化专家评分校正偏置(self.e_score_correction_bias)。

  • 调用 reset_parameters 方法初始化权重。

2.权重初始化 (reset_parameters):

  • 使用 Kaiming 均匀分布初始化门控权重。

3.前向传播 (forward):

  • 将输入张量展平以便处理。

  • 使用线性变换计算路由得分(logits)。

  • 根据评分函数(如 softmax 或 sigmoid)计算路由权重(scores)。

  • 如果 top_k > 1 且 norm_topk_prob 为 True,对路由权重进行归一化。

  • 在训练模式下,计算辅助损失(aux_loss)以优化路由机制。

  • 返回路由索引(topk_idx)、路由权重(topk_weight)和辅助损失(aux_loss)。

class MoEGate(paddle.nn.Layer):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.top_k = config.num_experts_per_tok
        self.n_routed_experts = config.n_routed_experts
        self.routed_scaling_factor = config.routed_scaling_factor
        self.scoring_func = config.scoring_func
        self.alpha = config.aux_loss_alpha
        self.seq_aux = config.seq_aux
        self.topk_method = config.topk_method
        self.n_group = config.n_group
        self.topk_group = config.topk_group
        # topk selection algorithm
        self.norm_topk_prob = config.norm_topk_prob
        self.gating_dim = config.hidden_size
        self.weight = paddle.base.framework.EagerParamBase.from_tensor(
            tensor=paddle.empty(shape=(self.gating_dim, self.n_routed_experts))
        )
        if self.topk_method == "noaux_tc":
            self.e_score_correction_bias = paddle.base.framework.EagerParamBase.from_tensor(
                tensor=paddle.empty(shape=[self.n_routed_experts])
            )

    def forward(self, hidden_states):
        bsz, seq_len, h = tuple(hidden_states.shape)
        hidden_states = hidden_states.reshape([-1, h])
        logits = paddle.nn.functional.linear(
            x=hidden_states.astype("float32"), weight=self.weight.astype("float32"), bias=None
        )
        if self.scoring_func == "softmax":
            scores = paddle.nn.functional.softmax(logits, axis=-1, dtype="float32")
        elif self.scoring_func == "sigmoid":
            scores = logits.sigmoid()
        else:
            raise NotImplementedError(f"insupportable scoring function for MoE gating: {self.scoring_func}")
        if self.topk_method == "greedy":
            topk_weight, topk_idx = paddle.topk(k=self.top_k, sorted=False, x=scores, axis=-1)
        elif self.topk_method == "group_limited_greedy":
            group_scores = scores.reshape(bsz * seq_len, self.n_group, -1).max(dim=-1).values

            group_idx = paddle.topk(k=self.topk_group, sorted=False, x=group_scores, axis=-1)[1]
            group_mask = paddle.zeros_like(x=group_scores)
            group_mask.put_along_axis_(axis=1, indices=group_idx, values=1, broadcast=False)
            score_mask = (
                group_mask.unsqueeze(axis=-1)
                .expand(shape=[bsz * seq_len, self.n_group, self.n_routed_experts // self.n_group])
                .reshape([bsz * seq_len, -1])
            )
            tmp_scores = scores.masked_fill(mask=~score_mask.astype(dtype="bool"), value=0.0)
            topk_weight, topk_idx = paddle.topk(k=self.top_k, sorted=False, x=tmp_scores, axis=-1)
        elif self.topk_method == "noaux_tc":
            assert not self.training
            scores_for_choice = scores.reshape([bsz * seq_len, -1]) + self.e_score_correction_bias.unsqueeze(axis=0)
            group_scores = scores_for_choice.reshape([bsz * seq_len, self.n_group, -1]).topk(k=2, axis=-1)[0].sum(axis=-1)

            group_idx = paddle.topk(k=self.topk_group, sorted=False, x=group_scores, axis=-1)[1]
            group_mask = paddle.zeros_like(x=group_scores)
            group_mask.put_along_axis_(axis=1, indices=group_idx, values=1, broadcast=False)
            # todo
            score_mask = (
                group_mask.unsqueeze(axis=-1)
                .expand(shape=[bsz * seq_len, self.n_group, self.n_routed_experts // self.n_group])
                .reshape([bsz * seq_len, -1])
            )
            tmp_scores = scores_for_choice.masked_fill(mask=~score_mask.astype(dtype="bool"), value=0.0)
            _, topk_idx = paddle.topk(k=self.top_k, sorted=False, x=tmp_scores, axis=-1)
            topk_weight = scores.take_along_axis(axis=1, indices=topk_idx, broadcast=False)

        if self.top_k > 1 and self.norm_topk_prob:
            denominator = topk_weight.sum(axis=-1, keepdim=True) + 1e-20
            topk_weight = topk_weight / denominator * self.routed_scaling_factor
        else:
            topk_weight = topk_weight * self.routed_scaling_factor
        if self.training and self.alpha > 0.0:
            scores_for_aux = scores
            aux_topk = self.top_k
            topk_idx_for_aux_loss = topk_idx.reshape([bsz, -1])
            if self.seq_aux:
                scores_for_seq_aux = scores_for_aux.reshape([bsz, seq_len, -1])
                ce = paddle.zeros(shape=[bsz, self.n_routed_experts])
                ce.put_along_axis_(
                    axis=1,
                    indices=topk_idx_for_aux_loss,
                    values=paddle.ones(shape=[bsz, seq_len * aux_topk]),
                    reduce="add",
                ).divide_(y=paddle.to_tensor(seq_len * aux_topk / self.n_routed_experts))
                aux_loss = (ce * scores_for_seq_aux.mean(axis=1)).sum(axis=1).mean() * self.alpha
            else:
                mask_ce = paddle.nn.functional.one_hot(
                    num_classes=self.n_routed_experts, x=topk_idx_for_aux_loss.reshape([-1])
                ).astype("int64")
                ce = mask_ce.astype(dtype="float32").mean(axis=0)
                Pi = scores_for_aux.mean(axis=0)
                fi = ce * self.n_routed_experts
                aux_loss = (Pi * fi).sum() * self.alpha
        else:
            aux_loss = None
        return topk_idx, topk_weight, aux_loss


05 上手教程

5.1 DeepSeek-VL2在 PaddleMIX 里快速体验

通过解析代码我们也更深入地理解模型的实现细节和技术创新,快跟着我们的 aistudio 教程一起来动手实践一下吧!

  • AI Studio 教程链接:

aistudio.baidu.com/projectdeta…

我们以 DeepSeek-VL2-tiny 为例,在单卡 V100上需23G 显存可推理完成图像理解。 首先下载 PaddleMIX 代码库:

# clone PaddleMIX代码库
git clone https://github.com/PaddlePaddle/PaddleMIX.git

cd PaddleMIX


安装 PaddlePaddle:

# 提供三种 PaddlePaddle 安装命令示例,也可参考PaddleMIX主页的安装教程进行安装

# 3.0.0b2版本安装示例 (CUDA 11.8)
python -m pip install paddlepaddle-gpu==3.0.0b2 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/

# Develop 版本安装示例
python -m pip install paddlepaddle-gpu==0.0.0.post118 -f https://www.paddlepaddle.org.cn/whl/linux/gpu/develop.html

# sh 脚本快速安装
sh build_paddle_env.sh


安装 PaddleMIX 环境依赖包:

# 提供两种 PaddleMIX 依赖安装命令示例

# pip 安装示例,安装paddlemix、ppdiffusers、项目依赖、paddlenlp
python -m pip install -e . --user
python -m pip install -e ppdiffusers --user
python -m pip install -r requirements.txt --user
python -m pip install paddlenlp==3.0.0b3 --user

# sh 脚本快速安装
sh build_env.sh


5.2图像理解

运行以下命令即可:

# Deepseek-vl2-tiny multi image understanding
python paddlemix/examples/deepseek_vl2/multi_image_infer.py \
    --model_path="deepseek-ai/deepseek-vl2-tiny" \
    --image_file_1="paddlemix/demo_images/examples_image1.jpg" \
    --image_file_2="paddlemix/demo_images/examples_image2.jpg" \
    --image_file_3="paddlemix/demo_images/twitter3.jpeg" \
    --question="Can you tell me what are in the images?" \
    --dtype="bfloat16"


输出结果:

<|User|>: This is image_1:

This is image_2:

This is image_3:

Can you tell me what are in the images?

<|Assistant|>: The first image shows a red panda resting on a wooden platform. The second image features a giant panda sitting among bamboo plants. The third image captures a rocket launch at night, with the bright trail of the rocket illuminating the sky.<|end▁of▁sentence|>

06 总结

DeepSeek-VL2是一个基于 MoE 架构的前沿多模态大模型。通过引入动态图像切片编码策略,高效处理不同长宽比的高分辨率图像,大幅提升了视觉理解、视觉问答等任务的表现;其语言模型部分 DeepSeek-MoE 也通过压缩键值缓存的方式优化了推理速度和吞吐量。

百度飞桨团队推出的 PaddleMIX 套件现已完整实现这个热门模型的推理训练全流程支持,通过深入解析其代码实现,研究人员和开发者能够更透彻地理解模型的核心技术细节与创新突破。我们诚挚推荐您访问 AI Studio 平台的专项教程(点击以下链接🔗),通过实践演练掌握前沿多模态模型的开发与应用技巧。

▎论文链接

DeepSeek-VL: Towards Real-World Vision-Language Understanding

arxiv.org/pdf/2403.05…

DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding arxiv.org/pdf/2412.10…

▎项目地址

DeepSeek-VL2:github.com/PaddlePaddl…

▎AI Studio 教程链接

aistudio.baidu.com/projectdeta…

END

推荐阅读

秒哒首发即爆发!上线首日吸引2万用户,打造3万应用!

秒哒,全面开放!

图灵数据洞察平台-TDF(Turing Data Finder)

两连发!文心大模型4.5及X1,上线千帆!

百度百舸万卡集群的训练稳定性系统设计和实践

秒哒首发即爆发!上线首日吸引2万用户,打造3万应用!

作者 百度Geek说
2025年4月1日 09:57
3月24日,国内首个对话式应用开发平台百度秒哒全量上线,上线24小时就迅速吸引超2万用户体验,创建应用数量突破3万个,相当于每3秒就诞生1个应用! 秒哒以 "无代码编程+多智能体协作+多工具调用" 的

图灵数据洞察平台-TDF(Turing Data Finder)

作者 百度Geek说
2025年3月25日 11:03
导读 在数字化时代,企业对用户数据的挖掘和分析能力直接影响业务增长和竞争力。图灵数据洞察平台(TDF) 是一款面向企业的数据分析与用户增长平台,提供一站式的行为数据生产、用户行为分析、及广告效果评估等

百度百舸万卡集群的训练稳定性系统设计和实践

作者 百度Geek说
2025年3月18日 10:25

01 AI 训练稳定性的演进历程

2012 年 ImageNet 竞赛中 AlexNet 的横空出世,开启了现代 AI 发展的新纪元。彼时我们不会想到,十年后支撑 AI 训练的 GPU 集群会从研究室里的几台服务器,发展成需要专门供电系统的万卡级计算矩阵。在这个算力爆发式增长的过程中,训练系统的稳定性管理正经历着从「简单运维」到「精密工程」的深刻变革。

1.1 标早期的小模型时代:手动运维的黄金年代

2022 年之前的 AI 训练,更像是手工作坊式的精雕细琢。大多数训练任务只需十几块 GPU,利用 PyTorch 或 TensorFlow 的数据并行功能就能轻松应对。记得那时算法工程师们有个共识:如果训练遇到问题,重启往往比排查更高效。

当时我们构建的监控系统就像汽车仪表盘,只能显示最基本的任务状态。当训练意外中断时,工程师们会像侦探一样翻查日志 —— 如果发现是 GPU 报错,就联系运维同事。运维人员则带着「NVIDIA三件套」(nvidia-smi、dcgm、nsys)到机房巡检,像老中医把脉般通过温度、功耗等指标判断硬件状态。这种工作模式虽简单,但应对数十卡规模的集群还算游刃有余。

1.2 大模型风暴:从量变到质变的冲击

ChatGPT 的登场如同打开潘多拉魔盒,将 AI 训练带入新的纪元。当我们开始部署千卡/万卡集群时,才发现原有的运维体系就像用小渔网捕鲸鱼 —— 完全无法匹配新需求。

让我们通过百度百舸经历过的一个真实案例来深入理解这个问题:

2024 年初,百度百舸帮助一家 AIGC 创业公司迅速将其训练规模从百卡扩展到千卡级别。然而在训练数天后的某个周末凌晨,训练进程意外发生了 hang 死。由于当时缺乏有效的故障感知和容错机制,直到第二天算法工程师发现任务超时退出时,已经耽误了数小时宝贵的训练时间。更糟糕的是,任务日志中除了简单的 timeout 报错外毫无线索,平台监控也显示所有训练节点状态正常。

着急恢复训练的算法工程师没有立即上报问题,而是选择直接重新提交任务。但不幸的是,新任务运行数小时后再次出现相同的超时退出。这时他们才不得不寻求技术支持,但值班工程师面对这种任务 hang 死的问题也缺乏诊断经验,只能通过二分法慢慢定位。最终发现是某个节点的静默故障(SDC)导致了训练进程假死。等问题得到解决时,距离首次故障已经过去将近 30 小时,这意味着损失了价值巨大的千卡算力资源。

02 百度百舸集群训练稳定性全景图

站在现在的时间点回望,AI 训练稳定性已从辅助功能演变为核心基础设施。就像现代建筑中的抗震结构,它虽不直接参与空间构成,却是万丈高楼得以屹立的关键。当行业向着数万卡集群迈进时,这套隐形护甲的质量,将直接决定 AI 进化的速度与边界。

在 2024 年百度百舸对训练过程的生命周期进行了更细致的拆分,提出了「无效训练时间」这一关键指标,并致力于将其最小化。具体来说:

任务无效训练时间 = 故障中断次数 × 任务故障恢复时长 + 任务常态写 Ckpt 总时长

其中,任务故障恢复时长 = 故障感知召回耗时(自动/人工定位)+ 任务调度耗时 + 任务初始化耗时 + 任务重算时长。

通过这个公式可以看出,要降低无效训练时间,需要「围绕基础设施稳定性」、「任务容错」两个维度来系统展开,重点解决三个方面的问题:

  • 提高基础设施的交付质量。

  • 提高任务故障容错的召回率、准确率和时效性。

  • 优化 checkpoint 机制,减少保存时间和恢复时的重算时间。

经过容错架构的整体变革,百度百舸形成了从 「任务负载 — 框架 — 通信 — 基础架构」全链路的自动异常感知、诊断、恢复能力,可覆盖 90%+ 的训练异常场景,时效性最快可以实现秒级异常感知、分钟级定位,以及平均 3 分钟的故障自愈能力。

图片

03 基础设施交付质量保障

基础设施的交付质量保障是稳定性的基础。

CPU 时代,机器的交付前可能仅会跑一些常规的 CPU 计算、网络的压力测试,并不会从业务视角去评估基础架构,机器交付后硬件异常的故障频率相对较少。有硬件故障时,通常走工单系统人工换机用户相对是可接受的。

而 GPU 时代,AI Infra 的交付则需要考虑 CPU、GPU、RDMA 网络、存储,甚至机房的功率、温度等各方面因素,遗漏任何一个环节都会成为后续稳定性的隐患。在交付给客户后,机器也可能会由于长时间的高负载运行频繁出现硬件故障,而 GPU 机器的高昂成本,使客户对节点故障感知、换机的时效性提出了非常高的要求。

图片

因此百度百舸对 GPU 机器交付前及交付后的稳定性质量进行了系统性管理:

  • 交付前,百度百舸会对机器进行 200 多项指标检测,然后进行 48 小时烤机,以及 NCCL-Test 的机内、机间的大环、同号卡通信性能基准测试,端到端的大模型训练、推理性能基准测试。

  • 交付后,需要能够实时的感知节点故障及定期巡检,并具备分级处理的自愈能力,例如 Error 级别的故障实现自动排水、重启,Fault 级别故障实现自动换机。

04 任务容错的准召率保障

任务层面稳定性最核心的就是做好容错,能够让业务在无论遇到何种故障时都能快速恢复。

那么,首要的工作就是我们能够准确的识别出异常,然后对故障进行诊断定位,最后能够自动化的从异常中恢复。

因此,任务容错需要能够从端侧(即每个训练 worker)探测到进程与环境的各类异常,同时有个中心服务(Master)从任务全局的视角去诊断、定位异常,最终做出相应的决策来使任务能够快速从异常中恢复。

图片

任务容错最重要的就是提升故障的召回率与准确率,即如何能够尽可能的准确识别、定位所有故障。我们将故障分类两类:显式故障和隐式故障。

  • 显式的故障通常比较容易召回,我们将实践积累的各种进程异常状态及各类报错pattern形成专家知识库,再结合硬件感知服务(HAS Agent)的硬件全链路 10 秒级监控能力,可以实现显式故障的召回率达到 95%+。

  • 隐式的异常则往往很难轻易的识别,例如训练进程 hang、慢节点就是典型的隐式故障,需要丰富的经验积累才能准确的识别出异常。

下面我们就以最典型的隐式故障场景 —— 训练进程 hang 死为例,来看下如何能够做好 hang 自动感知、诊断。

4.1 训练****hang 的自动感知

训练任务发⽣ hang 之后,绝⼤多数情况都会以 timeout 的⽅式报错并退出进程,最常⻅的就是在通信过程中如果发⽣ hang,NCCL 的 watchdog 会中断通信,并有报如下 timeout 报错,然后再由 pytorch 的 torchrun 进程感知并中断训练过程。

[E ProcessGroupNCCL.cpp:828] [Rank 1] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=15173, OpType=ALLREDUCE, Timeout(ms)=1800000) ran for 1802710 milliseconds before timing out.
[E ProcessGroupNCCL.cpp:828] [Rank 0] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=15173, OpType=ALLREDUCE, Timeout(ms)=1800000) ran for 1802713 milliseconds before timing out.


Pytorch 默认为 10 分钟 NCCL 通信超时,而 Megatron-LM 为 30 分钟。在万卡规模训练场景中,意味着一万张卡要至少浪费 30 分钟才能被发现。这个时效性是不可接受的。而且当 30 分钟超时后程序会立马退出,很难有机会进行下一步定位,需要一些时效性更高的感知机制,并且在程序退出前获取一些有效信息供后续诊断分析。

很多公司、实验室在面对 hang 的问题时,会在采用框架层插桩的方式来 trace 训练进程,这种方式通常是比较直接且准确的,但是有比较强的侵入性,而且可能还会有一些性能开销。对于云厂商来说,需要寻找对用户更透明、更无损的方式来感知、定位 hang 异常。

如何感知训练 hang,以百度百舸的产品设计思路为例,我们可以从以下几个方向去思考:

  1. 训练进程 hang 的最直观表现是什么?

    人工判断一个任务是否 hang 了,最直接的方式就是看是否所有 worker 的任务日志一段时间内都不输出日志了,所以 hang 自动感知的第一种方法就是采集所有 worker 的日志,并判断所有 worker 日志中最后一行日志是否为 x 分钟前的(x 小于 Pytorch 的通信超时时间,例如 8 分钟),如果是则基本可以判定为 hang。

  2. 任务 hang 时进程有什么样的表现?

    任务 hang 时,可能进程的调用栈都不在发生变化,进程的调用栈可以通过 py-spy/pystack 等工具进行探测,所以我们可以用此类工具对所有训练任务进行一个定时采样,当采集 n 个样本所有进程栈都没有变化时,可以判定一次 hang,这种方式通常可以将 hang 感知缩小至 3~5 分钟。

  3. 任务 hang 时监控指标有哪些变化?

    训练进程中的 CUDA 算子计算、集合通信操作通常都是在毫秒,甚至微秒、纳秒内完成的,当任务在正常迭代过程中发生了 hang,我们常遇到的情况是所有 rank 的 RDMA 流量会降到 0,而 GPU 的利用率为 100%、SM 利用率则在很低的水位。如果持续几分钟都是这种状态时,意味着训练进程已经计算完成,在等着集合通信完成,这种情况下基本可以判定为 hang。

  4. 是否能在通信库中更快的感知通信 hang?

    通常单次集合通信操作都是在 ms 级的,如果一次操作在 30 秒钟都没有完成,那就可以判定为通信 hang 死了。百度自研的 BCCL 集合通信库层可以对每一次集合通信操作都进行打点,来实现通信 hang 感知。

上述几种方法,我们可以分别实现一种探针,来抓取相应的特征到中心端 master 组件进行下一步诊断和容错决策。

百度集合通信库 BCCL是百度智能云推出的一款面向大模型训练场景优化的集合通信库。

BCCL 基于开源的 NCCL 进行了功能扩展和能力增强,针对大模型训练场景在可观测性、故障诊断、稳定性等方面进行优化,进一步提升集合通信库的可运维能力。相比 NCCL,BCCL 的关键特性如下:

* 可观测性:新增集合通信带宽实时统计能力;

* 故障诊断:新增集合通信 hang 时的故障诊断能力;

* 稳定性:增强网络稳定性和故障容错能力;

* 性能优化:提升大模型训练主流 GPU 芯片的集合通信性能。

4.2 训练 hang 的自动诊断

有了以上感知手段,我们需要进一步的诊断、定位,来确定是否真的发生了 hang,以及 hang 的具体位置。具体的来讲,master 收集到各类 agent 的数据后,会做一些综合分析:

  1. 是否真的发生了 hang?

    感知阶段各种探针只能探测到 hang 的一种特征,并没有办法 100% 的确定是否真的 hang 住了,事实上不侵入用户进程是很难做到 100% 确定 hang 的。因此,为了提高 hang 的判定准确率,我们需要将各种特种综合起来判断,探针上报到 master 后,由一个 hang 诊断模块,按照一个时间窗口(例如 5 分钟),进行综合判断。如果在时间窗口内日志、监控、进程调用栈、通信库中有 2 条以上都处于不处于活跃状态时,我们判断任务真正发生了 hang。

  2. hang 的具体发生的位置?

    确定任务 hang 了之后,我们需要找到 hang 所在的节点来对它进行隔离。因此诊断模块需要在探针上报的数据中进一步找寻特征,来确定 hang 发生的位置:

  3. BCCL Tracehang 诊断:在感知阶段,BCCL 可以在通信库层面对所有 rank 的通信进行打点。如果有节点一直未完成通信则是发生了 hang。但是此节点可能并非真正发生 hang 的源头,有可能是在等待其他节点完成通信。诊断模块可以根据 BCCL 打印的通信组信息,进行交叉判断,如果某个节点在多个通信组中都未完成通信,那这个节点就是 hang 的源头。

  4. RDMA/GPU 指标诊断:上文中我们提到,通信阶段发生 hang 之后,所有 rank 的 RDMA 流量都会降到 0,而同时绝大部分 rank 的 GPU 利用率持续为 100%,只有某一两个 rank 的 GPU 利用率为 0,那这个 rank 很有可能是 hang 的源头。

  5. 进程调用栈诊断:进程调用栈也可以作为一个 hang 源头诊断的重要参考。当发生 hang 之后,绝大部分的 rank 都要么处于 barrier 等待状态,要么处于通信等待阶段。只有个别的 rank 卡在其他函数上,那么通过对比分析,可以将调用栈与其他 rank 不同的节点初步判定为 hang 的源头。

  6. 综合诊断:上面 3 种特征为我们提供了 hang 的诊断依据,将 3 者关联起来分析后,我们基本上可以比较准确的确定一个具体的 hang 的源头,再结合硬件故障感知的相关信息可以进一步明确根因。

4.3 基于 eBPF 的隐式故障感知与诊断

在复杂的大规模分布式训练场景中,传统用户态监控往往难以捕获系统内核层面的异常事件。

百度百舸基于 eBPF(Extended Berkeley Packet Filter)技术的隐式故障感知体系,能够在不侵入用户代码的前提下,对训练进程的系统调用、网络通信、CPU 调度等内核态行为以及训练框架关键函数运行时间建立立体观测能力。

eBPF 探针部署原理通过在内核关键路径注入轻量级探针,实现低开销的系统级行为捕获。针对训练场景特点,主要聚焦 4 类事件跟踪:

  • 训练关键函数跟踪:微秒级跟踪训练过程中,前向计算、反向计算、集合通信操作等关键函数执行耗时,记录函数间调用关系。

  • 进程调度阻塞跟踪:挂钩 sched_switch 事件,检测进程在 TASK_UNINTERRUPTIBLE 状态持续时间,当单次持续超过阈值(如 5 秒)时捕获调用栈。

  • CUDA 运行时 API 监控:通过 uprobe 在 libcuda.so 等关键库注入探针,记录 CUDA API 调用耗时分布。

  • RDMA Verbs 级通信监控:在 ibv_post_send/ibv_poll_cq 等核心通信接口设置观测点,统计通信时延分布。

结合上面 4 类事件,完成以下 2 类数据分析:

  • 单体异常探测基线与实时数据对比。

  • 群体一致性检测。采用卡间对比算法,当某一 rank 的以下指标偏离集群中位数超过阈值时判定异常,包括系统调用频率、进程就绪队列等待时长、NVLink/RDMA 带宽利用率等。

基于以上所述方法,百度百舸针对以下 2 类典型的隐式故障进行诊断:

  • 训练 hang 根因定位。通过关联 eBPF 捕获的多维度数据进行如下操作:

  • 当检测到某 rank 的 GPU  Kernel 执行出现分钟级空跑(SM 利用率 > 70% 但无有效计算输出)。

  • 同时伴随该节点 RDMA QP 状态停滞(ibv_poll_cq 无新完成事件)。

  • 内核调度器显示进程处于 D 状态超过阈值。

  • 性能抖动溯源。基于 eBPF 火焰图、时序图等进行分析:

  • 抓取发生性能下降时段的 CPU on-cpu/off-cpu 堆栈。

  • 对比正常时段数据,识别出异常的锁竞争(futex 调用占比上升)。

  • 结合 NUMA 内存访问统计,定位跨 NUMA 内存访问导致的 TLB 颠簸问题。

此类技术已在百度百舸的万卡规模训练集群中验证,相比单纯依赖应用层监控的方案,将隐式故障的平均检测时间从分钟级缩短至秒级,诊断准确率提升 40% 以上。

通过与既有硬件故障感知服务、BCCL 通信库监测体系联动,百度百舸形成了覆盖从硬件到系统内核再到应用层的立体化诊断能力。

05 任务故障恢复的时效性保障

故障恢复的时效性也是容错能力的一个重要指标,反映的是任务从故障发生到再次重新进入训练迭代的时间,恢复效率越高则算力浪费越少。影响到任务恢复效率有 2 个重要因素,一是任务平均中断时间,二是训练重算时间。

5.1 多级重启策略减少故障中断时间

任务发生异常后,上文中我们提到需要经过故障自动感知、诊断和自愈等 3 个环节,那么减少中断时间的核心思想,就是尽可能的缩短这 3 个环节的时间,通过多维度的感知、诊断手段可以将故障发现、定位的时效性降低至分钟级甚至秒级。自愈则需要能够根据不同的诊断结果进行分级恢复和故障屏蔽的能力:

  • 单点显式故障:重调度异常节点(replace),对节点进行集群级别屏蔽。

  • 单点隐式故障:重调度异常节点,对节点进行任务级别屏蔽。

  • 非单点故障:原地重启尝试恢复(restart),无法恢复时重新调度所有节点(resubmit)。

通过多级重启策略,尽可能避免单点故障引发全部节点的重新调度。在万卡级别的训练场景中,百度百舸将大部分训练异常场景恢复时间从过去的 30min 缩短至现在的 30s 内,成功率到 95%+。

5.2 触发式 checkpoint 减少训练重算时间

除了上述的多级任务重启策略外,另一个提高任务故障恢复效率的重要手段就是减少训练重算时间。在探讨具体技术方案之前,我们先来看看目前主流的 checkpoint 保存策略。

传统的 checkpoint 保存通常采用固定间隔策略,比如每隔 N 个 step 或每隔 T 小时保存一次,这种方式实现简单但缺乏灵活性,可能会产生大量冗余存储,同时在故障发生时可能会损失较多训练进度。

而触发式 checkpoint 则是一种更智能的方案,它根据特定条件或异常事件(如故障、显存不足、显式指令等)动态触发模型状态保存。其核心目标是通过灵活的控制保存时机,减少不必要的存储开销和训练中断时间,从而降低因频繁或冗余保存导致的重算时间浪费。

随着大模型训练规模的扩大,还有一种更激进的「零重复 checkpoint」技术,即在每个训练 step 都保存一次 checkpoint。这种方案的优势在于可以将重算时间降到最低,确保故障发生时能够从最近的 step 恢复,几乎不会损失训练进度。但其显著的缺点是存储开销巨大,即使采用增量式存储,仍然需要相当大的存储空间和 I/O 带宽。此外,频繁的 checkpoint 操作也可能影响训练性能。

相比之下,触发式 checkpoint 走的是一条平衡之路。我们来看下它实现的几个核心要点:

  • 集成容错:训练进程集成容错的故障感知与定位机制,在进程退出前自动触发保存。这种主动感知机制能够在故障发生的第一时间保存训练状态,最大限度减少进度损失。

  • 高速转储:异步 checkpoint 保存机制会将 checkpoint 暂存到共享内存中,再由外部程序转储至磁盘。当某个节点异常时,容错组件会拉起新节点,并在新节点训练进程启动前,利用 RDMA 技术实现 checkpoint 快速从故障节点转储至新节点,这大大减少了从远程存储拉取 checkpoint 的时间。

  • 冗余备份:触发式 checkpoint 也并非完美无缺,例如在节点发生内核 crash 等严重故障时,可能无法触发自动保存。因此,需要通过定期的冗余备份机制进行兜底,确保 checkpoint 不会完全丢失。

实践表明,当触发式 checkpoint 与异步、增量式的 checkpoint 机制结合使用时,可以在保证数据安全性的同时,显著提高 checkpoint 保存效率,减少训练重算时间。

相比零重复 checkpoint 的重型方案,触发式 checkpoint 提供了一个更实用的折中方案,在合理的存储开销下实现较好的容错效果。当然,具体选择哪种方案,还需要根据实际的训练规模、硬件条件和可用资源来权衡。

随着分布式训练规模的持续增长,相信未来会出现更多创新的 checkpoint 方案,比如基于预测的主动保存策略、多级存储架构的智能调度等,这些都将为提高大规模训练的可靠性提供新的可能。

06 业务发展对稳定性的要求

AI 训练的稳定性管理已经演变为智能时代的精密工程。从最初靠人工重启解决问题的摸索阶段,到如今能自动感知异常、快速恢复的智能系统,每一次进步都映照着算力规模的跨越式发展。

让人不禁思考,在未来十万卡集群的算力洪流中,或许会出现更精妙的动态平衡方案:既能像鹰隼般敏锐捕捉故障征兆,又能如雁群迁移般智能调度资源,在秒级恢复与 PB 级存储成本之间找到新的平衡支点。

目前百度百舸支持厂内千卡和万卡集群有效训练时长已经可达 99.5%,为客户大模型的预训练保驾护航,比如国内第一个数学大模型——九章算术,国内第一个类 Sora 大模型 —— Vidu 等。

----------END----------

推荐阅读

LLM增强语义嵌入的模型算法综述

持续推进“人工智能+”行动,百度智能云+DeepSeek为何成为国有企业首选?

GPU 云服务器的软件系统设计和实践

基于Flink的配置化实时反作弊系统

百度智能云xDeepSeek,最具性价比的DeepSeek一体机合集来了!

LLM增强语义嵌入的模型算法综述

作者 百度Geek说
2025年3月13日 10:56

导读

语义嵌入是自然语言处理、信息检索、推荐系统等领域的核心技术,对于精准捕捉文本深层次语义信息至关重要。近年来,大语言模型(LLM)的兴起为语义嵌入技术开拓了新的方向。本文介绍了LLM在提升语义嵌入效果的最新模型与算法,聚焦在如何利用LLM生成合成数据以及如何作为模型骨干来优化语义嵌入。文章概述了当前研究的主要方向和先进成果,展示了LLM在学习语义嵌入方面的独特优势,并展望了其在搜索、推荐等下游任务的广阔应用前景。

01 背景介绍

1.1 语义嵌入

文本语义嵌入,作为将文本映射到语义空间的关键技术,通过将原本高维且稀疏的向量转化为低维稠密向量,实现了对单词、句子乃至整个文档深层次语义信息的精确捕捉。这一技术在信息检索、问答系统、文本相似度计算及推荐系统等自然语言处理(NLP)的诸多任务中展现出广泛的应用价值。

早期语义嵌入方法,诸如 Word2vec 和 GloVe,主要基于统计特性构建,然而,这些方法受限于其静态性,难以充分捕捉自然语言复杂多变的上下文信息。随后,BERT 及其衍生的一系列上下文敏感模型(如 RoBERTa、DistilBERT、ALBERT 等)应运而生,通过独特的模型增强与优化策略,不仅保留了双向编码的核心优势,还显著提升了语义嵌入对上下文信息的感知能力。此外,Sentence-BERT 模型的提出,通过引入连体网络(Siamese Network)和三重网络(Triplet Network)结构,实现了高效的句子级嵌入生成。近年来,随着对比学习框架的兴起,如 SimCSE 等方法利用标准 dropout 作为噪声源,无需额外监督数据即可生成高质量的句子向量,进一步推动了语义嵌入技术的革新与发展。

当前研究热点聚焦于通用文本嵌入技术的优化,通过引入多阶段训练范式和复杂的数据混合策略,如 E5[1]、BGE[2]、GTE[3] 等模型,在数据规模、质量及多样性方面取得了显著进展。随着大语言模型(LLM)的蓬勃发展,利用 LLM 生成语义嵌入成为新的研究方向。研究者们通过合成高质量训练数据以提升嵌入性能,或直接以 LLM 作为模型主干生成嵌入,显著增强了语义嵌入的鲁棒性和泛化能力,为 NLP 领域的未来发展探索出了新的道路。

1.2 大语言模型(LLM)

LLM 作为一种规模宏大的预训练语言模型,通常具有数亿乃至数十亿之多的参数,经由海量数据的训练,已具备理解和生成更为繁复且丰富文本内容的能力。随着模型规模的不断扩张与数据量的显著增加,LLM 已能极为娴熟地应对众多下游自然语言处理任务。凭借其强大的表达能力和出色的泛化性能,LLM 能够应对各类自然语言处理任务,并在诸多场景下展现出超越传统机器学习方法的卓越表现。“预训练+提示”作为 LLM 的第四范式,开创了一种引导生成输出以匹配多样化下游任务需求的新颖路径。在此范式下,模型的适应不再单纯依赖微调,而是通过引入“提示”这一文本或模板元素来引导生成过程,旨在促使模型在接收任务时能够有效唤醒预训练阶段所学到的知识,并据此精准地生成符合任务特定要求的输出。诸如 LLaMA-2[4]、LLaMA-3[5] 及 Mistral[6] 等开源 LLM 模型已取得了显著成效,它们不仅推动了 LLM 在语义嵌入领域的广泛应用,更掀起了利用 LLM 进行语义嵌入研究的热潮。

LLM 语义嵌入与传统语义嵌入之间的对比:

综上所述,使用 LLM 进行语义嵌入与传统语义嵌入(如使用BERT)在模型结构与训练方式、嵌入质量、应用场景等方面都存在显著差异。这些差异使得 LLM 语义嵌入在复杂的 NLP 任务中表现出更强的性能和适应性。下文将介绍一些当前主流的 LLM 语义嵌入方法。

02 算法解读

随着 LLM 的广泛应用,出现了一些利用 LLM 来生成语义嵌入的尝试。Jiang等人[7] 首次提出了基于提示(prompt)的句子嵌入方法,结合对比学习框架,通过设计如 “[X] means [MASK]” (其中,[X] 表示一个 placeholder,对应一个句子,[MASK] 则表示待预测的 token)的模板捕捉句子表征,并借助模板去噪避免语义偏向。随后,Zeng等人[8] 提出了 Prompt-derived Virtual semantic Prototypes(ConPVP)的对比学习方法,利用提示构建虚拟语义原型及否定原型,通过原型对比损失优化句子嵌入。Cheng等人[9] 则进一步提出了基于AI反馈(CLAIF)的句子嵌入对比学习方法,利用来自 LLM 的AI反馈来构建具有细粒度样本相似性分数的样本对,提升句子嵌入的监督对比学习的效果。

当前,利用 LLM 提升语义嵌入的研究热点聚焦于合成数据模型骨干两大方向,如图 1 所示。下面将具体介绍各方向的一些代表模型。

图片

△图1: LLM 提升语义嵌入的算法模型梳理

2.1 合成数据

利用 LLM 进行数据合成正日益受到业界的广泛关注,该方法能够显著提升模型在处理多任务及多语言环境下的能力多样性,从而训练出更为强健的语义嵌入模型,可广泛应用于各类下游任务中。具体而言,LLM 在生成高质量、多语言、多任务合成数据方面展现出巨大潜力。例如,通过将 LLM 作为数据注释工具,可以高效地标注伪监督数据以强化模型训练效果;利用如 GPT-4 等先进的 LLM,可以生成覆盖广泛语言范围及多种语义嵌入任务的合成数据,极大地丰富了训练数据的多样性;此外,合成数据还被用于从大模型中提取知识并融入检索系统中。接下来,本文将重点介绍在 MTEB 基准测试中表现突出的几个典型语义嵌入模型,包括 E5-mistral-7b-instruct[10] 混合真实与 LLM 合成数据进行微调、SFR-Embedding-Mistral[11] 采用改进的难负样本进行多任务微调的方法,以及 Gecko[12] 采用两步蒸馏法将LLM知识融入检索器的技术。

2.1.1 E5-mistral-7b-instruct

【主要贡献】

微软的研究团队提出的语义嵌入训练方法,无需复杂的流程设计或人工构建的数据集,只需要利用 LLM 来合成多样化的文本数据,就可以为93种语言的数十万文本嵌入任务生成高质量的语义嵌入,整个训练过程还不到1000步。

实验结果证明,当仅对合成数据进行微调时,Mistral-7B 在 BEIR 和 MTEB 基准上获得了非常有竞争力的性能;当同时加入合成和标注数据进行微调时,即可实现 SOTA 性能。

【算法概述】

  • 数据合成:

为了生成不同的合成数据,提出了一种简单的分类法,将嵌入任务分为几个组,然后对每个组应用不同的提示模板。如图 2 所示,对于每个组,该算法设计了一个两步提示模板,首先提示 LLM 生成一系列的任务,然后为每个任务生成(用户查询、正样本、难负样本)三元组。“{...}”表示一个占位符,将在其中填入从预先定义的一组值中随机选取的值。

为了覆盖不同的应用场景,该算法为每个任务类型设计了多个提示模板,并将不同模板生成的数据进行组合。为了进一步提高合成数据的多样性,在每个提示模板中加入了几个占位符,在运行时随机采样,例如 {query_length} 是从集合 {少于5个单词,5-10个单词,至少10个单词} 中采样的。

图片

△图2: E5-mistral-7b-instruct 数据合成两步提示模板

  • 训练阶段:

给定一个预训练的 LLM,在查询和文档的末尾添加一个 [EOS] 标记。最后一层 [EOS] 向量被用作语义嵌入。为了帮助模型适应不同的任务,在生成新的查询时,可以使用统一的指令模板,给定相关的查询-文档对(q+,d+)(q^+, d^+),先使用原始查询 q+q^+ 来生成一个新的指令qinst+q_{inst}^+,其中 {task_definition} 是嵌入任务的一句话描述的占位符:

图片

最后,选择预训练的开源 LLM Mistral-7B 模型,在对一组混合的合成和标记数据(包含 13 个公开数据集)进行采样后进行微调。

2.1.2 SFR-Embedding-Mistral

【主要贡献】

用改进的难负样本对 E5-mistral-7b-instruct 进行多任务微调,将性能提高了0.93%。主要结论有:

  • 语义嵌入与聚类任务集成后检索性能显著提高,并通过多任务知识转移进一步增强检索性能。此外,通过采用多任务训练并使模型适应特定任务,可以增强泛化能力。

  • 采用任务同构批处理,即同个batch里的所有样本来自于同个任务,这样可以保证对比学习的 in-batch negatives 更具挑战性。

  • 之前的难负样本挖掘方法都是先通过检索将排序靠前的文档作为难负样本,这样有可能混入部分错误的负样本,影响模型训练结果。该方法发现使用排序在30-100之间的文档作为难负样本能提升模型性能,而使用排序在0-100之间的文档则容易引入错误的负样本,使用排序在50-100之间的文档则缺乏训练难度。

2.1.3 Gecko

【主要贡献】

Gecko 提出的主要思想:从 LLM 中提取知识到检索器中。使用两步蒸馏过程:首先使用 LLM 生成不同的任务-查询对数据。接下来通过为每个查询检索一组候选段落,并使用相同的 LLM 重新标记正样本和难负样本段落,进一步改进数据质量。

图片

△图3: Gecko 整体流程概述

Gecko 选用 gtr-t5-xl (1.2B, encoder from T5-3B model) 模型骨架。通过将 LLM 生成的和经 LLM 排序的数据,与人工标注的数据相结合,Gecko 模型在 MTEB 基准上实现了较好性能。

算法概述】

该方法利用知识蒸馏的思想,创建了一个两步骤的 LLM 驱动的嵌入模型。

  • 多元查询生成

如图 4 所示,首先向 LLM 中输入一段网络文章节选,让其生成任务描述和任务的相关查询:

图片

其中 pseedp_{seed} 是从web语料库中随机抽取的一个段落,而 PQGP_{QG} 是一个固定的提示符。对于每个示例来说,提示模板是相同的,并且由几个示例和说明组成。LLM 生成一个任务描述 t(描述了检索的类型,如问答或事实检查)。通过对这些任务描述进行抽样,可以指导 LLM 生成与任务一致的查询 𝑞。

  • 正负样本挖掘

首先,给定生成的查询 𝑞,使用一个嵌入模型来检索最相关的段落。然后,使用 LLM 根据检索到的段落与查询的相关性对它们进行排序。排序方法采用的是查询似然(query likelihood)和相关性分类(relevance classification)这两个少样本提示的 LLM 排序函数。最后将两种不同提示结果的排名与标准的倒数秩融合(RRF)方法集成在一起,获得排名函数𝑅(𝑞,𝑝),并根据排名找到更多相关的正样本以及生成查询的难负样本。

图片

△图4 :两步检索流程

2.2 模型骨干

另一类主流方法是将 LLM 作为语义嵌入的主干网络,原因在于它们无需遵循现有语义嵌入模型中普遍采用的对比预训练步骤,使得 LLM 在训练过程中能够更加灵活地处理文本数据。得益于全面的自回归预训练,LLM 能够充分捕捉到文本中的上下文信息和语义关系,具有出色的文本表征能力,并且仅需最少的微调即可转化为高效的通用文本嵌入模型。

同样,后续内容将着重介绍在 MTEB 基准测试中表现优异的几个语义嵌入模型。其中,NV-Embed-v2[13] 模型通过关注潜在向量并采用两阶段对比指令调优方法来提升性能;BGE-EN-ICL[14] 模型则利用LLM中的 in-context learning 能力来优化语义嵌入的生成;Echo-mistral[15] 模型采用双向注意机制,通过重复输入并提取第二次出现的嵌入来增强效果;LLM2Vec[16] 模型同样采用了双向注意力机制,还结合掩码下一个token预测以及无监督对比学习来提升嵌入效果;GRIT[17] 模型通过训练LLM和指令,实现了生成和嵌入任务的统一处理;GTE-Qwen1.5-7B-instruct[18] 模型则利用双向注意力机制、查询侧指令调优,并融合了弱监督与监督数据进行训练;最后,stella_en_1.5B_v5[19] 模型简化了提示的使用,为大多数通用任务提供了序列到段落(s2p)和序列到序列(s2s)两种便捷的提示方式。

2.2.1 NV-Embed-v2

【主要贡献】

一个通用文本嵌入模型,NV-Embed-v2 提出了几个新的设计,包括让 LLM 关注潜在向量以获得更好的池化嵌入输出,并展示了一种两阶段指令调优方法以提高检索和非检索任务的准确性。此外,NV-Embed-v2 采用了一种新的难负样本挖掘方法,该方法考虑了正样本的相关分数,以更好地去除假负样本。

基于预训练的 Mistral-7B 模型进行训练,该模型在大规模文本嵌入基准(MTEB基准)(截至2024年12月3日)中排名第一,在56个文本嵌入任务中得分为72.31。

【算法概述】

  • 模型架构

提出了一种潜在注意层来获得一系列 token 的池嵌入。如图 5 所示,将解码器最后一个隐藏层表示为查询 Q,然后结合潜在数组 K = V(可训练的“字典”),用于获得更好的表示。该交叉注意的输出是:

图片

最后通过一个正则 MLP 层和平均池化来获得整个序列的嵌入。

为了进一步增强表征学习,在 decoder-only 的 LLM 对比训练过程中去掉了因果注意掩码,从而缓解了单向注意力对模型表示能力的限制。

图片

△图5: NV-Embed-v2 模型架构

  • 模型训练

引入了一种两阶段的对比指令调优方法。第一阶段利用批量负样本和精选的难负样本,在多种检索数据集上利用指令进行对比训练。在第二阶段,该算法在检索和非检索数据集的组合上执行对比指令调优。由于同一批次内的负样本可能会误导非检索任务,该算法在第二阶段不采用 in-batch negatives 方案。这种设计不仅提高了分类、聚类和语义文本相似度任务的准确性,而且显著提高了检索性能。

2.2.2 BGE-EN-ICL

【主要贡献】

利用 LLM 中的in-context learning(ICL)能力来增强语义嵌入生成的过程。BGE-EN-ICL 模型使用少量示例来生成高质量的语义嵌入,直接将与任务相关的示例集成到查询端,从而在多种任务上取得了显著的改进。此外,还研究了如何有效地将 LLM 用作嵌入模型,包括各种注意力机制、池化方法等。

该模型采用 Mistral-7B 作为模型骨架,研究结果表明,保留原始框架往往能获得最佳结果。在 MTEB 基准测试上的实验结果目前排名第二。

【算法概述】

  • 上下文学习增强嵌入模型

图片

△图6: 基于ICL的模型体系结构

通过少样本对比训练实现 ICL 增强嵌入模型。考虑嵌入任务中的一个查询-段落对(q_i,p_i)(q\_i , p\_i ),首先构建一个示例模板如下:

图片

“task definition”表示特定嵌入任务的描述(图 6)。对于一个相关的查询-段落对(q+,p+)(q^+, p^+),修改后的查询构建如下:

图片

  • 表征方法

该方法认为在嵌入微调过程中引入双向注意力与模型的预训练设计不匹配,可能会破坏其上下文学习和生成属性。为了保留特定任务的嵌入表示与生成属性,与大多数现有的嵌入方法一样,该方法保留了单向注意力机制。具体来说,在输入修改后的查询和段落的末尾添加一个 [EOS] 标记,以通过因果注意力机制捕捉语义和上下文学习模式,然后将它们输入到 LLM 中,通过提取最后一层的 [EOS] 向量来获得嵌入。训练过程中采用标准的 InfoNCE 损失函数,同时利用 in-batch negatives 和 hard negatives。

  • 基于上下文学习的指令微调

实验表明,如果在训练过程中一直提供示例,可能会降低模型的零样本推理能力。因此,该方法提出了一种动态训练过程。即在每个训练步骤中,查询会被提供数量可变(0 到 n)的少量样本,这种方法在 ICL 能力和零样本性能之间取得了平衡。

2.2.3 Echo-mistral

【主要贡献】

自回归模型中由于存在因果注意力掩码,会导致token嵌入无法包含出现在输入中较靠后的token的信息。为了解决这一限制,Echo-mistral 模型中设计了 “Echo embeddings”(如图 7 所示),即使用双向注意:重复两次输入并从第二次出现中提取嵌入。原则上,第二次出现的语境化嵌入可以关注第一次中呈现的整个句子。此外,需要在 LLM 的提示信息中包括如“重写”或“重述”等词,从而尽可能确保第二次真的“编码”了关于第一次的信息。实验表明,Echo嵌入可以编码靠后token的信息,从而最大限度地利用 LLM 进行嵌入。

在 MTEB 排行榜上,Echo嵌入比传统嵌入提高了9%以上,在微调后提高了0.7%左右。与之前没有利用合成微调数据的开源模型相比,Mistral-7B 模型的Echo嵌入也有较大提升。

图片

△图7: Echo嵌入概念介绍

2.2.4 LLM2Vec

【主要贡献】

与 Echo-mistral 模型的思想类似,语义嵌入任务中解码器模型的因果注意力机制,限制了从整个输入序列中获取并创建双向上下文表示的能力。因此,为了改进 decoder-only 获得的语义嵌入,LLM2Vec 提出了一种简单的无监督方法,可以将任何 decoder-only LLM 转换为强大的文本编码器,如图 8 所示,只需三步即可:1)启用双向注意力机制(bidirectional attention);2)掩码下一个token预测(masked next token prediction);3)无监督对比学习(unsupervised contrastive learning)。

图片

△图8:LLM2Vec的三个步骤

LLM2Vec 选择 Llama-3 和 Mistral-7B 作为模型骨架,实验结果和广泛的分析表明,能够以参数高效的方式将 LLM 有效地转变为通用文本编码器,而无需额外的调整或利用 GPT-4 合成的数据。

【算法概述】

  • 双向注意力机制

用全1矩阵替换 decoder-only LLM 的因果注意掩码,转换为双向 LLM,每个token可以访问序列中的其他token。

  • 掩码下一个token预测

通过掩码下一个token预测(MNTP)来调整模型,使其更好的利用双向注意力。MNTP 是一种训练目标,它将下一个token预测与掩码语言建模相结合。给定一个任意序列作为输入,首先掩蔽输入 token 的一部分,然后训练模型根据前后文来预测这些掩蔽的 token。

  • 无监督对比学习

decoder-only LLM 没有经过明确训练来捕捉整个序列的上下文,该方法采用 SimCSE 的无监督对比学习弥补了这一缺陷。具体来说,给定一个输入句子,让句子两次通过模型,每次使用独立采样的dropout掩码,从而为同一个句子生成两种不同的表征。模型被训练为最大化这两种表征之间的相似性,同时最小化它们与批次中其他句子表征之间的相似性。最后对词表征进行池化操作,以获得句子表征。

2.2.5 GRIT

【主要贡献】

Generative Representational Instruction Tuning (GRIT) 模型**,**与 Echo-mistral 和 LLM2Vec 的思想类似,也强调了双向注意力对通用文本嵌入的重要性。然而,生成式表征指令调优(GRIT)方法的关键在于,通过训练 LLM 和指令来统一处理生成和嵌入任务。对于长文本,不再需要单独的检索和生成模型,该模型可以将检索增强生成(RAG)的速度提高60%以上。模型骨架选用 Mistral-7b 和 Mistral-8x7b。

【算法概述】

GRIT 将表征式指令调优和生成式指令调优统一到了一个模型中。采用一致的数据格式,使用表征和生成式指令数据对预训练的 LLM 进行微调,如图 9 所示。对于表征数据,使用 in-batch negatives 的对比目标来计算损失,同时采用双向注意力机制,随后进行平均池化对序列长度上的最终隐藏状态进行平均。为了计算生成式数据的损失,GRIT 使用语言建模目标,即模型需要预测下一个 token。最后,将目标函数与损失权重λRep λ_{Rep}(表征式损失权重)和 λGenλ_{Gen}(生成式损失权重)相加。

图片

图片

△图9: GRIT的架构和格式

2.2.6 GTE-Qwen1.5-7B-instruct

【主要贡献】

GTE-Qwen1.5-7B-instruct 基于 GTE 嵌入模型和 Qwen1.5-7B LLM 所构建,借鉴了 Qwen1.5-7B 模型强大的自然语言处理能力。通过先进的嵌入训练技术,该模型融入了多项关键改进:

  • 整合了双向注意力机制,丰富了模型的上下文理解能力;

  • 仅在查询侧应用了指令调优,以提高效率;

  • 在涵盖不同领域和场景的大规模、多语言文本语料库上进行了全面训练。这种训练同时利用了弱监督和监督数据,确保了模型在多种语言和广泛的下游任务中的适用性。

此外,还推出了 GTE-base-en-v1.5 和 GTE-large-en-v1.5 两个最新的英文嵌入模型,在同模型尺寸类别的MTEB基准测试上取得了很好的成绩,并且支持长达8192的上下文长度。

2.2.7 stella_en_1.5B_v5

【主要贡献】

该模型是基于 GTE-large-en-v1.5 和 GTE-Qwen2-1.5B-instruct 进行训练的。简化了提示的使用,为大多数通用任务提供了两个提示,一个是用于序列到段落(s2p)任务,另一个是用于序列到序列(s2s)任务。

  • 序列到段落(s2p)任务(例如检索任务)的提示:“Instruct: Given a web search query, retrieve relevant passages that answer the query.\n Query: {query}”

  • 序列到序列(s2s)任务(例如语义文本相似性任务)的提示:“Instruct: Retrieve semantically similar text.\n Query: {query}”

该模型最终选用 MRL 框架进行训练,从而具备多个维度设置,包括512维、768维、1024维、2048维、4096维、6144维以及8192维等多个层次。在理论及实践层面,通常观察到的一个趋势是,随着维度的提升,模型的性能呈现出增强的态势。然而在多数应用场景中,1024维的配置已经展现出了极为可观的性能表现,其在 MTEB 测试中的得分与最高维度的8192维模型相比,差距仅有0.001分。这表明1024维模型在性能与计算资源之间的良好平衡,也为后续模型选择与优化提供了有价值的参考依据。

2.3 方法小结

在本节中,我们详细阐述了基于 LLM 的通用文本嵌入算法模型(特别是在 MTEB 测试中排名前10的模型)。多数算法研究表明,通过全面的自回归预训练策略,LLM 能够习得高质量的文本表征,仅需少量微调即可转型为高效的通用文本嵌入模型。具体而言,微软提出的 E5-mistral-7b-instruct 与谷歌 DeepMind 的 Gecko 模型展示了两种创新途径,即通过 LLM 生成合成数据以进一步优化通用文本嵌入性能。同时,Echo-mistral 与LLM2Vec 的研究则强调,专为 decoder-only LLM 设计双向注意力机制,无需依赖合成数据,同样能实现出色的通用文本嵌入效果。BGE-EN-ICL 利用 LLM 中的 ICL 能力来增强文本嵌入生成的过程。NV-Embed-v2 设计了关注潜在向量的池化嵌入输出,并提出一种两阶段指令调优方法以提高检索和非检索任务的准确性。值得注意的是,本节介绍的所有专注于文本语义嵌入的 LLM 模型均采用了指令调优方法。这主要归因于 LLM 卓越的指令遵循能力,从而可以构建能够灵活应对多样化任务的通用文本嵌入模型的优选。此外,Mistral-7B 模型在 LLM 增强文本嵌入技术中是最流行的基线模型。其中一个关键因素在于,即便未经任何特定训练,为 Mistral-7B 启用双向注意力机制也已展现出了显著成效。LLM2Vec的作者据此推测,Mistral 模型可能已预先经历了某种形式的双向注意力训练。

03 总结

本文开篇即对文本语义嵌入方法进行了系统性概述,剖析了当前主流算法模型的架构特征及其发展脉络与趋势。鉴于 LLM 的迅速崛起,文章进一步在多维视角下对比了 LLM 文本嵌入技术与传统语义嵌入方法之间的显著差异。传统的文本语义嵌入技术以其高效性、广泛应用性和强大的语义表示能力为众多任务提供了有力支持,在自然语言处理领域占据重要地位。然而,该技术也面临着数据依赖性、静态性以及计算资源消耗等瓶颈问题。相比之下,LLM 通过捕捉文本上下文信息、支持多语言处理及出色的生成能力,为提升文本嵌入质量带来了新视角。随后,核心内容聚焦于 LLM 在生成文本嵌入领域的最新研究进展。当前,研究界对通用文本嵌入模型给予了高度关注,该模型旨在构建一个统一且全面的框架,以灵活应对不同长度的输入文本、多样化的下游任务、广泛的领域覆盖以及多语言处理需求。为实现 LLM 在提升文本嵌入能力上的潜力,研究者们探索了两条主要路径:一是通过合成数据生成策略来增加训练数据多样性和灵活性;二是直接将 LLM 作为核心架构,来优化通用文本嵌入的性能。本文介绍了这两条路径下的代表性模型,这些前沿方法均在多文本嵌入基准测试(MTEB)排行榜上名列前茅,在训练数据的规模上实现了显著提升,同时在数据质量与多样性方面展现了创新性的突破。这些进展不仅为文本语义嵌入技术提供了新的研究视角,也为未来自然语言处理领域的发展奠定了坚实的基础。

尽管 LLM 能生成更精确的文本语义嵌入,但也面临计算资源消耗大、数据隐私与伦理挑战以及解释性不足等难题。尤为关键的是,LLM 高度依赖于提示的质量,然而为各种任务创建精确且全面的提示不仅繁琐且耗时,同时,将提示整合到文本嵌入中会增加输入长度,这对于大型数据集和模型而言,将带来额外的计算开销。随着技术的持续进步,未来应该会出现更高效的训练算法,这将显著加速 LLM 的训练过程,进而推动其在 NLP 领域的广泛应用。同时,文本嵌入与图像、音频等其他模态嵌入的融合将成为趋势,旨在实现多模态自然语言处理任务,拓宽模型的应用范围并提升其性能。此外,为应对日益增长的模型解释性需求,未来 LLM 将朝着更强可解释性方向发展,优化提示生成算法和质量评估,确保决策过程的合理性、准确性和伦理性。随着这些技术的不断成熟,LLM 语义嵌入生成技术将在智能客服、内容创作、教育等众多领域展现更为广阔的应用前景,开启自然语言处理的新篇章。

主要参考文献:

[1] Wang L, Yang N, Huang X, et al. Text embeddings by weakly-supervised contrastive pre-training[J]. arXiv preprint arXiv:2212.03533, 2022.

[2] Xiao S, Liu Z, Zhang P, et al. C-pack: Packed resources for general chinese embeddings[C]//Proceedings of the 47th International ACM SIGIR Conference on Research and Development in Information Retrieval. 2024: 641-649.

[3] Li Z, Zhang X, Zhang Y, et al. Towards general text embeddings with multi-stage contrastive learning[J]. arXiv preprint arXiv:2308.03281, 2023.

[4] Touvron H, Martin L, Stone K, et al. Llama 2: Open foundation and fine-tuned chat models[J]. arXiv preprint arXiv:2307.09288, 2023.

[5] Dubey A, Jauhri A, Pandey A, et al. The llama 3 herd of models[J]. arXiv preprint arXiv:2407.21783, 2024.

[6] Jiang A Q, Sablayrolles A, Mensch A, et al. Mistral 7B[J]. arXiv preprint arXiv:2310.06825, 2023.

[7] Jiang T, Jiao J, Huang S, et al. PromptBERT: Improving BERT Sentence Embeddings with Prompts[C]//Proceedings of the 2022 Conference on Empirical Methods in Natural Language Processing. Association for Computational Linguistics, 2022.

[8] Zeng J, Yin Y, Jiang Y, et al. Contrastive Learning with Prompt-derived Virtual Semantic Prototypes for Unsupervised Sentence Embedding[C]//Findings of the Association for Computational Linguistics: EMNLP 2022. 2022: 7042-7053.

[9] Cheng Q, Yang X, Sun T, et al. Improving Contrastive Learning of Sentence Embeddings from AI Feedback[C]//Findings of the Association for Computational Linguistics: ACL 2023. 2023: 11122-11138.

[10] Wang L, Yang N, Huang X, et al. Improving Text Embeddings with Large Language Models[J]. arXiv preprint arXiv:2401.00368, 2024.

[11] M. Rui, L. Ye, J. Shafiq Rayhan, X. Caiming, Z. Yingbo, and Y. Semih, “Sfr-embedding-mistral:enhance text retrieval with transfer learning.” Salesforce AI Research Blog, 2024.

[12] Lee J, Dai Z, Ren X, et al. Gecko: Versatile text embeddings distilled from large language models[J]. arXiv preprint arXiv:2403.20327, 2024.

[13] Lee C, Roy R, Xu M, et al. NV-Embed: Improved Techniques for Training LLMs as Generalist Embedding Models[J]. arXiv preprint arXiv:2405.17428, 2024.

[14] Li C, Qin M H, Xiao S, et al. Making text embedders few-shot learners[J]. arXiv preprint arXiv:2409.15700, 2024.

[15] Springer J M, Kotha S, Fried D, et al. Repetition improves language model embeddings[J]. arXiv preprint arXiv:2402.15449, 2024.

[16] BehnamGhader P, Adlakha V, Mosbach M, et al. Llm2vec: Large language models are secretly powerful text encoders[J]. arXiv preprint arXiv:2404.05961, 2024.

[17] Muennighoff N, Hongjin S U, Wang L, et al. Generative Representational Instruction Tuning[C]//ICLR 2024 Workshop: How Far Are We From AGI.

[18] Li Z, Zhang X, Zhang Y, et al. Towards general text embeddings with multi-stage contrastive learning[J]. arXiv preprint arXiv:2308.03281, 2023.

[19] Dun Zhang. stella_en_1.5B_v5. huggingface.co/dunzhang/st…, 2023.

----------END----------

推荐阅读

持续推进“人工智能+”行动,百度智能云+DeepSeek为何成为国有企业首选?

GPU 云服务器的软件系统设计和实践

基于Flink的配置化实时反作弊系统

百度智能云xDeepSeek,最具性价比的DeepSeek一体机合集来了!

基于Flink的配置化实时反作弊系统

作者 百度Geek说
2025年3月4日 10:33
导读 本文详细阐述了基于Flink构建的实时反作弊流式过滤系统,针对大流量场景下的复杂特征计算、高频策略热更新、模拟过滤验证及多场景数仓对接等核心挑战,提出来多项解决方案,实现了秒级特征计算的实时过滤

图引擎在智能体开发场景的应用实践

作者 百度Geek说
2025年2月25日 10:06

导读

随着AGI理论的不断突破,智能体已经成为LLM在企业落地的最重要的形式之一。一个完备的智能体必须能实现:感知、推理、计划、执行等一套完整的功能,从工程的角度来看workflow特别适合这种复杂任务的分析、拆解、重组、执行,  再结合CoT技术, 实现LLM和业务功能完美契合的智能体应用。本文尝试用成熟的图引擎技术驱动workflow探索更多样性的拓展agent能力的方法,以更好应对各类业务场景。

01 简介

1.1 什么是智能体

以大模型(LLM)为核心, 具备以下特性的智能化系统:

  • 交互性: 通过文字,语音,图像等多种交互方式来理解用户的持续性需求  (感知);

  • 适应性: 感知环境的变化持续进化,以更好地完成任务和适应复杂环境      (记忆);

  • 自主性: 能够自主学习,主动思考和决策                                               (推理);

图片

图片

1.2 业务形态、流程

一个智能体生态平台,用户可以在上面体验功能各异的智能体app,同时也能让用户将自己的优秀想法以极低的成本(通过快速组装已有的插件、workflow、知识库、记忆) 快速实现成新的agent。

图片

图片

图片

系统特色:

  • 流程编排能力:支持可视化的数据流加工,通过编辑各个处理节点将原始input加工成output;

  • 功能复用能力:众多的agent库、插件库都可直接复用到自己的智能体里, 可插拔、替换;

  • 低代码能力:无需大量写代码,直接通过拖拽元素就能拼装出想要的功能。

图片

图片

1.3 业务场景的需求难点

1.3.1 能自由组装流程实现人机无缝衔接、数据解耦

  • 能将人的需求表达和agent思考结果的进行完美串联融合,发挥各自优点;

  • 除context外更多样性的数据传递方式,更好满足workflow、cot等流程编排的场景;

  • 细粒度控制数据传递、适配方式,满足特定场景的灵活性和性能的平衡需求。

1.3.2 能更精细规划路径、简化流程设计

  • 支持多种路径控制能力,满足多样性的静态化任务编排;

  • 支持在workflow内部动态编排新的子flow, 满足动态化的场景。

1.3.3 能对流程进行统一的控制、干预

  • 流程运行过程中当出现超时、异常等非预期情况需要框架能提供快速干预、退出机制;

  • 摆脱对executor(执行器的依赖),更低成本支持大量功能异构的流程。

1.3.4 能进行简单的功能注入

  • 支持在模型前后、工具调用前后等地方注入策略逻辑和观测代码,避免对大量节点进行浸入式改造;

  • 支持流程编排时给节点初始化赋值,降低数据传递的成本;

  • 支持任意节点信息的流式输出能力,满足长流程中阶段性结果的sse输出需求。

1.3.5 能支持缺少代码能力的使用场景

  • 将用户生或者LLM产生的cot转化成具体流程配置;

  • 将流程配置转换成可运行的代码。

1.4 为什么自研图引擎

1.4.1 常用智能体开发框架简介

  • LangChain框架:一个开发智能体的框架,定义了prompts,  index, memory, agents, tools, outputParser等一系列功能抽象,通过chains将各个功能串联成应用。

  • 开发模式:

  • Chains:  规划静态任务,  很多抽象都实现了chains的接口,规划好路径就能让各功能有序执行

  • AgentExecutor:  执行动态任务,某些场景无法预知执行路径,需要不同的输入走不同的分支,因此引入代理人(AgentExecutor), 通过多轮循环推理产生最终结果

  • 总结:多轮学习和推理是自主ai系统的基本的能力, Chains不具备循环”能力,  AgentExecutor多轮调度是一个不透明度黑盒。

图片

图片

  • LangGraph:基于LangChain基础上演化的框架,引入条件边,赋予用户对循环的控制能力。

  • 开发模式:用透明化的有向状态图打破LangChain动态任务的循环黑盒 (AgentExecutor)

图片

图片

已有框架比较注重系统的自主性,对业务执行路径的编排能力较弱。

1.4.2 业务需求的挑战

  • 强化的路径控制能力:既能满足llm的多轮循环特性, 又能结合cot模式的功能编排;

  • 传统功能的结合能力:模型存在知识能力边界,业务需要结合之前传统功能来满足多样性、个性化的需求, 在数据的校验、传递、并发、同步,流程控制等这些贯穿整个业务随处可见的基建功能都需要支持。

这些都不是已有智能体开发框架本身所擅长的,从下层视角看需要提供一个更通用、更精细化控制能力的流程驱动框架增强以下特性来满足业务需求。

02 用seda图引擎驱动workflow的模式开发智能体

对于以上共性需求我们引入图引擎驱动workflow的开发模式:将任务拆解成独立的功能节点,不仅可以包含 LLM, prompts, memory, tools, 等智能体(ai)元素还融入了 分支、循环、条件、多路复用、数据传递等传统应用所擅长的路径编排、数据转发、超时控制、错误处理等方面的功能,为智能体应用提供一个更强大、稳定、便于解耦且可黏合性强的基座环境。

图片

图片

2.1 实现更灵活的流程拆分组装、数据解耦

2.1.1 流程拆分

元素:

算子:  若干个函数的集合,组成一个业务逻辑上可简单描述的功能模块;

边:  联接2个算子,具有方向性,代表执行顺序,起始节点作为上游算子,指向节点作为下游算子;

联接:

串联: 一个上游算子联接一个下游算子,上下游顺序执行;

并联: 一个上游算子联接多个下游算子,上下游顺序执行,下游算子之间并行执行;

join:   多个上游算子联接一个下游算子,上游之间并行执行,下游等待所有上游执行完后再执行,实现汇聚、归并。

flow:

将复杂业务功能分解成若干个易实现、解耦、可复用的算子,根据业务执行顺序用边将算子串联起来,形成工作流。

用户请求从起始算子流入,通过flow的算子进行加工,最终从结束算子输出,完成整个业务流程。同时支持 dag 和 dcg(有环图)。

图片

2.1.2 分层组装

  • 子图(sub-flow):把一个flow也当成一个算子(sub-flow),直接挂到另一flow上,当数据推动到这个算子的时候就会触发这个(sub-flow)的内部逻辑,实现flow级别的抽象和复用;

  • 分层脉络地图:功能复杂导致算子数量过多时可以按不同粒度划分层级,把相同抽象粒度的算子放到同一个层级,不同层级的算子通过子图实现串联。通过点击进入子图内部浏览功能细节,通过收拢子图回到上层抽象,以此实现功能导航地图,既方便浏览又方便解耦拆分到多人协作开发。

图片

2.1.3 数据解耦

context共享可以方便的在所有算子间传递数据,算子的插拔替换、顺序调整也无需考虑数据的匹配,但同时也带来了数据加工处理过程黑盒,以及为了尽量避免参数读、写范围放大而需要加强数据访问权限保护这2个问题。

为此我们提供了额外的方式,满足不同场景的需求。

  • 链式推导 -- 更细粒度数据解耦

描述:上游output和下游input类型一致,就能串联并传递数据。

优势:output/intput是数据传播的契约约束,数据加工流程清晰。相同intput, output定义的算子之间能串联且插拔替换;相互之间不匹配的算子能通过定义中间类型的"桥接"算子来实现串联。

短板:需要用户手工串联算子,而且算子间容易产生串联类型不匹配以及并发问题也需要用户自己解决。

  • 自动推导 -- 自动优化使用和运行效率

描述:算子数量越多人工编排效率越低,在链式推导的方式上引入Referential Transparency, Single Assignment等规则约束来实现调用链自动推导。

优势:可以帮助用户自动管理大量算子的联接关系, 省时省力的同时还能在保证数据并发安全性的同时实现最大程度的并行化。

短板:关注的焦点从过程转移到数据,用户需要对流程做设计、优化时需要从数据入手做逆向推导流程(数据是在流程中慢慢产生和迭代的),违背了用户的使用习惯。而且对现有系统来说这种对数据读写的严格拆分、解耦往往需要全部推翻重来。

图片

2.1.4 拷贝与引用

除了以上的数据传递方式外在不同的需求场景下我们同时还需要思考是传递数据的副本拷贝还是传递数据引用(本身)的问题

  • context共享:出于性能考虑,基本都是采用传递引用的方式;

  • 链式推导:可以手工指定,默认通过简单的判断下游算子的数量来自动决定:下游算子个数等于1:传引用,大于1: 第一个算子传引用,剩余算子传副本,尽可能在局部范围内降低用户心智负担;

  • 自动推导:在Referential Transparency, Single Assignment双重数据访问规则保护下无需用户考虑并发安全性问题;

  • 自定义:用户可以在联接2个算子之间的边(edge)上显示指定是副本拷贝还是传递数据引用(本身)来获取更大的灵活度。

图片

2.1.5 类型适配

同一类功往往有多种实现,各自针对不同的使用场景有自己的优化,这些算子的input/output 往往基本结构一致,但又稍稍有一些小差异,为了更方便让这些算子能快速插拔,提高功能复用度,降低复用成本,我们提供了一系列自动适配机制。

  • 类型自动放大:内置多种数据类型及其变体自动转换逻辑:

A  <--->  *A,  interface{}

A  -> []A, []*A, []interface{}

  • 特型自动匹配:上游算子的output类型是被下游算子input类型内部组合的子类型,相互能串联,并完成自动赋值。

  • 自定义适配器:一个单独的适配器完成2个功能类同,但是intput/output参数形式差异较大的算子之间串联,适配器的input是上游算子的output, 其output是下游算子的input。

  • 为什么不直接用过度算子实现:避免大量转换算子干扰业务流程;

  • 为什么不把适配逻辑放算子内:避免侵入式改造和过度引用导致耦合。

图片

2.2 实现精细化的路径规划

2.2.1 多功能边

  • if:                    条件边 (单分支);

  • switch:               多条件边 (多分支);

  • multiplex:           多路复用边 (同时监听多个资源、信号);

  • optional edges:  可选边 (按需放弃对非强依赖上游的等待);

  • while:                 循环边 (条件和循环次数组合实现dcg);

图片

2.2.2 动态规划

编译时构建一个基础的大致性的功能脉络(上层基础逻辑定义),具体实现逻辑由执行期根据代码运行情况及LLM返回结果动态规划做逻辑的实时增删、拼接、构建。

图片

2.3 实现统一的驱动控制和干预

2.3.1 流程驱动

  • executor 执行器:

  • 存算分离设计:执行器读取flow信息并驱动执行,提供路径控制、资源调配,flow仅存储数据;

  • 一次解析多次执行:对flow进行一次解析后可以得到该flow的一个excutor, 后续相同的flow都可以通过该executor进行执行;

  • 适用场景:系统里flow异构类型有限, 都需要大量重复的被执行, 能节省每次构建重复flow的开销。

  • flow自驱动:

  • 无需解析,直接执行:flow被构建出来后,利用flow自驱动的功能直接运行, 无需构建执行器;

  • 适用场景:系统里大量异构flow,或者会动态产生出新构型的flow,能节省复用度低的执行器构建的开销。

图片

2.3.2 错误处理

  • 退出流程

当算子返回值 <0 时表示发生错误,默认直接跳到最后一个算子执行(让系统能有一个给用户回包、打日志的机会) 后并退出当前流程,快速终止无效的执行逻辑,迅速释放资源。

  • 逐层退出

当有多层(子图)时候,每一层有算子返回值 <0都会直接跳转到本层子图的最后一个算子执行,随即返回回上一层。用户可以按需给上层指定返回值,当给上层的返回值 >=0时候上游正常往后面算子执行,否则继续跳到本层的最后一个算子执行,以此类推直到整个flow结束。

图片

2.3.3 超时控制

  • 图超时

我们可以给整个flow指定一个执行的超时时间,触发后直接跳入到本层最后一个算子(让系统能有一个给用户回包、打日志的机会),这样快速终止无效的执行逻辑,迅速释放资源。

  • 算子超时

一般没有特殊需求我们建议根据业务接口要求通过flow控制整体超时即可,由系统自行判断可以尽量避免一些超时设置不合理的问题,同时我们也保留单独指定算子超时的能力,算子发生超时但flow整体没有超时时会跳过超时算子继续往下执行;,尽可能保持必要的灵活性。

图片

2.4 实现通用注入

2.4.1 事件监听

  • 监听通用事件

提供以aop接口的形式统一支持算子 on_enter, on_leave, on_timeout, on_error等关键事件的钩子机制,以全局函数或者算子成员函数的形式进行改写,以便用户能统一加入自定义的日志记录、监控、通知、错误处理等应对机制。

  • 监听自定义事件

除了上面的通用事件,我们还提供统一的机制,提供用户在算子内部任意地方加入自定义事件的能力,帮用户简便地完成应用层框架监听机制的建设需求。

图片

2.4.2 附加属性

除了context共享,链式推导的传递机制外我们还提供了额外第三种"附加属性"的方式来给算子传递数据,方便用户在编辑算子时就能给算子指定一些固定属性值,算子运行时能快速被读取,降低初始化成本。

图片

2.4.3 流式输出

放置一个内置的流式输出的算子到workflow里,通过向这个算子的channel里写入数据即可实现在任意算子里流式输出信息来满足sse需求,同时将流式输出算子和最后一个算子相连,即可实现优雅退出。

图片

2.5 实现低代码

  • 提供可视化编辑器,让用户拖拽设计流程并产生对应的配置文件;

  • 后端提供算子仓库作为用户功能实现的基础素材;

  • 图引擎的generate负责将配置翻译成流程代码, builder动态构建流程,driver负责驱动流程运行并返回结果。

图片

2.6 seda相较其他图引擎实现的优势

2.6.1 图引擎实现方案一:多线程并发(thread-base-on-request)

本质:线程数和请求数N:M的模型,基于请求数量规划线程的设计, 由操作系统保证线程调度、资源分配的均衡。

优势:实现简单、数据局部性好,负载在系统处理能力阈值内性能及佳,适用于对耗时要求苛刻的场景。

短板:

  • 流程黑盒:线程粒度太粗(请求粒度),不利于功能迭代、优化。

  • 扩展性差:请求数受系统线程数制约, 负载超出系统处理能力阈值会使系统陷入“调度内耗” (上下文切换,锁竞争),处理能力指数级下降。

图片

2.6.2 图引擎实现方案二:事件驱动并发(thread-base-on-resource)

本质:资源数和线程数N:M的模型, scheduler根据系统资源初始化若干线程,将请求拆解成由若干个non-blocking节点组成的有限状态机(FSM),节点执行后将状态回传给scheduler, 由其根据当时资源使用情况分配下一个节点的处理线程,直到整个有限状态机结束。

优势:

  • 流程可视:通过有线状态机实现各个功能节点之间互相解耦;

  • 扩展性佳:线程数不受请求数影响,能始终控制在系统资源可高效运行的阈值范围内;

  • 吞吐量大:事件驱动极大程度避免了多线程之间的"资源内耗",能有效提升系统并发和吞图。

短板:

  • 时延增大:一次请求处理过程跨多个线程执行增加了数据传递消耗的同时也降低了硬件缓存命中率导致请求延迟增大;

  • 实现困难:中心化的scheduler调度器既要驱动业务状态流转又要管理资源调度往往会顾此失彼。

图片

2.6.3 图引擎实现方案三:基于seda的图引擎驱动(thread-base-on-stage)

seda:staged event driven architecture

本质:将上面中心化的scheduler模块给拆分成多个子部件实现。

  • 用多个事件队列将每个状态节点(stage), 组成一张数据流动网络 (Directed Graph);

  • 每个stage都由事件队列(接收数据)、控制器(分配资源,驱动stage流转)、线程池(调节线程数)、事件处理器(业务处理handler)组成;

优势:

  • 资源按流程stage拆分,粒度适当 (按request粒度过小,容易陷入内耗;按resource粒度过大,容易浪费);

  • 去除中心化模块,通过对事件队列的流速控制使得每个stage可以单独进行负载调节。

短板:

相比运行状态良好情况下的单线程处理一个请求的设计, 时延上会有增大 。

图片

03 通用图引擎在智能体场景的实际应用

3.1 功能场景应用

3.1.1 根据大模型COT结果动态生成子workflow

  • query:请预测下明年下周的天气情况

  • 大模型将问题拆解成具备先后依赖关系的多个小步骤:

  1. 计算下一周对应的时间范围

  2. 查询本周天气情况

  3. 查询历史上前n年对应时间范围的的天气情况,

  4. 根据历史查询结合当前情况推测明年对应的时间范围的天气情况(结果保存到短期记忆)

  5. 如样本范围太小或结果单一则重复前面过程3-4,直到给出预测结果的具体概率分布

  • 大模型根据当前执行到的具体步骤将工作内容动态分解到子图并执行。

图片

3.1.2 复杂场景的功能拆分解耦和精细化路径控制能力

  • 用"多路复用"同时监听多值,支持任意数量路径分发,将 "路由和子功能调用" 算子进行拆分解耦;

  • 用"可选边"将多处可能会触发到的公共逻辑"润色模型"模块拆分成独立算子;

  • 用过"融合边"将各种不同类型的边融合汇聚到一个算子, 便于整体控制流程结束逻辑;

  • 通过以上多种精细化路径控制功能,减少大量胶水代码的同时方便对流程图做快速修改,让用户专注于业务逻辑自身。

图片

3.1.3 通用注入和循环增强

  • 由侵入式改造转变成通用事件注入来统一控制算子内部的共性行为;

  • 个性化功能增强也可以通过非侵入式方式注入算子内部;

  • 在之前纯代码逻辑控制循环结束条件的同时增加了框架保护机制,避免响应不及时和资源长时间侵占。

图片

3.2 小结

通过图引擎驱动workflow的开发模式提供了一个强大的基座,用户可以快速在其上通过插拔替换、顺序调整、串联汇聚、编辑出任意自己想要的流程,其强大的解耦和精细化路径控制能力从根本上解决传统ai开发模式带来的黑盒问题和相关不确定性问题,同时还能获得极佳的运行时效率(天然并发);其自带的低代码、分层导航等特性减少了大量胶水代码,还有助于多人同时入场并行开发,降低开发、维护成本。

目前系统已经接入80w开发者,15w合作企业,超过10w个智能体。

————END————

推荐阅读

直播间互动框架性能优化与稳定性实践

百度网盘防雪崩架构实践

如何在百度百舸部署满血版DeepSeek-V3、DeepSeek-R1模型

首日调用客户破1.5万!DeepSeek-V3/R1上线背后的超低推理成本技术揭秘

唤醒 AI 算力,专有云 ABC Stack 面向企业级智算平台的 GPU 提效实践

直播间互动框架性能优化与稳定性实践

作者 百度Geek说
2025年2月20日 10:29

导读

直播间互动体验框架技术实践,揭秘性能与稳定性优化之道,快来探索吧!在百度直播间歌会红包等活动中,我们创新性地将红包互动与高质内容深度融合,通过技术架构升级与系统性优化,打造了"音乐+红包"(边听歌边抢红包)的沉浸式体验。本次实践显著提升了直播间的并发承载能力、实时互动响应速度和用户参与满意度,同时沉淀出可复用的技术方案,为后续大型直播活动奠定坚实基础。

01 百度直播间歌会红包运营活动介绍

为提升直播内容质量和用户粘性,需注入多元化内容,增强直播间多样性和观赏性。同时,通过活动裂变扩大影响力,吸引特定用户群体,保持用户新鲜感和期待感,为平台长期发展奠定基础。

为落实直播歌会目标要求,需加快直播间互动体验框架建设,探索新型混合模式和沉淀通用能力,着力适配重点业务场景,打造"音乐+红包"的互动体验,提升直播间品质:

一是通用基础。主要包括组件复用、大图压缩等减少产物体积,页面异常、性能、白屏监控,BFF服务编排扩缩、稳定性监控等。

二是访问保障。主要包括页面多域名容灾、开启强缓存;字体、图片、CSS、JS等静态文件单独CDN强缓存域名,开启多级缓存等。

三是红包性能。主要包括页面预静态化、数据预加载、文档预取、资源预取、视图预渲染、动效降级等。

四是开发体验。主要基于直播前端一站式,建强队伍,确保项目开发流程规范统一,搭建增质增效的研发环境等。

图片

02 体积

2.1 页面划分

在大型产品需求中,通过合理的页面划分策略,实现高效开发与维护。面对产品需求中罗列的多样玩法功能和19种以上的红包状态,研发团队面临的首要挑战是如何将这些功能合理的拆解成多个页面承载。合理的页面划分不仅关乎用户体验的流畅性,更是减小产物体积、提升跨页面资源缓存利用率的关键。通过深入分析业务逻辑与用户行为路径,我们精心设计了页面边界,确保每个页面和组件都承载着唯一元素,同时避免了冗余代码的产生。此外,这一策略还极大地促进了开发团队的协作效率,明确的页面划分减少了代码冲突的可能性,使得团队成员可以高效并行集成,从而加速了开发迭代周期。在直播间端能力的规范化构建上,同样遵循了通用化这一原则。

在页面划分时,我们非常注重跨页面资源的最优利用,通过策略性地缓存HTML、CSS和JavaScript等资源,确保一旦用户在任意时刻首次触发了红包弹出事件,这些资源即可被全面缓存,使用户在后续的页面切换过程中无需再次加载这些核心资源。

通过一系列设计举措,划分多页应用(MPA)10+个、单页应用(SPA)20+个、红包组件状态(Component)19+个、规范化直播间端能力(Scheme)30+个,每一项都经过精心设计,共同作用于提升应用的整体性能,为用户带来更加轻盈、快速且协同良好的使用体验。

2.2 性能优化

在直播歌会抢红包运营活动中,Web页占据了80%的比重,对于每一个依赖较多网络资源的玩法页面,在直播间中实现即时加载和快速展现确实面临较大挑战,尤其是在高并发、低延迟的场景下。

图片

△页面展现过程

为了有效应对这些挑战,通过深入分析页面展现过程中的各个环节,直播间互动框架提炼出七种通用的优化方案。旨在提升用户交互体验、增强系统的整体性能。并确保直播间玩法在高并发场景下依然能够流畅运行。这些优化方案覆盖了从页面加载、资源获取到实时交互的各个方面,形成了一个全方位的性能提升样板,具体方案如下:

图片

2.3 页面预静态化(SSG)

在直播歌会抢红包的场景中,所有不变的内容(如活动规则、活动主页框架等)使用SSG能够显著提高页面通用静态内容的加载速度,同时通过集成CSR可以实现部分动态内容的及时更新。

图片

△框架原生SSG Webpack插件

图片

△图1:活动规则 △图2:攒百元半屏页 △图3:支线攒碎片

2.4 页面静态化(SSR)

在直播歌会抢红包的场景中,节目单页作为用户获取歌曲节目信息的第一入口,其快速加载至关重要。SSR提供快速的节目单页初始加载,后续通过客户端的JavaScript动态增强功能(如进度提醒、节目回放等)获得更丰富的交互体验。

图片

2.5 增量静态渲染(ISR)

在直播歌会抢红包的场景中,对于实时性要求极高的红包抢夺场景,ISR的动态更新和实时交互特性为活动的各个环节提供了实时回显的用户体验:

  • 首先,在全屏红包弹窗页(如初始红包、任务红包和裂变红包)中,ISR使得页面无需刷新即可实时更新用户的红包状态。当用户参与活动或完成任务时,ISR的快速响应确保用户能即时获得任务状态和奖励领取情况,增强了用户的参与感与互动性。

  • 对于实时轮次切换功能,ISR保障用户迅速在游戏阶段间切换,提升了同页面不同状态的连续性。当活动结束时,系统能够快速通知用户并更新活动状态为下线,避免误导用户继续参与。

  • 在内容分享与社交互动方面,ISR处理高效的页面加载与实时显示,如微信邀请和海报分享,保证用户能快速刷新助力进度。在邀请分享页,主态用户能立即看到受邀好友的参与情况和贡献,进一步增强社交互动体验。

图片

2.6 数据预取(Prefetch Data)

在直播歌会抢红包的场景中,通过NA与H5之间的有效数据预取和缓存衔接,实现了端数据的复用,有效减少与服务器的交互频率,消除了数据加载的等待时间,确保了在直播环境中用户能够高效参与活动:

  • 预取皮肤元素配置,进入直播间后,NA会预取皮肤元素配置,预加载与活动相关的皮肤素材,并将这些信息进行缓存,包括页面主题色和红包动画等。同时,前端JavaScript能够在页面弹出时,通过端能力或全局变量直接获取相关数据,用户不需要等待皮肤配置加载,界面视觉能够立即呈现,从而实现在操作上的流畅体验。

  • 攒百元红包的进度更新,在活动进行中,用户需要实时查看攒百元红包的进度,通过数据预取的方式,能够迅速更新至用户界面。在启动WebView的同时,NA实现数据的并行获取。这意味着在用户点击挂件后,相关的数据请求会立即开始,前端JavaScript则能够在执行时通过端能力直接获取这些已经预取的数据,降低了数据延迟加载等待时间,增强了用户参与活动的效率。

图片

2.7 文档预取(Prefetch HTML)

在互动性较强的直播歌会抢红包的场景中,用户不仅可以观看演出,还能参与抢红包活动。为提供最佳的用户体验,确保用户在首次点击不同功能时能够快速上屏相关内容,采用文档预取能力在后台主动下载歌会相关HTML内容,如攒百元半屏页、节目单页等。当用户最终点击某个链接时,直接从内存中读取HTML文档内容,无需网络请求,从而显著提高页面加载速度,确保用户在直播间里的互动预期。

通过数据结果来看,文档预取的效果非常显著。在优化了节目单页的性能后,Android用户的首屏加载时间从3秒级减少到500毫秒级,iOS用户的首屏加载时间从2.5秒级减少到500毫秒级。这样的性能提升显然改善了用户体验,使得用户能够快速获取所需信息,进而积极参与到活动中,营造出活跃的直播间氛围。

图片

△Prefetch SSR/CSR HTML

2.8 资源预取(Prefetch Resource)

在直播歌会的场景中,用户参与抢红包是一个关键的互动环节。在此过程中,确保红包弹出的多层动画和红包图能够迅速、完整地展示对于增强用户体验至关重要。为此,资源预取在这一场景中得到了有效应用,在正式直播活动开始前期,后台服务主动下载、缓存、更新关键资源,包括红包的动画文件和高质量的红包皮图像。以确保当红包正式弹出时,最新的文件已被准备妥当,用户能够立即看到完整的红包图和流畅的动画效果,避免了图片逐块加载造成的卡顿和不完整展示。

通过数据结果来看,资源预取的效果非常显著。Android用户资源加载耗时提升幅度约46.7%,iOS用户资源加载耗时提升幅度达86.1%,大幅提升了整体互动体验,使用户在关键时刻享受到快速且流畅的操作体验。

为了确保资源预取的有效性,需要注意以下几点:

  • 预取的资源应以用户行为的合理预测为基础,避免过度预取,从而造成带宽浪费。

  • 采用分模块的离线包设计,将每个模块的资源单独管理。

  • 在活动结束后,应及时下线不再需要的资源,释放带宽和用户手机空间。

图片

2.9 视图预渲染(Prerender WebView)

在直播歌会的场景中,观众们期待快速响应的抢红包互动体验,此时视图预渲染能力发挥了重要作用。当用户进入直播间后,提前在后台加载并渲染抢红包页面内容,并注册页面可见性监听器。即使用户专注于观看直播,红包页面也已准备妥当。用户点击按钮,抢红包页面便迅速显示,无需等待加载和渲染时间,同时触发监听器实时更新数据。这样的即时反馈使得用户几乎可以瞬间查看抢红包的结果,极大提升了参与的积极性和体验感,进一步增强了直播的互动乐趣。

在预渲染过程中,仅对用户频繁访问的页面进行预渲染,避免资源浪费,确保当前视图性能不受影响。由于预渲染占用内存资源,因此需要控制WebView的数量,防止内存泄漏。在实施时应关注内存管理、时机选择、兼容性和安全性,以灵活适应具体应用场景。

图片

图片

03 稳定性

3.1 弹窗稳定性

保障直播间红包弹层的进退场稳定性,防止透明弹层卡住以致用户无法互动,是一项关键挑战。在直播间中,红包弹层通过覆盖全屏透明WebView实现,且与动画控制密切相关,用户在拆红包动画播放过程中无法进行任何交互,关闭按钮在动画结束后才会显示。这要求我们确保红包动画的持续时间和效果稳定,以便在合适的时机正确显示关闭按钮。为确保红包弹窗正常退出,尤其是在H5页面渲染异常或网络不稳定的情况下,用户也能得到一个状态友好的反馈。保障直播间抢红包互动的稳定性,我们设计了“一次握手”和“双重兜底”策略:

  • 一次握手,即Web内容健康检查:

  • JavaScript通过WebContentLoaded端能力,表示H5成功接管用户交互,并通知Native端取消WebView的超时销毁策略,以确保全屏红包弹窗能够稳定展示。

  • 如果H5接管未在规定时间内完成,Native端将销毁上层全屏透明的WebView。这一措施确保用户不会因弹窗问题而中断观看体验,从而能够持续与直播间进行交互。

  • 双重兜底,即NA兜底页和H5兜底页:

  • NA兜底页,当HTML入口文件请求异常时,展示Native兜底页面,确保用户有可见的替代内容。

  • H5兜底页,在JS业务组件发生异常(例如接口请求异常、端能力调用失败、组件内部异常、重要资源缺失)时,展示H5兜底内容,为用户提供实质反馈。

图片

图片   

△图1:NA兜底页 △图2:H5__兜底页 △图3:请求______兜底

3.2 动效降级

炫酷的动效的表现直接影响用户的体验,在直播歌会场景中,红包动效由复杂的元素组成,包括Lottie动画、AFX透明视频和CSS动画。炫酷的动效虽然可以增强视觉吸引力,但在低端手机上可能导致卡顿。为确保所有用户可以顺畅参与活动,我们实施了分级动效降级策略:

  • 高性能设备(High):在高性能设备上,展示完整的动画和丰富的动态效果,享受到丰富的视觉效果。

  • 低性能设备(Low):对于低端手机,复杂的动效将被简化为静态图像或低复杂度的CSS动画。例如,红包拆开时只展示基本的静态图形,替代激烈的动态效果,确保用户能够正常阅读红包金额,而不至于因动效卡顿而影响体验。

分级动效降级策略能够根据当前手机的实时性能情况,在用户点击拆红包时动态调整展示的动效级别,确保以最佳效果参与活。这种适应性有效地解决了不同设备用户在参与红包活动时可能遇到的性能问题,从而提升整体用户体验的品质。

图片

3.3 组件响应

随着用户体验的不断优化,直播歌会抢红包活动中页面组件的运行环境日益复杂。特别是在复杂组件的开发中,组件开发者必须意识到各项适配工作的必要性,以确保用户体验与开发体验之间的平衡。为了有效满足用户需求并提升开发效率,我们需要综合考虑多个环境及其不同状态。至此,在一个组件的设计和实现过程中,需要针对以下五种状态进行响应和适配:

  1. SSG环境(编译线环境):组件在编译过程中,通过Node.js将公共的信息(如活动规则)提前生成静态内容,以提供快速响应时间。

  2. SSR环境(服务端环境):组件服务器集群上,通过Node.js根据用户请求动态生成相应的内容(如歌会节目单),减去客户端JavaScript加载执行时间,加快页面首屏展示速度。

  3. ISR环境(客户端环境):组件在浏览器中,通过JavaScript进行动态渲染、响应用户点击、滑动等操作,通过异步接口获取最新数据(如红包金额、助力信息)并即时更新界面,保证用户体验的实时性和互动性。

  4. 页面可见(Visibility):组件在浏览器中,通过JavaScript控制组件的渲染时机,仅在内容需要展示时才进行渲染(如播放红包动画),减少不必要的DOM操作,提升性能并降低资源消耗。

  5. 动效级别(High / Low):组件在浏览器中,通过Native端能力获取用户设备的性能,动态调整组件中的动效,在高性能设备上展示更炫酷的动效,在低性能设备上则展示更简单的动效,确保流畅体验。

04 总结

  • 沉淀直播框架能力:通过优化直播间视图容器组件,并形成标准化的组合能力样板,拉升直播间活动页面的性能水准,这些方案具备良好复用性,适用于未来各种直播活动。

  • 系统稳定性保障:组件复用、性能监控和容错机制,减少重复开发和维护成本,进行压力测试与优化,提升系统可靠性和用户体验,确保高峰流量下的稳定性。

  • 强化互动性体验:在直播歌会中建立综合能力框架,特别是在抢红包等互动性强的活动中,确保用户在享受歌会演出的同时体验流畅的互动,鼓励积极参与

————END————

推荐阅读

百度网盘防雪崩架构实践

如何在百度百舸部署满血版DeepSeek-V3、DeepSeek-R1模型

首日调用客户破1.5万!DeepSeek-V3/R1上线背后的超低推理成本技术揭秘

唤醒 AI 算力,专有云 ABC Stack 面向企业级智算平台的 GPU 提效实践

百度APP iOS端磁盘优化实践(上)

百度网盘防雪崩架构实践

作者 百度Geek说
2025年2月18日 10:33
导读 大模型在研发效能领域代码生成方面发挥了越来越大的作用 而大模型的预训练依赖大量的精标代码,这些精标数据必须是比较好的工程实践代码 这些比较好的工程实践代码,需要大量的技术沉淀,包括工程架构,代码
❌
❌