Faster RCNN layer.py

def setup(self, bottom, top)方法: 該方法主要是在創建RoIDataLayer的時候調用,初始化self._name_to_top_map(從blobname 到 blobid的一個映射)。結合_caffe.cpp裏面.def("setup", &Layer<Dtype>::LayerSetUp),個人認爲,setup(self, bottom, top)應該還是調用底層的Layer::LayerSetUp方法,同時bottom, top也分別對應着:const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top
回顧底層的src/Net.cpp文件中,caffe將在Creating Layer,AppendTob 和 AppendBottom完成之後,再調用Layer::SetUp方法來 setting up layer…

def setup(self, bottom, top):
        """Setup the RoIDataLayer."""
        # print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Creating layer input-data'
        # parse the layer parameter string, which must be valid YAML
        layer_params = yaml.load(self.param_str_)

        # 解析prototxt文件中Python Layer的python_param參數
        self._num_classes = layer_params['num_classes']

        self._name_to_top_map = {}
        # print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ _name_to_top_map'
        # data blob: holds a batch of N images, each with 3 channels
        idx = 0

        # 設定top[0]即‘data’的shape,這樣,即使每次迭代的minibatch中圖片的shape不同,也能保證在前向傳播的
        # 時候不發生錯誤,訓練日誌中輸出的Top shape信息也是在這裏設置的。但是每次具體的foward的時候都需要重新reshape top blobs。
        top[idx].reshape(cfg.TRAIN.IMS_PER_BATCH, 3,
            max(cfg.TRAIN.SCALES), cfg.TRAIN.MAX_SIZE)
        self._name_to_top_map['data'] = idx
        idx += 1

        # 在訓練RPN的時候,cfg.TRAIN.HAS_RPN爲true
        if cfg.TRAIN.HAS_RPN:
            top[idx].reshape(1, 3)
            self._name_to_top_map['im_info'] = idx
            idx += 1

            top[idx].reshape(1, 4)
            self._name_to_top_map['gt_boxes'] = idx
            idx += 1
        else: # not using RPN
            # rois blob: holds R regions of interest, each is a 5-tuple
            # (n, x1, y1, x2, y2) specifying an image batch index n and a
            # rectangle (x1, y1, x2, y2)
            top[idx].reshape(1, 5)
            self._name_to_top_map['rois'] = idx
            idx += 1

            # labels blob: R categorical labels in [0, ..., K] for K foreground
            # classes plus background
            top[idx].reshape(1)
            self._name_to_top_map['labels'] = idx
            idx += 1

            # 例如,在訓練fast rcnn的時候,cfg.TRAIN.BBOX_REG
            if cfg.TRAIN.BBOX_REG:
                # bbox_targets blob: R bounding-box regression targets with 4
                # targets per class
                top[idx].reshape(1, self._num_classes * 4)
                self._name_to_top_map['bbox_targets'] = idx
                idx += 1

                # bbox_inside_weights blob: At most 4 targets per roi are active;
                # thisbinary vector sepcifies the subset of active targets
                # bbox_inside_weights blob 和 bbox_outside_weights blob 是用在SmoothL1Loss layer
                #中
                top[idx].reshape(1, self._num_classes * 4)
                self._name_to_top_map['bbox_inside_weights'] = idx
                idx += 1

                top[idx].reshape(1, self._num_classes * 4)
                self._name_to_top_map['bbox_outside_weights'] = idx
                idx += 1

        print 'RoiDataLayer: name_to_top:', self._name_to_top_map
        assert len(top) == len(self._name_to_top_map)

def _shuffle_roidb_inds(self): 打亂training roidb的順序

def _shuffle_roidb_inds(self):
        """Randomly permute the training roidb."""
        if cfg.TRAIN.ASPECT_GROUPING:
       # 將roidb中長寬比近似的圖像放在一起(其實也就2種情況,扁的還是豎的),有利於計算速度(具體的,還不清除)
            widths = np.array([r['width'] for r in self._roidb])
            heights = np.array([r['height'] for r in self._roidb])
            horz = (widths >= heights)
            vert = np.logical_not(horz)
            horz_inds = np.where(horz)[0]
            vert_inds = np.where(vert)[0]
            inds = np.hstack((
                np.random.permutation(horz_inds),
                np.random.permutation(vert_inds)))
            inds = np.reshape(inds, (-1, 2))
            # permutation隨機打亂,而且返回的元素沒有重複(np.random.choice()中replace=False), 類似功能的函數還有np.random.choice()
            row_perm = np.random.permutation(np.arange(inds.shape[0]))
            inds = np.reshape(inds[row_perm, :], (-1,))
            self._perm = inds
        else:
            self._perm = np.random.permutation(np.arange(len(self._roidb)))
        #當前處理的圖像的索引
        self._cur = 0

def _get_next_minibatch_inds(self) 在這個方法中,爲什麼要考慮“self._cur + cfg.TRAIN.IMS_PER_BATCH >= len(self._roidb)” 這是因爲訓練的時候要迭代好幾遍整個訓練集

def _get_next_minibatch_inds(self):
        """Return the roidb indices for the next minibatch."""
        if self._cur + cfg.TRAIN.IMS_PER_BATCH >= len(self._roidb):
            self._shuffle_roidb_inds()

        db_inds = self._perm[self._cur:self._cur + cfg.TRAIN.IMS_PER_BATCH]
        self._cur += cfg.TRAIN.IMS_PER_BATCH
        return db_inds

def _get_next_minibatch(self)

def _get_next_minibatch(self):
        """Return the blobs to be used for the next minibatch.

        If cfg.TRAIN.USE_PREFETCH is True, then blobs will be computed in a
        separate process and made available through self._blob_queue.
        """
        if cfg.TRAIN.USE_PREFETCH:
            return self._blob_queue.get()
        else:
            db_inds = self._get_next_minibatch_inds()
            minibatch_db = [self._roidb[i] for i in db_inds]
            # 調用minibatch.py中的get_minibatch方法
            return get_minibatch(minibatch_db, self._num_classes)

def forward(self, bottom, top): 前向傳播,這個層的前向傳播只需要進行拷貝就可以了,在不同的階段下,根據各自的prototxt文件定義的網絡結構來拷貝數據;
+ 有一點需要記住的是:在模板類Layer的forward函數裏面,會再次調用調用Reshape()函數,也就是說,即使我們每次迭代每個minibatch裏的圖像(或者特徵)的shape不一致,也沒有關係,因爲在真正調用forward_cpu / forward_gpu 之前都會重新Reshape;SetUp裏面的Reshape只是設置了初始的Top blobs 的shape

def forward(self, bottom, top):
        """Get blobs and copy them into this layer's top blob vector."""
        blobs = self._get_next_minibatch()

        # 1. 對於stage1_rpn_train.pt文件中,該layer只有3個top blob:'data'、'im_info'、'gt_boxes'
        # 2. 對於stage1_fast_rcnn_train.pt文件中,該layer有6個top blob:top: 'data'、 
        #'rois'、'labels'、'bbox_targets'、'bbox_inside_weights'、'bbox_outside_weights'
        for blob_name, blob in blobs.iteritems():
            top_ind = self._name_to_top_map[blob_name]
            # Reshape net's input blobs  調用Caffe.Blob的reshape方法
            # 每次迭代forwad的時候都需要reshape,是因爲每次迭代都需要去取minibatch,即
            # _get_next_minibatch, 在train fast-rcnn的時候,每個minibatch所包含的圖像的data,rois, 
            # labels, bbox_targets等的具體的shape都會有所改變,所以每次迭代都需要reshape top blobs
            top[top_ind].reshape(*(blob.shape))
            # Copy data into net's input blobs
            top[top_ind].data[...] = blob.astype(np.float32, copy=False)

def backward(self, top, propagate_down, bottom):

def backward(self, top, propagate_down, bottom):
        """This layer does not propagate gradients."""
        pass

def reshape(self, bottom, top):

def reshape(self, bottom, top):
        """Reshaping happens during the call to forward."""
        pass

def set_roidb(self, roidb): 主要工作:1. RoIDataLayer設置roidb,2. 打亂shuffle

def set_roidb(self, roidb):
        """Set the roidb to be used by this layer during training."""
        # self._roidb = roidb,self表示RoIDataLayer的實例對象,而非類 pascal_voc 或者 imdb的實例對象;
        # 賦值符號右側的roidb是我們在創建imdb 或者pascal_voc實例對象時設置的,並且在新建SolverWrapper實例
        # 之後在其__init__方法中調用self.solver.net.layers[0].set_roidb(roidb) 傳參而來。
        self._roidb = roidb
        self._shuffle_roidb_inds()
        if cfg.TRAIN.USE_PREFETCH:
            self._blob_queue = Queue(10)
            self._prefetch_process = BlobFetcher(self._blob_queue,
                                                 self._roidb,
                                                 self._num_classes)
            self._prefetch_process.start()
            # Terminate the child process when the parent exists
            def cleanup():
                print 'Terminating BlobFetcher'
                self._prefetch_process.terminate()
                self._prefetch_process.join()
            import atexit
            atexit.register(cleanup)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章