mask rcnn算法分析_在modelarts上部署mask-rcnn模型
最近老山完成了對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程序分成前處理+預測+后處理三段,做以下工作:
遇到的問題
輸出張量大小限制
模型輸出張量(定義可見模型部署介紹)有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幾個維度的參數意義如下
mrcnn_detection的幾個維度的意義:
我們可以從2個方面去精簡輸出張量:
通過這種方式,我們不能減少輸出的上限,但對大部分情況,輸出的張量都能減少到原來的10%左右;
通過這種方式,輸出張量可以固定縮減成原來的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類算法:
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壓縮結果是使用索引只有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
更多精彩內容,請滑至頂部點擊右上角關注小宅哦~
作者:山找海味
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的mask rcnn算法分析_在modelarts上部署mask-rcnn模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: circle函数用法 turtle_Tu
- 下一篇: .bin 文件用excel文件打开_用P