<label id="jgr5k"></label>
    <legend id="jgr5k"><track id="jgr5k"></track></legend>

    <sub id="jgr5k"></sub>
  1. <u id="jgr5k"></u>
      久草国产视频,91资源总站,在线免费看AV,丁香婷婷社区,久久精品99久久久久久久久,色天使av,无码探花,香蕉av在线
      您正在使用IE低版瀏覽器,為了您的雷峰網(wǎng)賬號安全和更好的產(chǎn)品體驗,強烈建議使用更快更安全的瀏覽器
      此為臨時鏈接,僅用于文章預(yù)覽,將在時失效
      人工智能開發(fā)者 正文
      發(fā)私信給汪思穎
      發(fā)送

      0

      Keras版faster-rcnn算法詳解(RPN計算)

      本文作者: 汪思穎 2017-09-20 17:32
      導語:讀懂RPN是理解faster-rcnn的第一步

      雷鋒網(wǎng) AI科技評論按:本文首發(fā)于知乎專欄Learning Machine,作者張瀟捷,雷鋒網(wǎng) AI科技評論獲其授權(quán)轉(zhuǎn)載。

      前段時間學完Udacity的機器學習和深度學習的課程,感覺只能算剛剛摸到深度學習的門檻,于是開始看斯坦福的cs231n(http://cs231n.stanford.edu/syllabus.html),一不小心便入了計算機視覺的坑。原來除了識別物體,還可以進行定位(localization),檢測(object detection),語義分割(semantic segmentation),實例分割(instance segmentation),左右手互搏(GAN),風格學習(transfer learning)等等。。。真是一下開了眼。從detection學起,開干!

      detection的話,自然是rgb大神的一系列工作,從rcnn一路到Y(jié)OLO。這里貼一個YOLO的視頻,給各位看官鑒賞一下:YOLO: Real-Time Object Detection(https://www.youtube.com/watch?v=VOC3huqHrss&feature=youtu.be) 。也可以直接看這個地址,有更詳細的內(nèi)容:YOLO: Real-Time Object Detection(https://pjreddie.com/darknet/yolo/)。Faster-rcnn的原文在這里:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks(https://arxiv.org/abs/1506.01497)。

      由于tensorflow使用的不是很熟練,大部分項目都是用keras做的 ,因此在github上找到了一個keras版的faster-rcnn(https://github.com/yhenon/keras-frcnn),學習一下。基本上clone下來以后稍微調(diào)整幾處代碼就能成功跑起來了。我用Oxford的pet數(shù)據(jù)集進行了訓練,在我的老爺卡gtx970上訓練了差不多1個多小時,就能夠比較有效的實現(xiàn)detection了。下面是效果圖。

      Keras版faster-rcnn算法詳解(RPN計算)

      接下來就是理解代碼了,faster-rcnn的核心思想就是通過RPN替代過往的獨立的步驟進行region proposal,實現(xiàn)完全的end-to-end學習,從而對算法進行了提速。所以讀懂RPN是理解faster-rcnn的第一步。下面的代碼是如何得到用于訓練RPN的ground truth的,完全理解之后也就理解RPN的原理了。

      計算過程比較長,但沒有復(fù)雜的數(shù)學知識,我畫了一個大概的流程圖,在此基礎(chǔ)上理解應(yīng)該就容易多了。

      Keras版faster-rcnn算法詳解(RPN計算)

      下面來看代碼:

      def calc_rpn(C, img_data, width, height, resized_width, resized_height, img_length_calc_function):

        downscale = float(C.rpn_stride)
        anchor_sizes = C.anchor_box_scales
        anchor_ratios = C.anchor_box_ratios
        num_anchors = len(anchor_sizes) * len(anchor_ratios)

        # calculate the output map size based on the network architecture

        (output_width, output_height) = img_length_calc_function(resized_width, resized_height)

        n_anchratios = len(anchor_ratios)

        # initialise empty output objectives
        y_rpn_overlap = np.zeros((output_height, output_width, num_anchors))
        y_is_box_valid = np.zeros((output_height, output_width, num_anchors))
        y_rpn_regr = np.zeros((output_height, output_width, num_anchors * 4))

        num_bboxes = len(img_data['bboxes'])

        num_anchors_for_bbox = np.zeros(num_bboxes).astype(int)
        best_anchor_for_bbox = -1*np.ones((num_bboxes, 4)).astype(int)
        best_iou_for_bbox = np.zeros(num_bboxes).astype(np.float32)
        best_x_for_bbox = np.zeros((num_bboxes, 4)).astype(int)
        best_dx_for_bbox = np.zeros((num_bboxes, 4)).astype(np.float32)

        # get the GT box coordinates, and resize to account for image resizing
        gta = np.zeros((num_bboxes, 4))
        for bbox_num, bbox in enumerate(img_data['bboxes']):
          # get the GT box coordinates, and resize to account for image resizing
          gta[bbox_num, 0] = bbox['x1'] * (resized_width / float(width))
          gta[bbox_num, 1] = bbox['x2'] * (resized_width / float(width))
          gta[bbox_num, 2] = bbox['y1'] * (resized_height / float(height))
          gta[bbox_num, 3] = bbox['y2'] * (resized_height / float(height))

      首先看一下參數(shù),C是配置信息,img_data包含一張圖片的路徑,bbox坐標和對應(yīng)的分類(可能一張圖片有多組,即表示圖片里包含多個對象)。后面是圖片的原尺寸和resize之后的尺寸,用于求bbox坐標在resize之后圖片上的坐標,img_length_calc_function是一個方法,基于我們的設(shè)置來從圖片尺寸計算出經(jīng)過網(wǎng)絡(luò)之后特征圖的尺寸。

      接下來讀取了幾個參數(shù),downscale就是從圖片到特征圖的縮放倍數(shù),anchor_size和anchor_ratios是我們初步選區(qū)大小的參數(shù),比如3個size和3個ratios,可以組合成9種不同形狀大小的選區(qū)。接下來通過img_.....function這個方法計算出了特征圖的尺寸。

      下一步是幾個變量初始化,可以先不看,后面用到的時候再看。因為我們的計算都是基于resize以后的圖像的,所以接下來把bbox中的x1,x2,y1,y2分別通過縮放匹配到resize以后的圖像。這里記做gta,尺寸為(num_of_bbox,4)。

      for anchor_size_idx in range(len(anchor_sizes)):
        for anchor_ratio_idx in range(n_anchratios):
          anchor_x = anchor_sizes[anchor_size_idx] * anchor_ratios[anchor_ratio_idx][0]
          anchor_y = anchor_sizes[anchor_size_idx] * anchor_ratios[anchor_ratio_idx][1]

          for ix in range(output_width):
            # x-coordinates of the current anchor box
            x1_anc = downscale * (ix + 0.5) - anchor_x / 2
            x2_anc = downscale * (ix + 0.5) + anchor_x / 2

            # ignore boxes that go across image boundaries
            if x1_anc < 0 or x2_anc > resized_width:
              continue

            for jy in range(output_height):

              # y-coordinates of the current anchor box
              y1_anc = downscale * (jy + 0.5) - anchor_y / 2
              y2_anc = downscale * (jy + 0.5) + anchor_y / 2

              # ignore boxes that go across image boundaries
              if y1_anc < 0 or y2_anc > resized_height:
                continue

              # bbox_type indicates whether an anchor should be a target
              bbox_type = 'neg'

              # this is the best IOU for the (x,y) coord and the current anchor
              # note that this is different from the best IOU for a GT bbox
              best_iou_for_loc = 0.0

      上面這一段計算了anchor的長寬,然后比較重要的就是把特征圖的每一個點作為一個錨點,通過乘以downscale,映射到圖片的實際尺寸,再結(jié)合anchor的尺寸,忽略掉超出圖片范圍的。一個個大小、比例不一的矩形選框就躍然紙上了。對這些選框進行遍歷,對每個選框進行下面的計算:

      # bbox_type indicates whether an anchor should be a target
      bbox_type = 'neg'

      # this is the best IOU for the (x,y) coord and the current anchor
      # note that this is different from the best IOU for a GT bbox
      best_iou_for_loc = 0.0

      for bbox_num in range(num_bboxes):

        # get IOU of the current GT box and the current anchor box
        curr_iou = iou([gta[bbox_num, 0], gta[bbox_num, 2], gta[bbox_num, 1], gta[bbox_num, 3]], [x1_anc,y1_anc, x2_anc, y2_anc])
        # calculate the regression targets if they will be needed
        if curr_iou > best_iou_for_bbox[bbox_num] or curr_iou > C.rpn_max_overlap:
          cx = (gta[bbox_num, 0] + gta[bbox_num, 1]) / 2.0
          cy = (gta[bbox_num, 2] + gta[bbox_num, 3]) / 2.0
          cxa = (x1_anc + x2_anc)/2.0
          cya = (y1_anc + y2_anc)/2.0

          tx = (cx - cxa) / (x2_anc - x1_anc)
          ty = (cy - cya) / (y2_anc - y1_anc)
          tw = np.log((gta[bbox_num, 1] - gta[bbox_num, 0]) / (x2_anc - x1_anc))
          th = np.log((gta[bbox_num, 3] - gta[bbox_num, 2]) / (y2_anc - y1_anc))

      定義了兩個變量,bbox_type和best_iou_for_loc,后面會用到。計算了anchor與gta的交集,比較簡單,就不展開說了。然后就是如果交集大于best_iou_for_bbox[bbox_num]或者大于我們設(shè)定的閾值,就會去計算gta和anchor的中心點坐標,再通過中心點坐標和bbox坐標,計算出x,y,w,h四個值的梯度值(不知道這么理解對不對)。為什么要計算這個梯度呢?因為RPN計算出來的區(qū)域不一定是很準確的,從只有9個尺寸的anchor也可以推測出來,因此我們在預(yù)測時還會進行一次回歸計算,而不是直接使用這個區(qū)域的坐標。

      接下來是根據(jù)anchor的表現(xiàn)對其進行標注。

      if img_data['bboxes'][bbox_num]['class'] != 'bg':
        # all GT boxes should be mapped to an anchor box, so we keep track of which anchor box was best
        if curr_iou > best_iou_for_bbox[bbox_num]:
          best_anchor_for_bbox[bbox_num] = [jy, ix, anchor_ratio_idx, anchor_size_idx]
          best_iou_for_bbox[bbox_num] = curr_iou
          best_x_for_bbox[bbox_num,:] = [x1_anc, x2_anc, y1_anc, y2_anc]
          best_dx_for_bbox[bbox_num,:] = [tx, ty, tw, th]

        # we set the anchor to positive if the IOU is >0.7 (it does not matter if there was another better box, it just indicates overlap)
        if curr_iou > C.rpn_max_overlap:
          bbox_type = 'pos'
          num_anchors_for_bbox[bbox_num] += 1
          # we update the regression layer target if this IOU is the best for the current (x,y) and anchor position
          if curr_iou > best_iou_for_loc:
            best_iou_for_loc = curr_iou
            best_regr = (tx, ty, tw, th)

        # if the IOU is >0.3 and <0.7, it is ambiguous and no included in the objective
        if C.rpn_min_overlap < curr_iou < C.rpn_max_overlap:
          # gray zone between neg and pos
          if bbox_type != 'pos':
            bbox_type = 'neutral'

      # turn on or off outputs depending on IOUs

      if bbox_type == 'neg':
        y_is_box_valid[jy, ix, anchor_ratio_idx + n_anchratios * anchor_size_idx] = 1
        y_rpn_overlap[jy, ix, anchor_ratio_idx + n_anchratios * anchor_size_idx] = 0

      elif bbox_type == 'neutral':
        y_is_box_valid[jy, ix, anchor_ratio_idx + n_anchratios * anchor_size_idx] = 0
        y_rpn_overlap[jy, ix, anchor_ratio_idx + n_anchratios * anchor_size_idx] = 0

      elif bbox_type == 'pos':
        y_is_box_valid[jy, ix, anchor_ratio_idx + n_anchratios * anchor_size_idx] = 1
        y_rpn_overlap[jy, ix, anchor_ratio_idx + n_anchratios * anchor_size_idx] = 1
        start = 4 * (anchor_ratio_idx + n_anchratios * anchor_size_idx)

        y_rpn_regr[jy, ix, start:start+4] = best_regr

      前提是這個bbox的class不是'bg',即背景。如果交集大于這個bbox的最佳值,則進行一系列更新。如果交集大于我們設(shè)定的閾值,則定義為一個positive的anchor,即存在與之重合度比較高的bbox,同時該bbox的num_anchors加1。如果交集剛好也大于best_iou_for_loc,則將best_regr設(shè)為當前的梯度值。這里best_iou_for_loc指的是該anchor下的最佳交集,我的理解就是一個anchor如果能匹配到1個以上的bbox為pos,那我們?nèi)est_iou_for_loc下的梯度,要知道這一步我們只要找到最佳的選區(qū)就行了,并不管選區(qū)里是哪個class。如果剛好處于最大和最小閾值之間,那我們不確定它是背景還是對象,將其定義為neutral,即中性。

      接下來根據(jù)bbox_type對本anchor進行打標,y_is_box_valid和y_rpn_overlap分別定義了這個anchor是否可用和是否包含對象。

      for idx in range(num_anchors_for_bbox.shape[0]):
        if num_anchors_for_bbox[idx] == 0:
          # no box with an IOU greater than zero ...
          if best_anchor_for_bbox[idx, 0] == -1:
            continue
          y_is_box_valid[
            best_anchor_for_bbox[idx,0], best_anchor_for_bbox[idx,1], best_anchor_for_bbox[idx,2] + n_anchratios *
            best_anchor_for_bbox[idx,3]] = 1
          y_rpn_overlap[
            best_anchor_for_bbox[idx,0], best_anchor_for_bbox[idx,1], best_anchor_for_bbox[idx,2] + n_anchratios *
            best_anchor_for_bbox[idx,3]] = 1
          start = 4 * (best_anchor_for_bbox[idx,2] + n_anchratios * best_anchor_for_bbox[idx,3])
          y_rpn_regr[
            best_anchor_for_bbox[idx,0], best_anchor_for_bbox[idx,1], start:start+4] = best_dx_for_bbox[idx,:]

      這里又出現(xiàn)了一個問題,很多bbox可能找不到心儀的anchor,那這些訓練數(shù)據(jù)就沒法利用了,因此我們用一個折中的辦法來保證每個bbox至少有一個anchor與之對應(yīng)。下面是具體的方法,比較簡單,對于沒有對應(yīng)anchor的bbox,在中性anchor里挑最好的,當然前提是你不能跟我完全不相交,那就太過分了。。

      y_rpn_overlap = np.transpose(y_rpn_overlap, (2, 0, 1))
      y_rpn_overlap = np.expand_dims(y_rpn_overlap, axis=0)

      y_is_box_valid = np.transpose(y_is_box_valid, (2, 0, 1))
      y_is_box_valid = np.expand_dims(y_is_box_valid, axis=0)

      y_rpn_regr = np.transpose(y_rpn_regr, (2, 0, 1))
      y_rpn_regr = np.expand_dims(y_rpn_regr, axis=0)

      pos_locs = np.where(np.logical_and(y_rpn_overlap[0, :, :, :] == 1, y_is_box_valid[0, :, :, :] == 1))
      neg_locs = np.where(np.logical_and(y_rpn_overlap[0, :, :, :] == 0, y_is_box_valid[0, :, :, :] == 1))

      num_pos = len(pos_locs[0])

      接下來通過numpy大法進行了一系列操作,對pos和neg的anchor進行了定位。

      num_regions = 256


      if len(pos_locs[0]) > num_regions/2:
        val_locs = random.sample(range(len(pos_locs[0])), len(pos_locs[0]) - num_regions/2)
        y_is_box_valid[0, pos_locs[0][val_locs], pos_locs[1][val_locs], pos_locs[2][val_locs]] = 0
        num_pos = num_regions/2


      if len(neg_locs[0]) + num_pos > num_regions:
        val_locs = random.sample(range(len(neg_locs[0])), len(neg_locs[0]) - num_pos)
        y_is_box_valid[0, neg_locs[0][val_locs], neg_locs[1][val_locs], neg_locs[2][val_locs]] = 0

      因為negtive的anchor肯定遠多于postive的,因此在這里設(shè)定了regions數(shù)量的最大值,并對pos和neg的樣本進行了均勻的取樣。

      y_rpn_cls = np.concatenate([y_is_box_valid, y_rpn_overlap], axis=1)
      y_rpn_regr = np.concatenate([np.repeat(y_rpn_overlap, 4, axis=1), y_rpn_regr], axis=1)

      return np.copy(y_rpn_cls), np.copy(y_rpn_regr)

      最后,得到了兩個返回值y_rpn_cls,y_rpn_regr。分別用于確定anchor是否包含物體,和回歸梯度。

      再來看一下網(wǎng)絡(luò)中RPN層的結(jié)構(gòu):

      def rpn(base_layers,num_anchors):
        x = Convolution2D(512, (3, 3), padding='same', activation='relu', kernel_initializer='normal', name='rpn_conv1')(base_layers)

        x_class = Convolution2D(num_anchors, (1, 1), activation='sigmoid', kernel_initializer='uniform', name='rpn_out_class')(x)
        x_regr = Convolution2D(num_anchors * 4, (1, 1), activation='linear', kernel_initializer='zero', name='rpn_out_regress')(x)

        return [x_class, x_regr, base_layers]

      通過1*1的窗口在特征圖上滑過,生成了num_anchors數(shù)量的channel,每個channel包含特征圖(w*h)個sigmoid激活值,表明該anchor是否可用,與我們剛剛計算的y_rpn_cls對應(yīng)。同樣的方法,得到x_regr與剛剛計算的y_rpn_regr對應(yīng)。

      得到了region proposals,接下來另一個重要的思想就是ROI,可將不同shape的特征圖轉(zhuǎn)化為固定shape,送到全連接層進行最終的預(yù)測。等我學習完了再更新。由于自己也是學習過程,可能很多地方的理解有誤差,歡迎指正~

      雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知

      Keras版faster-rcnn算法詳解(RPN計算)

      分享:

      編輯

      關(guān)注AI學術(shù),例如論文
      當月熱門文章
      最新文章
      請?zhí)顚懮暾埲速Y料
      姓名
      電話
      郵箱
      微信號
      作品鏈接
      個人簡介
      為了您的賬戶安全,請驗證郵箱
      您的郵箱還未驗證,完成可獲20積分喲!
      請驗證您的郵箱
      立即驗證
      完善賬號信息
      您的賬號已經(jīng)綁定,現(xiàn)在您可以設(shè)置密碼以方便用郵箱登錄
      立即設(shè)置 以后再說
      主站蜘蛛池模板: 亚洲国产精品ⅴa在线观看| 久久精品国产2020| 亚洲色成人网站| 一本色道精品| 久久综合激情网| 精品99re66一区三区| 国产av激情久久无码天堂| 无码人妻一区二区三区线| 国内精品伊人久久久久777 | 久久99嫩草熟妇人妻蜜臀| www.狠狠干| 久久人妻无码一区二区三区av| 国产精品国产三级国产aⅴ下载| 精品国产乱码久久久久久郑州公司| aa片在线观看视频在线播放| 精品无码日韩国产不卡av| 未满十八18禁止免费无码网站| 国产精品一区二区无线| 超碰97人人天天蜜芽| 一本色道久久亚洲综合精品| 91网站免费| 亚洲真人无码永久在线| 日本免费观看mv免费版视频网站| 成人无码专区免费播放三区| 亚洲色大成网站WWW永久麻豆| 亚洲国产综合精品 在线 一区| 无码专区人妻系列日韩精品| 国产人伦精品一区二区三| 欧美色aⅴ欧美综合色| 嵩明县| 乱人伦人妻中文字幕| 超碰福利导航| 少妇洁白无删减版178txt| 午夜福制92视频| 涩欲国产一区二区三区四区| xxxx欧美| 欧美精品中文字幕亚洲专区| 国产精品国三级国产av| 偷偷色噜狠狠狠狠的777米奇| 亚洲免费性爱视频| 日本一区二区三区在线 |观看|