当前位置: 首页 > news >正文

玩转 CANN:在 Notebook 中实战 Python 版 ResNet-50

文章目录

    • 摘要
    • 一、 引言:“玩转” CANN 的正确姿势
    • 二、 环境配置与准备工作
      • 步骤 1:配置并启动 Notebook 环境
      • 步骤 2:打开终端
      • 步骤 3:克隆 CANN 官方示例仓库
      • 步骤 4:进入 Python 示例目录
      • 步骤 5:下载官方 .om 模型
      • 步骤 6:准备数据文件
    • 三、 核心实操(在 Notebook 单元格中进行)
      • 步骤 1:创建新的 Notebook
      • 步骤 2:逐个单元格执行 Python 代码
        • 单元格 1:导入必要的库
        • 单元格 2:定义常量和路径
        • 单元格 3:初始化 ACL (已修正)
        • 单元格 4:加载模型
        • 单元格 5:准备输入数据
        • 单元格 6:准备输出数据
        • 单元格 7:执行推理(核心)
        • 单元格 8:获取并解析结果
        • 单元格 9:清理所有资源
    • 四、 总结与展望

摘要

随着 AI 技术的飞速发展,异构计算架构成为推动创新的核心动力。华为 CANN(Compute Architecture for Neural Networks)作为面向 AI 场景的统一架构,为开发者提供了强大的算力支持和高效的开发工具链。本文将紧扣“昇腾应用既玩”的主题,以“保姆级”指南的形式,带领读者在 Jupyter Notebook 环境中,利用 acl-python 库(AscendCL 的 Python 接口)实战部署一个经典的 ResNet-50 图像分类模型。我们将从环境准备、官方示例克隆开始,一步步详解 ACL 初始化的每一步含义,直至模型推理成功,直观感受 CANN 架构的便捷性与高性能。

一、 引言:“玩转” CANN 的正确姿势

CANN 是华为专为 AI 场景打造的异构计算架构。它像一个“超级翻译官”,“向上”能听懂 PyTorch、TensorFlow 等主流框架的指令,“向下”能精准指挥昇腾(Ascend)系列 NPU 高效工作。

对于开发者而言,“玩转” CANN 不仅仅是停留在框架层调用 model.to('npu')。更深入的“玩法”,是直接调用它的核心——AscendCL(昇腾计算语言)。AscendCL 就像是 CANN 开放给开发者的“底层 API”,它让我们能更精细地控制内存分配、模型加载和推理执行。

本次实操,我们将选择最受 AI 开发者喜爱的 Jupyter Notebook 环境,利用 CANN 官方 samples 仓库中提供的 Python 示例,来一场“看得见、摸得着”的 ResNet-50 推理实战。

二、 环境配置与准备工作

在开始实操之前,我们首先需要一个已经配置好 CANN 驱动和 NPU 硬件的 Notebook 环境。昇腾 AI 社区或 GitCode 平台通常会提供此类免费的“云端实验室”。

步骤 1:配置并启动 Notebook 环境

当你找到入口并点击“立即体验”或“新建 Notebook”时,你通常会看到一个资源确认界面(如下图所示)。
在这里插入图片描述

请务必按如下规则配置:

  • Notebook 计算类型: 必须选择 NPU
  • (第一个下拉框): 选择任意 Ascend 处理器,例如 Ascend 910
  • 容器镜像: (最关键) 必须选择一个预装了 CANN 的镜像
    • 如下图所示,在下拉菜单中,我们推荐选择 euler2.9-py38-torch2.1.0-cann8.0-openmind0.6-notebook
  • 存储大小: [限时免费] 50G 即可。

原因: 它包含了 cann8.0 核心包和 py38 (Python 3.8) 环境,非常适合我们的 acl-python 实操。
在这里插入图片描述

配置完成后,点击“立即启动”。稍等片刻,系统将为你准备好一个 JupyterLab 实例。
(接下来的步骤,都是在这个启动好的 JupyterLab 环境中进行的)
在这里插入图片描述

步骤 2:打开终端

在 JupyterLab 界面的顶部菜单栏,点击 文件 -> 新建 -> 终端。这是我们执行 Linux 命令的主窗口。
在这里插入图片描述

步骤 3:克隆 CANN 官方示例仓库

CANN 官方在 GitCode 上维护了大量示例,这是我们学习的最佳起点。
在弹出的黑色终端窗口中,输入以下命令:

# 克隆仓库
git clone https://gitee.com/ascend/samples.git

步骤 4:进入 Python 示例目录

samples 仓库中包含了 C++ 和 Python 两套示例。由于我们在 Notebook 中操作,因此选择 Python 目录。

# 注意:这次我们进入的是 python 目录,而不是 cplusplus!
cd samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification

这个路径 level2_simple_inference 意味着它是一个中等难度的“简单推理”示例,非常适合入门。
在这里插入图片描述

步骤 5:下载官方 .om 模型

(注意:我们跳过了 pip install 步骤,因为我们选择的容器镜像已预装所有依赖。)
CANN 无法直接运行 .pth.onnx 模型,它需要的是经过 ATC(Ascend Tensor Compiler) 工具转换后的 .om(Offline Model) 离线模型。官方示例很贴心地为我们准备好了转换后的模型。

# 使用 -P ~/model 选项,将模型下载到你“主目录”下的 model 文件夹中
wget -P ~/model https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/resnet50/resnet50.om

值得注意的是: 这个 resnet50.om 模型是内置了 AIPP(AI 预处理) 功能的。这意味着模型本身就能完成图片的缩放、色域转换等操作,我们后续在 Python 中无需再使用 OpenCV 或 PIL 进行繁琐的预处理,可以直接将 .jpg 文件喂给 NPU!
在这里插入图片描述

看最后一行,100% 并且 saved,文件已经保存到 /home/service/model/resnet50.om

步骤 6:准备数据文件

平台在主目录 (~) 下还提供了 dataset 文件夹。我们需要将示例中的 dog1.jpg 复制过去。
请继续在当前目录,执行以下命令:

# 使用绝对路径,从 samples 仓库复制图片到 dataset 目录
cp ~/samples/python/level2_simple_inference/data/dog1.jpg ~/dataset/

(执行后,你可以在左侧文件浏览器的 dataset 目录中看到 dog1.jpg

三、 核心实操(在 Notebook 单元格中进行)

文件都准备好了!现在,我们回到 JupyterLab 的文件浏览器(左侧面板)。

步骤 1:创建新的 Notebook

  1. 在左侧文件浏览器中,导航到你刚刚进入的目录:
    samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification
    在这里插入图片描述

  2. 在顶部菜单栏,点击 文件 -> 新建 -> 笔记本。(当提示选择内核时,选择 Python 3)。
    在这里插入图片描述

  3. 右键点击新创建的 Untitled.ipynb 文件,将其重命名为 my_test.ipynb
    在这里插入图片描述

步骤 2:逐个单元格执行 Python 代码

现在,双击打开 my_test.ipynb。你将看到一个可以输入代码的单元格。请按顺序复制以下代码块到不同的单元格中,然后点击“运行”按钮(或按 Shift + Enter)来逐个执行它们。

单元格 1:导入必要的库
import acl # 导入 acl-python 库
import numpy as np
import os  # 导入 os 模块,用于处理路径
from PIL import Image # PIL 用于后续显示图片(可选)print("导入库成功!")

在这里插入图片描述

这是 Python 程序的起点。我们导入 acl(核心库)、numpy(用于数据转换)和 os(用于路径操作)。

单元格 2:定义常量和路径
# --- 1. 定义常量和路径 ---
import os # 再次导入 os 确保此单元格可独立运行# 获取主目录(即 File Browser 里的 '/')的绝对路径
# 例如:/home/service
HOME_DIR = os.path.expanduser('~') # 模型路径(拼接主目录和 model 文件夹)
MODEL_PATH = os.path.join(HOME_DIR, "model/resnet50.om")
# 图片路径(拼接主目录和 dataset 文件夹)
IMAGE_PATH = os.path.join(HOME_DIR, "dataset/dog1.jpg") # NPU 设备 ID
DEVICE_ID = 0print(f"主目录绝对路径: {HOME_DIR}")
print(f"模型路径: {MODEL_PATH}")
print(f"图片路径: {IMAGE_PATH}")

在这里插入图片描述

我们将所有配置项(如模型路径、图片路径、设备 ID)定义为常量,便于后续修改和维护。执行这个单元格,你应该能看到被正确解析的绝对路径被打印出来。

单元格 3:初始化 ACL (已修正)
# --- 2. 初始化 ACL ---
print("开始初始化 ACL...")# 1. ACL 初始化
# [修正] 直接调用,失败时将自动引发异常
acl.init()# 2. 分配 Device
acl.rt.set_device(DEVICE_ID)# 3. 创建 Context
context, ret = acl.rt.create_context(DEVICE_ID)
# [注] create_context 仍然返回元组(tuple),我们保留它,但不再检查 retprint("ACL 初始化成功!")

在这里插入图片描述

这是最重要的步骤之一。我们要开始与昇腾 NPU“对话”了。

单元格 4:加载模型
# --- 3. 加载模型 ---
print(f"开始加载模型: {MODEL_PATH}...")# [修正] load_from_file 返回 model_id, ret 元组
model_id, ret = acl.mdl.load_from_file(MODEL_PATH)# 获取模型描述(用于了解输入输出)
model_desc = acl.mdl.create_desc()
acl.mdl.get_desc(model_desc, model_id)print(f"加载模型成功。")

在这里插入图片描述

初始化完成后,我们把 .om 模型文件从硬盘加载到 NPU 的内存中。

单元格 5:准备输入数据
# --- 4. 准备输入数据 ---
print(f"开始准备输入图片: {IMAGE_PATH}...")# 1. 获取模型 AIPP 配置的输入 buffer 大小
input_size = acl.mdl.get_input_size_by_index(model_desc, 0)
print(f"模型 AIPP 输入 buffer 大小: {input_size} bytes")# 2. 读取 .jpg 图片文件到内存 (Host 侧)
#    (我们使用修正后的 IMAGE_PATH)
with open(IMAGE_PATH, 'rb') as f:image_data = f.read()
image_size = len(image_data)# 3. 申请 NPU 上的内存 (Device 侧)
input_device, ret = acl.rt.malloc(input_size, acl.rt.ACL_MEM_MALLOC_HUGE_FIRST)# 4. 拷贝图片数据到 NPU 内存 (Host -> Device)
# 注意:我们拷贝的是原始 .jpg 数据流
ret = acl.rt.memcpy(input_device, input_size, image_data, image_size, acl.rt.ACL_MEMCPY_HOST_TO_DEVICE)
# [修正] 使用 acl.rt.ACL_SUCCESS
if ret != acl.rt.ACL_SUCCESS:print(f"memcpy H2D failed, ret={ret}")# 5. 创建 aclmdlDataset 结构
input_dataset = acl.mdl.create_dataset()
# [修正] 使用 acl.mdl.create_data_buffer
input_databuffer = acl.mdl.create_data_buffer(input_device, input_size)
acl.mdl.add_dataset_buffer(input_dataset, input_databuffer)print(f"成功将图片加载到 NPU 内存。")

在这里插入图片描述

这里我们能深刻体会到 AIPP 的便捷性。

单元格 6:准备输出数据
# --- 5. 准备输出数据 ---
print("开始准备输出 buffer...")output_dataset = acl.mdl.create_dataset()# 1. 获取模型输出大小 (ResNet-50 是 1000 个 float)
output_size = acl.mdl.get_output_size_by_index(model_desc, 0)
print(f"模型输出大小: {output_size} bytes") # 应该会打印 4000# 2. 申请 NPU 上的内存 (Device 侧)
output_device, ret = acl.rt.malloc(output_size, acl.rt.ACL_MEM_MALLOC_HUGE_FIRST)# 3. 创建 aclmdlDataset 结构
# [修正] 使用 acl.mdl.create_data_buffer
output_databuffer = acl.mdl.create_data_buffer(output_device, output_size)
acl.mdl.add_dataset_buffer(output_dataset, output_databuffer)print("准备输出 buffer 成功。")

在这里插入图片描述

与输入类似,我们还需要在 Device 侧为 NPU 准备一块“空白”内存,用于存放推理的输出结果。

单元格 7:执行推理(核心)
# --- 6. 执行推理 ---
print("开始执行推理...")ret = acl.mdl.execute(model_id, input_dataset, output_dataset)
# [修正] 使用 acl.mdl.ACL_SUCCESS
if ret != acl.mdl.ACL_SUCCESS:print(f"execute model failed, ret={ret}")print("推理执行成功!")

在这里插入图片描述

这是最激动人心的一步!万事俱备,只欠“执行”。

单元格 8:获取并解析结果
# --- 7. 获取并处理结果 ---
print("开始从 NPU 回传并解析结果...")# 1. 申请 Host 内存
output_host, ret = acl.rt.malloc_host(output_size)# 2. 拷贝数据回 Host 内存 (Device -> Host)
ret = acl.rt.memcpy(output_host, output_size, output_device, output_size, acl.rt.ACL_MEMCPY_DEVICE_TO_HOST)
# [修正] 使用 acl.rt.ACL_SUCCESS
if ret != acl.rt.ACL_SUCCESS:print(f"memcpy D2H failed, ret={ret}")# 3. 将 Host 内存 (void*) 转换为 numpy 数组
# (1000 个 float, 每个 float 4 字节)
data = acl.util.ptr_to_numpy(output_host, (output_size // 4,), np.float32)# 4. 找到 Top-5 概率的索引
top_k = 5
top_k_indices = data.argsort()[-top_k:][::-1] # 排序并反转print("\n======== 推理结果 Top-5 ========")
# (官方示例的 data 目录里有 imagenet_1000.json 标签文件,
#  我们这里为了简单,只打印索引号。在实际应用中,
#  我们会用索引号去查表,得到 "Pekinese" 这样的标签)
for i, index in enumerate(top_k_indices):print(f"Top {i+1}: 类别索引 [ {index} ]    概率: {data[index]:.5f}")
print("===============================\n")

在这里插入图片描述

推理已完成,但结果(1000 个概率值)还静静地躺在 Device 侧的内存中。我们需要把它“拿回” Host 侧,才能在 Python 中读取它。

执行这个单元格,看到和 C++ 示例完全一致的 Top-5 结果!dog1.jpg 被高概率识别为索引 162(京巴犬)。

单元格 9:清理所有资源
# --- 8. 清理资源 ---
print("开始清理所有 ACL 资源...")# 释放内存 (Host 和 Device)
acl.rt.free(input_device)
acl.rt.free(output_device)
acl.rt.free_host(output_host)# 销毁 dataset 和 databuffer
acl.mdl.destroy_dataset(input_dataset)
acl.mdl.destroy_dataset(output_dataset)
# [修正] 使用 acl.mdl.destroy_data_buffer
acl.mdl.destroy_data_buffer(input_databuffer)
acl.mdl.destroy_data_buffer(output_databuffer)# 卸载模型
acl.mdl.unload(model_id)
acl.mdl.destroy_desc(model_desc)# 销毁 Context
acl.rt.destroy_context(context)# 重置 Device
acl.rt.reset_device(DEVICE_ID)# ACL 去初始化
acl.finalize()print("清理完毕。")

在这里插入图片描述

“有借有还,再借不难”。在 CANN 编程中,资源清理至关重要。

四、 总结与展望

通过以上 9 个单元格的操作,我们在 Jupyter Notebook 环境中,使用 acl-python 库完成了一次完整且规范的端到端 AI 推理。

回顾整个过程,我们深刻体验了“昇腾应用既玩”的精髓:

  • “玩”得明白:我们不再是简单调用框架 API,而是深入到了 AscendCL 层。我们清晰地看到了一个 AI 推理任务的完整生命周期:初始化 -> 加载模型 -> 申请内存 (H/D) -> 拷贝数据 (H2D) -> 执行推理 -> 拷贝结果 (D2H) -> 解析数据 -> 释放资源。
  • “玩”得高效:我们体验了 CANN 的 AIPP 核心特性,它极大地简化了数据预处理流程,让开发者能更专注于推理逻辑本身。
  • “玩”得便捷acl-python 库与 Notebook 的结合,为 AI 开发者提供了最熟悉的“配方”。我们可以逐个单元格验证想法,快速调试,这大大降低了学习底层 API 的门槛。

CANN 架构的潜力远不止于此。从这里出发,你还可以继续探索更多高级“玩法”,例如:模型的多线程推理、动态 Batch/Shape 处理、使用 acl.media 接口进行视频解码等。希望这份教程能真正带你入门,激发你更多“玩转”昇腾的灵感!

http://www.dtcms.com/a/601849.html

相关文章:

  • 深圳网站建设top028公众号怎么做网站
  • 关于未备案网站网站属性
  • Distributed Architecture: 分布式服务架构演进
  • WPS PPT模板中心:免费模板的查找与使用!
  • Qt 内存管理---创建对象
  • 单页网站还能用吗哪个网站做照片书最好看
  • C语言编译程序与优化技术解析
  • 淄博市住房和城乡建设局官方网站3d模型网
  • Day34-动态规划
  • 衡水网站建设知识做甜品网站的需求分析
  • 千兆网口NET8506与NET8516系列高速数字化仪,为高动态范围信号采集提供了全面的解决方案
  • 小程序开通aso优化分析
  • 拉取github更新到本地
  • wordpress站点搭建怎么做多语言网站
  • 提交异步任务后,无法查询数据库数据问题
  • Redis核心使用场景
  • 普中51单片机学习笔记-按键
  • 学校网站网页建设开题报告书建设网站设计的公司
  • 学习笔记:利用JQuery直接调用asp.net后台方法
  • STM32时钟源分析
  • 文件上传之基础过滤方式
  • Explain 执行计划详解:SQL 性能瓶颈与索引命中分析
  • 汕头网址模板建站广西明电建设有限公司网站
  • 新增目录在vscode git中不可见但git status可见的问题
  • 网站备案信息更改审核要多久智能产品创新设计
  • 大模型加速的其他方法简记
  • Linux C语言编译器的使用与调试技巧
  • [c++]宏函数与内联函数
  • 广州网站定做西安网站开发服务费用
  • 桂林网站建设招聘制作公司网站怎么做