CANN hixl 异构跨语言调用优化库概念拆解:零拷贝通信与批量传输原理深度解析与技术实战全攻略(入门版)
前言
你是否遇到过这样的情况:在昇腾NPU上写了一个 PyTorch 模型,前向传播跑得飞快,结果换了一个自定义 C++ 算子之后,整个推理管道突然慢了一截?明明硬件还是那块硬件,代码逻辑也没变,怎么就卡了?这不是你的错觉,这是 Python 和 C++ 之间的那道"墙"在作祟。
昇腾异构计算架构(CANN)上运行的大模型推理系统,天然就是多语言混合体——Python 负责调度和控制流,C++ 负责算子的核心计算逻辑,底层还有 C 驱动与硬件寄存器打交道。这套分层本身是合理的,但不同语言之间的数据传递从来都不是免费的。当数据从一个语言的内存空间流向另一个语言的内存空间时,涉及的开销往往超出开发者的直觉预期。
CANN 生态下的 hixl 仓库,正是为了解决这类异构跨语言通信问题而诞生的。从能力定位来看,它是一个面向昇腾芯片的高效单边通信库,核心能力是提供零拷贝的数据传输通道,同时在 API 层面做了大量简化,让 Python 和 C++ 之间的互调不再成为性能瓶颈。这个仓库支持 D2D、D2H、H2D 等多种内存类型之间的传输,兼容 HCCS 和 RDMA 等高速互联协议,最高带宽可达 119GB/s(基于昇腾 A3 芯片和 HCCS 链路)。
接下来的内容,我会把"异构交叉调用"这个听起来抽象的概念拆开来讲,接着用生活里的例子来类比 hixl 的几个核心设计思路,再给出接入指南和代码示例。如果你在做 PyTorch 推理加速、大模型 PD 分离、或者任何涉及多语言协作的项目,这篇文章可能会帮你省下不少调优时间。
什么是异构交叉调用问题
从一道家常菜说起
想象你在一间开放式厨房里做菜。灶台是 C++ 算子(高温、精准、快速),而你本人是 Python 调度层(规划流程、判断火候、决定下什么料)。问题来了:当你从案板(Python 内存)把切好的菜端到锅里(C++ 内存)的时候,你需要用一个盘子作为中转。每次端菜都要洗盘子、拿盘子、装盘子、递盘子,菜本身并没有变,但中转这个动作本身消耗了大量时间。
在软件层面,这个"中转盘子"的问题体现在三个地方。
第一层是 Python GIL(全局解释器锁)。Python 的多线程机制并不能真正并行执行字节码,同一时刻只有一个线程在执行 Python 解释器字节码。当 Python 代码尝试调用一个 C++ 扩展时,GIL 需要被释放,控制权随之切换到 C++ 代码。这个获取和释放的过程并非零开销,在高频调用的场景下(比如每秒调用数万次小算子),GIL 切换本身会累积成可观的延迟。
第二层是 ABI 调用约定。Python 的数据对象(比如 PyObject指针、PyArrayObject)和 C++ 内部数据结构之间的格式并不兼容。PyTorch 的 tensor 在 Python 侧是一个 Python 对象,但到了 C++ 侧需要转换成 ATen 张量格式。这个转换涉及指针解引用、shape 解析、dtype 映射、stride 计算等步骤。数据本身可能只需要搬运一次,但格式适配的过程往往是多层函数调用栈,每一层都在做类型检查和内存分配。
第三层是数据格式转换产生的临时拷贝。Python 侧的 NumPy 数组或者 PyTorch tensor,其内存布局与 C++ 侧期望的布局往往存在差异。比如 row-major 和 column-major 的差异,比如连续内存和分段内存的差异,这些差异迫使系统至少要创建一份中间 buffer 来做格式适配。即使框架层做了原地操作(in-place)的优化,格式转换逻辑本身也必须在运行时执行。
把这三层叠加起来,结果就是:当你在 Python 里写一个简单的 model(input_tensor) 时,如果 model 内部包含一个 C++ 自定义算子,那么从 Python 的 tensor 到 C++ 的数据结构的转换过程,会在每次推理迭代中重复执行。如果这个算子在一个 batch 的每条数据上都要被调用一次,那么转换开销就会直接叠加到整体延迟上。
PyTorch 推理延迟为什么会增加
在纯 PyTorch 的场景下,数据一直在 PyTorch 的内部世界里流转,格式高度统一,不需要频繁跨越语言边界。但当你引入自定义 C++ 算子时,情况就变了。
考虑一个典型的推理场景:Prefill 阶段由 Python 调度层驱动,输入 token 先经过 embedding 层(在 Python/PyTorch 中),紧接着需要调用一个 attention kernel(可能是 C++ 实现)。这个 kernel 期望的输入格式是某种特定的数据排布,但 PyTorch 传过来的 tensor 在 layout 上不完全一致。于是,数据在进入 kernel 之前要先做一次格式调整。Prefill 完成后,进入 Decode 阶段,每个新 token 都要重复这个过程。由于 Decode 是自回归的,每个 token 都会触发一次前向传播,每次前向传播都会遇到同样的数据转换开销。这就是为什么 PyTorch 推理在引入自定义算子后延迟会明显增加——不是因为计算本身变重了,而是因为"搬运"的次数变多了。
此外,在大模型推理的 PD 分离架构(Prefill-Decoder 分离)中,Prompt 侧的 Prefill 结果(比如 KV Cache)需要从 Prefill 节点传输到 Decoder 节点。这个跨进程甚至跨节点的数据传输,如果用传统的序列化+Socket 方式来做,数据会在内存中经历从 NPU 到 Host、再从 Host 到网络的多次拷贝,每一跳都是一次完整的格式序列化和反序列化。hixl 解决的正是这个层面的问题——它提供了跨节点零拷贝的直接内存访问能力,数据不需要经过中间缓冲区,直接从一块 NPU 的显存传输到另一块 NPU 的显存。
hixl 的核心设计思路
零拷贝数据通道
hixl 的"零拷贝"并不是说数据完全不需要搬运——数据从节点 A 的显存到节点 B 的显存物理上肯定是要移动的——而是说在整个传输路径中,数据不会因为格式转换或中间缓冲而产生额外的内存拷贝操作。
在传统的 RPC 方式中,数据从 A 节点的 Python 进程到 C++ 运行时,再到网络缓冲区,一路到达 B 节点的接收端,整个链路中数据可能被序列化了多次、拷贝了多次。每一层都需要把数据放到自己的缓冲区里,再由下一层来读取。零拷贝的思路是:跳过中间缓冲区,让发送端和接收端的内存区域建立直接的映射关系。hixl 底层依赖 RDMA 或 HCCS 这样的高速互联硬件,这些硬件支持"注册内存"机制——把一块用户空间的虚拟内存地址注册到硬件,硬件可以直接绕过操作系统内核去访问这块物理内存,从而实现跨节点的高速数据传输而不需要经过内核协议栈。
具体来说,hixl 的零拷贝路径是这样的:用户在 Python 或 C++ 侧准备好数据(已经在 NPU 显存中),调用 hixl 的传输接口,hixl 将这块已注册的内存地址告知硬件,硬件直接执行 DMA 传输,数据从源头到目的地,中间不经过任何中间 buffer。这条路径的设计取舍在于:省掉了中间 buffer 意味着省掉了两次内存读写(写入 buffer 和从 buffer 读取),但代价是需要提前注册内存区域,让硬件知道如何访问这块物理地址。注册过程本身有一次性开销,所以零拷贝更适合大块数据的传输场景(比如 KV Cache 的批量传输),对于极小的控制消息,零拷贝的注册开销反而可能得不偿失。
延迟绑定
“延迟绑定”(Lazy Binding)这个概念,可以类比为餐厅里的"先点菜、后做菜"模式。传统方式下,当你走进餐厅,服务员会立刻把所有菜都做好端上来,不管你实际吃不吃得完。这种" eager"(急切)的方式对应到跨语言调用中,就是每次调用时都把所有可能需要的数据都打包好、传输好,哪怕这次调用根本不需要其中某些数据。
延迟绑定则更聪明一些:你先告诉厨房你可能会点什么菜,厨房把准备工作做好(切配、调料预混),等你真正点了某道菜时,厨房只需要执行最终的烹饪步骤就行,不需要再从头开始准备原材料。在 hixl 中,延迟绑定体现在:连接建立、内存注册、传输资源配置这些准备工作在初始化阶段一次性完成,而具体的数据传输操作等到真正需要时才触发。这样,每次传输操作的路径被压缩到了最小——只有 DMA 指令的发起和数据在硬件层面的移动,没有额外的协议握手或资源发现开销。
批量请求合并
假设你要从上海寄一批快递到北京,每件单独寄,每件都要填单子、称重、装车、运单追踪,成本很高。但如果把这批快递打包成一个集装箱一起运,单件的平均成本就大幅下降了。批量请求合并的思路与此类似:当多个小尺寸的数据传输请求同时到达时,hixl 不会立即为每个请求单独发起一次 DMA 操作,而是先把这些请求暂存到内部队列中,等到积累到一定数量或者达到时间窗口阈值后,统一打包执行。
这样做的好处有两方面。一方面,硬件层面一次批量 DMA 的吞吐量远高于多次小尺寸 DMA 的吞吐量之和,因为每次 DMA 都有固定的启动开销(命令构造、硬件队列排队、延迟确认),批量操作可以把启动开销分摊到多个数据块上。另一方面,批量合并减少了对硬件队列的竞争,在高并发场景下避免了频繁的队列切换和锁争用。设计上的权衡在于:批量合并会引入一定的排队延迟(数据要等一下才能发出),所以 hixl 提供了可配置的时间窗口和批次大小参数,让用户根据实际业务对延迟的敏感程度来调整合并策略。
快速接入 hixl
安装方式
hixl 库目前提供两种安装途径:pip 预编译包和 conda-forge 通道。对于大多数用户来说,pip 是最直接的选择。
pip install cann-hixl
如果你是 conda 环境的管理者,也可以通过 conda 来安装:
conda install cann-hixl -c conda-forge
安装完成后,可以验证一下:
import hixl
print(hixl.__version__)
hixl 作为 CANN 生态的一部分,预编译包中已经包含了针对昇腾芯片的优化过的 native 库,不需要用户手动编译底层 C++ 代码。conda 通道的提供是为了照顾科学计算场景中广泛使用 conda 环境的研究团队。
环境变量配置
hixl 的行为受多个环境变量控制,在多机多卡场景下需要正确配置。
# 指定使用的昇腾设备 ID
export ASCEND_DEVICE_ID=0
# 启用 HCCS 传输协议(用于单机内或超节点内通信)
export HCCL_INTRA_ROCE_ENABLE=1
# 指定 RDMA 网卡名称(跨节点通信时必须)
export GLOO_SOCKET_IFNAME=enp67s0f5
# 设置日志级别(INFO/WARN/ERROR/DEBUG)
export HIXL_LOG_LEVEL=INFO
HCCL_INTRA_ROCE_ENABLE 看起来名字里有 HCCL,但它控制的是 hixl 在超节点内的传输链路选择——开启后走 HCCS 直连通道,不经过传统网络协议栈,延迟更低。GLOO_SOCKET_IFNAME 则指定了用于跨节点 RDMA 通信的网卡,这在使用 RoCE 协议的超节点间传输时是必需的。
初始化顺序与依赖关系
在使用 hixl 的 Python 接口之前,必须先正确初始化 CANN 的基础层。这个顺序是有约束的,不可以颠倒。
import acl
# 第一步:初始化 ACL(昇腾计算语言层)
acl.init() # 必须在 hixl 之前调用
# 第二步:初始化 hixl
import hixl
hixl.init()
# 此后就可以正常使用 hixl 的 API 了
# 使用完毕后按反序销毁
hixl.finalize()
acl.finalize()
acl 是 CANN 生态的最底层运行时抽象,负责管理昇腾 NPU 的上下文、设备内存分配和硬件资源句柄。hixl 的底层传输引擎依赖 ACL 分配的设备内存和句柄,所以在逻辑上必须建立在 ACL 初始化完成之后。finalize 的反序调用也是同样的原因——hixl 需要在 ACL 释放设备资源之前先释放自己持有的传输句柄,否则 ACL 会报资源泄漏错误。
性能对比与适用场景
为什么需要 hixl 的零拷贝方案
在大模型推理的 KV Cache 传输场景中,数据量通常非常大。一次 Decode 请求涉及的 KV Cache 可能达到几百 MB 甚至 GB 级别。如果用传统方式进行传输,数据在发送端要经历 NPU 显存到 Host 内存的拷贝(pinned memory),接着经过序列化后发到网络缓冲区,再到接收端的网络缓冲区反序列化,再拷贝到目标 NPU 显存。这个链路中至少包含了 4 次内存拷贝操作,而且序列化/反序列化本身还要消耗 CPU 周期。
hixl 的零拷贝方案在硬件层面支持直接内存访问,数据只需要经过一次物理层面的 DMA 传输就可以到达对端显存,整个过程不需要经过操作系统的网络协议栈,也不需要额外的中间 buffer。根据官方 README 中的数据,在昇腾 A3 芯片上使用 HCCS 链路传输 128MB 数据时,hixl 的带宽可以达到 119GB/s;使用 RDMA 链路时,带宽可以达到 22GB/s。这个数字意味着传输 1GB 的 KV Cache 数据在 HCCS 链路上只需要不到 10ms,而在传统 TCP 方式下通常需要数十毫秒甚至更高。
以下是从多个维度对比使用 hixl 前后差异的数据表格。
| 对比维度 | 传统方案(序列化+Socket) | hixl 零拷贝方案 | 差异来源分析 |
|---|---|---|---|
| 单次传输延迟 | 数据需经多次内存拷贝和序列化,延迟随数据量线性增长 | 零拷贝直传,延迟主要由硬件带宽决定 | 省掉了中间 buffer 写入和读取,以及序列化 CPU 开销 |
| 内存带宽占用 | 发送端和接收端各需要额外的中间 buffer,内存占用翻倍 | 数据直接在用户内存和硬件之间传输,无需额外 buffer | 消除了中间 buffer 造成的内存空间浪费 |
| 吞吐量(多链路) | 单一 TCP 连接容易成为瓶颈 | 支持多链路聚合传输,带宽可线性扩展 | 底层支持链路池,硬件资源利用率更高 |
| 跨节点通信能力 | 依赖标准网络协议栈,跨 IDC 场景性能受限 | 支持 RDMA/HCCS 跨节点直连 | 硬件直连避免了网络协议栈的额外处理开销 |
hixl 适用的典型场景
第一个典型场景是大模型推理的 PD 分离架构。Prefill 节点和 Decoder 节点各自持有完整的模型副本,Prefill 阶段生成的 KV Cache 需要高效传输到 Decoder 节点继续使用。hixl 的 LLM-DataDist 组件专门为此场景优化,提供了携带 KV Cache 语义的传输接口,可以直接对接 vLLM 和 SGLang 等主流推理引擎,传输延迟比传统方案有显著改善。
第二个典型场景是 RL 后训练中的参数切换。策略模型和价值模型的参数在不同训练步骤之间需要频繁切换,切换过程中涉及大量参数数据的传输。hixl 的批量传输能力可以把多次小尺寸参数更新合并为一次大尺寸 DMA 操作,大幅降低参数同步的总体开销。
第三个典型场景是多卡推理中的 KV Cache 聚合。当单个节点的显存不足以容纳完整上下文时,需要把 KV Cache 分散到多张 NPU 卡上,统一传输到下一阶段。hixl 支持 D2D 直传,可以绕过 Host 内存直接在各卡之间搬运数据。
hixl 不适用的场景
hixl 并不是万能药。有些场景下使用它反而会增加复杂度而得不到预期收益。
单卡、单进程内部的 Python 到 C++ 函数调用,并不适合用 hixl 来优化——hixl 解决的是跨节点、跨进程的传输问题,而不是同进程内语言边界之间的调用开销。这类问题应该通过 PyTorch 的自定义算子注册机制(torch.library)或者 TorchScript 融合来解决。
传输数据量极小的场景(比如几十字节的控制消息)也不适合 hixl。hixl 的零拷贝机制需要提前注册内存区域,注册操作本身有固定开销。如果每次传输的数据量只有几十字节,注册开销会比实际传输开销还大。对于这类场景,直接用 HCCL 的点对点通信原语会更高效。
多语言混合编程示例
Python 调用 C++ 自定义算子的完整流程
这里给出一个完整的示例,演示如何在 Python 侧通过 hixl 来传输 KV Cache 数据到远端节点。示例包含内存注册、集群初始化、传输配置和实际传输四个步骤。
import torch
import hixl
# 初始化 hixl(依赖 ACL 环境变量)
hixl.init()
# 从配置构建集群信息
config = {
"device_id": 0,
"cluster_id": 1,
"role": "prompt", # prompt 侧还是 decoder 侧
}
cluster_info = hixl.LLMClusterInfo.from_dict(config)
# 申请一块 PyTorch tensor 并注册为远端可访问的内存块
x = torch.randn(1024, 1024, dtype=torch.float16, device="npu")
registered_blocks = hixl.allocate_cache(x, mem_type="device")
# 配置传输参数
transfer_cfg = hixl.TransferConfig(max_concurrent=4, timeout_ms=5000)
# 从远端 pull 数据到本地
task = hixl.pull_cache(
remote_rank=1,
local_cache=registered_blocks,
transfer_config=transfer_cfg,
)
# 等待传输完成
result = task.wait()
print(f"传输完成,状态码: {result.status_code}")
hixl.finalize()
allocate_cache 的作用是把 PyTorch tensor 的底层 NPU 内存页锁定并注册到 hixl 的传输引擎中。注册后的内存区域硬件可以直接访问,不需要操作系统介入。mem_type="device" 指定注册的是 NPU 设备内存;如果是 Host 内存则传 "host"。这里用 PyTorch 的 tensor 作为数据源是因为推理框架本身就在用 PyTorch 管理数据,直接复用已有的 tensor 可以避免额外的数据拷贝。
推送模式:从 Decoder 侧主动推送数据
在某些架构下,Decoder 节点是数据的持有方,需要主动把 KV Cache 推送给多个 Prompt 节点。hixl 支持 push 模式:
import hixl
hixl.init()
# Decoder 侧持有数据并注册
y = torch.randn(2048, 2048, dtype=torch.float16, device="npu")
remote_cache = hixl.allocate_cache(y, mem_type="device")
# 主动推送到远端 prompt 节点
push_task = hixl.push_cache(
remote_ranks=[0, 1, 2], # 推送到多个节点
src=remote_cache,
transfer_config=hixl.TransferConfig(async_enable=True),
)
# 异步模式下可以先去做其他计算
compute_result = do_other_work()
push_result = push_task.wait()
hixl.finalize()
push 模式支持一次操作向多个远端节点同时推送数据,hixl 底层会为每个目标节点发起独立的 DMA 流,但数据源 buffer 是共享的,不需要为每个目标单独拷贝一份数据。async_enable=True 开启了异步传输模式,调用 wait() 之前可以并行执行其他计算任务,实现传输与计算的重叠掩盖。
异步分层传输
对于超大规模的 KV Cache 数据,hixl 还提供了异步分层传输能力,可以在数据传输的同时进行部分解码计算:
import hixl
hixl.init()
# 注册大型 KV Cache
big_cache = torch.randn(8192, 8192, dtype=torch.float16, device="npu")
layers = hixl.allocate_cache(big_cache, mem_type="device")
# 配置分层同步器,实现逐层传输和计算重叠
syncer = hixl.LayerSynchronizer(
total_layers=32,
sync_interval=1, # 每传完 1 层就开始下一层的传输
)
async_task = hixl.transfer_cache_async(
remote_rank=1,
local_cache=layers,
synchronizer=syncer,
)
# 在传输过程中可以同时进行其他层级的计算
while not async_task.is_done():
current_layer = syncer.get_current_layer()
decode_layer(current_layer)
syncer.wait_sync()
hixl.finalize()
分层传输的核心设计思想是"传输-计算流水线化"。当第 N 层的数据还在传输时,第 N-1 层的解码计算就可以开始了。这种流水线结构在延迟敏感的场景下非常重要——用户感知的端到端延迟等于"计算时间 + 收尾层的传输时间",而不是"所有层传输时间之和 + 计算时间"。sync_innterval=1 意味着每传完一层就立即触发下一层的传输,这样可以最大化流水线并行的效果。
调试与排查
日志级别配置
hixl 提供了分级的日志输出能力,默认级别是 WARN。如果遇到初始化失败或传输异常,可以通过调整日志级别来获取详细的诊断信息。
import os
# 在代码开头设置环境变量
os.environ["HIXL_LOG_LEVEL"] = "DEBUG" # DEBUG 会输出每个传输操作的详细信息
import hixl
hixl.init()
# 也可以在运行时动态设置日志级别
hixl.set_log_level("INFO")
# 运行你的传输逻辑
transfer_and_compute()
hixl.finalize()
DEBUG 级别会打印出每次 DMA 传输的源地址、目标地址、传输大小和耗时,这些信息在排查传输失败或者性能不达预期时非常有用。但 DEBUG 日志量很大,在生产环境中应该切回 INFO 或 WARN 级别,避免日志文件膨胀。
常见错误码解读
hixl 和 LLM-DataDist 的错误码体系分为两层:通用 hixl 层错误码和 LLM-DataDist 业务层错误码。理解错误码的前缀有助于快速定位问题来源。
| 错误码 | 含义 | 常见原因 | 处理建议 |
|---|---|---|---|
| HIXL_001001 | 内存注册失败 | 指定的 tensor 内存区域已被占用或不在 NPU 上 | 检查 tensor 的 device 属性,确保在 npu 上 |
| HIXL_001002 | 连接建立超时 | 远端节点未启动或网络不通 | 确认两端节点都已执行 hixl.init() 且 cluster_id 匹配 |
| HIXL_001003 | 传输句柄无效 | 调用了已 finalize 的 hixl 实例 | 检查 finalize 和 init 的调用顺序,确保没有悬空引用 |
| LLM_002001 | 远端 Cache 区域不存在 | 远端未调用 allocate_cache 或角色配置错误 | 确认两端角色配置一致,prompt 和 decoder 不可互换 |
| LLM_002002 | 传输数据量超限 | 单次传输超过了注册的 Cache 大小 | 检查 registered_blocks 的 shape 和传输 tensor 的 shape 是否匹配 |
hixl 错误码的第一段数字(如 001)标识了错误所属的子系统,第二段数字(如 001、002)是该子系统内的具体错误编号。看到 HIXL 前缀的错误说明问题出在传输引擎层,可能与硬件链路或内存注册有关;看到 LLM 前缀的错误说明问题出在 LLM-DataDist 业务层,可能与集群配置或 Cache 管理有关。
hixl 与 ACL 错误的区分
在实际调试中,hixl 的错误有时会和底层 ACL 的错误混在一起输出。区分两者有助于缩小排查范围。
如果错误信息中包含 “acl” 关键字(如 “ACL error: memory allocate failed”),说明问题出在 CANN 的基础运行时层,与硬件驱动或 NPU 上下文有关。遇到这类错误时,排查的第一步是检查昇腾 NPU 驱动是否正常运行:npu-smi 命令能正常显示设备信息是排查的第一步。同时确认 CANN 软件包版本和驱动版本是否匹配——版本不匹配是导致 ACL 初始化失败的最常见原因。
如果错误信息中没有 acl 关键字,而是以 HIXL 或 LLM 开头,说明问题出在 hixl 库本身,可能是传输配置不正确或者集群成员之间的通信超时。遇到这类错误时,应该优先检查网络连通性(尤其是 RDMA 网卡的 link 状态),紧接着核对集群配置文件中的 cluster_id 和 role 是否在所有参与节点上保持一致。
还有一类容易混淆的错误:Python 侧的 tensor 已经在 NPU 上,但 hixl 报告无法注册该内存。这种情况通常是因为 tensor 的底层内存不是 page-locked 的。PyTorch 在 NPU 上分配的 tensor 默认是 page-locked 的,但如果你手动用 torch.empty() 或其他方式重新创建了 tensor,需要确认 device 设置正确。解决方法是始终使用 torch.empty(device="npu") 或 torch.randn(..., device="npu") 来分配设备内存,而不是先在 CPU 上创建再移动到 NPU。
结尾
hixl 是昇腾生态中专门针对跨节点零拷贝传输场景设计的通信库,它的核心价值在于通过单边 DMA 操作省掉了传统传输方式中的多次内存拷贝和序列化开销。在 KV Cache 传输这类大块数据场景下,它提供的带宽可以达到 119GB/s(HCCS 链路)或 22GB/s(RDMA 链路),远高于传统 RPC 方式。hixl 的 API 设计非常精简,核心调用数量控制在十几个,同时提供了完整的 Python 和 C++ 接口,可以直接集成到 vLLM、SGLang 等主流推理框架中使用。对于大模型推理的 PD 分离架构、RL 后训练的参数切换、以及多卡推理中的 KV Cache 聚合,hixl 都是值得考虑的技术选型。需要注意的是,hixl 主要面向跨节点传输场景,对于同进程内的语言边界调用问题,应该通过 PyTorch 的自定义算子机制来解决而不是引入 hixl。
仓库地址:https://atomgit.com/cann/hixl
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐


所有评论(0)