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

鸿蒙开发--CANNKit-AscendC-sobel

HarmonyOS AscendC 算子:用 NPU 实现图像边缘检测

什么是 AscendC 算子

前面我们介绍了很多图形渲染相关的技术,这篇来看看 AI 领域的东西。AscendC 是华为提供的一种 NPU(神经网络处理器)编程框架,让你可以自己写算子在 NPU 上运行。

算子是什么?简单说就是一种计算操作。比如加法是一个算子,乘法也是一个算子。在 AI 和图像处理领域,有很多复杂的算子,比如卷积、池化等。AscendC 让你可以自己实现这些算子,然后在 NPU 上高效运行。

这篇我们用一个实际的例子来说明:图像边缘检测。边缘检测是图像处理中最基础的操作之一,用 Sobel 算子来实现。边缘检测的结果可以用于物体识别、图像分割等场景。

为什么要用 NPU

你可能会问:图像处理用 CPU 不就行了,为什么要用 NPU?

答案是性能。NPU 是专门为 AI 和图像处理设计的硬件,它有大量的计算单元,可以并行处理很多数据。对于 Sobel 这种需要对每个像素做相同操作的任务,NPU 的优势非常明显。

举个例子:CPU 就像一个很聪明的人,什么都能做,但一次只能做一件事;NPU 就像一群不太聪明但很勤奋的人,每个人只做很简单的事,但大家一起做,速度就快多了。

环境搭建

硬件要求

  • 设备类型:请参考 CANN Kit 开发指南的约束与限制
  • HarmonyOS 系统:HarmonyOS 5.0.5 Release 及以上

软件要求

  • DevEco Studio 版本:DevEco Studio 6.1.0 Release 及以上
  • HarmonyOS SDK 版本:HarmonyOS 6.1.0 Release SDK 及以上

开发环境要求

AscendC 的开发环境比较特殊,需要在 Linux 上搭建:

  • Ubuntu 版本:22.04 及以上(仅支持 x86)
  • Python 版本:3.7 到 3.10 之间
  • GCC/G++ 版本:7.0 及以上
  • CMake 版本:3.22.1 及以上

搭建步骤

  1. 安装 DevEco Studio:去华为开发者官网下载安装
  2. 下载 DDK Tools:下载 DDK_tools_5.1.1.0,并在 Linux 环境上解压
  3. 下载平台插件:下载需要的平台插件包,解压后拷贝到ddk_external/tools/platform目录下
  4. 安装工具:进入ddk_external/tools/tools_ascendc目录,执行安装脚本
  5. 设置环境变量:执行set_ascendc_env.sh设置环境变量
  6. 安装 Python 依赖:安装 toml、jinja2、numpy、torch 等依赖库

项目结构

├── build.sh // 编译入口脚本 ├── build_devices.sh // 编译devices侧交付件脚本 ├── cmake │ ├── config.cmake │ └── util // 算子工程编译所需脚本及公共编译文件存放目录 ├── CMakeLists.txt // 算子工程的CMakeLists.txt ├── CMakePresets.json // 编译配置项 ├── framework // 算子插件实现文件目录 ├── op_host // host侧实现文件 │ ├── sobel_custom_tiling.h // 算子Tiling定义文件 │ ├── sobel_custom.cpp // 算子原型注册、shape推导、信息库、tiling实现等内容文件 │ └── CMakeLists.txt ├── op_kernel // Kernel侧实现文件 │ ├── CMakeLists.txt │ ├── sobel_custom_base.h // 算子代码定义文件 │ └── sobel_custom.cpp // 算子代码实现文件 └── scripts // 自定义算子工程打包相关脚本所在目录

这个项目结构和前面的图形渲染项目很不一样。主要分为两部分:

  • op_host:Host 侧代码,负责算子的注册、shape 推导、Tiling 策略等
  • op_kernel:Kernel 侧代码,负责在 NPU 上实际执行的计算逻辑

边缘检测算法原理

在看代码之前,先了解一下 Sobel 边缘检测的原理。

处理流程

整个处理流程分四步:

  1. RGB 转灰度:把彩色图像转成灰度图像
  2. Sobel X 方向滤波:检测水平方向的边缘
  3. Sobel Y 方向滤波:检测垂直方向的边缘
  4. XY 方向融合:把两个方向的边缘信息合并

Sobel 滤波核

Sobel 算子使用 3x3 的滤波核。X 方向的滤波核是:

-1 0 1 -2 0 2 -1 0 1

Y 方向的滤波核是:

-1 -2 -1 0 0 0 1 2 1

简单说,X 方向的滤波核会检测左右像素的差异,Y 方向的滤波核会检测上下像素的差异。

XY 方向融合

融合的方式很简单:用曼哈顿距离 G = |Gx| + |Gy| 来替代欧几里得距离。这样计算更快,效果也差不多。

第一步:实现 RGB 转灰度

RGB 转灰度的公式是:Gray = 0.299 * R + 0.587 * G + 0.114 * B。

在 AscendC 中,这个操作可以用向量指令高效完成。

第二步:实现 Sobel 滤波

这是核心部分。Sobel 滤波需要对每个像素,用它周围的 3x3 邻域和滤波核做卷积。

使用 Gather 操作

由于数据不是 32 字节对齐的,需要用Gather操作来获取特定位置的数据。

// 生成index: [2, 3, 4, ..., w - 1]AscendC::CreateVecIndex(index,int16_t(2),w-2);AscendC::Muls(index,index,int16_t(2),w-2);// index:int16->uint32AscendC::Cast(newindex,index,AscendC::RoundMode::CAST_NONE,w-2);

这段代码生成一个索引数组,用来获取每个像素右侧第 2 个位置的数据。CreateVecIndex创建一个连续的索引序列,Muls把索引乘以 2(因为每个像素有两个字节),Cast把索引转成 uint32 类型。

for(inti=0;i<h-2;i++){// 将data[i][2,3,4,...,w-1]存储到tmpBuf0[0, 1, 2, ..., w-2]AscendC::Gather(tmpBuf0,data[i*w],newindex,0,w-2);AscendC::Gather(tmpBuf1,data[(i+1)*w],newindex,0,w-2);AscendC::Gather(tmpBuf2,data[(i+2)*w],newindex,0,w-2);

对每一行,用Gather获取右侧第 2 个位置的像素值。这样就得到了 Sobel 滤波核中 “j+2” 位置的数据。

// part1AscendC::Muls(dx[i*w],data[i*w],half(-1),w-2);AscendC::Muls(tmpBuf3,data[(i+1)*w],half(-2),w-2);AscendC::Muls(tmpBuf4,data[(i+2)*w],half(-1),w-2);AscendC::Add(dx[i*w],dx[i*w],tmpBuf3,w-2);AscendC::Add(dx[i*w],dx[i*w],tmpBuf4,w-2);

计算 Sobel X 方向的第一部分:左侧列的加权和。对应滤波核的 [-1, -2, -1] 这一列。

// part2AscendC::Muls(tmpBuf1,tmpBuf1,half(2),w-2);AscendC::Add(dx[i*w],dx[i*w],tmpBuf0,w-2);AscendC::Add(dx[i*w],dx[i*w],tmpBuf1,w-2);AscendC::Add(dx[i*w],dx[i*w],tmpBuf2,w-2);}

计算 Sobel X 方向的第二部分:右侧列的加权和。对应滤波核的 [1, 2, 1] 这一列。两部分加起来就是完整的 Sobel X 方向滤波结果。

第三步:实现 XY 方向融合

// G = |Gx| + |Gy|AscendC::Abs(dx,dx,totalSize);AscendC::Abs(dy,dy,totalSize);AscendC::Add(result,dx,dy,totalSize);

先对 Gx 和 Gy 取绝对值,然后相加。这就是曼哈顿距离融合。

第四步:归一化

// 归一化为[0,255]AscendC::Cast(output,result,AscendC::RoundMode::CAST_NONE,totalSize);

把 half 类型的结果转成 uint8 类型,输出范围 [0, 255]。

Vector 编程范式

AscendC 使用 Vector 编程范式,把算子的实现分为三个基本任务:

  1. CopyIn:把输入数据从 Global Memory 搬运到 Local Memory
  2. Compute:在 Local Memory 上进行计算
  3. CopyOut:把计算结果从 Local Memory 搬运回 Global Memory
__aicore__inlinevoidProcess(){cntH=SobelCustom::CeilDiv(this->H,h);cntW=SobelCustom::CeilDiv(this->W,w);for(int32_ti=0;i<cntH;i++){for(int32_tj=0;j<cntW;j++){CopyIn(i,j);Compute(i,j);CopyOut(i,j);}}}

整个处理过程是:把图像分成很多小块(tile),对每个小块依次执行 CopyIn、Compute、CopyOut。

内存管理

AscendC 使用 TQue 和 TBuf 来管理内存:

  • TQue:队列,用于 CopyIn 和 CopyOut 的数据传输
  • TBuf:缓冲区,用于计算过程中的临时数据
constexprint32_tBUFFER_NUM=2;constuint32_th=9;constuint32_tw=256;pipe.InitBuffer(inQueueX,BUFFER_NUM,tileLength*sizeof(T));pipe.InitBuffer(outQueueY,BUFFER_NUM,tileLength*sizeof(T));

这里使用 double buffer(BUFFER_NUM = 2),可以在计算当前块的同时搬运下一块的数据,提高效率。

Tiling 策略

Tiling 是把大任务分成小块的策略。每个 tile 的大小是 h x w,其中:

  • w 必须是 32 的倍数(对齐约束)
  • h * w * 34 + w * 12 <= 120KB(UB 大小限制)

选 h=9, w=256 是一个合理的值。

数据搬运

__aicore__inlinevoidCopyIn(int32_ti,int32_tj){LocalTensor<T>xLocal=inQueueX.AllocTensor<T>();DataCopyExtParams dataCopyParams;// ... 设置参数DataCopyPadExtParams<T>padParams(false,0,0,0);DataCopyPad(xLocal,xGm[offset],dataCopyParams,padParams);inQueueX.EnQue(xLocal);}

DataCopyPad是一个支持非对齐搬运的接口。因为图像的宽度不一定是 32 的倍数,所以需要用这个接口来处理边界情况。

dataCopyParams设置了搬运的参数:

  • blockCount:搬运多少行
  • blockLen:每行搬运多少字节
  • srcStride:源地址的行间距
  • dstStride:目标地址的行间距

编译和运行

创建算子工程

msopgen gen-i./SobelCustom.json-cai_core-kirin9020-fONNX-out./SobelCustom

msopgen工具根据配置文件自动创建算子工程。

编译算子

cdSobelCustom/SobelCustom ./build.sh

编译成功后会显示 “Install the project…Build and install success”。

调试算子

# NPU 仿真调试ascendebug kernel--backendsimulator --repo-type customize --json-file../ascendebug/temp.json --core-type AiCore --chip-version kirin9020 --work-dir../ascendebug/myWorkDir/ --block-num1--rel-err-thd0.5# NPU 实际调试ascendebug kernel--backendnpu --repo-type customize --json-file../ascendebug/temp.json --core-type AiCore --chip-version kirin9020 --work-dir../ascendebug/myWorkDir/ --block-num1--rel-err-thd0.5

可以先在仿真器上调试,再在实际 NPU 上调试。调试成功后会生成.omc文件,这就是编译好的算子。

集成到应用

把生成的.omc文件放到应用的resources/rawfile目录下,就可以在应用中调用了。

AscendC 的优势

  1. 性能:在 NPU 上运行,比 CPU 快很多
  2. 可复用:端侧和云侧的算子代码可以复用
  3. 可调试:提供了仿真器和实际 NPU 两种调试方式
  4. 标准化:使用统一的编程范式,学习成本低

适用场景

AscendC 算子开发适合以下场景:

  • 图像处理:边缘检测、滤波、变换等
  • AI 推理:自定义的神经网络层
  • 信号处理:FFT、滤波器等
  • 科学计算:矩阵运算、数值计算等

注意事项

  1. 环境搭建:AscendC 的开发环境比较复杂,需要在 Linux 上搭建
  2. 对齐约束:数据宽度必须是 32 的倍数,否则需要特殊处理
  3. 内存管理:UB 大小有限(120KB),要合理规划 Tiling 策略
  4. 调试工具:建议先用仿真器调试,再在实际 NPU 上调试
  5. 平台插件:不同芯片需要不同的平台插件,要确保下载正确

核心流程图

Sobel 边缘检测算法的处理流程:

渲染错误:Mermaid 渲染失败: Parse error on line 7: ... --> G[XY 方向融合: G = |Gx| + |Gy|] F - -----------------------^ Expecting 'SQE', 'TAGEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PIPE'

AscendC 算子开发的完整流程:

搭建 Linux 开发环境

下载 DDK Tools 和平台插件

使用 msopgen 创建算子工程

实现 Host 侧: 算子注册与 Tiling 策略

实现 Kernel 侧: CopyIn / Compute / CopyOut

配置 Tiling 参数

编译算子工程

仿真器调试

调试是否通过?

修复问题

实际 NPU 调试

生成 .omc 文件集成到应用

总结

AscendC 是一个强大的 NPU 编程框架,让你可以自己实现算子在 NPU 上运行。核心流程:

  1. 搭建开发环境(Linux + DDK Tools)
  2. 设计算法(RGB 转灰度、Sobel 滤波、XY 融合)
  3. 实现算子(CopyIn、Compute、CopyOut)
  4. 配置 Tiling 策略
  5. 编译、调试、集成

如果你的应用需要高性能的图像处理或 AI 推理,AscendC 是一个值得学习的技术。

http://www.jsqmd.com/news/958689/

相关文章:

  • SMT贴片加工锡膏储存和使用注意事项
  • 杰理之IO_CONTROL 功能介绍可以参考【篇】
  • 告别KD树搜索!用Voxelized GICP在CPU/GPU上实现120Hz的实时点云配准
  • 终极免费Steam创意工坊下载器:无需客户端轻松获取千款游戏模组
  • 碳硅共生认知场方程:碳基-硅基协同智能的数学基础(世毫九实验室原创研究)
  • 别再手动调Excel了!Easypoi合并单元格与自适应行高避坑指南
  • 【AI家庭中枢搭建指南】:20年智能家居架构师亲授7大避坑法则与实时联动配置秘籍
  • Mi-Create:如何为2021年后小米穿戴设备开发个性化表盘的完整技术指南
  • 2023年软考-术资源的镜像数据库—软件设计师—东方仙盟
  • 别再乱用马尔可夫链了!先花5分钟用Excel自带的CHISQ.TEST做个马氏性预检验
  • 别再手动导ROM了!教你搭建一个免下载、即点即玩的Web版FC游戏库
  • OSPF联邦作业
  • 【字节跳动】GR3六轴协作机械臂·底层裸数据机密台账(工业原始未脱敏完整版·万字归档版)
  • 别再只盯着权重剪枝了!聊聊那些更‘实用’的CNN通道与过滤器剪枝实战
  • Windows用户福音:3分钟免费获取iPhone USB网络共享驱动终极方案
  • FPGA实现近传感器特征提取
  • OpenClaw从入门到应用——CLI:Gateway
  • 别再手动算参数量了!用fvcore一键分析PyTorch模型(附ResNet50/VGG16实测对比)
  • Sunshine游戏串流实战指南:构建低延迟自托管云游戏平台的完整技术方案
  • 无需安装python,用快马平台5分钟创建你的第一个交互式代码运行器
  • AI辅助设计:让快马为你构思并生成Harness流水线最佳实践代码
  • Markdown文档可视化技术突破:Typora drawIO插件架构解析与工程实践
  • 三步搞定抖音评论采集:零代码获取完整用户反馈数据 [特殊字符]
  • 必应推广行业百科:核心逻辑与杭州专业服务商指南
  • pycharm python sqlalchemy mysql增删改查实例csdn
  • arduino新手必看,用快马平台生成带详解注释的第一个控制程序
  • 手把手教你用Simulink搭建无穷大电源模型:从理论计算到短路仿真全流程
  • 铝方通推荐,吉林省万发装饰装潢工程的产品有什么优势? - myqiye
  • AI搜索环境下东莞本地企业GEO优化全流程实战指南
  • R 语言线性余弦调色板:简单方法在生成艺术中获超预期效果!