日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/3/19 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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程序分成前處理+預測+后處理三段,做以下工作:

  • 把前處理和后處理分別寫成子函數,把預測部分去掉,保留類的結構,盡可能減少代碼更改量;
  • 前處理和后處理的數據交換通過類屬性傳遞;
  • 把無關程序(主要是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幾個維度的參數意義如下

    mrcnn_detection的幾個維度的意義:

    我們可以從2個方面去精簡輸出張量:

  • 檢測物體的數目不需要必須湊成100個,我們以實際輸出的數目作為準,去掉classid是0的值,這個對mrcnn_mask和mrcnn_detection都做精簡;
    通過這種方式,我們不能減少輸出的上限,但對大部分情況,輸出的張量都能減少到原來的10%左右;
  • 我們關系的不是所有類別的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類算法:

  • 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
  • 索引壓縮的想法是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

    更多精彩內容,請滑至頂部點擊右上角關注小宅哦~


    作者:山找海味

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的mask rcnn算法分析_在modelarts上部署mask-rcnn模型的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。