跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • 浅色
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • 深色
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(LCZ-Blue)
  • 不使用皮肤
  • LCZ-Green
  • LCZ-Blue
折叠
品牌标识

抡锤者

  1. 主页
  2. 版块
  3. LLM讨论区
  4. 第二张 AMD 显卡该怎么用?一次 128K Agent 双卡推理实测

第二张 AMD 显卡该怎么用?一次 128K Agent 双卡推理实测

已定时 固定直到 2026/8/24 01:00 已锁定 已移动 LLM讨论区
amd多卡部署agent
13 帖子 2 发布者 284 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • BunseiB 在线
    BunseiB 在线
    Bunsei
    编写于 最后由 编辑
    #3

    一、为什么是RX 9070?

    严格来说,RX 9070并不是我为这套系统确定的最终升级方案。它更像是一张便宜的的“测试卡”,我想先用它验证主板、PCIe拓扑、P2P和ROCm多卡路径,再决定未来是否值得升级到双R9700,我选择它,主要有三个原因:

    1、 P2P

    第一个原因,也是我在增加第二张显卡之前最没底的。不是Linux和ROCm能不能识别两张卡,而是这套消费级B850平台,究竟能不能真正实现PCIe Peer-to-Peer,也就是P2P访问。

    我的主板拥有两条物理全长插槽,也能够把来自CPU的PCIe通道拆分成x8/x8,但这并不等于两张显卡一定能够直接访问彼此的显存。PCIe拓扑、BIOS、IOMMU和驱动实现中的任何一个环节,都可能让看起来一切正常的双卡平台,在真正进行跨卡通信时退回CPU内存中转,这也是我在租来RX 9070之前最担心的问题。

    虽然P2P不可用,第二张显卡不会完全失去价值,它仍然可以承担一部分模型权重和KV Cache,也可以在PP模式下作为容量扩展卡使用。但这和我真正想测试的东西已经不是一回事了。

    PP只需要在不同模型阶段之间传递数据,而TP几乎每一层都要进行跨卡同步。如果这些通信必须绕经CPU内存,双卡就可能从共同加速退化成只是勉强共同运行,甚至因为通信和同步开销而比单卡更慢。所以在实验开始之前,我其实已经为它准备好了两种完全不同的结局:

    1) 如果平台不支持P2P,就把RX 9070降级为容量扩展卡或者普通副卡,不再对TP性能抱太高期待。以后要升级那我就卖掉R9700,再补差价更换一张48GB魔改版RTX 4090 D,不再考虑双卡。

    2) 如果平台支持P2P,那就把RX 9070当成进入多卡世界的第一张实验卡,实际看看PP、TP和RCCL究竟能为本地推理带来多少提升,同时也为未来可能升级的双R9700提前验证平台、积累经验。

    幸运的是,最后的结果走向了第二条路。

    实测中,这张B850主板确实能够让两张显卡运行在PCIe 5.0 x8/x8,并实现双向P2P访问,跨卡传输速度约为26.08GiB/s。对我来说,这才是整套双卡实验真正成立的那一刻。

    不过P2P测试通过并不代表双卡一定会更快。它只是证明两张显卡具备了直接协作的基本条件,排除了所有数据都必须绕经CPU内存的这一最糟糕的情况。如果把后面的性能测试看作一场比赛,那么P2P不是最终成绩,而只是一张入场券。但至少到了这里,TP、PP和RCCL终于值得被认真放到同一张测试表上了。

    2. 架构

    第二个原因,则是RX 9070与R9700在软件和硬件层面具有较高的一致性。

    两张显卡都属于RDNA4,并且在ROCm中使用相同的LLVM目标gfx1201。这意味着llama.cpp的HIP内核可以面向同一个GPU目标进行构建,不需要像R9700搭配RX 7900 XTX那样,同时处理RDNA4 gfx1201与RDNA3 gfx1100两套不同目标。

    这并不代表跨架构双卡一定不能工作,但在一个本身仍带有实验性质的多卡环境中,少一种架构、编译目标和驱动路径的差异,就少一种出现兼容问题时需要排查的变量。而且从规格上看,两张卡也有一些适合组成双卡的共同点。根据AMD官方规格,R9700和RX 9070都拥有256-bit显存接口与640GB/s标称显存带宽,但RX 9070只有56个CU和16GB显存,FP32峰值也明显低于R9700。

    当然这种组合仍然是不对称的,在TP中R9700可能需要等待较慢的RX 9070,16GB的显存容量也限制了模型和KV Cache的分配比例。但与跨代架构组合相比,它至少减少了软件层面的变量。而相同的标称显存带宽,也让RX 9070在部分偏向显存带宽的Decode负载中,不至于仅凭显存容量和CU数量就被视作一张过慢的副卡。

    项目 R9700 RX 9070
    架构 RDNA4 RDNA4
    LLVM目标 gfx1201 gfx1201
    计算单元 64 56
    显存 32GB 16GB
    显存位宽 256-bit 256-bit
    显存带宽 640GB/s 640GB/s
    FP32峰值 47.8TFLOPS 36.1TFLOPS

    3. 价格

    京东有“租赁”服务,RX 9070的售价低于6000元。通过租赁方式使用两个月,租金大约为750元。而RX 9070 XT的两个月租金则接近1100元,两者相差三百多元。

    虽然RX 9070 XT拥有64个CU和更高的运行频率,计算能力确实强于RX 9070。但两者同样只有16GB显存,显存位宽同为256-bit,标称显存带宽也同为640GB/s。

    考虑到这次实验的首要目的,是验证主板P2P、ROCm多卡和llama.cpp的TP/PP路径,而不是直接搭建最终配置,我没有必要为尚未确认的平台额外增加三百多元试错成本。

    RX 9060 XT 16GB虽然价格可能更低,也同属于RDNA4,但它使用的是gfx1200目标,只有32个CU、128-bit显存接口和320GB/s标称显存带宽,只有RX 9070和R9700的一半。这意味着它不仅引入了另一个GPU编译目标,计算规模与显存带宽也和R9700相差更大。在PP中它仍然可以承担一部分层和显存容量,但在需要频繁同步的TP中,更可能成为限制整体速度的参与者。

    由于这次实验本来就在为未来的双R9700做平台验证,选择RX 9060 XT得到的结果也不够具有代表性。

    综合来看,RX 9070并不是R9700最完美的长期搭档,却是当时最适合验证这套平台的一张测试卡。它没有RX 9070 XT那么强,也没有第二张R9700那么理想,但它用相对有限的试错成本,提供了16GB额外显存、相同的gfx1201目标和相同的标称显存带宽。

    但对我来说,这已经足以让它完成这次实验最重要的任务,就是回答这套平台,究竟值不值得继续走多卡路线。

    1 条回复 最后回复
    0
    • BunseiB 在线
      BunseiB 在线
      Bunsei
      编写于 最后由 编辑
      #4

      二、两张显卡,究竟应该怎样分工?

      RX 9070已经选好了,P2P测试也顺利通过了测试。但这只解决了两张显卡能不能直接交换数据的问题,还有一个更加关键的问题没有回答,那就是它们究竟应该怎样一起计算?

      毕竟,llama.cpp可不会因为系统里多出一张显卡,就自动把两张卡的性能相加,显卡插上去只是第一步,模型权重、KV Cache和计算任务究竟怎样分配,仍然需要由我们自己选择。

      相同的硬件可以采用完全不同的模型切分方式,而切分方式会直接影响跨卡通信频率、显存分配以及最终的性能特征。这一步选得是否合适,可能决定第二张显卡究竟是一块加速器,还是一项额外的通信负担。

      目前llama.cpp的--split-mode支持none、layer、row和tensor四种模式。其中none只使用单张显卡,真正涉及多卡切分的是layer、row和tensor。

      row模式会按行切分部分模型权重,但中间结果和KV Cache仍主要放在指定的主显卡上。它没有充分利用两张卡共同分担长上下文KV Cache,与这次利用48GB总显存服务128K Agent的目标并不完全一致,因此本文不再展开测试(官方也不推荐使用)。

      最终,我真正需要比较的是两条路径,layer模式(也就是下文所说的PP),tensor模式(也就是仍处于实验阶段的TP)。
      它们使用的是同一套硬件,却代表了两种完全不同的多卡思路。

      把不同的模型层交给不同显卡(PP)

      PP在llama.cpp中对应 --split-mode layer。

      它会把模型的不同层分配给两张显卡。例如,前面一部分层由R9700负责,后面一部分层由RX 9070负责。数据完成一段计算后,再通过PCIe传递给下一张显卡继续处理,它更像是把一条生产线拆成了两个工段。

      这种方式的优势是跨卡通信相对简单。模型不需要在每一层都让两张显卡交换中间结果,通常只需要在不同模型阶段的边界传递数据。因此,即使PCIe互联速度远不及显存带宽,PP仍然比较容易获得可用的性能。

      兼容性也相对成熟,量化KV Cache、视觉模型和独立草稿模型通常更容易在PP模式下运行。

      但PP的问题同样明显,那就是对于单个token来说,两张显卡并不是同时完成同一层计算的,而是依次经过两个模型阶段。R9700完成自己的部分之后,RX 9070才能继续处理后面的层。

      所以在单并发的Agent任务中,这种串行关系会限制逐token生成速度。即使两张卡都在参与推理,也不代表生成速度一定会比单卡更快。

      让两张显卡共同计算每一层(TP)

      TP对应 --split-mode tensor。

      与PP不同,TP不是把不同模型层分别交给两张卡,而是把同一层中的张量切分到两张显卡上。R9700和RX 9070会同时计算这一层的不同部分,然后再通过跨卡通信合并结果,继续进入下一层,它更像是让两个人同时完成同一道工序。

      这种方式更有机会降低单个token的生成延迟,也更加符合我最初希望双卡共同加速的设想。但它对跨卡通信的要求明显高于PP,因为两张卡几乎每一层都要交换和归约数据,任何通信延迟都会不断累积。所以TP是本次实验的预期目标。

      这也是PCIE-P2P对TP格外重要的原因。如果没有P2P,每一层的同步都可能绕经CPU内存,而即使P2P已经可用,PCIe延迟、两张卡的性能差异以及PCIE归约实现,仍然可能限制最终收益。

      两种模式可以简单概括为:

      项目 PP / Layer Split TP / Tensor Split
      切分对象 不同模型层 同一层中的张量
      跨卡通信 主要发生在阶段边界 几乎每层都要通信
      对P2P依赖 相对较低 很高
      单流Decode 容易受串行阶段限制 更有机会降低延迟
      长提示Prefill 通常较有优势 受跨卡同步影响
      软件兼容性 相对成熟 仍带有实验性质
      异规格双卡问题 阶段负载不均 快卡频繁等待慢卡

      存算比例

      在本次测试中无论使用PP还是TP,都不能不加思考地把两张显卡按照50/50平均切分。

      R9700拥有32GB显存和64个CU,RX 9070则拥有16GB显存和56个CU。两张卡的显存容量比例接近2:1,但计算单元比例只有大约53:47。这意味着显存分配和算力分配之间,本身就不存在一个绝对完美的比例。

      如果按照50/50切分,计算负载看起来比较接近两张卡的CU比例,但RX 9070只有16GB显存。在128K上下文、FP16 KV、mmproj和投机解码组件同时存在时,它会比R9700更早接近显存上限,也很难为计算缓冲区和软件版本变化留下足够余量。
      如果完全按照32GB与16GB的显存容量切成67/33,又可能把过多计算交给R9700,没有充分利用RX 9070的56个CU。

      最终,这次严格对照测试主要使用了一个相对保守的折中比例:

      --tensor-split 65,35

      它更接近两张卡的显存容量比例,优先保证16GB的RX 9070不会过度接近显存边界,同时让计算能力更强、显存更大的R9700承担更多模型权重和额外组件。

      在128K、FP16 KV、完整模型、mmproj和MTP同时加载的情况下,两种实际测试过的比例大致表现为:

      切分比例(R9700 / RX 9070) R9700显存占用 RX 9070显存占用
      65/35 约23.3GB 约12.9GB
      60/40 约22.1GB 约14.1GB

      60/40能够更充分地使用RX 9070,但副卡显存余量会进一步缩小,而65/35则为16GB显存留下了更安全的运行空间。因此,后面的严格性能对照统一采用65/35,避免显存压力变化干扰测试结果。

      在测试开始之前,还有一个很容易踩坑的问题,那就是设备顺序。

      本机原始设备编号为:

      GPU0 = RX 9070
      GPU1 = R9700
      

      但测试时使用了:

      HIP_VISIBLE_DEVICES=1,0
      

      这条环境变量重新排列了ROCm设备顺序。进入llama.cpp之后,R9700成为逻辑上的ROCm0,RX 9070成为ROCm1。

      所以:

      --tensor-split 65,35
      

      在本文中实际表示:

      R9700:65
      RX 9070:35
      

      这里的65和35本质上是相对权重,并不强制要求总和等于100写成65/35,只是更方便按照百分比理解。

      另外值得一提的是,--tensor-split这个名字也容易让人误以为它只对TP有效。实际上,在layer模式中,它同样用于决定不同显卡获得模型层的相对比例,在tensor模式中,则用于控制模型张量和KV Cache在不同设备间的目标分配比例。

      还需要注意,65/35只是模型切分的目标权重,并不意味着两张显卡最终的显存占用、计算量和执行时间都会严格保持65/35。

      KV Cache、计算缓冲区、输出层、mmproj、草稿模型以及无法无限细分的模型层,都会让最终结果发生偏移。它不保证两张卡最后一定按照同样的百分比工作。

      RCCL

      TP会把同一层的模型张量分到两张显卡上并行计算。完成各自的部分后,两张卡还需要对中间结果进行Reduce和Sync,才能继续进入下一层。这个过程会在模型的许多层中反复发生。

      如果把P2P理解成两张显卡之间的一条直达道路,那么RCCL负责的,就是怎样在这条道路上组织跨卡数据交换。

      RCCL是AMD面向多GPU集合通信提供的运行库,可以为Reduce、AllReduce等操作提供专门的通信实现。启用RCCL之后,llama.cpp可以使用这套路径完成TP中的部分跨卡Reduce,减少普通后端路径中的同步和数据合并开销。

      但需要强调的是,RCCL并不是一个让TP从不能运行变成能够运行的开关!

      在没有RCCL时,llama.cpp依然可以通过普通后端路径完成跨卡Reduce,启用RCCL只是尝试让这部分通信更加高效。最终能够带来多少提升,取决于跨卡通信在整个推理过程中的耗时占比。

      如果瓶颈主要来自跨卡Reduce,那么RCCL的收益就会比较明显。如果主要时间已经消耗在长上下文Attention、显存访问或者模型本身的计算上,那么RCCL即使优化了通信,在总耗时中的提升也可能很有限。

      1 条回复 最后回复
      0
      • BunseiB 在线
        BunseiB 在线
        Bunsei
        编写于 最后由 编辑
        #5

        三、哪条路线更快?

        前面讲了这么多硬件、切分比例和通信方式,到这里终于该看成绩了。

        不过,在公布结果之前,还需要补上最后两个会出现在表格里的名字,那就是 MTP 和 DFlash2 。

        它们都属于投机解码方案。简单来说,就是先尝试一次预测多个候选token,再由主模型统一验证,如果候选token被接受,主模型就不必严格按照一次一个token的方式向前生成。两者的区别在于MTP使用模型自身携带的多token预测能力,不需要额外加载独立草稿模型。而DFlash2需要加载一个额外的草稿模型,由草稿模型提出候选,再交给主模型验证。

        经过兼容性测试后,最终形成了三条可以实际运行的路线:

        路线 多卡模式 投机方式 定位
        TP + MTP Tensor Split + RCCL 模型内置MTP 双卡性能路线
        PP + MTP Layer Split 模型内置MTP 简单、省显存的PP路线
        PP + DFlash2 Layer Split 外部DFlash2 Q4草稿 PP下追求更高解码性能

        PS:至于TP + DFlash2,它会在当前llama.cpp的分片输出权重与GET_ROWS路径上失败,因此没有进入正式性能对照。这个问题会在后文单独说明。

        为了尽量减少变量,我重新进行了一轮对照,保持以下条件一致:

        项目 条件
        主模型 Qwen3.8-27B HauhauCS-Aggressive Q6_K_P
        双卡比例 R9700 / RX 9070 = 65/35
        上下文容量 163840 tokens
        主模型KV Cache FP16
        mmproj 加载相同的BF16视觉投影
        并发 parallel=1
        R9700功耗上限 210W
        RX 9070功耗上限 200W
        采样 temperature=0,seed=123
        TP路线 TP + RCCL + MTP,n-max=3
        PP路线 PP + DFlash2 Q4_K_M,n-max=4

        测试时,每个端点都尽量保持输入内容、输出长度和缓存状态一致。我选择了四种更接近日常Agent使用方式的负载。

        第一种是96-token短输入,并强制生成512个token。这里的96是96个token,不是96K。它主要考察短输入、持续生成时的Decode能力,Prefill数字只作为记录,不适合拿来判断长提示吞吐。

        第二种是从零载入129481个token,再生成256个token。它模拟缓存完全失效、服务重启或者上下文压缩后重新载入完整历史的情况。

        第三种是命中128965个token的长前缀缓存,只追加1547个新token,再生成256个token。它最接近日常Agent完成一次工具调用后,把新结果追加到既有上下文中的场景。

        第四种是在命中129996个token之后,一次性追加31413个token,再生成256个token。它模拟工具突然返回大量日志、源码或文档的突发情况。

        TP + MTP与PP + DFlash2结果:

        测试场景 路线 Prefill Decode 总墙钟时间
        96输入 + 512输出 TP + MTP 225.823 t/s 44.901 t/s 11.813秒
        96输入 + 512输出 PP + DFlash2 206.037 t/s 42.116 t/s 12.606秒
        129481冷输入 + 256输出 TP + MTP 397.916 t/s 33.610 t/s 333.067秒
        129481冷输入 + 256输出 PP + DFlash2 269.625 t/s 24.424 t/s 490.752秒
        命中128965,追加1547 + 256输出 TP + MTP 226.741 t/s 36.621 t/s 13.872秒
        命中128965,追加1547 + 256输出 PP + DFlash2 159.674 t/s 22.839 t/s 20.938秒
        命中129996,追加31413 + 256输出 TP + MTP 221.005 t/s 34.119 t/s 149.716秒
        命中129996,追加31413 + 256输出 PP + DFlash2 147.937 t/s 22.997 t/s 223.533秒

        TP + MTP相对PP + DFlash2的领先幅度:

        测试场景 Prefill领先 Decode领先 总墙钟缩短
        96-token短输入、长生成 9.60% 6.61% 6.29%
        129K冷重建 47.58% 37.61% 32.13%
        129K高命中、追加约1.5K 42.00% 60.34% 33.75%
        约130K高命中、突发约31K 49.39% 48.36% 33.02%

        结果比我最初预期的更加明确。

        在96-token短输入中,两条路线的差距并不大。TP + MTP的总时间只缩短了6.29%,说明当输入很短、主要时间用于持续生成时,两种投机方案都能获得比较接近的效果,但进入真正的长上下文之后,差距迅速拉开。

        在129K冷启动中,TP + MTP将总时间从490.752秒缩短到333.067秒;在高缓存命中、只追加约1.5K的情况下,总时间从20.938秒缩短到13.872秒;面对约31K的突发追加,总时间也从223.533秒缩短到149.716秒。

        三种长上下文工况的最终结果非常接近,TP + MTP都把总时间缩短了大约32%到34%,这也推翻了我在测试前的一个重要预期。

        我原本认为,PP通信更少,应该更擅长完整吞入长提示。TP则主要在深上下文Decode中占优。但严格复测表明,在这套具有真实P2P、启用RCCL的R9700 + RX 9070平台上,TP不仅提高了Decode,也显著提高了129K冷启动和长上下文追加时的Prefill。换句话说,TP + MTP并不是只在某一个指标上跑出了更漂亮的数字,而是在三种最接近真实128K Agent的工作负载中,都取得了更短的端到端等待时间。

        因此,这轮测试给出的第一个核心结论是:

        在当前硬件、模型和软件构建下,TP + RCCL + MTP是这套双卡系统的默认性能路线。

        不过,这张表同时留下了另一个很有意思的问题,PP + DFlash2在部分测试中拥有更高的草稿接受率和更长的连续接受长度,按直觉似乎应该生成得更快,但最终却没有赢得端到端速度。

        为什么接受了更多候选token,反而还是更慢?

        这就是下一部分需要回答的问题。

        1 条回复 最后回复
        0
        • BunseiB 在线
          BunseiB 在线
          Bunsei
          编写于 最后由 编辑
          #6

          四、接受率≠速度。

          投机解码最容易让人产生误解的指标,就是接受率。

          从原理上看,草稿模型一次提出多个候选token,主模型验证后接受得越多,理论上就越能减少逐token前向计算。因此,看到更高的接受率和更长的连续接受长度时,我们很自然地会认为它应该更快,但实际速度并不只由接受率决定。

          一次投机解码所消耗的时间,包含以下几个部分:

          草稿模型生成候选token -> 主模型批量验证候选 -> 接受或者拒绝候选并更新KV Cache -> 多卡之间完成模型计算和数据同步 -> 采样器选择最终输出。

          所以更准确的理解应该是:

          实际速度 ≈ 每轮最终接受的有效token ÷ 草稿生成、主模型验证、跨卡同步和采样的总耗时

          这就好像是一个公式,接受率只能反映分子的一部分,却没有告诉我们为了获得这些候选,系统在分母上付出了多少成本。

          DFlash2接受率更高,却没有赢下对照实验

          在96-token短输入中,PP + DFlash2的接受率为57.96%,平均连续接受长度为3.32,TP + MTP的接受率只有48.24%,平均连续接受长度为2.44。

          单看这两个数字,DFlash2明显更漂亮,但最终Decode速度却是TP + MTP:44.901 t/s 而 PP + DFlash2:42.116 t/s。TP + MTP仍然更快,端到端时间也从12.606秒缩短到了11.813秒。

          在129K冷启动测试中,同样的现象更加明显:

          路线 接受率 平均接受长度 Decode
          TP + MTP 52.88% 2.58 33.610 t/s
          PP + DFlash2 57.28% 3.27 24.424 t/s

          PP + DFlash2接受了更多候选,平均连续接受长度也更高,但Decode仍然明显落后。

          DFlash2提高了PP的投机效率,但它无法消除PP本身的串行分层路径。对于每一个需要主模型验证的token,数据仍然要依次经过R9700与RX 9070负责的模型阶段。相反,TP + MTP虽然接受率不一定更高,但两张显卡能够同时参与同一层的主模型计算。在真实P2P与RCCL都能够工作的情况下,主模型基础路径上的优势,最终超过了DFlash2在接受率上的领先。

          所以这张主对照表能够证明“TP + MTP比PP + DFlash2更快”,却还不能单独证明“MTP这种投机算法比DFlash2更好”,如果要把多卡模式和投机算法拆开,就必须让它们在相同的PP环境中再比一次。

          MTP与DFlash2的差距其实很小

          为了只比较两种投机方案,我又补充了一轮PP内部对照,结果如下:

          测试场景 PP + MTP PP + DFlash2 端到端结果
          96输入 + 512输出 267.90 prefill / 39.70 decode / 13.30秒 206.04 prefill / 42.12 decode / 12.61秒 DFlash2快5.22%
          129K输入 + 256输出 260.32 prefill / 23.81 decode / 508.14秒 269.62 prefill / 24.42 decode / 490.75秒 DFlash2快3.42%
          命中约129K,追加1547 + 256输出 149.12 prefill / 25.17 decode / 20.59秒 159.67 prefill / 22.84 decode / 20.94秒 MTP快1.65%
          命中约130K,追加31413 + 256输出 140.30 prefill / 21.77 decode / 235.71秒 147.94 prefill / 23.00 decode / 223.53秒 DFlash2快5.17%

          DFlash2在四项测试中三项领先,但它的领先幅度并不大,基本集中在3%到5%。

          唯一由MTP获胜的,是高缓存命中后只追加约1.5K的Agent工况。这里PP + MTP的Prefill低于DFlash2,但深上下文Decode达到25.17 t/s,高于DFlash2的22.84 t/s,最终以20.59秒对20.94秒小幅获胜。

          这组结果说明,两种投机方案并不存在数量级上的差距。

          DFlash2通常能够获得更长的连续接受长度,在多数PP工况中略快,MTP则不需要加载外部草稿模型,在部分深上下文增量生成中也可能取得更好的Decode表现。

          因此,主对照中TP + MTP领先32%到34%,主要原因并不是MTP在投机算法上全面击败了DFlash2,而是TP主模型计算路径本身取得了明显优势。

          MTP更省显存,也更容易部署

          两种PP投机方案在显存分配上有差异。

          路线 R9700显存占用 RX 9070显存占用
          PP + MTP 约25.0GB 约12.9GB
          PP + DFlash2 Q4 约26.7GB 约11.7GB

          DFlash2需要把额外草稿模型放在R9700上,因此比MTP多占用大约1.7GB主卡显存。它还需要单独下载草稿文件,并使用支持DFlash2的实验性llama.cpp构建。

          MTP则直接使用模型内部能力,不需要额外草稿文件,也为R9700留下了更多显存余量。

          所以,如果PP只是TP不可用时的兼容降级路线,我更倾向于把MTP作为默认选择。如果愿意为多数工况大约3%到5%的提升,增加约1.7GB显存占用和一套额外草稿依赖,再考虑启用DFlash2会更合理。

          为什么没有TP + DFlash2?

          既然TP的主模型路径更快,而DFlash2在PP中又能获得不错的投机效果,一个很自然的想法就是:

          能不能把它们组合起来,使用TP + DFlash2?

          我确实进行了尝试,但很可惜当前版本无法正常运行。

          DFlash2的候选选择器需要从主模型的输出权重中取出指定token对应的行,也就是执行GET_ROWS。在TP模式下,这张输出权重表已经被切分到两张显卡上,当前llama.cpp的多卡后端还不能在这条路径中,正确完成跨分片取行与结果聚合。

          最终表现为split axis、shared tensor或者backend ownership相关错误,缺少DFlash2候选选择器面对分片输出权重时的完整语义。

          所以至少在当前构建中,DFlash2只能留在PP路径上。

          1 条回复 最后回复
          0
          • BunseiB 在线
            BunseiB 在线
            Bunsei
            编写于 最后由 编辑
            #7

            五、RCCL究竟带来了多少提升?

            前面提到,RCCL是对跨卡Reduce路径的一次优化。

            这次测试分别在4K短上下文和128K长上下文下,对启用与关闭RCCL进行了严格对照。

            4K上下文:Prefill提升约9%

            TP构建 Prefill Decode
            不使用RCCL 1183.30 t/s 28.53 t/s
            使用RCCL 1291.31 t/s 29.18 t/s
            提升 9.13% 2.27%

            在4K测试中,RCCL带来的Prefill提升比较明显,从1183.30 t/s提高到1291.31 t/s,增幅约为9.13%,Decode也有所提高,但幅度只有2.27%。

            这说明RCCL确实优化了TP的跨卡通信,但跨卡归约并不是Decode中的唯一成本。即使通信变得更高效,模型计算、显存访问和采样等部分仍然不会因此消失。

            128K上下文:收益收敛到约2%

            TP构建 Append Prefill Deep Decode
            不使用RCCL 266.89 t/s 19.28 t/s
            使用RCCL 273.24 t/s 19.55 t/s
            提升 2.38% 1.44%

            第二组测试在已有约128K上下文的情况下,继续追加约1K新输入并生成输出。

            到了128K,RCCL带来的提升明显缩小,增量Prefill从266.89 t/s提高到273.24 t/s,提升2.38%;Deep Decode从19.28 t/s提高到19.55 t/s,提升1.44%。

            我更倾向于把这种变化理解为瓶颈占比发生了转移。

            在4K工况下,跨卡通信和同步在总耗时中占有相对明显的比例,因此优化归约路径能够直接反映到Prefill速度上。随着上下文增长到128K,Attention和KV Cache访问开始消耗更多时间,跨卡通信即使变快,在整个任务中的占比也随之下降。

            RCCL仍然有效,只是它能够优化的那部分,已经不再是主要矛盾,所以,对这套平台来说,RCCL值得作为TP的默认构建选项,这份收益不算惊人,但方向稳定,而且没有在本次测试中观察到明显负作用。既然决定使用TP,就没有理由主动放弃它。

            1 条回复 最后回复
            0
            • BunseiB 在线
              BunseiB 在线
              Bunsei
              编写于 最后由 编辑
              #8

              六、我应该怎样部署?

              经过前面的测试之后,我并不打算为每一种任务都准备一套完全不同的启动参数。

              理论上,针对冷启动、缓存追加、短输入生成和大段突发内容分别切换Llama的启动配置,或许能够再挤出一点性能,但在实际工作中,频繁重启服务、修改参数和重新建立缓存,本身也会带来额外成本。

              所以我更需要的是一条能够覆盖大多数128K Agent任务的默认路线,所以我选择了,TP + RCCL + MTP。

              核心配置为:

              HIP_VISIBLE_DEVICES=1,0
              --split-mode tensor
              --tensor-split 65,35
              --ctx-size 163840
              --parallel 1
              --cache-type-k f16
              --cache-type-v f16
              --flash-attn on
              --fit off
              MTP n-max=3
              

              这选择163840作为分配容量,并不意味着日常任务一定要把上下文用到160K,我的实际目标仍然是把主要工作上下文长度控制在128K附近,额外留下大约32K空间,用于工具突然返回大量日志、源码或者文档。这样既能避免上下文刚到128K就立刻触发裁剪,也能为Agent完成当前步骤留下足够余量。

              1 条回复 最后回复
              0
              • BunseiB 在线
                BunseiB 在线
                Bunsei
                编写于 最后由 编辑
                #9

                结论:第二张显卡究竟值不值得?

                回到最开始的问题,那就是这套AMD平台究竟值不值得继续折腾多卡?

                我的答案是:

                值得,但需要清楚自己得到的是什么。

                RX 9070并没有让R9700的性能简单翻倍。这套同架构异规格双卡仍然受到显存容量不对称、计算能力差异和PCIe通信的限制。TP需要快卡等待慢卡,PP又无法自动提高单流生成速度,额外的驱动、构建和参数维护也都是真实存在的成本。

                但第二张显卡同样不只是增加了16GB显存,在严格同条件测试中,TP + RCCL + MTP把129K启动、高缓存命中追加和31K突发追加三种长上下文任务的总等待时间缩短了大约32%到34%。

                对于一次十几秒的短对话,这种差距可能不算久,但对于一个持续运行数小时、不断搜索、编译、测试和调用工具的Agent任务,每一轮节省下来的几秒或者几分钟,最终都会累积成可以真实感受到的工作效率。

                这也是这次实验给我最重要的答案:

                双卡没有让本地模型突然变成另一种级别的产品,但它确实让一个已经能够完成工作的模型,变得更适合持续工作。

                RX 9070也完成了它作为“测试卡”的任务。

                它证明了这张B850主板可以实现PCIe 5.0 x8/x8和双向P2P,证明了ROCm上的TP与RCCL能够在消费级平台上获得实际收益,也暴露了DFlash2在TP分片权重路径中的兼容问题。更重要的是,它让我在真正购买第二张R9700之前,先用相对有限的成本看清了多卡能够带来什么,又需要付出什么。

                如果未来升级到双R9700,两张卡拥有相同的显存容量和计算规模,切分与同步应该会比现在更加自然。

                至于这篇文章本身,如果后来有人在相似的平台上尝试AMD双卡,能够因为这些记录少走一点弯路,那么这次折腾就已经超过了它最初的意义。

                1 条回复 最后回复
                1
                • BunseiB 在线
                  BunseiB 在线
                  Bunsei
                  编写于 最后由 编辑
                  #10

                  - 完 -

                  1 条回复 最后回复
                  0
                  • BunseiB 在线
                    BunseiB 在线
                    Bunsei
                    编写于 最后由 编辑
                    #11

                    补充:R9700 单卡Q8 KV、无 mmproj 的 DFlash2 验证

                    刚准备睡觉发现还落了单卡的性能测试,这里补上。

                    GPU: R9700 单卡,210W PPT 上限
                    主模型: HauhauCS-Aggressive Q6_K_P
                    配置上下文: 163840
                    主 KV: Q8_0 / Q8_0
                    草稿 KV: Q8_0 / Q8_0
                    草稿: DFlash2 Q4_K_M,n-max=4
                    mmproj: 不加载
                    parallel: 1
                    Flash Attention: on
                    
                    配置 R9700 VRAM GTT CPU offload
                    Q6_K_P + Q8 KV,无投机 28.6GB 约 8MB 无
                    Q6_K_P + Q8 KV + DFlash2 Q4 30.7GB 约 8MB 无

                    512-token A/B

                    相同 96-token 代码 Agent 提示、temperature 0、seed 123、强制生成 512 token:

                    指标 无投机 DFlash2 Q4 差异
                    Prefill 335.81 t/s 272.85 t/s 仅 96 token,绝对差 66ms
                    Decode 21.01 t/s 42.01 t/s +99.93%
                    Decode time 24.321 s 12.165 s -49.98%
                    总墙钟 24.613 s 12.523 s -49.12%
                    Draft accepted/generated — 357/615 58.05%
                    平均接受长度 — 3.32 —

                    在短输入、持续生成的工况中,DFlash2 几乎把 R9700 单卡速度翻倍,属于明确收益。

                    129K 输入后的深上下文 A/B

                    相同 129,481-token Agent 工具历史、256 输出 token、temperature 0、seed 123:

                    指标 无投机 DFlash2 Q4 差异
                    Full prefill 277.266 t/s 275.524 t/s -0.63%
                    Prefill time 466.992 s 469.944 s +2.951 s
                    Deep decode 13.814 t/s 20.538 t/s +48.68%
                    Decode time / 256 18.460 s 12.416 s -6.044 s
                    总墙钟 485.536 s 482.445 s -3.091 s / -0.64%
                    Draft accepted/generated — 176/312 56.41%
                    平均接受长度 — 3.26 —

                    单卡 MTP 与 DFlash2 Q4

                    为补齐投机算法之间的直接比较,又以完全相同的 R9700 单卡、210W、Q6_K_P、Q8 主/草稿 KV、163840 上下文、不加载 mmproj、parallel=1、temperature 0、seed 123 条件补测了模型内置 MTP(n-max=3)。每个端点前均重新启动服务,129K 工况为 cache_n=0 的完整冷输入。DFlash2 使用前述同条件 Q4_K_M、n-max=4 数据。

                    工况 MTP DFlash2 Q4 端到端结果
                    96 输入 + 512 输出,Prefill 267.432 t/s 272.850 t/s DFlash2 高 2.03%
                    96 输入 + 512 输出,Decode 38.210 t/s 42.010 t/s DFlash2 高 9.95%
                    96 输入 + 512 输出,总墙钟 13.869 s 12.523 s DFlash2 缩短 9.71%
                    129K 输入 + 256 输出,Prefill 266.561 t/s 275.524 t/s DFlash2 高 3.36%
                    129K 长度 Decode 20.962 t/s 20.538 t/s MTP 高 2.06%
                    129K 输入 + 256 输出,总墙钟 497.994 s 482.445 s DFlash2 缩短 3.12%
                    工况 路线 接受率 平均接受长度
                    96 输入 + 512 输出 MTP 59.24%(327/552) 2.78
                    96 输入 + 512 输出 DFlash2 Q4 58.05%(357/615) 3.32
                    129K 输入 + 256 输出 MTP 60.52%(164/271) 2.80
                    129K 输入 + 256 输出 DFlash2 Q4 56.41%(176/312) 3.26

                    MTP 的 token 接受率略高,但连续接受长度更短,不能只凭接受率判断端到端速度。短生成由 DFlash2 明显胜出。129K 深度 decode 则由 MTP 小胜约 2%,但 DFlash2 更快的冷 prefill 仍令整项任务缩短约 3.1%。两者的进程 VRAM 都约 30.6~30.7GB,MTP 在 129K 满载时 AMD-SMI 总显存达到约 32.26/32.62GB,只剩约 0.36GB 设备级余量。

                    1 条回复 最后回复
                    1
                    • ,terryT terry 固定了此主题
                    • terryT 在线
                      terryT 在线
                      terry
                      超级版主
                      编写于 最后由 编辑
                      #12

                      挺有意思的,不过门槛其实挺高,这两张卡都不便宜,而且都是pcie5.0的接口好像。主板也要支持x8拆分。

                      油管:https://www.youtube.com/@抡锤者

                      BunseiB 1 条回复 最后回复
                      0
                      • terryT terry

                        挺有意思的,不过门槛其实挺高,这两张卡都不便宜,而且都是pcie5.0的接口好像。主板也要支持x8拆分。

                        BunseiB 在线
                        BunseiB 在线
                        Bunsei
                        编写于 最后由 Bunsei 编辑
                        #13

                        @terry 说:

                        挺有意思的,不过门槛其实挺高,这两张卡都不便宜,而且都是pcie5.0的接口好像。主板也要支持x8拆分。

                        其实说实话还好,Amd多卡玩下来其实挺简单的。 主板我原本以为不支持需要有专门的那种pcie switch芯片,但实测下来好像没有问题,我觉得可以去发个帖子,吹一下这块板子,毕竟他只要1400块,虽然价格比不上那些洋垃圾或者是华南金牌,但他性价比在新平台里真的没法比,如果要玩新平台,我首推这块!

                        1 条回复 最后回复
                        0

                        你好!看起来您对这段对话很感兴趣,但您还没有一个账号。

                        厌倦了每次访问都刷到同样的帖子?您注册账号后,您每次返回时都能精准定位到您上次浏览的位置,并可选择接收新回复通知(通过邮件或推送通知)。您还能收藏书签、为帖子顶,向社区成员表达您的欣赏。

                        有了你的建议,这篇帖子会更精彩哦 💗

                        注册 登录
                        回复
                        • 在新帖中回复
                        登录后回复
                        • 从旧到新
                        • 从新到旧
                        • 最多赞同


                        • 登录

                        • 登录或注册以进行搜索。
                        • 第一个帖子
                          最后一个帖子
                        0
                        • 版块
                        • 最新
                        • 标签
                        • 热门
                        • 用户
                        • 群组