天天看點

R-FCN keras實作代碼詳細分析

代碼位址

https://github.com/xiaoxu1025/r-fcn

對于看了論文一知半解的朋友可以看看我的RCNN系列的實作。

CSDN連結位址:

https://blog.csdn.net/xiaoxu1025/article/details/104134569  RCNN系列之-RCNN keras實作

https://blog.csdn.net/xiaoxu1025/article/details/104127684  RCNN系列之-Faster-RCNN keras實作

https://blog.csdn.net/xiaoxu1025/article/details/104101234  RCNN系列之-Fast-RCNN keras實作

github連結位址:

https://github.com/xiaoxu1025/rcnn-keras

https://github.com/xiaoxu1025/fast-rcnn-keras

https://github.com/xiaoxu1025/faster-rcnn-keras

實作很簡單也很好了解,隻是作為一個學習記錄。有興趣的朋友可用下載下傳下來看看,比看網上各種文章好懂多了。rcnn系列keras實作基本上和源碼實作方式差不多,也不會誤導同學們。如果有幫助到你們,希望給我點個👍哦!!!

接下來 分析下 R-FCN 關于R-FCN的文章網上有很多,我這裡隻簡單講解下

R-FCN其實是為了給faster-rcnn加速的,因為faster-rcnn 在roi層後的全連接配接對所有proposal不共享,比如一張圖檔最後生成300個proposal 每個proposal都需要走一遍後面的全連接配接結構。這其實是很耗時的。所有R-FCN作者提出把roi後的操作提前。但是簡單提前不行,所有作者弄出來了個 Position-sensitive score map

其中r-fcn難點在于roipooling 因為它和faster-rcnn的roipooling操作有點不同。

下面我就具體分析一下(這是我用keras實作的一個roipooling層):

import tensorflow as tf
from tensorflow.keras.layers import Layer

"""
該層是用來對r-fcn進行roipooling
和faster-rcnn roipooling實作不同
"""


class RRoiPooling(Layer):
    def __init__(self, im_dims, last_dim, k=3, **kwargs):
        # k 是超參數 對 position-sensitive score maps or position-sensitive regression
        # 進行roi後feature maps大小
        super(RRoiPooling, self).__init__(**kwargs)
        self._im_dims = im_dims
        self._k = k
        # 因為cls 和 reg 都是用的這一層實作 是以這裡将最後一次元穿進來
        # cls: C + 1  reg : 4
        self._last_dim = last_dim

    def call(self, inputs, **kwargs):
        """

        :param inputs: inputs shape (None, H, W, K * K * (C + 1)) or (None, H, W, K * K * 4)
        第一個是 position-sensitive score maps 第二個是 position-sensitive regression maps
        :param rois: (N, 5) (batch_id, x1, y1, x2, y2)
        :param kwargs:
        :return:
        """
        feature_maps, rois = inputs[0], inputs[1]
        # reshape 成rank: 2
        rois = tf.reshape(rois, (-1, 5))
        # 進行rois标準化
        k = self._k
        feature_split = tf.split(feature_maps, num_or_size_splits=k * k, axis=-1)
        # y1, x1, y2, x2
        boxes, batch_ids = self._normalize_boxes(rois)
        # 将boxes分成k * k個bin 每個bin大小為bin_w * bin_h
        bin_w = (boxes[..., 3] - boxes[..., 1]) / k
        bin_h = boxes[..., 2] - boxes[..., 0] / k
        sensitive_boxes = []
        for ih in range(k):
            for iw in range(k):
                box_coordinates = [boxes[..., 0] + ih * bin_h,
                                   boxes[..., 1] + iw * bin_w,
                                   boxes[..., 0] + (ih + 1) * bin_h,
                                   boxes[..., 1] + (iw + 1) * bin_h]
                sensitive_boxes.append(tf.stack(box_coordinates, axis=-1))
        features = []
        for (feature, box) in zip(feature_split, sensitive_boxes):
            # crop對于區域後resize 成 (2k, 2k) 這個大小可以調整 不要太離譜就行
            pooled_features = tf.image.crop_and_resize(feature, box, tf.cast(batch_ids, dtype=tf.int32), [k * 2, k * 2])
            features.append(pooled_features)
        # [(N, 6, 6, self._last_dim), (N, 6, 6, self._last_dim), (N, 6, 6, self._last_dim), ...] 總共9個
        # N 為 len(rois) == len(boxes)
        # 然後對list中的tesor各個位置上的值相加并求平均
        sensitive_features = tf.add_n(features) / len(features)
        # (N, self._last_dim)
        output = tf.reduce_mean(sensitive_features, axis=[1, 2])
        output = tf.expand_dims(output, axis=0)
        return output

    def _normalize_boxes(self, rois):
        """
        對rois 進行normalize 使其滿足tf.image.crop_and_resize方法參數格式
        :param rois: (None, 5)  batch_id, x1, y1, x2, y2
        :return:
        """
        im_dims = self._im_dims
        normalization = tf.cast(tf.stack([im_dims[1], im_dims[0], im_dims[1], im_dims[0]], axis=0),
                                dtype=tf.float32)
        batch_ids = rois[..., 0]
        boxes = rois[..., 1:]
        boxes = tf.div(boxes, normalization)
        # tf.stop_gradient
        # y1, x1, y2, x2
        boxes = tf.stack([boxes[..., 1], boxes[..., 0], boxes[..., 3], boxes[..., 2]], axis=-1)
        return boxes, batch_ids
           

計算公式如下:

R-FCN keras實作代碼詳細分析
R-FCN keras實作代碼詳細分析

講一下我個人對這個公式的了解

對于 sensitive position score map 的次元是[H, W, K * K * (C + 1)]

通道次元可以分成 K * K 組 每組(C + 1)維的向量,同時我們還會對我們要進行roipooling的區域(h, w)進行劃分,将其分成 k * k 個bin

每個bin的大小 h / k, w/k 每個bin對應通道中一組C + 1次元向量  順序則是 從上到下 從左到又 就像下面表格中的索引順序。具體實作細節可以參考下我上面的代碼。

1 2
3 4 5
6 7 8

對于regresion map 就和score map 是一樣的操作 這裡就不重複了

其他的功能實作,請參考代碼。我就不全部講解了

如果有幫助到大家,請給我點個贊~

與君共勉!!!

繼續閱讀