在我們學習的這個項目中,模型主要分為兩種狀態,即進行推斷用的inference模式和進行訓練用的training模式。所謂推斷模式就是已經訓練好的的模型,我們傳入一張圖片,網絡將其分析結果計算出來的模式。
本節我們從demo.ipynb入手,一窺已經訓練好的Mask-RCNN模型如何根據一張輸入圖片進行推斷,得到相關信息,即inference模式的工作原理。
一、調用推斷網絡
網絡配置
首先進行配置設定,設定項都被集成進class config中了,自建新的設定只要基礎改class並更新屬性即可,在demo中我們直接使用COCO的預訓練模型所以使用其設置即可,但由於我們想檢測單張圖片,所以需要更新幾個相關數目設定:
# 父類繼承了Config類,目的就是記錄配置,並在其基礎上添加了幾個新的屬性 class InferenceConfig(coco.CocoConfig): # Set batch size to 1 since we'll be running inference on # one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU GPU_COUNT = 1 IMAGES_PER_GPU = 1 config = InferenceConfig() config.display()
打印出配置如下:
Configurations: BACKBONE resnet101 BACKBONE_STRIDES [4, 8, 16, 32, 64] BATCH_SIZE 1 BBOX_STD_DEV [ 0.1 0.1 0.2 0.2] COMPUTE_BACKBONE_SHAPE None DETECTION_MAX_INSTANCES 100 DETECTION_MIN_CONFIDENCE 0.7 DETECTION_NMS_THRESHOLD 0.3 FPN_CLASSIF_FC_LAYERS_SIZE 1024 GPU_COUNT 1 GRADIENT_CLIP_NORM 5.0 IMAGES_PER_GPU 1 IMAGE_CHANNEL_COUNT 3 IMAGE_MAX_DIM 1024 IMAGE_META_SIZE 93 IMAGE_MIN_DIM 800 IMAGE_MIN_SCALE 0 IMAGE_RESIZE_MODE square IMAGE_SHAPE [1024 1024 3] LEARNING_MOMENTUM 0.9 LEARNING_RATE 0.001 LOSS_WEIGHTS {'rpn_class_loss': 1.0, 'rpn_bbox_loss': 1.0, 'mrcnn_class_loss': 1.0, 'mrcnn_bbox_loss': 1.0, 'mrcnn_mask_loss': 1.0} MASK_POOL_SIZE 14 MASK_SHAPE [28, 28] MAX_GT_INSTANCES 100 MEAN_PIXEL [ 123.7 116.8 103.9] MINI_MASK_SHAPE (56, 56) NAME coco NUM_CLASSES 81 POOL_SIZE 7 POST_NMS_ROIS_INFERENCE 1000 POST_NMS_ROIS_TRAINING 2000 PRE_NMS_LIMIT 6000 ROI_POSITIVE_RATIO 0.33 RPN_ANCHOR_RATIOS [0.5, 1, 2] RPN_ANCHOR_SCALES (32, 64, 128, 256, 512) RPN_ANCHOR_STRIDE 1 RPN_BBOX_STD_DEV [ 0.1 0.1 0.2 0.2] RPN_NMS_THRESHOLD 0.7 RPN_TRAIN_ANCHORS_PER_IMAGE 256 STEPS_PER_EPOCH 1000 TOP_DOWN_PYRAMID_SIZE 256 TRAIN_BN False TRAIN_ROIS_PER_IMAGE 200 USE_MINI_MASK True USE_RPN_ROIS True VALIDATION_STEPS 50 WEIGHT_DECAY 0.0001
模型初始化
首先初始化模型,然后載入預訓練參數文件,在末尾我可視化了模型,不過真的太長了,所以注釋掉了。在第一步初始化時就會根據mode參數的具體值建立計算圖,本節介紹的推斷網絡就是在mode參數設定為"inference"時建立的計算網絡。
# 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) # model.keras_model.summary()
檢測圖片
# Load a random image from the images folder file_names = next(os.walk(IMAGE_DIR))[2] # 只要是迭代器調用next方法獲取值,學習了 image = skimage.io.imread(os.path.join(IMAGE_DIR, random.choice(file_names))) print(image.shape) # Run detection results = model.detect([image], verbose=1) # Visualize results r = results[0] visualize.display_instances(image, r['rois'], r['masks'], r['class_ids'], class_names, r['scores'])
讀取一張圖片,調用model的detect方法,即可輸出結果,最后使用輔助方法可視化結果:
二、推斷邏輯概覽
inference的前向邏輯如下圖所示,我們簡單的看一下其計算流程是怎樣的,
- 左上模塊為以ResNet101為基礎的FPN特征金字塔網絡的特征提取邏輯,可以看到,作者並沒有直接將up-down特征使用,而是又做了一次3*3卷積進行了進一步的特征融合。
- 出來的各層FPN特征首先(各自獨立地)進入了RPN處理層:根據錨框數目信息確定候選區域的分類(前景背景2分類)和回歸結果。
rpn_class:[batch, num_rois, 2]
rpn_bbox:[batch, num_rois, (dy, dx, log(dh), log(dw))] - 有了眾多的候選區域,我們將之送入Proposal篩選部分,首先根據前景得分排序進行初篩(配置會指定這一步保留多少候選框),然后為非極大值抑制做准備:用RPN的回歸結果修正anchors,值得注意的是anchors都是歸一化的這意味着修值之后還需要做檢查以防越界,最后非極大值一致,刪減的太多了的話就補上[0, 0, 0, 0]達到配置文件要求的數目(非極大值部分會造成同一個batch中不同圖片的候選框數目不一致,但是tensor的維數不能參差不齊,所以要補零使得各張圖片候選區域數目一致)
rpn_rois:[IMAGES_PER_GPU, num_rois, (y1, x1, y2, x2)]
- 根據候選區的實際大小(歸一化候選區需要映射回原圖大小)為候選區選擇合適的RPN特征層,ROI Align處理(實際上就是摳出來進行雙線性插值到指定大小),得到我們需要的眾多等大子圖
- 對這些子圖各自獨立的進行分類/回歸
mrcnn_class_logits: [batch, num_rois, NUM_CLASSES] classifier logits (before softmax)
mrcnn_class: [batch, num_rois, NUM_CLASSES] classifier probabilities
mrcnn_bbox(deltas): [batch, num_rois, NUM_CLASSES, (dy, dx, log(dh), log(dw))] - 在分類回歸之后使用回歸結果對候選框進行修正,然后重新進行FPN特征層選擇和ROI Align特征提取,最后送入Mask網絡,進行Mask生成。
最后,我們希望網絡輸出下面的張量:
# num_anchors, 每張圖片上生成的錨框數量
# num_rois, 每張圖片上由錨框篩選出的推薦區數量,
# # 由 POST_NMS_ROIS_TRAINING 或 POST_NMS_ROIS_INFERENCE 規定
# num_detections, 每張圖片上最終檢測輸出框,
# # 由 DETECTION_MAX_INSTANCES 規定
# detections, [batch, num_detections, (y1, x1, y2, x2, class_id, score)]
# mrcnn_class, [batch, num_rois, NUM_CLASSES] classifier probabilities
# mrcnn_bbox, [batch, num_rois, NUM_CLASSES, (dy, dx, log(dh), log(dw))]
# mrcnn_mask, [batch, num_detections, MASK_POOL_SIZE, MASK_POOL_SIZE, NUM_CLASSES]
# rpn_rois, [batch, num_rois, (y1, x1, y2, x2, class_id, score)]
# rpn_class, [batch, num_anchors, 2]
# rpn_bbox [batch, num_anchors, 4]
具體每種張量的意義我們會在源碼分析中一一介紹。