基于昇腾CANN的推理应用开发--语义分割(Python)

2023-10-27

前情提要

基于 Python 开发,通过网络模型加载、推理、结果输出的部署全流程展示,快速熟悉并掌握语义分割基本开发流程。

目录

1 内容及目标
1.1 内容
1.2 目标
1.3 先导知识
2 理解原始模型
2.1 网络结构
2.2 查看模型推理结果
3 编写推理应用
3.1 模型转换
3.2 初始化
3.3 加载模型
3.4 读取图像数据并进行预处理
3.5 模型推理
3.6 解析模型推理结果
4 结语

1. 内容及目标

1.1 内容

这里主要介绍基于昇腾 CANN 平台的语义分割的开发方法,是基于 DeepLab_v3+ 语义分割网络编写的示例代码,通过读取本地图像数据作为输入,对图像中的物体进行语义分割,最后使用 OpenCV 将推理结果写到本地文件中。旨在了解如何在昇腾平台上实现一个基于语义分割模型的推理应用。

1.2 目标

1.掌握一个基于昇腾CANN平台的推理应用的基本结构。
2.理解 deeplabv3_plus 模型的网络结构及其数据预处理/后处理方式。

1.3 先导知识

1.熟悉和掌握Python语言,具备一定的开发能力
2.深度学习基础知识,理解神经网络模型输入输出数据结构

2. 理解原始模型

2.1 网络结构

DeepLabv3+模型的整体架构如图所示,它的Encoder的主体是带有空洞卷积的DCNN,可以采用常用的分类网络如ResNet,然后是带有空洞卷积的空间金字塔池化模块(Atrous Spatial Pyramid Pooling, ASPP)),主要是为了引入多尺度信息;相比DeepLabv3,v3+引入了Decoder模块,其将底层特征与高层特征进一步融合,提升分割边界准确度。从某种意义上看,DeepLabv3+在DilatedFCN基础上引入了EcoderDecoder的思路。

image.png

对原始模型代码感兴趣的小伙伴可以参考链接

2.2 查看模型推理的效果

通过下一张图可以很快了解到该模型是对图片进行与语义分割。

image.png

3. 编写推理应用

image.png

  1. 运行管理资源申请:用于初始化系统内部资源,固定的调用流程。
  2. 加载模型文件并构建输出内存:
  • 从文件加载离线模型,模型加载进系统之后占用的内存需要由用户自行管理;
  • 获取模型的基本信息,包含模型输入/输出的个数,每个输入/输出占用内存的大小;
  • 上一步获取的信息申请模型输出内存,为接下来的模型推理做好准备。
  1. 获取本地图像并进行预处理:使用OpenCV从本地存放有图像数据的目录中循环读取图像数据,对读入的图像数据进行预处理,然后构建模型的输入数据。
  2. 模型推理:根据加载的模型、构建好的模型输入数据、申请好的模型输出内存进行模型推理。
  3. 解析推理结果:将推理结果作用于原始图片上,形成语义分割图像;随后使用OpenCV将转换后的结果图像数据保存为图片文件。

执行下方的代码,进行推理代码开发前的系统初始化。

3.1 模型转换

原始网络模型是Caffe预训练模型,而昇腾CANN软件栈推理所需要的的模型是.om离线模型。因此,需要将Caffe预训练模型通过ATC模型转换工具做一下转换。

ATC模型转换命令举例:

atc --model=./deeplabv3_plus.pb --framework=3 --output=./model/deeplabv3_plus --soc_version=Ascend310 -- --input_shape="data:1,513,513"

最终已转好的om模型,模型路径如下:

./model/deeplabv3_plus.om

3.2 初始化

在调用任何AscendCL接口进行操作之前,首先要对AscendCL的运行时环境进行初始化操作,以及申请运行时资源。
初始化及资源申请操作主要有以下几个步骤:

  1. 初始化系统内部资源,调用acl.init接口实现ACL初始化
  2. 调用acl.rt.set_device接口指定运算的Device
  3. 调用acl.rt.create_context接口显式创建一个Context
  4. 调用acl.rt.create_stream接口显式创建一个Stream

当所有数据处理都结束后,需要释放运行管理资源,释放资源时,需要按顺序释放,先释放Stream,再释放Context,最后再释放Device。释放运行管理资源时主要有以下几个步骤:

需按顺序依次释放:Stream、Context、Device。

  1. 调用acl.finalize接口实现ACL去初始化。
  2. 调用acl.rt.destroy_stream接口释放Stream
  3. 调用acl.rt.destroy_context接口释放Context
  4. 调用 acl.rt.reset_device接口释放Device上的资源。

我们针对上述操作封装了一套工具库,其中,初始化和去初始化,资源申请和资源释放部分,由一个“AclResource”类来实现

对初始化和去初始化的源码感兴趣的小伙伴可以从此链接查看:

运行下方代码,查看效果,并阅读“init()”方法,观察初始化和运行时资源申请的详细操作步骤。

import sys
import os
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

home_path = !echo ${HOME}
sys.path.append(os.path.join(home_path[0] , "jupyter-notebook/"))
print('System init success.')

# atlas_utils是昇腾团队基于pyACL封装好的一套工具库,如果您也想引用的话,请首先将
# https://gitee.com/ascend/samples/tree/master/python/common/atlas_utils
# 这个路径下的代码引入您的工程中
from atlas_utils.acl_resource import AclResource
from constants import *
from acl_model import Model

# 创建一个AclResource类的实例
acl_resource = AclResource()
#AscendCL资源初始化(封装版本)
acl_resource.init()

# 上方“init”方法具体实现(仅供参考),请阅读“init()”方法,观察初始化和运行时资源申请的详细操作步骤
def init(self):
    """
    Init resource
    """
    print("init resource stage:")
    ret = acl.init()
    utils.check_ret("acl.init", ret)

    #指定用于运算的Device
    ret = acl.rt.set_device(self.device_id)
    utils.check_ret("acl.rt.set_device", ret)
    print("Set device n success.")

    #显式创建一个Context
    self.context, ret = acl.rt.create_context(self.device_id)
    utils.check_ret("acl.rt.create_context", ret)

    #创建一个Stream
    self.stream, ret = acl.rt.create_stream()
    utils.check_ret("acl.rt.create_stream", ret)

    #获取当前昇腾AI软件栈的运行模式
    #0:ACL_DEVICE,表示运行在Device的Control CPU上或开发者版上
    #1:ACL_HOST,表示运行在Host CPU上
    self.run_mode, ret = acl.rt.get_run_mode()
    utils.check_ret("acl.rt.get_run_mode", ret)

    print("Init resource success")

# 请阅读下方代码,观察释放运行时资源的详细操作步骤
def __del__(self):
    print("acl resource release all resource")
    resource_list.destroy()

    # 调用acl.rt.destroy_stream接口释放Stream
    if self.stream:
        acl.rt.destroy_stream(self.stream)
        print("acl resource release stream")

    # 调用acl.rt.destroy_context接口释放Context
    if self.context:
        acl.rt.destroy_context(self.context)
        print("acl resource release context")

    # 调用acl.rt.destroy_context接口释放Context
    acl.rt.reset_device(self.device_id)
    acl.finalize()
    print("Release acl resource success")

3.3 加载模型

在调用模型进行推理之前,首先要将模型加载进来。对模型的操作,这里封装了一个类“Model”,源码路径在Gitee官仓

加载模型的过程主要分以下几个步骤:

  1. 从磁盘读取om模型
  2. 分析该om模型,提取其描述信息,主要是模型有几个输入/输出,每个输入/输出占用多大内存
  3. 模型的输出尺寸通常是固定的,可以先为输出申请好内存

运行下方代码,观察效果。感兴趣的读者可以阅读一下Model类的源码。

# 从文件加载离线模型数据
model_path = './model/deeplabv3_plus.om'
model = Model(model_path)

3.4 读取图像数据并进行预处理

本应用的图像预处理部分主要做了以下几件事情::

  1. 使用opencv的imread接口读取图片,读取出来的是BGR格式;
  2. 得到原始图片的shape
  3. 模型输入为513×513,因此需要把读取到的图像resize到513×513

下面我们首先看一下原始图片的样貌:

import sys
import os
import numpy as np
import cv2 as cv
from PIL import Image

MODEL_WIDTH = 513
MODEL_HEIGHT = 513

#图片路径
image_dir = './deeplabv3_pascal_data/'

IMG_EXT = ['.jpg', '.JPG', '.png', '.PNG', '.bmp', '.BMP', '.jpeg', '.JPEG']
images_list = [os.path.join(image_dir,img)for img in os.listdir(image_dir)if os.path.splitext(img)[1] in IMG_EXT]
images_list
Image.open(images_list[0])
type(images_list[0])

接下来我们要对原始数据做上述3步预处理动作,具体操作说明参考注释:

# 1. 读取图片
bgr_img = cv.imread(images_list[0])

# 2. 得到图片shape
orig_shape = bgr_img.shape[:2]
print("Shape of original image:",bgr_img.shape)

# 3.对图片进行resize,缩放至模型要求的宽高:
img = cv.resize(bgr_img, (MODEL_WIDTH, MODEL_HEIGHT))
print("The size of the model to be entered:",img.shape)

# 保存并展示resize之后的图片
if not os.path.isdir('./outputs'):
   os.mkdir('./outputs')
output_path = os.path.join("./outputs", "out_" + os.path.basename(images_list[0]))
cv.imwrite(output_path, img)
Image.open(output_path)
img = img.astype(np.int8)
if not img.flags['C_CONTIGUOUS']:
        img = np.ascontiguousarray(img)
img.shape
img.nbytes

3.5 模型推理

准备好预处理后的数据以及模型之后,我们来到了核心的模型推理环节。
这一环节有一些细小的操作需要完成,主要有以下几步:

  1. 在Device侧申请内存,并把数据从Host侧发送到Device侧,这样昇腾 310 AI处理器才能获取到数据进行计算
  2. 为模型推理准备专用数据结构。原始图片数据是不能直接送进模型进行推理的,需要用两个特定的数据结构包装一下。
  • 模型可能存在多个输入,例如第1个输入是若干张图片,第二个输入是每个图片的信息;此时,每个原始输入的数据要为其建立一个“dataBuffer”对象
  • 所有的dataBuffer构成1个“dataSet”对象送进模型进行推理。
  • 输出同理。1个模型只会有1个输入dataset,1个输出dataset,但是每个dataset可能包含多个databuffer
  1. 执行模型推理

上述这几步,在官方封装好的工具类中都做了通用实现,所以在使用过程中,只需要调用一下model.execute方法,将数据传进去就可以执行推理了:

# 根据构建好的模型输入数据进行模型推理
result_list = model.execute([img])
print(result_list)

3.6 解析模型推理结果

拿到模型推理结果之后,我们来到了最后一步——后处理。

解析模型推理结果的步骤:

  1. 获取模型推理输出数据并且将其 reshape 成 513 * 513;
  2. 对reshape之后的图片进行通道合并,重新合并成一个多通道的图像
  3. 将多通道图像resize到原始图片的大小;
  4. 保存为jpeg图片,得到分割后的图像。

下边是具体的操作步骤,执行一下观察结果:

# 1. 得到推理结果并且reshape成513*513,并且转换成uint8类型
result_img = result_list[0].reshape(513, 513)
result_img = result_img.astype('uint8')
result_img.shape

cv.imwrite(output_path, result_img)
Image.open(output_path)

# 2. 多通道图像融合
img = cv.merge((result_img, result_img, result_img))
print("Multi channel merged shape:",img.shape)

# 3. 将融合后的图像resize成原始图片的大小
bgr_img = cv.resize(img, (orig_shape[1], orig_shape[0]))
print("Shape of the original image size that is resized:",bgr_img.shape)
bgr_img = (bgr_img * 255)

# 保存图片
cv.imwrite(output_path, bgr_img)
Image.open(output_path)

结语

至此,语义分割应用代码编写完毕。让我们回顾一下在使用atlas_util库的场景下,我们都做了哪些主要的事情:

  1. 将Caffe训练出来的deeplabv3_plus模型转换为.om离线模型
  2. 初始化AscendCL运行时环境,申请运行资源
  3. 加载om模型
  4. 对原始图片做预处理
  5. 调用模型的推理接口进行推理
  6. 将推理结果作用于原始数据上进行语义分割,保存处理后的图片。

这里我们在atlas_util中屏蔽了很多对AscendCL接口的调用细节,感兴趣的朋友可以阅读一下atlas_util的源码

如果您对上述代码有疑问请提交ISSUE到官仓

更多昇腾有趣内容请移步至昇腾社区

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于昇腾CANN的推理应用开发--语义分割(Python) 的相关文章

  • 如何手动计算分类交叉熵?

    当我手动计算二元交叉熵时 我应用 sigmoid 来获取概率 然后使用交叉熵公式并平均结果 logits tf constant 1 1 0 1 2 labels tf constant 0 0 1 1 1 probs tf nn sigm
  • 在 django ORM 中查询时如何将 char 转换为整数?

    最近开始使用 Django ORM 我想执行这个查询 select student id from students where student id like 97318 order by CAST student id as UNSIG
  • Python 中的哈希映射

    我想用Python实现HashMap 我想请求用户输入 根据他的输入 我从 HashMap 中检索一些信息 如果用户输入HashMap的某个键 我想检索相应的值 如何在 Python 中实现此功能 HashMap
  • Pandas/Google BigQuery:架构不匹配导致上传失败

    我的谷歌表中的架构如下所示 price datetime DATETIME symbol STRING bid open FLOAT bid high FLOAT bid low FLOAT bid close FLOAT ask open
  • 使用 Python 从文本中删除非英语单词

    我正在 python 上进行数据清理练习 我正在清理的文本包含我想删除的意大利语单词 我一直在网上搜索是否可以使用像 nltk 这样的工具包在 Python 上执行此操作 例如给出一些文本 Io andiamo to the beach w
  • 使用 kivy textinput 的 'input_type' 属性的问题

    您好 我在使用 kivy 的文本输入小部件的 input type 属性时遇到问题 问题是我制作了两个自定义文本输入 其中一个称为 StrText 其中设置了 input type text 然后是第二个文本输入 名为 NumText 其
  • 将 python2.7 与 Emacs 24.3 和 python-mode.el 一起使用

    我是 Emacs 新手 我正在尝试设置我的 python 环境 到目前为止 我已经了解到在 python 缓冲区中使用 python mode el C c C c将当前缓冲区的内容加载到交互式 python shell 中 显然使用了什么
  • 您可以格式化 pandas 整数以进行显示,例如浮点数的“pd.options.display.float_format”?

    我见过this https stackoverflow com questions 18404946 py pandas formatdataframe and this https stackoverflow com questions
  • datetime.datetime.now() 返回旧值

    我正在通过匹配日期查找 python 中的数据存储条目 我想要的是每天选择 今天 的条目 但由于某种原因 当我将代码上传到 gae 服务器时 它只能工作一天 第二天它仍然返回相同的值 例如当我上传代码并在 07 01 2014 执行它时 它
  • Python beautifulsoup 仅限 1 级文本

    我看过其他 beautifulsoup 得到相同级别类型的问题 看来我的有点不同 这是网站 我正试图拿到右边那张桌子 请注意表的第一行如何展开为该数据的详细细分 我不想要那个数据 我只想要最顶层的数据 您还可以看到其他行也可以展开 但在本例
  • 从Python中的字典列表中查找特定值

    我的字典列表中有以下数据 data I versicolor 0 Sepal Length 7 9 I setosa 0 I virginica 1 I versicolor 0 I setosa 1 I virginica 0 Sepal
  • 如何使用python在一个文件中写入多行

    如果我知道要写多少行 我就知道如何将多行写入一个文件 但是 当我想写多行时 问题就出现了 但是 我不知道它们会是多少 我正在开发一个应用程序 它从网站上抓取并将结果的链接存储在文本文件中 但是 我们不知道它会回复多少行 我的代码现在如下 r
  • Numpy - 根据表示一维的坐标向量的条件替换数组中的值

    我有一个data多维数组 最后一个是距离 另一方面 我有距离向量r 例如 Data np ones 20 30 100 r np linspace 10 50 100 最后 我还有一个临界距离值列表 称为r0 使得 r0 shape Dat
  • pip 列出活动 virtualenv 中的全局包

    将 pip 从 1 4 x 升级到 1 5 后pip freeze输出我的全局安装 系统 软件包的列表 而不是我的 virtualenv 中安装的软件包的列表 我尝试再次降级到 1 4 但这并不能解决我的问题 这有点类似于这个问题 http
  • 如何在 Windows 命令行中使用参数运行 Python 脚本

    这是我的蟒蛇hello py script def hello a b print hello and that s your sum sum a b print sum import sys if name main hello sys
  • 如何解决 PDFBox 没有 unicode 映射错误?

    我有一个现有的 PDF 文件 我想使用 python 脚本将其转换为 Excel 文件 目前正在使用PDFBox 但是存在多个类似以下错误 org apache pdfbox pdmodel font PDType0Font toUnico
  • 实现 XGboost 自定义目标函数

    我正在尝试使用 XGboost 实现自定义目标函数 在 R 中 但我也使用 python 所以有关 python 的任何反馈也很好 我创建了一个返回梯度和粗麻布的函数 它工作正常 但是当我尝试运行 xgb train 时它不起作用 然后 我
  • Pandas 每周计算重复值

    我有一个Dataframe包含按周分组的日期和 ID df date id 2022 02 07 1 3 5 4 2022 02 14 2 1 3 2022 02 21 9 10 1 2022 05 16 我想计算每周有多少 id 与上周重
  • 更改 Tk 标签小部件中单个单词的颜色

    我想更改 Tkinter 标签小部件中单个单词的字体颜色 我知道可以使用文本小部件来实现与我想要完成的类似的事情 例如使单词 YELLOW 显示为黄色 self text tag config tag yel fg clr yellow s
  • 使用 z = f(x, y) 形式的 B 样条方法来拟合 z = f(x)

    作为一个潜在的解决方案这个问题 https stackoverflow com questions 76476327 how to avoid creating many binary switching variables in gekk

随机推荐

  • 如何让网页自适应所有屏幕宽度

    随着网络的快熟发展 越来越多的人使用手机上网 移动设备正超过桌面设备 成为访问互联网的最常见终端 于是 网页设计师不得不面对一个难题 如何才能在不同大小的设备上呈现同样的网页 手机的屏幕比较小 宽度通常在600像素以下 PC的屏幕宽度 一般
  • Markdown 文本居中、字体颜色以及数学公式

    文章目录 文本格式 文字居中 字体 字体颜色 字体大小 背景色 颜色 数学公式 希腊字母 行内与独行 上标 下标与组合 汉字 字体与格式 占位符 定界符与组合 四则运算 高级运算 逻辑运算 集合运算 数学符号 文本格式 文字居中 1 文字居
  • 数据结构---求最大公约数

    求最大公约数 穷举法 辗转相除法法 第一步 第二步 第三步 JAVA实现 更相减损术 第一步 第二步 第三步 JAVA实现 更相减损术与移位相结合 操作逻辑 例子 JAVA实现 写一段代码 求出两个整数的最大公约数 要尽量优化算法的性能 例
  • Python 处理错误和异常

    微信公众号 数据分析与统计学习如有问题或建议 请公众号留言最近更新时间 2018 7 2 一 前言 Python的系列文章主要介绍python语言的基础语法知识 按照核心内建数据类型 语句 函数 类 异常 标准模块的顺序对相关的语法知识进行
  • imx6ull开发板,usb免驱摄像头的配置

    在 dev下面 只能找到video0 说明开发板并没有识别出有新连接进来的摄像头 需要在内核中 配置支持UVC标准的USB驱动 重新配置即可
  • cve 爬虫_爬虫CNVD构建漏洞库

    import requests from lxml import etree import xlsxwriter from requests utils import add dict to cookiejar import execjs
  • 关于电路交换、报文交换和分组交换

    交换 所谓交换 指的就是服务器与服务器之间的数据交换 考纲要求掌握三种 电路交换 报文交换和分组交换 这篇文章主要介绍这三种交换方式 以及分组交换中的数据报和虚电路 电路交换 电路交换即在通信之前 在通信双方之间建立一条被双方独占的物理通路
  • obsidian加git备份,同时忽略掉自己不想同步的文件夹

    最近想用这个语雀进行知识库的分享 但是这个语雀的会员费太贵了 思来想去还是用 git 比较好 因为这个知识库的内容都是自己的笔记 为了能够访问的更加方便我选择了这个 gitte 而不是 github 我的知识库链接 knowledge 第一
  • 如何在sqlplus执行sql文件

    1 Oracle数据库的sqlplus可以直接执行SQL语句吗 2 SQL Plus中怎么执行多个 sql脚本文件 3 如何在sqlplus执行sql文件 4 怎样在sqlplus中批量执行sql文件 Oracle数据库的sqlplus可以
  • 在模仿中精进数据分析与可视化01——颗粒物浓度时空变化趋势(Mann–Kendall Test)

    本文是在模仿中精进数据分析与可视化系列的第一期 颗粒物浓度时空变化趋势 Mann Kendall Test 主要目的是参考其他作品模仿学习进而提高数据分析与可视化的能力 如果有问题和建议 欢迎在评论区指出 若有其他想要看的作品 也欢迎在评论
  • GIT合并分支的三种方法

    一 使用merge命令合并分支 1 目标 将dev分支合并到master分支 1 1 首先切换到master分支上 git checkout master 1 2 如果是多人开发的话 需要把远程master上的代码pull下来 git pu
  • 【华为OD机试 】 单词搜索(C++ Java JavaScript Python)

    题目描述 找到它是一个小游戏 你需要在一个矩阵中找到给定的单词 假设给定单词 HELLOWORD 在矩阵中只要能找到 H gt E gt L gt L gt O gt W gt O gt R gt L gt D连成的单词 就算通过 注意区分
  • flask 写数据mysql_Flask从入门到精通之MySQL数据库操作

    前面的章节中我们已经学习了如何建立模型和关系 接下来我们学习如何使用模型的最好方法是在Python shell 中实际操作 并将介绍最常用的数据库操作 一 创建表 首先 我们要让Flask SQLAlchemy 根据模型类创建数据库 方法是
  • 27.EI文章复现《高比例清洁能源接入下计及需求响应的配电网重构》

    下载地址 高比例清洁能源接入下计及需求响应的配电网重构 1主要内容 该程序复现 高比例清洁能源接入下计及需求响应的配电网重构 以考虑网损成本 弃风弃光成本和开关操作惩罚成本的综合成本最小为目标 针对配电网重构模型的非凸性 引入中间变量并对其
  • Templates and Classes___CH_19

    19 1 Template classes Templates and container classes Template classes in the standard library Now that we ve covered te
  • 分库分表

    名词解释 库 database 表 table 分库分表 sharding 为什么要分库分表 移动互联网时代 海量的用户每天产生海量的数量 比如 用户表 订单表 交易流水表 以支付宝用户为例 8亿 微信用户更是10亿 订单表更夸张 比如美团
  • Python 20.opencv 直方图均衡化,CLAHE(对比度改变)

    import cv2 import numpy as np img cv2 imread pic1 png 0 进行直方图均衡化 equ cv2 equalizeHist img CLAHE有限对比适应性直方图均衡化 作用 限制对比度下降
  • 第一个项目单个交换机接入网络

    按图片上的要求来将一个交换机接入网络 配置明细路由 vlanif当网关
  • MATLAB中LSTM时序分类的用法与实战

    MATLAB中LSTM时序分类的用法与实战 说明 本教程适用于R2018b版本的matlab 不知道R2018a有没有 但是2017版本的肯定是没有LSTM工具箱的了 所以版本低的趁这个机会卸载然后重新下载安装吧 引用参考 1 matlab
  • 基于昇腾CANN的推理应用开发--语义分割(Python)

    前情提要 基于 Python 开发 通过网络模型加载 推理 结果输出的部署全流程展示 快速熟悉并掌握语义分割基本开发流程 目录 1 内容及目标 1 1 内容 1 2 目标 1 3 先导知识 2 理解原始模型 2 1 网络结构 2 2 查看模