最近老山完成了对mask-rcnn在modelarts上的部署,部署模型来自于这个项目。部署的过程大体和我的上篇文章使用modelarts部署bert命名实体识别模型相似,许多细节也不在赘述。这篇文章主要介绍下大体的思路、遇到的问题和解决方案,文章结尾会附录运行需要的程序。

部署思路

生成savedModel

原模型是使用tensorflow做backend的keras模型。源程序中的keras模型又被封装在MaskRCNN类中。我们要先取出被封装的keras模型,在源程序提供的demo.ipynb第三步后,我们提取出keras模型

# Create model object in inference mode.
model = modellib.MaskRCNN(mode="inference", model_dir=MODEL_DIR, config=config)# Load weights trained on MS-COCO
model.load_weights(COCO_MODEL_PATH, by_name=True)# 前面来自于demo.ipynb
model = model.keras_model

之后就可以把keras模型变成tensorflow savedModel模型了,代码详见在modelarts上部署backend为TensorFlow的keras模型

customize_service.py书写

这仍然是工作最主要的部分,我们依然找到预测的源程序MaskRCNN.detect函数,我们把detect程序分成前处理+预测+后处理三段,做以下工作:

  1. 把前处理和后处理分别写成子函数,把预测部分去掉,保留类的结构,尽可能减少代码更改量;

  2. 前处理和后处理的数据交换通过类属性传递;

  3. 把无关程序(主要是train部分程序)尽可能去掉,以减少代码调试量。

class MaskRCNN:# .....def detect(self, images, verbose=0):# some code...if verbose:log("molded_images", molded_images)log("image_metas", image_metas)log("anchors", anchors)# 在此之前是前处理# 预测detections, _, _, mrcnn_mask, _, _, _ =\self.keras_model.predict([molded_images, image_metas, anchors], verbose=0)# 后处理程序results = []for i, image in enumerate(images):# ...})return results

遇到的问题

输出张量大小限制

模型输出张量(定义可见模型部署介绍)有30多M,超过了modelarts目前Tensorflow Serving的4M的限制,因此还需要对savedModel的模型进行更改,首先观察模型输出

0 mrcnn_detection shape:(1, 100, 6) size:600 dtype:float32
1 mrcnn_class shape:(1, 1000, 81) size:81000 dtype:float32
2 mrcnn_bbox shape:(1, 1000, 81, 4) size:324000 dtype:float32
3 mrcnn_mask shape:(1, 100, 28, 28, 81) size:6350400 dtype:float32
4 ROI shape:(1, 1000, 4) size:4000 dtype:float32
5 rpn_class shape:(1, 261888, 2) size:523776 dtype:float32
6 rpn_bbox shape:(1, 261888, 4) size:1047552 dtype:float32

由于输出的张量只有mrcnn_detection和mrcnn_mask两个应用于后处理,输出过大的原因在于mrcnn_mask。我们通过对后处理源程序的观察和运行结果发现,mrcnn_mask几个维度的参数意义如下

维度 意义
0 1 batch size
1 100 检测物体的数目,上限是100
2~3 (28, 28) 物体的mask,被压缩成28*28的网格,数据是float32
4 81 物体的类别id

mrcnn_detection的几个维度的意义:

维度 意义
0 1 batch size
1 100 检测物体的数目,上限是100
2 6 包括top, left, bottom, right, classid, score,如果classid是0,说明是不关心的部分

我们可以从2个方面去精简输出张量:

  1. 检测物体的数目不需要必须凑成100个,我们以实际输出的数目作为准,去掉classid是0的值,这个对mrcnn_mask和mrcnn_detection都做精简;

    通过这种方式,我们不能减少输出的上限,但对大部分情况,输出的张量都能减少到原来的10%左右;

  2. 我们关系的不是所有类别的mask,只关系被检测出物体的类别id下的mask;换言之,我们对于每个被检测的物体,可以在mrcnn_detection上找到他的classid,然后在mrcnn_mask物体类别id中,我们只需输出该id下的mask即可;

    通过这种方式,输出张量可以固定缩减成原来的1/81;

由于4M限制是对于模型输出的,因此更改也只能通过更改savedModel来实现。也因此只能使用tensorflow的一定底层操作。换言之,要把源程序中用python后处理的部分程序需要改写成tf.Operation。也许是考虑了自动求导的原因,tensorflow的张量操作虽然很多,但各个功能都弱的一逼,下面是老山的实现片段

# 前面程序是读入已保存的savedModel模型,读入输出张量y1-y7
detections = y1
mrcnn_masks = y4# 把detections的classid列取出
detections = detections[0]
classes = tf.cast(detections[:, 4], tf.int32)# 把classid做成一个是否为0的mask: boolean list
zero = tf.constant(0, tf.int32)
mask = tf.not_equal(classes, zero)# 使用mask把detensions,classid精简,range_trim存储了剩下的id号
detection_trim = tf.boolean_mask(detections, mask)
classes_trim = tf.boolean_mask(classes, mask)
range_trim = tf.boolean_mask(tf.range(classes.shape[0], dtype=tf.int32), mask)# 构造一个[index, classid]对的list,长度是已经精简完的classid,命名为stack
stack = tf.stack([range_trim, classes_trim], axis = 1)mrcnn_masks = mrcnn_masks[0]
# 通过transpose把stack的两列弄到前面去
mrcnn_masks = tf.transpose(mrcnn_masks, perm = [0,3,1,2])
# 使用stack来精简mrcnn_masks_trim
mrcnn_masks_trim = tf.gather_nd(mrcnn_masks, stack)# 后续是保存模型
# 详细可见附件

模型的输出张量改动之后,后处理模块的程序也需要做相应的调整。

输出结果的压缩

由于modelarts源程序的后处理的输出包括rois,masks, class_ids, scores等量,其中mask是每个识别物体在原图上的mask(换句话说,就是原图尺寸的boolean矩阵),如果直接变成json的话,原先的占1bit的True/False就会变成文字,下载数据量达到几十M,时间太长。为此,我们需要对输出的masks进行压缩。

老山尝试了这2类算法:

  1. PNG压缩

from PIL import Image
import base64
def mask2str(mask):# 变成图片image = Image.fromarray(mask.astype('uint8')*255, 'L').convert('1')# 把图片输出到buffer里buffered = BytesIO()image.save(buffered, format='PNG')# 使用base64变成文本base_bytes = base64.b64encode(buffered.getvalue())base_str = base_bytes.decode('utf-8')return base_str

2.自建索引压缩

import numpy as np
import base64
import lzmadef mask2str(mask):# 把mask打成一维,寻找值发生变化的索引序列mask_flatten = mask.reshape(-1)mask_flatten_toright= np.insert(mask_flatten, 0, False)[:-1]diff = np.where(mask_flatten!=mask_flatten_toright)[0]counts = np.diff(diff, prepend=0).astype('int32')# 使用lzma压缩counts_bytes = bytes(counts)lzma_bytes = lzma.compress(counts_bytes)# 使用base64变成文本base64_bytes = base64.b64encode(lzma_bytes)base64_str = base64_bytes.decode('utf-8')return base64_str
  1. 索引压缩的想法是mask通常是在False背景下的True图,对于每行我们其实只要知道True的起始index和末了index就好,或者更抽象一步的说,图中交替的存在大量的连续False和True序列,那我们只要把他们的长度值变成list即可(默认第一个序列是False,哪怕长度是0)。这样的话,记录长度的好处在于比记录位置值更小,更便于压缩。为此,我们干脆的,把图片拉成一维,然后记录交替False、True序列的长度,再用lzma压缩。

    压缩结果是使用索引只有PNG压缩大小的45%左右。

生成图片

源程序使用matplotlib画图,不好保存,老山用PIL重写了这段程序。

附件结构

附件结构如下,部署使用的模型大家自行在github上下载,然后在notebook上使用modify.py生成savedModel模型。预测中修改get_x_auth_token.py获取x_auth_token后,更改x_auth_token.py,然后下载图片数据,然后便可以使用predict预测了。

root
├── deploy # 部署相关文件
│   ├── coco.py
│   ├── compression_.py
│   ├── config_.py
│   ├── config.py
│   ├── customize_service.py
│   ├── image_util.py
│   ├── model_util.py
│   └── surround.py
├── modify.py # 用于notebook生成savedModel模型
└── predict # 用于预测├── compression_.py├── get_x_auth_token.py├── new_visualize.py├── predict.py└── x_auth_token.py

如果觉得老山的文章不错,不妨点击下关注。

present.zip

作者:山找海味

在modelarts上部署mask-rcnn模型相关推荐

  1. mask rcnn算法分析_在modelarts上部署mask-rcnn模型

    最近老山完成了对mask-rcnn在modelarts上的部署,部署模型来自于这个项目.部署的过程大体和我的上篇文章使用modelarts部署bert命名实体识别模型相似,许多细节也不在赘述.这篇文章 ...

  2. 在modelarts上部署backend为TensorFlow的keras模型

    最近老山在研究在modelarts上部署mask-rcnn,源代码提供的是keras模型.我们可以将keras转化成savedModel模型,在TensorFlow Serving上部署,可参考老山的 ...

  3. 终极指南:构建用于检测汽车损坏的Mask R-CNN模型(附Python演练)

    阅读时间将近11分钟 介绍 计算机视觉领域的应用继续令人惊叹着.从检测视频中的目标到计算人群中的人数,计算机视觉似乎没有无法克服的挑战. 这篇文章的目的是建立一个自定义Mask R-CNN模型,可以检 ...

  4. 如何在谷歌云平台上部署可解释性模型

    2020-02-26 21:52 导语:获取 TensorFlow 模型的局部和全局解释 图片来源于 Pixabay 现代机器学习和人工智能在解决复杂的问题方面取得了令人印象深刻的成果.然而,复杂的问 ...

  5. 通过MACE在Android手机上部署深度学习模型

    1. MACE的环境搭建 参考我的博客:MACE的环境搭建--conda实现 2. 构建项目 (1)下载MACE项目到本地 git clone https://github.com/XiaoMi/ma ...

  6. 在英特尔硬件上部署深度学习模型的无代码方法 关于OpenVINO深度学习工作台的三部分系列 第二部

    作者 Taylor, Mary, 翻译 李翊玮 关于 OpenVINO™ 深度学习工作台的三部分系列文章 关于该系列 了解如何转换.微调和打包 推理就绪的 TensorFlow 模型,该模型针对英特尔 ...

  7. 在英特尔硬件上部署深度学习模型的无代码方法 OpenVINO 深度学习工作台的三部分系列 - CPU AI 第二部

    作者 Taylor, Mary, 翻译 李翊玮 关于该系列 了解如何转换.微调和打包 推理就绪的 TensorFlow 模型,该模型针对英特尔®硬件进行了优化,仅使用 Web 浏览器.每一步都在云中使 ...

  8. 【Pytorch神经网络理论篇】 33 基于图片内容处理的机器视觉:目标检测+图片分割+非极大值抑制+Mask R-CNN模型

    基于图片内容的处理任务,主要包括目标检测.图片分割两大任务. 1 目标检测 目标检测任务的精度相对较高,主要是以检测框的方式,找出图片中目标物体所在的位置.目标检测任务的模型运算量相对较小,速度相对较 ...

  9. 在英特尔硬件上部署深度学习模型的无代码方法 OpenVINO 深度学习工作台的三部分系列文章 - CPU AI 第一部

    作者 Taylor, Mary, 翻译 李翊玮 关于该系列 了解如何转换.微调和打包推理就绪的 TensorFlow 模型,该模型针对英特尔®硬件进行了优化,仅使用 Web 浏览器.每一步都在云中使用 ...

最新文章

  1. C++知识点50——虚函数与纯虚函数(上)
  2. iOS 11开发教程(十九)iOS11应用视图美化按钮之设置按钮的外观
  3. sql server 语句
  4. AndroidStudio设置背景颜色,字体大小,默认显示行号
  5. 任正非未来出行三谈,在攀登无人驾驶珠峰路上沿途下蛋...
  6. Mac下web自动化环境部署
  7. Http Server : 一个差生的逆袭
  8. Memcache存储大数据的问题
  9. MVC如何添加Model
  10. Oracle数据库的Sequence(序列)
  11. java 反射实现 工厂模式_java – 用反射实现工厂模式
  12. 转载Silverlight AutoCompleteBox 增强key/value 拼音头检索
  13. jquery 立体走马灯_jQuery简单的文字跑马灯特效
  14. 用户遭骚扰质疑隐私被航旅纵横泄露 回应:用户有开启关闭的自主权
  15. B 树,B- 树,B+ 树,B* 树
  16. centos下eclipse的安装
  17. python按钮代码_Python QPalette.Button方法代码示例
  18. Configuring CODESYS
  19. Android 百度语音合成手把手教学
  20. 【绝知此事要躬行】线性表之链表OJ(下)

热门文章

  1. c 自动生成mysql表结构_EntityFrameworkCore 根据实体类自动创建数据库
  2. linux救援模式下卸载根目录,删除Linux的依赖库并进入救援模式恢复
  3. 对流扩散方程matlab向前向后差分,解纯对流方程几种向后特征差分格式的比较
  4. 最短哈密尔顿圈matlab解法_复杂制造过程最优哈密尔顿圈算法的MATLAB仿真与分析.doc...
  5. 服务器如何修复dll,Windows10系统修复KernelBase.dll错误的解决方法
  6. 多用户文件系统java实现_为什么要有文件系统?文件系统都有那些种类?
  7. delphi控件切图界面闪烁_DirectUI用户手册.pdf
  8. linux下python开发工具_Python开发工具 Wing IDE
  9. 4,GIL全局解释器锁,event事件,信号量
  10. 业务 T+1 T+2