转载
http://blog.youkuaiyun.com/u010668907/article/details/51946021
http://m.blog.youkuaiyun.com/u010668907/article/details/51945844
http://blog.youkuaiyun.com/iamzhangzhuping/article/details/51355497
博客一
1.初始数据通过imdb类的操作放在它的属性roidb里。
2.roidb只是一个字典,可以拿出来当做一个单独的字典,脱离imdb。
3.roi_data_layer下的layer就是input-data。Forward中加载数据并控制一次一张图片
的数据进入网络。送到rpn-data中三组数据:
gt_boxes :大小(一张图片xml中box个数, 5);一张图中box的坐标以及类别
data : 大小(1,3,高,宽);一张图的数据
im_info: 大小(1, 3); (高, 宽, 下面提到的比例)
图片的大小与原图不同,每张图的高或宽被rescale成600,另一边会按照相同的比例rescale
4.`AnchorTargetLayer就是rpn-data.计算anchors,以及anchors是否合理(大小,overlap),并根据每个anchor与gt_box的重叠度判断labels;anchors大小是卷积网络过来数据的高宽再乘9个(即,一个点有9个).最后产生四组数据(设k=len(anchors)):
labels:大小(k, 1); 前景=1,背景=0, 否则=-1
rpn_bbox_targets: 大小(k, 4)
bbox_inside_weights: 大小(k, 4);有前景=1,否则为0
bbox_outside_weights: 大小(k, 4); 有前景或背景=1/(前景+背景),否则为0
:
博客二:
3.1 setup在caffe.SGDSolver时调用;setup的top(list猜测是c++的vector)的每个项是caffe._caffe.Blob
(猜测,输出的Top shape就是上面的top,在setup中被shape;top[0],1 3 [600] 1000;top[1],1 3;top[2], 1 4)(疑问,在forward中blob的数据shape被重置,有时大小甚至会不定)
3.2 name_to_top: {'gt_boxes': 2, 'data': 0, 'im_info': 1}字典的value值是top的对应索引
3.3 solver.step(1)会调用layer的reshape、forward
3.4 self._perm: 把roidb的索引打乱,造成图片的shuffle,打乱的索引存储的地方
3.5 cfg.TRAIN.IMS_PER_BATCH: (猜测,每次取图片的数量)
3.6 self._cur: 相当于一个指向_perm的指针,每次取走图片后,他会跟着变化
3.7 db_inds: 本次取得图片的索引
3.8 def _get_next_minibatch_inds(self): 取得本次图片的索引,即db_inds
3.9 minibatch_db: 本次的roidb
3.10 _num_classes: 网络里的类别数值21
3.11 forward(): 得到blob并处理放进top
solver.step(1)-》reshape-》forward-》_get_next_minbatch-》_get_next_minbatch_inds-》(前面在layers里,现在进入minibatch组建真正的blob)get_minibatch
博客二:
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."""
layer_params = yaml.load(self.param_str_)
self._num_classes = layer_params['num_classes']
self._name_to_top_map = {}
idx = 0
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
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:
top[idx].reshape(1, 5)
self._name_to_top_map['rois'] = idx
idx += 1
top[idx].reshape(1)
self._name_to_top_map['labels'] = idx
idx += 1
if cfg.TRAIN.BBOX_REG:
top[idx].reshape(1, self._num_classes * 4)
self._name_to_top_map['bbox_targets'] = idx
idx += 1
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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
def _shuffle_roidb_inds(self): 打乱training roidb的顺序
def _shuffle_roidb_inds(self):
"""Randomly permute the training roidb."""
if cfg.TRAIN.ASPECT_GROUPING:
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))
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
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]
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()
for blob_name, blob in blobs.iteritems():
top_ind = self._name_to_top_map[blob_name]
top[top_ind].reshape(*(blob.shape))
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._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()
def cleanup():
print 'Terminating BlobFetcher'
self._prefetch_process.terminate()
self._prefetch_process.join()
import atexit
atexit.register(cleanup)
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."""
layer_params = yaml.load(self.param_str_)
self._num_classes = layer_params['num_classes']
self._name_to_top_map = {}
idx = 0
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
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:
top[idx].reshape(1, 5)
self._name_to_top_map['rois'] = idx
idx += 1
top[idx].reshape(1)
self._name_to_top_map['labels'] = idx
idx += 1
if cfg.TRAIN.BBOX_REG:
top[idx].reshape(1, self._num_classes * 4)
self._name_to_top_map['bbox_targets'] = idx
idx += 1
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)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
def _shuffle_roidb_inds(self): 打乱training roidb的顺序
def _shuffle_roidb_inds(self):
"""Randomly permute the training roidb."""
if cfg.TRAIN.ASPECT_GROUPING:
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))
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
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]
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()
for blob_name, blob in blobs.iteritems():
top_ind = self._name_to_top_map[blob_name]
top[top_ind].reshape(*(blob.shape))
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._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()
def cleanup():
print 'Terminating BlobFetcher'
self._prefetch_process.terminate()
self._prefetch_process.join()
import atexit
atexit.register(cleanup)