CANN Runtime 单 Device 图像处理场景实战:分水岭图像暂存与二维 Pitch 数据通路详解

发布时间:2026/9/20 20:57:17
CANN Runtime 单 Device 图像处理场景实战:分水岭图像暂存与二维 Pitch 数据通路详解 CANNAscend人工智能任务调度【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址https://gitcode.com/cann/runtime点击查看免费下载导读本文围绕 CANN Runtime 仓库中 example/6_scenarios/image_processing 目录下的图像处理场景样例展开聚焦单 Device 场景中的二维数据准备、任务下发、结果回读与正确性校验。核心样例0_watershed_image_staging展示了如何在正式执行下游图像算法如分水岭分割之前通过带行步长pitch的二维异步拷贝完成三帧灰度图的暂存staging从而验证 Runtime 数据通路是否就绪。读完本文你将掌握aclrtMemcpy2d/aclrtMemcpy2dAsync的 pitch 语义、快速同步 Stream 的配置与校验方法以及一套可复用的环境自检—内存分配—二维传输—像素级校验—资源清理样例工程骨架。一、场景定位为什么需要图像暂存在图像处理流水线中二维图像通常以**带行步长pitched**的形式存放在内存里每一行数据的起始地址按某个对齐宽度pitch排布而行尾到下一行起点之间可能存在填充字节padding。这种布局在 Host 与 Device 两侧往往使用不同的 pitch。如果直接按连续内存memcpy会把 padding 一并拷贝破坏行对齐语义如果只按width * height拷贝则无法把多行数据放入正确的行偏移。0_watershed_image_staging样例解决的正是这个问题的前置环节在运行分水岭等下游图像算法前先把三帧 8 位灰度图通过带不同 pitch 的二维传输异步上传到 Device 再回读逐像素、逐有效区校验和、逐行 padding 三重校验确认 Runtime 的数据通路、内存分配和 Stream 任务编排全部正常再进入正式算法阶段。从仓库目录结构看example/6_scenarios/image_processing 下共包含三个同场景样例构成暂存验证 → 分割标签 → 图像平移的递进关系样例目录核心主题传输方式0_watershed_image_staging三帧 512×512 灰度图暂存验证数据通路aclrtMemcpy2dAsync异步二维传输0_segmentation_tree8×8 图像生成两级分割标签树Ascend C Kernel 执行aclrtMemcpyAsync Kernel 下发1_pitched_image_shift8×8 图像按 Device pitch 做循环平移aclrtMemcpy2d同步二维传输下文以关联文档重点描述的0_watershed_image_staging为主线展开并交叉引用其余两个样例与 Runtime 源码作为佐证。二、核心参数设计pitch、padding 与像素构造进入源码前先理解样例中定义的关键常量。它们在 watershed_image_staging.cpp 中集中声明constexpr int32_t kDeviceId 0; // 使用 Device 0 constexpr size_t kImageCount 3; // 三帧图像 constexpr size_t kWidth 512; // 有效宽度像素 constexpr size_t kHeight 512; // 高度像素 constexpr size_t kHostPitch 544; // Host 侧行步长字节 constexpr size_t kDevicePitch 576; // Device 侧行步长字节 constexpr size_t kHostBytes kHostPitch * kHeight; // Host 缓冲区总字节数 constexpr size_t kDeviceBytes kDevicePitch * kHeight;// Device 缓冲区总字节数 constexpr uint8_t kInputPadding 0xA5U; // 输入行尾填充字节 constexpr uint8_t kOutputPadding 0xCDU; // 输出行尾填充字节 constexpr uint32_t kStreamFlags ACL_STREAM_FAST_SYNC;// 快速同步 Stream 标志这些参数集中体现了二维传输的三个核心语义Host 与 Device 采用不同的 pitch。图像有效宽度为 512 字节Host 侧每行按 544 字节对齐Device 侧按 576 字节对齐。二维传输接口只搬运有效区域行尾 3264 字节的 padding 由两端各自保持这正是 pitch 与普通一维memcpy的本质区别。padding 区域被填充了特征值输入 0xA5、输出 0xCD。这是为了在校验阶段能够区分未被触碰的正确 padding与被错误写覆盖的 padding。像素值由确定性公式生成便于回读时逐像素比对uint8_t PixelValue(size_t imageIndex, size_t row, size_t column) { return static_castuint8_t((imageIndex * 53U row * 3U column * 5U) % 251U); }以kImageCount3、kWidth×kHeight262144像素、校验和逐帧递增对应样例输出的checksum32759100 / 32764400 / 32769700。三、环境自检版本查询、Device 核对与 Stream 标志验证ValidateEnvironment见 watershed_image_staging.cpp在数据搬运开始前完成四项环境验证保证后续操作的前提成立3.1 Runtime 与驱动版本查询通过aclsysGetVersionNum分别查询runtime与driver两个软件包的版本号。该接口在头文件 acl_rt.h 中声明是本仓库推荐的新版版本查询接口旧版aclsysGetCANNVersion已被标记为 deprecated。样例对版本查询失败采取宽松策略记录WARN日志后继续运行失败时版本号显示为-1而不是直接终止——因为版本信息属于可选项不影响数据通路本身的功能验证。3.2 Device 核对与全局内存检查CHECK_ERROR(aclrtGetDevice(currentDevice)); CHECK_ERROR(aclrtGetDeviceInfo(kDeviceId, ACL_DEV_ATTR_TOTAL_GLOBAL_MEM_SIZE, globalMemory));aclrtGetDevice获取当前生效的 Device与期望的kDeviceId0比对不一致即报错返回aclrtGetDeviceInfo配合属性ACL_DEV_ATTR_TOTAL_GLOBAL_MEM_SIZE枚举值 301含义为 Device 上可用全局内存总字节数见 acl_rt.h查询总内存并与所需kDeviceBytes 576×512比较在分配之前就拒绝内存不足的环境。3.3 快速同步 Stream 的标志回读0_watershed_image_staging使用aclrtCreateStreamWithConfig创建带ACL_STREAM_FAST_SYNC标志的 Stream随后用aclrtStreamGetFlags回读确认标志生效CHECK_ERROR(aclrtCreateStreamWithConfig(resources.stream, 0, kStreamFlags)); // ... 环境校验阶段 CHECK_ERROR(aclrtStreamGetFlags(resources.stream, streamFlags)); if (streamFlags ! kStreamFlags) { ERROR_LOG(Stream flag mismatch: actual0x%x, expected0x%x, streamFlags, kStreamFlags); return -1; }ACL_STREAM_FAST_SYNC在 acl_rt.h 中定义为0x00000002U即快速同步流。头文件注释指出可通过aclrtCreateStreamWithConfig创建快速流见 acl_rt.h。快速同步流适合二维内存拷贝这类任务量确定、需要快速完成同步等待的场景这也是样例输出中Stream flag0x2的由来。四、二维传输的核心 API 与底层实现4.1 接口签名与参数语义两个二维传输接口在 acl_rt.h 中声明aclError aclrtMemcpy2d( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, aclrtMemcpyKind kind); aclError aclrtMemcpy2dAsync( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, aclrtMemcpyKind kind, aclrtStream stream);dst/dpitch目标地址与目标侧行步长src/spitch源地址与源侧行步长width/height传输矩阵的有效宽度每行字节数与行数kind传输方向本样例使用ACL_MEMCPY_HOST_TO_DEVICE与ACL_MEMCPY_DEVICE_TO_HOST异步版本额外带stream参数任务按 Stream 顺序执行。关键点width只描述有效像素区域的宽度两个 pitch 可以各不相同。样例中 H2D 方向spitch544Host→dpitch576DeviceD2H 方向则反过来源端与目标端 pitch 各自独立。4.2 底层实现链路从 ACL 实现源码 memory.cpp 可以看到aclrtMemcpy2dImpl与aclrtMemcpy2dAsyncImpl的调用链为记录 profiling 事件ACL_PROFILING_REG(AclrtMemcpy2d / AclrtMemcpy2dAsync)调用CheckMemcpy2dParam做参数合法性校验pitch、宽高、地址有效性CheckMemcpy2dSyncKind/CheckMemcpy2dAsyncKind将 ACL 的aclrtMemcpyKind映射为底层rtMemcpyKind_t最终下发到 Runtime 层rtMemcpy2d/rtMemcpy2dAsync在指定 Stream 上生成二维 DMA 任务。因此aclrtMemcpy2d系列本质上是对底层二维 DMA 引擎的封装行步长语义在驱动与硬件层面生效——这正是它能正确处理不同 pitch 行尾 padding数据布局的原因。五、样例主流程拆解RunWatershedImageStagingwatershed_image_staging.cpp以清晰的初始化 → 校验 → 分配 → 传输 → 清理五段式结构组织每一步失败都会跳过后续步骤并保证清理必然执行int RunWatershedImageStaging() { Resources resources; int result Initialize(resources); // aclInit aclrtSetDevice 创建快速同步 Stream if (result 0) { result ValidateEnvironment(resources); // 版本/Device/内存/Stream 标志自检 } if (result 0) { result AllocateBuffers(resources); // 锁页 Host 内存 Device 图像缓冲 } if (result 0) { result TransferImages(resources); // 三帧图像异步上传 回读 校验 } if (Cleanup(resources) ! 0) { // 同步等待、释放、销毁、重置 result -1; } return result; }5.1 初始化阶段CHECK_ERROR(aclInit(nullptr)); // ACL 初始化 CHECK_ERROR(aclrtSetDevice(kDeviceId)); // 选择 Device 0 CHECK_ERROR(aclrtCreateStreamWithConfig(resources.stream, 0, kStreamFlags)); // 创建快速同步 Stream5.2 内存分配CHECK_ERROR(aclrtMallocHost(reinterpret_castvoid**(resources.input), kHostBytes)); // 输入锁页内存 CHECK_ERROR(aclrtMallocHost(reinterpret_castvoid**(resources.output), kHostBytes)); // 输出锁页内存 CHECK_ERROR(aclrtMalloc(resources.device, kDeviceBytes, ACL_MEM_MALLOC_HUGE_FIRST)); // Device 图像缓冲Host 侧使用aclrtMallocHost分配锁页内存pinned memory保证异步 DMA 传输过程中页不被换出Device 侧使用aclrtMalloc搭配ACL_MEM_MALLOC_HUGE_FIRST优先使用大页分配策略。5.3 每帧图像的暂存循环TransferImageswatershed_image_staging.cpp对三帧图像逐一执行填 padding → 生成像素 → 异步上传 → 异步回读 → 同步等待 → 校验CHECK_ERROR(aclrtMemcpy2dAsync( resources.device, kDevicePitch, resources.input, kHostPitch, kWidth, kHeight, ACL_MEMCPY_HOST_TO_DEVICE, resources.stream)); CHECK_ERROR(aclrtMemcpy2dAsync( resources.output, kHostPitch, resources.device, kDevicePitch, kWidth, kHeight, ACL_MEMCPY_DEVICE_TO_HOST, resources.stream)); CHECK_ERROR(aclrtSynchronizeStream(resources.stream));注意一个重要的顺序保证同一 Stream 上的任务按提交顺序执行。两个aclrtMemcpy2dAsync都提交到同一个 Stream因此 D2H 回读必然发生在 H2D 上传完成之后无需额外的 Event 同步aclrtSynchronizeStream只需在回读完成后调用一次即可确保后续校验读取到完整结果。5.4 三重校验逻辑VerifyImagewatershed_image_staging.cpp对回读结果执行逐像素比对对每个有效像素(row, column)用PixelValue公式重新计算期望值并与回读值比对不匹配即打印行列坐标并返回失败有效区校验和累加全部512×512像素值得到 checksum随帧递增并打印Host padding 保护检查对每行[kWidth, kHostPitch)区间确认仍为初始的0xCD填充值——一旦二维 D2H 回写越界覆盖了 Host 行尾 padding立即报错。这一步直接验证了width参数的边界语义。5.5 资源清理Cleanupwatershed_image_staging.cpp逆序释放全部资源并且任何一个清理步骤失败都会把最终结果置为失败而不会中断清理流程aclrtSynchronizeStream → aclrtFree → aclrtFreeHost(input) → aclrtFreeHost(output) → aclrtDestroyStream → aclrtResetDevice → aclFinalize这种先同步收尾 → 释放内存 → 销毁 Stream → 重置 Device → 反初始化的顺序是 Runtime 编程的通用最佳实践与同目录下另外两个样例0_segmentation_tree的Cleanup、1_pitched_image_shift的PitchedShiftWorkflow::Cleanup完全一致后者还在其中插入了aclrtBinaryUnLoad用于卸载 Kernel 二进制。六、编译与运行6.1 环境准备按 0_watershed_image_staging/README_en.md 的说明在已安装 CANN 的环境中执行cd ${git_clone_path}/example/6_scenarios/image_processing/0_watershed_image_staging # 加载 CANN Runtime 环境${install_root} 替换为 CANN 安装根目录 source ${install_root}/set_env.sh # 设置样例编译所需的 SOC_VERSION 与 ASCENDC_CMAKE_DIR source ${git_clone_path}/example/set_sample_env.shset_sample_env.sh 会通过一个小型 ACL 辅助程序见 get_soc_version.cpp查询当前芯片的SOC_VERSION并自动定位 CANN 安装目录下的ascendc.cmake优先匹配当前宿主架构的布局如aarch64-linux/tikcpp/ascendc_kernel_cmake最终导出ASCEND_INSTALL_PATH、ASCEND_HOME_PATH、SOC_VERSION、ASCENDC_CMAKE_DIR四个变量。6.2 编译与执行bash run.shrun.sh 的构建逻辑为校验SOC_VERSION与ASCENDC_CMAKE_DIR已设置cmake -B build -DASCEND_CANN_PACKAGE_PATH${ASCEND_HOME_PATH}配置工程cmake --build build -j编译cmake --install build安装运行./build/main输出同时打印到终端并落盘到output_msg.txt。CMakeLists.txt 展示了关键编译配置C17、-D_GLIBCXX_USE_CXX11_ABI0、-Wall -Wextra -Werror链接库为ascendcl头文件搜索路径包含ASCEND_CANN_PACKAGE_PATH/include与样例公共目录即utils.h所在位置。公共宏 utils.h 提供了INFO_LOG/WARN_LOG/ERROR_LOG三个日志宏以及CHECK_ERROR快速失败宏——所有 Runtime API 调用失败时统一打印错误码并提前返回-1。6.3 预期输出[INFO] Start to run 0_watershed_image_staging sample. [INFO] Environment verified: runtime90200000, driver250505000, Device0, global memory65787658240 bytes, Stream flag0x2. [INFO] Image 0 staging verified: 262144 pixels, checksum32759100. [INFO] Image 1 staging verified: 262144 pixels, checksum32764400. [INFO] Image 2 staging verified: 262144 pixels, checksum32769700. [INFO] Run the 0_watershed_image_staging sample successfully.其中版本号与总内存大小随运行环境变化版本查询失败时显示为-1。三个校验和之间相差 5300恰好等于单帧 512 行 × 512 列 × 按(row*3 column*5)项累积的帧间差从数值上印证了像素公式与校验逻辑的一致性。6.4 产品支持范围按照 0_watershed_image_staging/README_en.md 的声明该样例支持以下产品产品支持Atlas A2 训练系列产品/Atlas A2 推理系列产品是Atlas A3 训练系列产品/Atlas A3 推理系列产品是Ascend 950PR/Ascend 950DT是其余两个样例 0_segmentation_tree 与 1_pitched_image_shift 当前声明支持 Atlas A2 训练/推理系列产品。实际可运行产品请以当前环境与版本配套为准。七、同场景样例补充从数据通路到算法执行为帮助理解0_watershed_image_staging在整个图像处理场景中的位置这里简要说明同目录下的另外两个样例如何在此数据通路之上叠加算法逻辑。7.1 0_segmentation_tree两级分割标签树该样例构造一幅确定的 8×8 灰度图像素值index*4即强度为 0、4、8、…、252先通过aclrtGetMemInfo(ACL_HBM_MEM, ...)查询 HBM 空闲与总容量执行任务准入控制要求freeMemory 3 * 64字节且freeMemory totalMemory然后下发 Ascend C Kernel 生成两级分割标签细粒度标签fine pixel / 644 类粗粒度标签coarse fine / 22 类。Kernel 实现在 segmentation_tree_kernel.cpp 中使用TPipeTBufVECCALC 位置完成 Global→Local 数据搬入、逐像素标号计算、Local→Global 搬出并通过MTE2_S搬入与S_MTE3搬出事件标志保证拷贝与计算之间的硬件同步。Host 侧校验要求每个 fine 类恰好 16 个像素、每个 coarse 类恰好 32 个像素并验证coarse fine / 2层级关系。其 Kernel 下发链路aclrtBinaryLoadFromFile → aclrtBinaryGetFunction → aclrtKernelArgsInit/Append/Finalize → aclrtLaunchKernelWithConfig体现了新版 Runtime 推荐的 Kernel 参数封装方式。7.2 1_pitched_image_shift按 Device pitch 的循环平移该样例在同步二维传输aclrtMemcpy2d之上演示 pitch 的完整闭环Host 侧 pitch 为 24 字节12 个uint16_tDevice 侧 pitch 为 32 字节16 个uint16_t行尾 padding 填充0xFFFF。Kernel pitched_shift_kernel.cpp 使用Device pitch每行 16 个元素计算源地址对 8×8 图像做水平循环右移 2 像素、垂直循环下移 1 像素const uint32_t sourceRow (row 1) % kHeight; const uint32_t sourceColumn (column 2) % kWidth; outputLocal.SetValue( row * kDevicePitchElements column, inputLocal.GetValue(sourceRow * kDevicePitchElements sourceColumn));由于 Kernel 以整行 16 个元素的缓冲为单位搬入/搬出DataCopy长度为kBufferElementspadding 区域在 Device 侧同样保留而 D2H 同步回读使用width kRowBytes 16 字节、spitch 32、dpitch 24只搬有效列最终校验确认 Host 行尾的0xFFFF未被覆盖。这一样例与0_watershed_image_staging正好形成同步二维传输与异步二维传输的对照。八、注意事项与最佳实践总结综合三个样例的源码实现可以提炼出以下可直接复用的经验Pitch 语义必须严格区分有效宽度与行步长aclrtMemcpy2d/aclrtMemcpy2dAsync的width是每行实际搬运字节数spitch/dpitch是行起始偏移。Host 与 Device 可各自采用不同 pitchpadding 区域不会被搬运。同 Stream 提交天然有序异步上传与回读放入同一 Stream无需额外 Event单次aclrtSynchronizeStream即可收尾。若跨 Stream 编排则需要 Event 或依赖快速同步流特性。内存分配策略异步二维传输要求 Host 源/目的内存为锁页内存aclrtMallocHostDevice 侧建议使用ACL_MEM_MALLOC_HUGE_FIRST以优先获得大页分配。分配前先做准入检查用aclrtGetMemInfo或aclrtGetDeviceInfo(ACL_DEV_ATTR_TOTAL_GLOBAL_MEM_SIZE)预查容量避免运行期 OOM0_watershed_image_staging与0_segmentation_tree均实现了这一检查。Padding 保护验证是二维传输的正确性试金石用特征值0xA5/0xCD/0xFFFF填充行尾回读后检查 padding 未被覆盖可直接暴露width或 pitch 参数用错导致的越界写。清理顺序固定且不可跳过先同步 Stream 收尾、再释放 Device/Host 内存、销毁 Stream、重置 Device、最后aclFinalize任何一步失败都应记录错误并继续清理最终返回失败。环境自检先行版本查询aclsysGetVersionNum、当前 Device 核对、Stream 标志回读aclrtStreamGetFlags可以显著降低排障成本且对可选信息如版本号采用警告而非中断的策略更利于自动化验证。如果需要将这套流程落地到自己的图像算法工程可以直接以 example/6_scenarios/image_processing 目录下的三个样例为模板参照其 CMakeLists.txt 与 run.sh 完成构建接入再按需替换像素公式与校验逻辑。赞分享CANNAscend人工智能任务调度【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址https://gitcode.com/cann/runtime点击查看免费下载相关推荐CANN Runtime 分水岭图像预处理数据通路演练基于 aclrtMemcpy2dAsync 的带行步长图像暂存样例深度解析CANN Runtime 分水岭图像预处理数据通路演练基于 aclrtMemcpy2dAsync 的带行步长图像暂存样例深度解析 本文围绕 CANN 开源仓库CANNAscend人工智能任务调度CANN Runtime 图像预处理数据通路演练分水岭图像三帧 Staging 样例深度解析CANN Runtime 图像预处理数据通路演练分水岭图像三帧 Staging 样例深度解析 本样例面向需要在单个 Device 上为分水岭WatersheCANNAscend人工智能任务调度CANN Runtime 业务场景示例导航图像处理、训练流水线、多Device推理与容错执行CANN Runtime 业务场景示例导航图像处理、训练流水线、多Device推理与容错执行 本文面向已掌握 CANN Runtime 基础接口StreamCANNAscend人工智能任务调度上一篇automl-gs架构设计哲学为什么选择生成完整建模管道而非仅训练下一篇攻克安卓桌面角标难题ShortcutBadger 1.0到1.1.23的十年进化史创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询