玩转昇腾 CANN:从 Hello World 到向量归一化的 Host--NPU 异构计算实战
前言:为什么 CANN 不再难上手
昇腾 CANN 一直被认为门槛高、资料散、难上手,但真正拦住新手的,并不是算子本身,而是对 Host 与 NPU 异构计算流程不清晰 。本文基于 GitCode Notebook 的真实昇腾 NPU 环境,从 CANN 是什么、怎么跑起来 讲起,通过 Hello World、数组加法到向量归一化三个最小可运行示例,完整演示 CPU 数据准备 → NPU 内存管理 → 数据传输 → 计算流程演示 → 结果回传 的全流程,帮助新手在 5 分钟内建立对 CANN 的正确认知,真正迈出昇腾异构计算的第一步。
1 分钟理解 CANN:概念、用途与适用场景
CANN 是啥?
CANN 是华为为昇腾 NPU 量身打造的 "异构计算工具包",核心作用类似 Java 里的 JVM,帮开发者屏蔽 NPU 底层硬件细节比如芯片架构、指令集,不用纠结硬件原理,只需要通过提供的统一编程接口,聚焦数据在 CPU 主机和 NPU 间的传输,以及计算任务在异构体系中的组织与调度方式,就能实现 "CPU 管调度、NPU 提供设备能力" 的协同开发
CANN 有啥用?
CANN 核心作用就是帮开发者节省时间,解决 CPU 和昇腾 NPU 配合干活的问题,把 NPU 底层复杂的硬件细节全屏蔽掉,不用去懂芯片架构、指令集这些难懂的东西,只需要通过现成编程接口,搞定数据在 CPU主机和 NPU 之间怎么传、该让 NPU 算什么就行,剩下的调度、计算的协同链路,不用跟硬件底层打交道,聚焦核心的计算开发,降低昇腾 NPU 的开发难度
CANN 谁能用?

CANN 是给昇腾芯片配套的开发工具,适合三类开发者用:做 AI 模型部署的、搞高性能数值计算的,以及专门开发昇腾芯片相关程序的开发者,比如你要做视觉识别、语音处理这类智能任务,或者算矩阵、向量这类科学运算,甚至在昇腾 Atlas 硬件上搞边缘计算,都能靠 CANN 来实现。不过得先有昇腾 NPU 的硬件或者用带 NPU 的云环境,再装上 CANN 的工具包才行;新手用它还能学会 CPU 和昇腾 NPU 怎么配合、怎么调度任务,快速上手昇腾相关的开发项目
CANN 怎么用?

CANN 的开发流程可以概括为 5 个相对固定的步骤,核心目标是打通 Host 与昇腾 NPU 之间的数据与运行环境:
第一步:环境初始化:初始化 CANN 运行环境,创建上下文并绑定可用的昇腾 NPU 设备,为后续计算和数据交互建立基础运行条件
第二步:内存分配:Host 侧准备数据缓冲区,同时为 NPU 设备申请对应的设备内存,用于存放待处理数据和中间结果,确保 Host 与 Device 之间的内存空间各自独立、可控
第三步:数据传输:通过同步或异步方式,将数据从 Host 内存拷贝到 NPU 设备内存,或在计算完成后将结果回传至 Host,完成 Host--Device 间的数据流转
第四步:计算流程验证:Host 与 NPU 协同的运行环境中,验证计算流程与数据通路是否正确,重点关注数据是否能够正确写入、读取以及流程是否按预期执行,为后续算子接入或性能优化做好准备
第五步:资源释放:任务结束后,统一释放已分配的内存资源,销毁执行流和上下文,确保运行环境干净可控,避免资源泄露
GitCode Notebook 环境与 Ascend NPU 初始化
GitCode启动NoteBook资源
GitCode NoteBook环境准备
- 计算类型:NPU
- NPU 硬件配置:NPU basic · 1 * Atlas 800T NPU · 32vCPU · 64GB
- 容器镜像:euler2.9-py38-cann8.0-openmind0.6-notebook

系统信息可以看到系统已安装 CANN Toolkit(npu-smi 是其配套的 NPU 管理工具),且环境状态完全正常,明确你的 NPU 设备 ID
bash
npu-smi info

手动添加 CANN 路径到环境变量
bash
# 把CANN的Python库目录添加到PYTHONPATH(让Python找到acl模块)
export PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:$PYTHONPATH
# 把CANN的依赖库目录添加到LD_LIBRARY_PATH(避免运行时缺库)
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/lib64:$LD_LIBRARY_PATH
- 验证环境是否成功
bash
python3 -c "from acl import *; print('✅ acl模块导入成功!CANN环境正常')"

Hello World 实战:Host 与 NPU 数据流演示

- 设备绑定阶段:acl.rt.set_device(0) 是直接绑定容器内映射的昇腾 910B3 NPU(物理 ID=2,容器内逻辑 ID=0),如果没有真实 NPU 硬件,这一步会直接报107001错误,而不是成功执行
- 内存分配阶段:acl.rt.malloc() 是在 NPU 的 HBM高带宽内存中分配物理内存,而非 CPU 内存,分配的内存地址是 NPU 硬件的专属地址空间
- 数据传输阶段:acl.rt.memcpy_async 调用的是昇腾 CANN 的硬件级数据传输接口,数据会通过 PCIe 总线真实传输到 NPU 内存,再从 NPU 内存回传至 Host
- 资源释放阶段:acl.rt.free()/acl.rt.reset_device() 是释放 NPU 的物理内存和硬件上下文,模拟场景下这些接口调用无意义且会报错

- cann_hello.py
python
import acl
import ctypes
import os
import platform
def main():
# 容器环境适配(昇腾NPU逻辑ID映射)
device_id = 0 # 容器内昇腾NPU逻辑ID(对应物理Atlas 800T NPU)
os.environ['ASCEND_DEVICE_ID'] = str(device_id)
os.environ['ASCEND_HOME'] = '/usr/local/Ascend'
os.environ['LD_LIBRARY_PATH'] = '/usr/local/Ascend/ascend-toolkit/latest/lib64:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:' + os.environ.get('LD_LIBRARY_PATH', '')
os.environ['PYTHONPATH'] = '/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:' + os.environ.get('PYTHONPATH', '')
# 初始化CANN环境
ret = acl.init()
if ret != 0:
print(f"ACL初始化失败,错误码: {ret}")
return -1
# 绑定昇腾NPU设备(兼容容器设备映射)
ret = acl.rt.set_device(device_id)
if ret != 0:
device_id = -1 # 自动绑定首个可用昇腾NPU设备
ret = acl.rt.set_device(device_id)
if ret != 0:
print(f"绑定NPU设备失败,错误码: {ret}")
acl.finalize()
return -1
# 创建昇腾NPU上下文
context, ret = acl.rt.create_context(device_id)
if ret != 0:
print(f"创建NPU上下文失败,错误码: {ret}")
acl.rt.reset_device(device_id)
acl.finalize()
return -1
# Host侧数据准备(32字节内存对齐,适配昇腾CANN接口)
cpu_str = "Hello, CANN!"
str_len = len(cpu_str) + 1
cpu_bytes = cpu_str.encode('utf-8') + b'\0'
host_buf = None
host_buf_addr = 0 # 整数类型内存地址(适配CANN接口要求)
if platform.system() == "Linux":
libc = ctypes.CDLL("libc.so.6", use_errno=True)
libc.posix_memalign.argtypes = [ctypes.POINTER(ctypes.c_void_p), ctypes.c_size_t, ctypes.c_size_t]
libc.posix_memalign.restype = ctypes.c_int
ptr = ctypes.c_void_p()
ret_val = libc.posix_memalign(ctypes.byref(ptr), 32, str_len)
if ret_val != 0:
print(f"内存对齐分配失败,错误码: {ret_val}")
return -1
host_buf = ptr
host_buf_addr = ctypes.cast(host_buf, ctypes.c_void_p).value
else:
host_buf = ctypes.c_void_p(ctypes.malloc(str_len))
host_buf_addr = host_buf.value
# 拷贝数据到对齐的Host内存
ctypes.memmove(host_buf, cpu_bytes, str_len)
# 分配昇腾NPU HBM内存
ACL_MEM_MALLOC_NORMAL_ONLY = 0
npu_buf, ret = acl.rt.malloc(str_len, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != 0:
print(f"NPU内存分配失败,错误码: {ret}")
return -1
# 创建CANN执行流
stream, ret = acl.rt.create_stream()
if ret != 0:
print(f"创建Stream失败,错误码: {ret}")
return -1
# Host → 昇腾NPU异步数据传输(DMA硬件通道)
ACL_MEMCPY_HOST_TO_DEVICE = 1
ret = acl.rt.memcpy_async(
npu_buf, # NPU内存地址(整数)
str_len, # 拷贝长度
host_buf_addr, # Host内存地址(整数)
str_len, # 源数据长度
ACL_MEMCPY_HOST_TO_DEVICE,
stream
)
if ret != 0:
print(f"Host→NPU拷贝失败,错误码: {ret}")
return -1
acl.rt.synchronize_stream(stream) # 等待传输完成
# NPU → Host异步数据回传
ACL_MEMCPY_DEVICE_TO_HOST = 2
host_out = ctypes.create_string_buffer(str_len)
host_out_addr = ctypes.cast(host_out, ctypes.c_void_p).value
ret = acl.rt.memcpy_async(
host_out_addr, # Host内存地址(整数)
str_len, # 拷贝长度
npu_buf, # NPU内存地址(整数)
str_len, # 源数据长度
ACL_MEMCPY_DEVICE_TO_HOST,
stream
)
if ret != 0:
print(f"NPU→Host拷贝失败,错误码: {ret}")
return -1
acl.rt.synchronize_stream(stream) # 等待传输完成
# 输出验证(Host-NPU数据传输完整性)
cpu_original = ctypes.string_at(host_buf, str_len).decode('utf-8').strip('\0')
npu_returned = host_out.value.decode('utf-8').strip('\0')
print(f"Host原始:{cpu_original}")
print(f"昇腾NPU回传:{npu_returned}")
# 释放资源(遵循昇腾CANN资源释放规范)
if platform.system() == "Linux" and host_buf:
libc.free(host_buf)
elif host_buf:
ctypes.free(host_buf)
acl.rt.free(npu_buf)
acl.rt.destroy_stream(stream)
acl.rt.destroy_context(context)
acl.rt.reset_device(device_id)
acl.finalize()
return 0
if __name__ == "__main__":
exit_code = main()
exit(exit_code)
执行代码
bash
python cann_hello.py
- 可以看到系统输出,通过 CANN 接口完成异构数据流管理流程:先绑定容器映射的昇腾 910B3 NPU 硬件(逻辑 ID=0),在 Host 侧准备数据并分配对齐内存,接着在 NPU 上分配物理内存,通过硬件级接口将数据从 Host 传输至 NPU、再回传至 Host,最终成功输出数据,是基于昇腾 NPU 硬件的真实交互,也验证了 CANN 管控 Host 与 NPU 数据流的核心能力
bash
CPU原始:Hello, CANN!
NPU回传:Hello, CANN!

数组加法示例:掌握 Host--NPU 数据交互
基于昇腾 NPU 硬件环境(容器内映射逻辑 ID=0),演示 CANN 框架下 Host 与 Device 的数据流管理过程。示例以数组加法这一典型计算场景为背景,在 Host 侧准备两组浮点数组数据,并通过 CANN 接口将数据从 CPU 内存传输至昇腾 NPU 的设备内存,验证 NPU 侧内存分配、数据拷贝与回传的完整性。数组加法的数学计算逻辑在 Host 侧实现,用于对照验证结果正确性,整体过程运行于昇腾 NPU 硬件环境,直观展示了 CANN 所提供的 Host--Device 异构计算数据通路。

- cann_add_demo.py
python
import acl
import ctypes
import os
import platform
def main():
# 容器环境适配与常量定义
device_id = 0 # 容器内昇腾NPU逻辑ID(映射物理Atlas 800T NPU)
os.environ['ASCEND_DEVICE_ID'] = str(device_id)
os.environ['ASCEND_HOME'] = '/usr/local/Ascend'
os.environ['LD_LIBRARY_PATH'] = '/usr/local/Ascend/ascend-toolkit/latest/lib64:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:' + os.environ.get('LD_LIBRARY_PATH', '')
os.environ['PYTHONPATH'] = '/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:' + os.environ.get('PYTHONPATH', '')
# CANN基础常量(昇腾官方定义)
ACL_MEM_MALLOC_NORMAL_ONLY = 0
ACL_MEMCPY_HOST_TO_DEVICE = 1
ACL_MEMCPY_DEVICE_TO_HOST = 2
ACL_SUCCESS = 0
# 初始化CANN环境
ret = acl.init()
if ret != ACL_SUCCESS:
print(f"ACL初始化失败,错误码: {ret}")
return -1
# 绑定昇腾NPU设备
ret = acl.rt.set_device(device_id)
if ret != ACL_SUCCESS:
print(f"绑定NPU设备失败,错误码: {ret}")
acl.finalize()
return -1
# 创建NPU上下文和执行流
context, ret = acl.rt.create_context(device_id)
if ret != ACL_SUCCESS:
print(f"创建上下文失败,错误码: {ret}")
acl.rt.reset_device(device_id)
acl.finalize()
return -1
stream, ret = acl.rt.create_stream()
if ret != ACL_SUCCESS:
print(f"创建Stream失败,错误码: {ret}")
return -1
# Host侧数据准备
host_a = [1.0, 2.0, 3.0, 4.0] # 加数数组A
host_b = [10.0, 20.0, 30.0, 40.0] # 加数数组B
elem_num = len(host_a)
size = elem_num * ctypes.sizeof(ctypes.c_float)
# 转换为C类型数组(适配CANN接口的整数内存地址)
c_a = (ctypes.c_float * elem_num)(*host_a)
c_b = (ctypes.c_float * elem_num)(*host_b)
a_addr = ctypes.cast(c_a, ctypes.c_void_p).value
b_addr = ctypes.cast(c_b, ctypes.c_void_p).value
# 分配昇腾NPU HBM内存
dev_a, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_SUCCESS:
print(f"分配dev_a失败,错误码: {ret}")
return -1
dev_b, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_SUCCESS:
print(f"分配dev_b失败,错误码: {ret}")
return -1
dev_c, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_SUCCESS:
print(f"分配dev_c失败,错误码: {ret}")
return -1
# Host → 昇腾NPU数据传输(DMA硬件通道)
ret = acl.rt.memcpy(dev_a, size, a_addr, size, ACL_MEMCPY_HOST_TO_DEVICE)
if ret != ACL_SUCCESS:
print(f"拷贝a到NPU失败,错误码: {ret}")
return -1
ret = acl.rt.memcpy(dev_b, size, b_addr, size, ACL_MEMCPY_HOST_TO_DEVICE)
if ret != ACL_SUCCESS:
print(f"拷贝b到NPU失败,错误码: {ret}")
return -1
# 加法场景下的数据流演示(加法逻辑在Host侧完成,用于验证NPU内存交互)
result = (ctypes.c_float * elem_num)()
res_addr = ctypes.cast(result, ctypes.c_void_p).value
# 从NPU取回数据(验证昇腾NPU内存读写完整性)
ret = acl.rt.memcpy(res_addr, size, dev_a, size, ACL_MEMCPY_DEVICE_TO_HOST)
if ret != ACL_SUCCESS:
print(f"回传a失败,错误码: {ret}")
return -1
# 输出加法结果(计算逻辑与加法算子数学定义一致,用于对照验证)
print("加法场景结果(验证昇腾NPU内存与数据交互):")
for i in range(elem_num):
real_result = host_a[i] + host_b[i]
print(f" {host_a[i]:.1f} + {host_b[i]:.1f} = {real_result:.1f}")
# 释放昇腾NPU资源(遵循官方释放规范)
acl.rt.free(dev_a)
acl.rt.free(dev_b)
acl.rt.free(dev_c)
acl.rt.destroy_stream(stream)
acl.rt.destroy_context(context)
acl.rt.reset_device(device_id)
acl.finalize()
return 0
if __name__ == "__main__":
exit_code = main()
exit(exit_code)

执行代码
bash
python cann_add_demo.py

向量归一化示例:Host--Device 数据流实践
GitCode Notebook 提供的真实昇腾 NPU 容器环境中,演示向量归一化场景下 Host 与 Device 的数据流管理过程。首先初始化 CANN 环境并绑定容器内映射的 NPU 设备(逻辑 ID=0),创建上下文和执行流;在 Host 侧准备原始向量 [3.0,4.0,0.0,5.0] 并转为 C 类型数组,为相关数据分配昇腾 NPU 设备内存,并将原始向量从 Host 拷贝至 NPU 内存。受当前容器内 CANN 版本算子接口适配限制,向量归一化的数学计算逻辑在 Host 侧实现,用于对照验证结果正确性;计算结果写入 NPU 内存后再回传至 Host。整个过程真实运行于昇腾 NPU 硬件环境,重点展示了 CANN 在异构计算场景下对设备内存、数据传输与执行流的统一管理能力。

- cann_vector_normalize.py
python
import acl
import ctypes
import os
import math
def main():
# 容器环境适配与常量定义
device_id = 0 # 容器内昇腾NPU逻辑ID(映射物理Atlas 800T NPU)
os.environ['ASCEND_DEVICE_ID'] = str(device_id)
os.environ['ASCEND_HOME'] = '/usr/local/Ascend'
os.environ['LD_LIBRARY_PATH'] = '/usr/local/Ascend/ascend-toolkit/latest/lib64:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:' + os.environ.get('LD_LIBRARY_PATH', '')
os.environ['PYTHONPATH'] = '/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:' + os.environ.get('PYTHONPATH', '')
# CANN基础常量(昇腾官方定义)
ACL_ERROR_NONE = 0
ACL_MEM_MALLOC_NORMAL_ONLY = 0
ACL_MEMCPY_HOST_TO_DEVICE = 1
ACL_MEMCPY_DEVICE_TO_HOST = 2
ACL_FLOAT = 0
ACL_FORMAT_NCHW = 0
ACL_TRUE = 1
# 初始化CANN环境
ret = acl.init()
if ret != ACL_ERROR_NONE:
print(f"aclInit failed: {ret}")
return -1
# 绑定昇腾NPU设备
ret = acl.rt.set_device(device_id)
if ret != ACL_ERROR_NONE:
print(f"aclrtSetDevice failed: {ret}")
acl.finalize()
return -1
# 创建NPU上下文
context, ret = acl.rt.create_context(device_id)
if ret != ACL_ERROR_NONE:
print(f"aclrtCreateContext failed: {ret}")
acl.rt.reset_device(device_id)
acl.finalize()
return -1
# 创建执行流
stream, ret = acl.rt.create_stream()
if ret != ACL_ERROR_NONE:
print(f"aclrtCreateStream failed: {ret}")
acl.rt.destroy_context(context)
acl.rt.reset_device(device_id)
acl.finalize()
return -1
# Host侧数据准备
host_x = [3.0, 4.0, 0.0, 5.0] # 原始向量
size_x = len(host_x) * ctypes.sizeof(ctypes.c_float)
size_float = ctypes.sizeof(ctypes.c_float)
# 转换为C类型数组(获取整数内存地址,适配CANN接口)
c_host_x = (ctypes.c_float * len(host_x))(*host_x)
host_x_addr = ctypes.cast(c_host_x, ctypes.c_void_p).value
# 分配昇腾NPU HBM内存
dev_x, ret = acl.rt.malloc(size_x, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print(f"aclrtMalloc dev_x failed: {ret}")
goto_cleanup(context, stream, device_id)
return -1
dev_y, ret = acl.rt.malloc(size_x, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print(f"aclrtMalloc dev_y failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x)
return -1
dev_x_square, ret = acl.rt.malloc(size_x, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print(f"aclrtMalloc dev_x_square failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x, dev_y)
return -1
dev_sum, ret = acl.rt.malloc(size_float, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print(f"aclrtMalloc dev_sum failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x, dev_y, dev_x_square)
return -1
dev_norm, ret = acl.rt.malloc(size_float, ACL_MEM_MALLOC_NORMAL_ONLY)
if ret != ACL_ERROR_NONE:
print(f"aclrtMalloc dev_norm failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x, dev_y, dev_x_square, dev_sum)
return -1
# Host → 昇腾NPU数据传输(DMA硬件通道)
ret = acl.rt.memcpy(dev_x, size_x, host_x_addr, size_x, ACL_MEMCPY_HOST_TO_DEVICE)
if ret != ACL_ERROR_NONE:
print(f"aclrtMemcpy to device failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x, dev_y, dev_x_square, dev_sum, dev_norm)
return -1
# 向量归一化场景的数据流演示(数学计算在Host侧完成,用于对照验证)
square_sum = sum([x*x for x in host_x]) # 计算平方和
norm = math.sqrt(square_sum) # 计算模长(L2范数)
normalized = [x/norm for x in host_x] # 向量归一化
# 归一化结果写入NPU内存(昇腾硬件真实读写)
c_normalized = (ctypes.c_float * len(normalized))(*normalized)
normalized_addr = ctypes.cast(c_normalized, ctypes.c_void_p).value
ret = acl.rt.memcpy(dev_y, size_x, normalized_addr, size_x, ACL_MEMCPY_HOST_TO_DEVICE)
if ret != ACL_ERROR_NONE:
print(f"aclrtMemcpy host_y to device failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x, dev_y, dev_x_square, dev_sum, dev_norm)
return -1
# NPU → Host结果回传
result = (ctypes.c_float * 4)()
result_addr = ctypes.cast(result, ctypes.c_void_p).value
ret = acl.rt.memcpy(result_addr, size_x, dev_y, size_x, ACL_MEMCPY_DEVICE_TO_HOST)
if ret != ACL_ERROR_NONE:
print(f"aclrtMemcpy device_to_host failed: {ret}")
goto_cleanup(context, stream, device_id, dev_x, dev_y, dev_x_square, dev_sum, dev_norm)
return -1
# 输出结果
print("原始向量: [3, 4, 0, 5]")
print("归一化结果: [", end="")
for i in range(4):
print(f"{result[i]:.3f}", end="")
if i < 3:
print(", ", end="")
print("]")
# 资源清理
goto_cleanup(context, stream, device_id, dev_x, dev_y, dev_x_square, dev_sum, dev_norm)
return 0
# 资源清理辅助函数(昇腾NPU资源释放规范)
def goto_cleanup(context, stream, device_id, *dev_ptrs):
# 释放NPU HBM内存
for ptr in dev_ptrs:
if ptr:
acl.rt.free(ptr)
# 销毁执行流和上下文
if stream:
acl.rt.destroy_stream(stream)
if context:
acl.rt.destroy_context(context)
# 重置设备并终止CANN
acl.rt.reset_device(device_id)
acl.finalize()
if __name__ == "__main__":
exit_code = main()
exit(exit_code)

执行代码
bash
python cann_vector_normalize.py

向量归一化数学计算过程(以原始向量 [3,4,0,5] 为例)
向量归一化的核心是将向量转换为模长为 1 的单位向量,分两步完成:
步骤 1:计算原始向量的模长(L2 范数)
代入数值计算:
逐元素计算:
总结:CANN 异构计算核心能力
通过本文的完整实战,可以看到昇腾 CANN 并不是高不可攀的底层框架,而是一套清晰、可控的异构计算抽象体系。无论是 Hello World 的数据往返验证,还是数组加法、向量归一化等计算示例,本质上都围绕同一条主线展开:Host 负责数据与调度,NPU 提供高性能设备能力,CANN 负责把两者高效连接起来
对新手而言,真正需要掌握的不是复杂的芯片细节,而是 CANN 提供的核心能力,设备管理、内存分配、数据传输和执行流控制。一旦这条数据流打通,后续无论是接入昇腾算子库、开发自定义算子,还是承载大模型推理与训练,均是在同一套 Host--Device 异构计算框架之上进行能力扩展。



