fei-modelzoo-1.0.0: src/MXNet/NN/ModelZoo/RCNN/MaskRCNN.hs
module MXNet.NN.ModelZoo.RCNN.MaskRCNN where
import RIO
import MXNet.Base
import qualified MXNet.Base.Operators.Tensor as T
import MXNet.NN.Layer
import qualified MXNet.NN.ModelZoo.RCNN.FasterRCNN as FasterRCNN
import MXNet.NN.ModelZoo.RCNN.RCNN
data MaskRCNN = MaskRCNN
{ _faster_rcnn_result :: FasterRCNN.FasterRCNN
, _masks_loss :: SymbolHandle
}
| MaskRCNNInferenceOnly
{ _faster_rcnn_result :: FasterRCNN.FasterRCNN
, _masks :: SymbolHandle
}
maskHead :: SymbolHandle -> Int -> Int -> Int -> Int -> Layer SymbolHandle
maskHead top_feat num_fcn_conv num_fg_classes batch_size num_mask_channels = do
-- top_feat: The network input tensor of shape (B * N, fC, fH, fW).
--
-- returns:
-- Mask prediction of shape (B, N, C, MS, MS)
feat <- sequential "conv" $ foldM one_conv top_feat ([1..num_fcn_conv] :: [_])
feat <- named "conv-transposed" $
prim T._Deconvolution (#data := feat
.& #num_filter := num_mask_channels
.& #kernel := [2, 2]
.& #stride := [2, 2]
.& #pad := [0, 0] .& Nil)
feat <- activation (#data := feat .& #act_type := #relu .& Nil)
mask <- named "conv-last" $
convolution (#data := feat
.& #kernel := [1, 1]
.& #num_filter := num_fg_classes
.& #stride := [1, 1]
.& #pad := [0, 0] .& Nil)
reshape [-4, batch_size, -1, 0, 0, 0] mask
where
one_conv x _ = do
x <- convolution (#data := x
.& #num_filter := num_mask_channels
.& #kernel := [3, 3]
.& #stride := [1, 1]
.& #pad := [1, 1] .& Nil)
activation (#data := x .& #act_type := #relu .& Nil)
graphT :: FasterRCNN.RcnnConfiguration -> Layer (MaskRCNN, SymbolHandle)
graphT conf@(FasterRCNN.RcnnConfigurationTrain{..}) = do
gt_masks <- variable "gt_masks"
(fr@FasterRCNN.FasterRCNN{..}, fr_outputs) <- FasterRCNN.graphT conf
unique "mask" $ do
let take_pos t = do
ts <- forM ([0..batch_size-1] :: [_]) $ \i -> do
ind <- slice_axis _positive_indices 0 i (Just (i+1)) >>= squeeze Nothing
bat <- slice_axis t 0 i (Just (i+1)) >>= squeeze Nothing
takeI ind bat
concat_ 0 ts
-- like box_feature, we select only layers of the feature/... that have
-- foreground gt, for each example in the batch.
-- positive_indices: (B, rcnn_fg_fraction * rcnn_batch_rois)
-- _top_feature: (B * rcnn_batch_rois, num_channels, rcnn_pooled_size, rcnn_pooled_size)
-- => (B * rcnn_fg_fraction * rcnn_batch_rois, .., .., ..)
-- _roi_boxes: (B, rcnn_batch_rois, 4) => (B, rcnn_fg_fraction * rcnn_batch_rois, 4)
-- _gt_matches: (B, rcnn_batch_rois) => (B, rcnn_fg_fraction * rcnn_batch_rois)
-- _cls_targets: (B, rcnn_batch_rois) => (B, rcnn_fg_fraction * rcnn_batch_rois)
feature <- take_pos =<< reshape [batch_size, -1, 0, 0, 0] =<< expandDims 0 _top_feature
roi_boxes <- reshape [batch_size, -1, 4] =<< take_pos _roi_boxes
gt_matches <- reshape [batch_size, -1] =<< take_pos _gt_matches
cls_targets <- reshape [batch_size, -1] =<< take_pos _cls_targets
let num_fcn_conv = case backbone of
FasterRCNN.RESNET50FPN -> 4
_ -> 0
num_fg_classes = rcnn_num_classes-1
-- mask_size should be twice the final feature size
-- becuase there is only one Conv2DTranspose layer
mask_size = rcnn_pooled_size * 2
masks <- unique "mask_head" $ maskHead feature num_fcn_conv num_fg_classes batch_size 256
(mask_targets, mask_weights) <- unique "target_gen" $
maskTargetGenerator batch_size
num_fg_classes
mask_size
gt_masks
roi_boxes
gt_matches
cls_targets
masks_loss <- unique "loss" $ do
masks_loss <- sigmoidBCE masks mask_targets (Just mask_weights) AggSum
num_pos_avg <- sum_ mask_weights Nothing False >>= divScalar (fromIntegral batch_size) >>= addScalar 1e-14
masks_loss <- divBroadcast masks_loss num_pos_avg
prim T._MakeLoss (#data := masks_loss .& #grad_scale := 1.0 .& Nil)
result_sym <- group $ [fr_outputs, masks_loss]
return $ (MaskRCNN {
_faster_rcnn_result = fr,
_masks_loss = masks_loss
}, result_sym)
graphI :: FasterRCNN.RcnnConfiguration -> Layer (MaskRCNN, SymbolHandle)
graphI conf@(FasterRCNN.RcnnConfigurationInference{..}) = do
(fr@FasterRCNN.FasterRCNNInferenceOnly{..}, fr_outputs) <- FasterRCNN.graphI conf
feature <- reshape [batch_size, -1, 0, 0, 0] =<< expandDims 0 _top_feature
let num_fcn_conv = case backbone of
FasterRCNN.RESNET50FPN -> 4
_ -> 0
num_fg_classes = rcnn_num_classes-1
masks <- unique "mask_head" $ maskHead feature num_fcn_conv num_fg_classes batch_size 256
masks <- prim T._sigmoid (#data := masks .& Nil)
res_sym <- group [fr_outputs, masks]
let res_data = MaskRCNNInferenceOnly fr masks
return (res_data, res_sym)