这里”C++版本的代码”是指: https://github.com/galian123/cpp_faster_rcnn_detect .
py-faster-rcnn中demo.py代码, 是指 https://github.com/rbgirshick/py-faster-rcnn/blob/master/tools/demo.py 以及
https://github.com/rbgirshick/py-faster-rcnn/tree/master/lib 目录下的一些代码.
涉及到的.py文件都是 https://github.com/rbgirshick/py-faster-rcnn/ 中的.
★ Reshape
♦ python代码
回到 py-faster-rcnn/lib/fast_rcnn/test.py, 继续分析_get_blobs()
之后的代码.
demo.py 中对cfg.TEST.HAS_RPN
设置了True.
def im_detect(net, im, boxes=None):
blobs, im_scales = _get_blobs(im, boxes)
# 由上面的代码,可以知道blobs中的'data'是image的blob, 是4维数组,
# 维度的含义是(1, 3, 高, 宽)
if cfg.TEST.HAS_RPN: # 执行这里
im_blob = blobs['data']
# 创建一个新的3维数组, 维度含义为(高, 宽, 缩放倍率)
blobs['im_info'] = np.array(
[[im_blob.shape[2], im_blob.shape[3], im_scales[0]]],
dtype=np.float32)
# reshape network inputs
net.blobs['data'].reshape(*(blobs['data'].shape)) # 见"解释1", "解释2", "解释3"
if cfg.TEST.HAS_RPN:
net.blobs['im_info'].reshape(*(blobs['im_info'].shape))
else:
net.blobs['rois'].reshape(*(blobs['rois'].shape))
- 解释1:
net.blobs['data']
的含义.
从前面的分析可知, net是Net类的实例. Net类是由boost.python定义的. 并且定义了两个属性: _blobs
和 _blob_names
. _blobs
用来存储图片数据, _blob_names
用来存储blob的名字,例如data
, im_info
, cls_prob
等.
py-faster-rcnn/caffe-fast-rcnn/python/caffe/_caffe.cpp
bp::class_<Net<Dtype>, shared_ptr<Net<Dtype> >, boost::noncopyable >("Net",
bp::no_init)
.def("__init__", bp::make_constructor(&Net_Init_Load))
.add_property("_blobs", bp::make_function(&Net<Dtype>::blobs,
bp::return_internal_reference<>()))
.add_property("_blob_names", bp::make_function(&Net<Dtype>::blob_names,
bp::return_value_policy<bp::copy_const_reference>()))
py-faster-rcnn/caffe-fast-rcnn/include/caffe/net.hpp
inline const vector<string>& blob_names() const { return blob_names_; }
inline const vector<shared_ptr<Blob<Dtype> > >& blobs() const {
return blobs_;
}
vector<shared_ptr<Blob<Dtype> > > blobs_;
vector<string> blob_names_;
Net是从 py-faster-rcnn/caffe-fast-rcnn/python/caffe/pycaffe.py 导出的,
pycaffe.py中对Net附加了一些方法(只列举部分):
Net.blobs = _Net_blobs
Net.blob_loss_weights = _Net_blob_loss_weights
Net.layer_dict = _Net_layer_dict
Net.params = _Net_params
Net.forward = _Net_forward
Net.backward = _Net_backward
Net.blobs = _Net_blobs
中的_Net_blobs
:
@property
def _Net_blobs(self):
"""
An OrderedDict (bottom to top, i.e., input to output) of network
blobs indexed by name
"""
if not hasattr(self, '_blobs_dict'):
self._blobs_dict = OrderedDict(zip(self._blob_names, self._blobs))
return self._blobs_dict
所以, 使用net.blobs['data']
时, 是对self._blobs_dict
中的key为’data’的项(blob)赋值,
字符串’data’(key)传给了self._blob_names
, 值传给了self._blobs
.
- 查看Net.blobs的信息:
>>> from caffe._caffe import Net
>>> help(Net.blobs)
Help on property:
An OrderedDict (bottom to top, i.e., input to output) of network
blobs indexed by name
net.blobs['data']
的类型与Blob<Dtype>
是对应的.
>>> import caffe
>>> from caffe import Net
>>>
>>> model = './output/faster_rcnn_end2end/voc_2007_trainval/vgg_cnn_m_1024_faster_rcnn_iter_70000.caffemodel'
>>> prototxt = 'models/pascal_voc/VGG_CNN_M_1024/faster_rcnn_end2end/test.prototxt'
>>> net = caffe.Net(prototxt, model, caffe.TEST)
>>> net.blobs['data']
<caffe._caffe.Blob object at 0x7f2511828b90>
- 打印
net.blobs
net.blobs: OrderedDict([('data', <caffe._caffe.Blob object at 0x7fcacce06938>), ('im_info', <caffe._caffe.Blob object at 0x7fcacce069b0>), ('conv1', <caffe._caffe.Blob object at 0x7fcacce06a28>), ('norm1', <caffe._caffe.Blob object at 0x7fcacce06aa0>), ('pool1', <caffe._caffe.Blob object at 0x7fcacce06b18>), ('conv2', <caffe._caffe.Blob object at 0x7fcacce06b90>), ('norm2', <caffe._caffe.Blob object at 0x7fcacce06c08>), ('pool2', <caffe._caffe.Blob object at 0x7fcacce06c80>), ('conv3', <caffe._caffe.Blob object at 0x7fcacce06cf8>), ('conv4', <caffe._caffe.Blob object at 0x7fcacce06d70>), ('conv5', <caffe._caffe.Blob object at 0x7fcacce06de8>), ('conv5_relu5_0_split_0', <caffe._caffe.Blob object at 0x7fcacce06e60>), ('conv5_relu5_0_split_1', <caffe._caffe.Blob object at 0x7fcacce06ed8>), ('rpn/output', <caffe._caffe.Blob object at 0x7fcacce06f50>), ('rpn/output_rpn_relu/3x3_0_split_0', <caffe._caffe.Blob object at 0x7fcacce14050>), ('rpn/output_rpn_relu/3x3_0_split_1', <caffe._caffe.Blob object at 0x7fcacce140c8>), ('rpn_cls_score', <caffe._caffe.Blob object at 0x7fcacce14140>), ('rpn_bbox_pred', <caffe._caffe.Blob object at 0x7fcacce141b8>), ('rpn_cls_score_reshape', <caffe._caffe.Blob object at 0x7fcacce14230>), ('rpn_cls_prob', <caffe._caffe.Blob object at 0x7fcacce142a8>), ('rpn_cls_prob_reshape', <caffe._caffe.Blob object at 0x7fcacce14320>), ('rois', <caffe._caffe.Blob object at 0x7fcacce14398>), ('pool5', <caffe._caffe.Blob object at 0x7fcacce14410>), ('fc6', <caffe._caffe.Blob object at 0x7fcacce14488>), ('fc7', <caffe._caffe.Blob object at 0x7fcacce14500>), ('fc7_drop7_0_split_0', <caffe._caffe.Blob object at 0x7fcacce14578>), ('fc7_drop7_0_split_1', <caffe._caffe.Blob object at 0x7fcacce145f0>), ('cls_score', <caffe._caffe.Blob object at 0x7fcacce14668>), ('bbox_pred', <caffe._caffe.Blob object at 0x7fcacce146e0>), ('cls_prob', <caffe._caffe.Blob object at 0x7fcacce14758>)])
- 解释2:
net.blobs['data'].reshape(*(blobs['data'].shape))
中星号 * 的含义
举个例子:
>>> import numpy as np
>>> a = np.array([[[1], [2], [3]]])
>>> a
array([[[1],
[2],
[3]]])
>>> a.shape
(1, 3, 1)
>>> def f(a, b, c):
... print a, b, c
...
>>> f(*a.shape)
1 3 1
在函数参数中的星号, 可以使传入的元组转换成位置参数, 例如上面的例子中a.shape是(1,3,1), 不能通过f(a.shape)
的方式传入(1,3,1), 需要星号的形式:f(*a.shape)
.
python帮助文档中的解释:
If the syntax *expression appears in the function call, expression must evaluate to an iterable. Elements from this iterable are treated as if they were additional positional arguments; if there are positional arguments x1, …, xN, and expression evaluates to a sequence y1, …, yM, this is equivalent to a call with M+N positional arguments x1, …, xN, y1, …, yM.
A consequence of this is that although the *expression syntax may appear after some keyword arguments, it is processed before the keyword arguments (and the **expression argument, if any – see below). So:
>>> def f(a, b):
... print a, b
...
>>> f(b=1, *(2,))
2 1
>>> f(a=1, *(2,))
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2
It is unusual for both keyword arguments and the *expression syntax to be used in the same call, so in practice this confusion does not arise.
- 解释3:
net.blobs['data'].reshape()
执行的是哪个函数?
由”解释1”可知, net.blobs['data']
的类型为caffe._caffe.Blob
对象.
所以, net.blobs['data'].reshape()
执行的是caffe._caffe.Blob
的函数.
caffe._caffe.Blob
是caffe包(py-faster-rcnn/caffe-fast-rcnn/python/caffe目录)下的_caffe.so中实现的Blob:
bp::class_<Blob<Dtype>, shared_ptr<Blob<Dtype> >, boost::noncopyable>(
"Blob", bp::no_init)
.def("reshape", bp::raw_function(&Blob_Reshape))
net.blobs['data'].reshape()
最终调用是Blob_Reshape()
.
Blob_Reshape()
是在py-faster-rcnn/caffe-fast-rcnn/python/caffe/_caffe.cpp
中.
bp::object Blob_Reshape(bp::tuple args, bp::dict kwargs) {
if (bp::len(kwargs) > 0) {
throw std::runtime_error("Blob.reshape takes no kwargs");
}
// args的内容是(blob对象地址, 1,3,高,宽), 其中(1, 3,高,宽)是一个blob的4个维度值
Blob<Dtype>* self = bp::extract<Blob<Dtype>*>(args[0]);
vector<int> shape(bp::len(args) - 1);
for (int i = 1; i < bp::len(args); ++i) {// 取出(1,3,高,宽)
shape[i - 1] = bp::extract<int>(args[i]);
}
self->Reshape(shape);
// We need to explicitly return None to use bp::raw_function.
return bp::object();
}
♦ C++代码
net_->blob_by_name("data")->Reshape(1, 3, height, width);
net_->Reshape();
————– 分割线 ————–
本系列文章如下:
- (1) py-faster-rcnn中demo.py代码与C++版本的代码对比: part01 铺垫, demo.py引入的模块
- (2) py-faster-rcnn中demo.py代码与C++版本的代码对比: part02 初始化, 创建Net
- (3) py-faster-rcnn中demo.py代码与C++版本的代码对比: part03 处理图片:减掉平均值, resize
- (4) py-faster-rcnn中demo.py代码与C++版本的代码对比: part04 图片转存为blob
- (5) py-faster-rcnn中demo.py代码与C++版本的代码对比: part05 Reshape
- (6) py-faster-rcnn中demo.py代码与C++版本的代码对比: part06 forward, rois boxes transform
- (7) py-faster-rcnn中demo.py代码与C++版本的代码对比: part07 nms, 获取符合条件的boxes