Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
PaddleDetection
提交
26f03ea1
P
PaddleDetection
项目概览
PaddlePaddle
/
PaddleDetection
大约 1 年 前同步成功
通知
695
Star
11112
Fork
2696
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
184
列表
看板
标记
里程碑
合并请求
40
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleDetection
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
184
Issue
184
列表
看板
标记
里程碑
合并请求
40
合并请求
40
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
26f03ea1
编写于
1月 30, 2018
作者:
W
wanghaox
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update detection_map operator
上级
67cbb3e3
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
231 addition
and
355 deletion
+231
-355
paddle/operators/detection_map_op.cc
paddle/operators/detection_map_op.cc
+60
-13
paddle/operators/detection_map_op.cu
paddle/operators/detection_map_op.cu
+0
-20
paddle/operators/detection_map_op.h
paddle/operators/detection_map_op.h
+131
-118
paddle/operators/math/detection_util.cc
paddle/operators/math/detection_util.cc
+0
-22
paddle/operators/math/detection_util.cu
paddle/operators/math/detection_util.cu
+0
-23
paddle/operators/math/detection_util.h
paddle/operators/math/detection_util.h
+0
-128
python/paddle/v2/fluid/tests/test_detection_map_op.py
python/paddle/v2/fluid/tests/test_detection_map_op.py
+40
-31
未找到文件。
paddle/operators/detection_map_op.cc
浏览文件 @
26f03ea1
...
...
@@ -24,6 +24,29 @@ class DetectionMAPOp : public framework::OperatorWithKernel {
using
framework
::
OperatorWithKernel
::
OperatorWithKernel
;
void
InferShape
(
framework
::
InferShapeContext
*
ctx
)
const
override
{
PADDLE_ENFORCE
(
ctx
->
HasInput
(
"Detection"
),
"Input(Detection) of DetectionMAPOp should not be null."
);
PADDLE_ENFORCE
(
ctx
->
HasInput
(
"Label"
),
"Input(Label) of DetectionMAPOp should not be null."
);
PADDLE_ENFORCE
(
ctx
->
HasOutput
(
"MAP"
),
"Output(MAP) of DetectionMAPOp should not be null."
);
auto
det_dims
=
ctx
->
GetInputDim
(
"Detection"
);
PADDLE_ENFORCE_EQ
(
det_dims
.
size
(),
2UL
,
"The rank of Input(Detection) must be 2, "
"the shape is [N, 6]."
);
PADDLE_ENFORCE_EQ
(
det_dims
[
1
],
6UL
,
"The shape is of Input(Detection) [N, 6]."
);
auto
label_dims
=
ctx
->
GetInputDim
(
"Label"
);
PADDLE_ENFORCE_EQ
(
label_dims
.
size
(),
2UL
,
"The rank of Input(Label) must be 2, "
"the shape is [N, 6]."
);
PADDLE_ENFORCE_EQ
(
label_dims
[
1
],
6UL
,
"The shape is of Input(Label) [N, 6]."
);
auto
ap_type
=
GetAPType
(
ctx
->
Attrs
().
Get
<
std
::
string
>
(
"ap_type"
));
PADDLE_ENFORCE_NE
(
ap_type
,
APType
::
kNone
,
"The ap_type should be 'integral' or '11point."
);
auto
map_dim
=
framework
::
make_ddim
({
1
});
ctx
->
SetOutputDim
(
"MAP"
,
map_dim
);
}
...
...
@@ -42,25 +65,49 @@ class DetectionMAPOpMaker : public framework::OpProtoAndCheckerMaker {
DetectionMAPOpMaker
(
framework
::
OpProto
*
proto
,
framework
::
OpAttrChecker
*
op_checker
)
:
OpProtoAndCheckerMaker
(
proto
,
op_checker
)
{
AddInput
(
"Detect"
,
"The detection output."
);
AddInput
(
"Label"
,
"The label data."
);
AddOutput
(
"MAP"
,
"The MAP evaluate result of the detection."
);
AddAttr
<
float
>
(
"overlap_threshold"
,
"The overlap threshold."
)
AddInput
(
"Label"
,
"(LoDTensor) A 2-D LoDTensor with shape[N, 6] represents the"
"Labeled ground-truth data. Each row has 6 values: "
"[label, is_difficult, xmin, ymin, xmax, ymax], N is the total "
"number of ground-truth data in this mini-batch. For each "
"instance, the offsets in first dimension are called LoD, "
"the number of offset is N + 1, if LoD[i + 1] - LoD[i] == 0, "
"means there is no ground-truth data."
);
AddInput
(
"Detection"
,
"(LoDTensor) A 2-D LoDTensor with shape [M, 6] represents the "
"detections. Each row has 6 values: "
"[label, confidence, xmin, ymin, xmax, ymax], M is the total "
"number of detections in this mini-batch. For each instance, "
"the offsets in first dimension are called LoD, the number of "
"offset is N + 1, if LoD[i + 1] - LoD[i] == 0, means there is "
"no detected data."
);
AddOutput
(
"MAP"
,
"(Tensor) A tensor with shape [1], store the mAP evaluate "
"result of the detection."
);
AddAttr
<
float
>
(
"overlap_threshold"
,
"(float) "
"The jaccard overlap threshold of detection output and "
"ground-truth data."
)
.
SetDefault
(
.3
f
);
AddAttr
<
bool
>
(
"evaluate_difficult"
,
"(bool, default true) "
"Switch to control whether the difficult data is evaluated."
)
.
SetDefault
(
true
);
AddAttr
<
std
::
string
>
(
"ap_type"
,
"The AP algorithm type, 'Integral' or '11point'."
)
.
SetDefault
(
"Integral"
);
"(string, default 'integral') "
"The AP algorithm type, 'integral' or '11point'."
)
.
SetDefault
(
"integral"
)
.
InEnum
({
"integral"
,
"11point"
});
AddComment
(
R"DOC(
Detection MAP Operator.
Detection MAP evaluator for SSD(Single Shot MultiBox Detector) algorithm.
Please get more information from the following papers:
https://arxiv.org/abs/1512.02325.
Detection mAP evaluate operator.
The general steps are as follows. First, calculate the true positive and
false positive according to the input of detection and labels, then
calculate the mAP evaluate value.
Supporting '11 point' and 'integral' mAP algorithm. Please get more information
from the following articles:
https://sanchom.wordpress.com/tag/average-precision/
https://arxiv.org/abs/1512.02325
)DOC"
);
}
...
...
paddle/operators/detection_map_op.cu
已删除
100644 → 0
浏览文件 @
67cbb3e3
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include "paddle/operators/detection_map_op.h"
namespace
ops
=
paddle
::
operators
;
REGISTER_OP_CUDA_KERNEL
(
detection_map
,
ops
::
DetectionMAPOpKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
,
ops
::
DetectionMAPOpKernel
<
paddle
::
platform
::
GPUPlace
,
double
>
);
paddle/operators/detection_map_op.h
浏览文件 @
26f03ea1
...
...
@@ -13,22 +13,37 @@ See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#include "paddle/framework/eigen.h"
#include "paddle/framework/op_registry.h"
#include "paddle/operators/math/detection_util.h"
#include "paddle/operators/math/math_function.h"
namespace
paddle
{
namespace
operators
{
enum
APType
{
kNone
=
0
,
kIntegral
,
k11point
};
APType
GetAPType
(
std
::
string
str
)
{
if
(
str
==
"integral"
)
{
return
APType
::
kIntegral
;
}
else
if
(
str
==
"11point"
)
{
return
APType
::
k11point
;
}
else
{
return
APType
::
kNone
;
}
}
template
<
typename
T
>
inline
bool
SortScorePairDescend
(
const
std
::
pair
<
float
,
T
>&
pair1
,
const
std
::
pair
<
float
,
T
>&
pair2
)
{
return
pair1
.
first
>
pair2
.
first
;
}
template
<
typename
T
>
inline
void
GetAccumulation
(
std
::
vector
<
std
::
pair
<
T
,
int
>>
in_pairs
,
std
::
vector
<
int
>*
accu_vec
)
{
std
::
stable_sort
(
in_pairs
.
begin
(),
in_pairs
.
end
(),
math
::
SortScorePairDescend
<
int
>
);
std
::
stable_sort
(
in_pairs
.
begin
(),
in_pairs
.
end
(),
SortScorePairDescend
<
int
>
);
accu_vec
->
clear
();
size_t
sum
=
0
;
for
(
size_t
i
=
0
;
i
<
in_pairs
.
size
();
++
i
)
{
// auto score = in_pairs[i].first;
auto
count
=
in_pairs
[
i
].
second
;
sum
+=
count
;
accu_vec
->
push_back
(
sum
);
...
...
@@ -39,126 +54,125 @@ template <typename Place, typename T>
class
DetectionMAPOpKernel
:
public
framework
::
OpKernel
<
T
>
{
public:
void
Compute
(
const
framework
::
ExecutionContext
&
ctx
)
const
override
{
auto
*
in
put_label
=
ctx
.
Input
<
framework
::
LoDTensor
>
(
"Label
"
);
auto
*
in
put_detect
=
ctx
.
Input
<
framework
::
Tensor
>
(
"Detect
"
);
auto
*
map_out
=
ctx
.
Output
<
framework
::
Tensor
>
(
"MAP"
);
auto
*
in
_detect
=
ctx
.
Input
<
framework
::
LoDTensor
>
(
"Detection
"
);
auto
*
in
_label
=
ctx
.
Input
<
framework
::
LoDTensor
>
(
"Label
"
);
auto
*
out_map
=
ctx
.
Output
<
framework
::
Tensor
>
(
"MAP"
);
float
overlap_threshold
=
ctx
.
Attr
<
float
>
(
"overlap_threshold"
);
float
evaluate_difficult
=
ctx
.
Attr
<
bool
>
(
"evaluate_difficult"
);
std
::
string
ap_type
=
ctx
.
Attr
<
std
::
string
>
(
"ap_type"
);
auto
ap_type
=
GetAPType
(
ctx
.
Attr
<
std
::
string
>
(
"ap_type"
)
);
auto
label_lod
=
input_label
->
lod
();
auto
label_lod
=
in_label
->
lod
();
auto
detect_lod
=
in_detect
->
lod
();
PADDLE_ENFORCE_EQ
(
label_lod
.
size
(),
1UL
,
"Only support one level sequence now."
);
auto
batch_size
=
label_lod
[
0
].
size
()
-
1
;
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
operators
::
math
::
BBox
<
T
>>>>
gt_bboxes
;
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
operators
::
math
::
BBox
<
T
>>>>>
detect_bboxes
;
if
(
platform
::
is_gpu_place
(
ctx
.
GetPlace
()))
{
framework
::
LoDTensor
input_label_cpu
;
framework
::
Tensor
input_detect_cpu
;
input_label_cpu
.
set_lod
(
input_label
->
lod
());
input_label_cpu
.
Resize
(
input_label
->
dims
());
input_detect_cpu
.
Resize
(
input_detect
->
dims
());
input_label_cpu
.
mutable_data
<
T
>
(
platform
::
CPUPlace
());
input_detect_cpu
.
mutable_data
<
T
>
(
platform
::
CPUPlace
());
framework
::
CopyFrom
(
*
input_label
,
platform
::
CPUPlace
(),
ctx
.
device_context
(),
&
input_label_cpu
);
framework
::
CopyFrom
(
*
input_detect
,
platform
::
CPUPlace
(),
ctx
.
device_context
(),
&
input_detect_cpu
);
GetBBoxes
(
input_label_cpu
,
input_detect_cpu
,
gt_bboxes
,
detect_bboxes
);
}
else
{
GetBBoxes
(
*
input_label
,
*
input_detect
,
gt_bboxes
,
detect_bboxes
);
}
PADDLE_ENFORCE_EQ
(
label_lod
[
0
].
size
(),
detect_lod
[
0
].
size
(),
"The batch_size of input(Label) and input(Detection) "
"must be the same."
);
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
Box
>>>
gt_boxes
;
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
Box
>>>>
detect_boxes
;
GetBoxes
(
*
in_label
,
*
in_detect
,
gt_boxes
,
detect_boxes
);
std
::
map
<
int
,
int
>
label_pos_count
;
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
int
>>>
true_pos
;
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
int
>>>
false_pos
;
CalcTrueAndFalsePositive
(
batch_size
,
evaluate_difficult
,
overlap_threshold
,
gt_bboxes
,
detect_bboxes
,
label_pos_count
,
true_pos
,
false_pos
);
CalcTrueAndFalsePositive
(
gt_boxes
,
detect_boxes
,
evaluate_difficult
,
overlap_threshold
,
label_pos_count
,
true_pos
,
false_pos
);
T
map
=
CalcMAP
(
ap_type
,
label_pos_count
,
true_pos
,
false_pos
);
T
*
map_data
=
nullptr
;
framework
::
Tensor
map_cpu
;
map_out
->
mutable_data
<
T
>
(
ctx
.
GetPlace
());
if
(
platform
::
is_gpu_place
(
ctx
.
GetPlace
()))
{
map_data
=
map_cpu
.
mutable_data
<
T
>
(
map_out
->
dims
(),
platform
::
CPUPlace
());
map_data
[
0
]
=
map
;
framework
::
CopyFrom
(
map_cpu
,
platform
::
CPUPlace
(),
ctx
.
device_context
(),
map_out
);
T
*
map_data
=
out_map
->
mutable_data
<
T
>
(
ctx
.
GetPlace
());
map_data
[
0
]
=
map
;
}
protected:
struct
Box
{
Box
(
T
xmin
,
T
ymin
,
T
xmax
,
T
ymax
)
:
xmin
(
xmin
),
ymin
(
ymin
),
xmax
(
xmax
),
ymax
(
ymax
),
is_difficult
(
false
)
{}
T
xmin
,
ymin
,
xmax
,
ymax
;
bool
is_difficult
;
};
inline
T
JaccardOverlap
(
const
Box
&
box1
,
const
Box
&
box2
)
const
{
if
(
box2
.
xmin
>
box1
.
xmax
||
box2
.
xmax
<
box1
.
xmin
||
box2
.
ymin
>
box1
.
ymax
||
box2
.
ymax
<
box1
.
ymin
)
{
return
0.0
;
}
else
{
map_data
=
map_out
->
mutable_data
<
T
>
(
ctx
.
GetPlace
());
map_data
[
0
]
=
map
;
T
inter_xmin
=
std
::
max
(
box1
.
xmin
,
box2
.
xmin
);
T
inter_ymin
=
std
::
max
(
box1
.
ymin
,
box2
.
ymin
);
T
inter_xmax
=
std
::
min
(
box1
.
xmax
,
box2
.
xmax
);
T
inter_ymax
=
std
::
min
(
box1
.
ymax
,
box2
.
ymax
);
T
inter_width
=
inter_xmax
-
inter_xmin
;
T
inter_height
=
inter_ymax
-
inter_ymin
;
T
inter_area
=
inter_width
*
inter_height
;
T
bbox_area1
=
(
box1
.
xmax
-
box1
.
xmin
)
*
(
box1
.
ymax
-
box1
.
ymin
);
T
bbox_area2
=
(
box2
.
xmax
-
box2
.
xmin
)
*
(
box2
.
ymax
-
box2
.
ymin
);
return
inter_area
/
(
bbox_area1
+
bbox_area2
-
inter_area
);
}
}
protected:
void
GetBBoxes
(
const
framework
::
LoDTensor
&
input_label
,
const
framework
::
Tensor
&
input_detect
,
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
operators
::
math
::
BBox
<
T
>>>>&
gt_bboxes
,
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
operators
::
math
::
BBox
<
T
>>>>>&
detect_bboxes
)
const
{
const
T
*
label_data
=
input_label
.
data
<
T
>
();
const
T
*
detect_data
=
input_detect
.
data
<
T
>
();
void
GetBoxes
(
const
framework
::
LoDTensor
&
input_label
,
const
framework
::
LoDTensor
&
input_detect
,
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
Box
>>>&
gt_boxes
,
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
Box
>>>>&
detect_boxes
)
const
{
auto
labels
=
framework
::
EigenTensor
<
T
,
2
>::
From
(
input_label
);
auto
detect
=
framework
::
EigenTensor
<
T
,
2
>::
From
(
input_detect
);
auto
label_lod
=
input_label
.
lod
();
auto
batch_size
=
label_lod
[
0
].
size
()
-
1
;
auto
detect_lod
=
input_detect
.
lod
();
int
batch_size
=
label_lod
[
0
].
size
()
-
1
;
auto
label_index
=
label_lod
[
0
];
for
(
size_
t
n
=
0
;
n
<
batch_size
;
++
n
)
{
std
::
map
<
int
,
std
::
vector
<
operators
::
math
::
BBox
<
T
>>>
b
boxes
;
for
(
in
t
n
=
0
;
n
<
batch_size
;
++
n
)
{
std
::
map
<
int
,
std
::
vector
<
Box
>>
boxes
;
for
(
int
i
=
label_index
[
n
];
i
<
label_index
[
n
+
1
];
++
i
)
{
std
::
vector
<
operators
::
math
::
BBox
<
T
>>
bbox
;
math
::
GetBBoxFromLabelData
<
T
>
(
label_data
+
i
*
6
,
1
,
bbox
);
int
label
=
static_cast
<
int
>
(
label_data
[
i
*
6
]);
bboxes
[
label
].
push_back
(
bbox
[
0
]);
Box
box
(
labels
(
i
,
2
),
labels
(
i
,
3
),
labels
(
i
,
4
),
labels
(
i
,
5
));
int
label
=
labels
(
i
,
0
);
auto
is_difficult
=
labels
(
i
,
1
);
if
(
std
::
abs
(
is_difficult
-
0.0
)
<
1e-6
)
box
.
is_difficult
=
false
;
else
box
.
is_difficult
=
true
;
boxes
[
label
].
push_back
(
box
);
}
gt_b
boxes
.
push_back
(
b
boxes
);
gt_b
oxes
.
push_back
(
boxes
);
}
size_t
n
=
0
;
size_t
detect_box_count
=
input_detect
.
dims
()[
0
];
for
(
size_t
img_id
=
0
;
img_id
<
batch_size
;
++
img_id
)
{
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
operators
::
math
::
BBox
<
T
>>>>
bboxes
;
size_t
cur_img_id
=
static_cast
<
size_t
>
((
detect_data
+
n
*
7
)[
0
]);
while
(
cur_img_id
==
img_id
&&
n
<
detect_box_count
)
{
std
::
vector
<
T
>
label
;
std
::
vector
<
T
>
score
;
std
::
vector
<
operators
::
math
::
BBox
<
T
>>
bbox
;
math
::
GetBBoxFromDetectData
<
T
>
(
detect_data
+
n
*
7
,
1
,
label
,
score
,
bbox
);
bboxes
[
label
[
0
]].
push_back
(
std
::
make_pair
(
score
[
0
],
bbox
[
0
]));
++
n
;
cur_img_id
=
static_cast
<
size_t
>
((
detect_data
+
n
*
7
)[
0
]);
auto
detect_index
=
detect_lod
[
0
];
for
(
int
n
=
0
;
n
<
batch_size
;
++
n
)
{
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
Box
>>>
boxes
;
for
(
int
i
=
detect_index
[
n
];
i
<
detect_index
[
n
+
1
];
++
i
)
{
Box
box
(
detect
(
i
,
2
),
detect
(
i
,
3
),
detect
(
i
,
4
),
detect
(
i
,
5
));
int
label
=
detect
(
i
,
0
);
auto
score
=
detect
(
i
,
1
);
boxes
[
label
].
push_back
(
std
::
make_pair
(
score
,
box
));
}
detect_b
boxes
.
push_back
(
b
boxes
);
detect_b
oxes
.
push_back
(
boxes
);
}
}
void
CalcTrueAndFalsePositive
(
size_t
batch_size
,
bool
evaluate_difficult
,
float
overlap_threshold
,
const
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
operators
::
math
::
BBox
<
T
>>>>&
gt_bboxes
,
const
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
operators
::
math
::
BBox
<
T
>>>>>&
detect_bboxes
,
const
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
Box
>>>&
gt_boxes
,
const
std
::
vector
<
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
Box
>>>>&
detect_boxes
,
bool
evaluate_difficult
,
float
overlap_threshold
,
std
::
map
<
int
,
int
>&
label_pos_count
,
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
int
>>>&
true_pos
,
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
int
>>>&
false_pos
)
const
{
for
(
size_t
n
=
0
;
n
<
batch_size
;
++
n
)
{
auto
image_gt_bboxes
=
gt_bboxes
[
n
];
for
(
auto
it
=
image_gt_bboxes
.
begin
();
it
!=
image_gt_bboxes
.
end
()
;
++
it
)
{
int
batch_size
=
gt_boxes
.
size
();
for
(
int
n
=
0
;
n
<
batch_size
;
++
n
)
{
auto
image_gt_boxes
=
gt_boxes
[
n
]
;
for
(
auto
it
=
image_gt_boxes
.
begin
();
it
!=
image_gt_boxes
.
end
();
++
it
)
{
size_t
count
=
0
;
auto
labeled_bboxes
=
it
->
second
;
if
(
evaluate_difficult
)
{
...
...
@@ -179,16 +193,16 @@ class DetectionMAPOpKernel : public framework::OpKernel<T> {
}
}
for
(
size_t
n
=
0
;
n
<
detect_b
b
oxes
.
size
();
++
n
)
{
auto
image_gt_b
boxes
=
gt_b
boxes
[
n
];
auto
detections
=
detect_b
b
oxes
[
n
];
for
(
size_t
n
=
0
;
n
<
detect_boxes
.
size
();
++
n
)
{
auto
image_gt_b
oxes
=
gt_
boxes
[
n
];
auto
detections
=
detect_boxes
[
n
];
if
(
image_gt_b
b
oxes
.
size
()
==
0
)
{
if
(
image_gt_boxes
.
size
()
==
0
)
{
for
(
auto
it
=
detections
.
begin
();
it
!=
detections
.
end
();
++
it
)
{
auto
pred_b
b
oxes
=
it
->
second
;
auto
pred_boxes
=
it
->
second
;
int
label
=
it
->
first
;
for
(
size_t
i
=
0
;
i
<
pred_b
b
oxes
.
size
();
++
i
)
{
auto
score
=
pred_b
b
oxes
[
i
].
first
;
for
(
size_t
i
=
0
;
i
<
pred_boxes
.
size
();
++
i
)
{
auto
score
=
pred_boxes
[
i
].
first
;
true_pos
[
label
].
push_back
(
std
::
make_pair
(
score
,
0
));
false_pos
[
label
].
push_back
(
std
::
make_pair
(
score
,
1
));
}
...
...
@@ -198,28 +212,27 @@ class DetectionMAPOpKernel : public framework::OpKernel<T> {
for
(
auto
it
=
detections
.
begin
();
it
!=
detections
.
end
();
++
it
)
{
int
label
=
it
->
first
;
auto
pred_b
b
oxes
=
it
->
second
;
if
(
image_gt_b
boxes
.
find
(
label
)
==
image_gt_b
boxes
.
end
())
{
for
(
size_t
i
=
0
;
i
<
pred_b
b
oxes
.
size
();
++
i
)
{
auto
score
=
pred_b
b
oxes
[
i
].
first
;
auto
pred_boxes
=
it
->
second
;
if
(
image_gt_b
oxes
.
find
(
label
)
==
image_gt_
boxes
.
end
())
{
for
(
size_t
i
=
0
;
i
<
pred_boxes
.
size
();
++
i
)
{
auto
score
=
pred_boxes
[
i
].
first
;
true_pos
[
label
].
push_back
(
std
::
make_pair
(
score
,
0
));
false_pos
[
label
].
push_back
(
std
::
make_pair
(
score
,
1
));
}
continue
;
}
auto
matched_bboxes
=
image_gt_b
b
oxes
.
find
(
label
)
->
second
;
auto
matched_bboxes
=
image_gt_boxes
.
find
(
label
)
->
second
;
std
::
vector
<
bool
>
visited
(
matched_bboxes
.
size
(),
false
);
// Sort detections in descend order based on scores
std
::
sort
(
pred_b
boxes
.
begin
(),
pred_b
boxes
.
end
(),
math
::
SortScorePairDescend
<
operators
::
math
::
BBox
<
T
>
>
);
for
(
size_t
i
=
0
;
i
<
pred_b
b
oxes
.
size
();
++
i
)
{
float
max_overlap
=
-
1.0
;
std
::
sort
(
pred_b
oxes
.
begin
(),
pred_
boxes
.
end
(),
SortScorePairDescend
<
Box
>
);
for
(
size_t
i
=
0
;
i
<
pred_boxes
.
size
();
++
i
)
{
T
max_overlap
=
-
1.0
;
size_t
max_idx
=
0
;
auto
score
=
pred_b
b
oxes
[
i
].
first
;
auto
score
=
pred_boxes
[
i
].
first
;
for
(
size_t
j
=
0
;
j
<
matched_bboxes
.
size
();
++
j
)
{
float
overlap
=
JaccardOverlap
(
pred_bboxes
[
i
].
second
,
matched_bboxes
[
j
]);
T
overlap
=
JaccardOverlap
(
pred_boxes
[
i
].
second
,
matched_bboxes
[
j
]);
if
(
overlap
>
max_overlap
)
{
max_overlap
=
overlap
;
max_idx
=
j
;
...
...
@@ -249,7 +262,7 @@ class DetectionMAPOpKernel : public framework::OpKernel<T> {
}
T
CalcMAP
(
std
::
string
ap_type
,
const
std
::
map
<
int
,
int
>&
label_pos_count
,
APType
ap_type
,
const
std
::
map
<
int
,
int
>&
label_pos_count
,
const
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
int
>>>&
true_pos
,
const
std
::
map
<
int
,
std
::
vector
<
std
::
pair
<
T
,
int
>>>&
false_pos
)
const
{
T
mAP
=
0.0
;
...
...
@@ -266,18 +279,18 @@ class DetectionMAPOpKernel : public framework::OpKernel<T> {
GetAccumulation
<
T
>
(
label_true_pos
,
&
tp_sum
);
std
::
vector
<
int
>
fp_sum
;
GetAccumulation
<
T
>
(
label_false_pos
,
&
fp_sum
);
std
::
vector
<
float
>
precision
,
recall
;
std
::
vector
<
T
>
precision
,
recall
;
size_t
num
=
tp_sum
.
size
();
// Compute Precision.
for
(
size_t
i
=
0
;
i
<
num
;
++
i
)
{
// CHECK_LE(tpCumSum[i], labelNumPos);
precision
.
push_back
(
static_cast
<
float
>
(
tp_sum
[
i
])
/
static_cast
<
float
>
(
tp_sum
[
i
]
+
fp_sum
[
i
]));
recall
.
push_back
(
static_cast
<
float
>
(
tp_sum
[
i
])
/
label_num_pos
);
precision
.
push_back
(
static_cast
<
T
>
(
tp_sum
[
i
])
/
static_cast
<
T
>
(
tp_sum
[
i
]
+
fp_sum
[
i
]));
recall
.
push_back
(
static_cast
<
T
>
(
tp_sum
[
i
])
/
label_num_pos
);
}
// VOC2007 style
if
(
ap_type
==
"11point"
)
{
std
::
vector
<
float
>
max_precisions
(
11
,
0.0
);
if
(
ap_type
==
APType
::
k11point
)
{
std
::
vector
<
T
>
max_precisions
(
11
,
0.0
);
int
start_idx
=
num
-
1
;
for
(
int
j
=
10
;
j
>=
0
;
--
j
)
for
(
int
i
=
start_idx
;
i
>=
0
;
--
i
)
{
...
...
@@ -292,7 +305,7 @@ class DetectionMAPOpKernel : public framework::OpKernel<T> {
}
for
(
int
j
=
10
;
j
>=
0
;
--
j
)
mAP
+=
max_precisions
[
j
]
/
11
;
++
count
;
}
else
if
(
ap_type
==
"Integral"
)
{
}
else
if
(
ap_type
==
APType
::
kIntegral
)
{
// Nature integral
float
average_precisions
=
0.
;
float
prev_recall
=
0.
;
...
...
paddle/operators/math/detection_util.cc
已删除
100644 → 0
浏览文件 @
67cbb3e3
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include "paddle/operators/math/detection_util.h"
#include "paddle/operators/math/math_function.h"
namespace
paddle
{
namespace
operators
{
namespace
math
{}
// namespace math
}
// namespace operators
}
// namespace paddle
paddle/operators/math/detection_util.cu
已删除
100644 → 0
浏览文件 @
67cbb3e3
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include "paddle/operators/math/detection_util.h"
#include "paddle/operators/math/math_function.h"
#include "paddle/platform/cuda_helper.h"
namespace
paddle
{
namespace
operators
{
namespace
math
{}
// namespace math
}
// namespace operators
}
// namespace paddle
paddle/operators/math/detection_util.h
已删除
100644 → 0
浏览文件 @
67cbb3e3
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#include "paddle/framework/selected_rows.h"
#include "paddle/platform/device_context.h"
namespace
paddle
{
namespace
operators
{
namespace
math
{
template
<
typename
T
>
struct
BBox
{
BBox
(
T
x_min
,
T
y_min
,
T
x_max
,
T
y_max
)
:
x_min
(
x_min
),
y_min
(
y_min
),
x_max
(
x_max
),
y_max
(
y_max
),
is_difficult
(
false
)
{}
BBox
()
{}
T
get_width
()
const
{
return
x_max
-
x_min
;
}
T
get_height
()
const
{
return
y_max
-
y_min
;
}
T
get_center_x
()
const
{
return
(
x_min
+
x_max
)
/
2
;
}
T
get_center_y
()
const
{
return
(
y_min
+
y_max
)
/
2
;
}
T
get_area
()
const
{
return
get_width
()
*
get_height
();
}
// coordinate of bounding box
T
x_min
;
T
y_min
;
T
x_max
;
T
y_max
;
// whether difficult object (e.g. object with heavy occlusion is difficult)
bool
is_difficult
;
};
template
<
typename
T
>
void
GetBBoxFromDetectData
(
const
T
*
detect_data
,
const
size_t
num_bboxes
,
std
::
vector
<
T
>&
labels
,
std
::
vector
<
T
>&
scores
,
std
::
vector
<
BBox
<
T
>>&
bboxes
)
{
size_t
out_offset
=
bboxes
.
size
();
labels
.
resize
(
out_offset
+
num_bboxes
);
scores
.
resize
(
out_offset
+
num_bboxes
);
bboxes
.
resize
(
out_offset
+
num_bboxes
);
for
(
size_t
i
=
0
;
i
<
num_bboxes
;
++
i
)
{
labels
[
out_offset
+
i
]
=
*
(
detect_data
+
i
*
7
+
1
);
scores
[
out_offset
+
i
]
=
*
(
detect_data
+
i
*
7
+
2
);
BBox
<
T
>
bbox
;
bbox
.
x_min
=
*
(
detect_data
+
i
*
7
+
3
);
bbox
.
y_min
=
*
(
detect_data
+
i
*
7
+
4
);
bbox
.
x_max
=
*
(
detect_data
+
i
*
7
+
5
);
bbox
.
y_max
=
*
(
detect_data
+
i
*
7
+
6
);
bboxes
[
out_offset
+
i
]
=
bbox
;
};
}
template
<
typename
T
>
void
GetBBoxFromLabelData
(
const
T
*
label_data
,
const
size_t
num_bboxes
,
std
::
vector
<
BBox
<
T
>>&
bboxes
)
{
size_t
out_offset
=
bboxes
.
size
();
bboxes
.
resize
(
bboxes
.
size
()
+
num_bboxes
);
for
(
size_t
i
=
0
;
i
<
num_bboxes
;
++
i
)
{
BBox
<
T
>
bbox
;
bbox
.
x_min
=
*
(
label_data
+
i
*
6
+
1
);
bbox
.
y_min
=
*
(
label_data
+
i
*
6
+
2
);
bbox
.
x_max
=
*
(
label_data
+
i
*
6
+
3
);
bbox
.
y_max
=
*
(
label_data
+
i
*
6
+
4
);
T
is_difficult
=
*
(
label_data
+
i
*
6
+
5
);
if
(
std
::
abs
(
is_difficult
-
0.0
)
<
1e-6
)
bbox
.
is_difficult
=
false
;
else
bbox
.
is_difficult
=
true
;
bboxes
[
out_offset
+
i
]
=
bbox
;
}
}
template
<
typename
T
>
inline
float
JaccardOverlap
(
const
BBox
<
T
>&
bbox1
,
const
BBox
<
T
>&
bbox2
)
{
if
(
bbox2
.
x_min
>
bbox1
.
x_max
||
bbox2
.
x_max
<
bbox1
.
x_min
||
bbox2
.
y_min
>
bbox1
.
y_max
||
bbox2
.
y_max
<
bbox1
.
y_min
)
{
return
0.0
;
}
else
{
float
inter_x_min
=
std
::
max
(
bbox1
.
x_min
,
bbox2
.
x_min
);
float
inter_y_min
=
std
::
max
(
bbox1
.
y_min
,
bbox2
.
y_min
);
float
inter_x_max
=
std
::
min
(
bbox1
.
x_max
,
bbox2
.
x_max
);
float
inter_y_max
=
std
::
min
(
bbox1
.
y_max
,
bbox2
.
y_max
);
float
inter_width
=
inter_x_max
-
inter_x_min
;
float
inter_height
=
inter_y_max
-
inter_y_min
;
float
inter_area
=
inter_width
*
inter_height
;
float
bbox_area1
=
bbox1
.
get_area
();
float
bbox_area2
=
bbox2
.
get_area
();
return
inter_area
/
(
bbox_area1
+
bbox_area2
-
inter_area
);
}
}
template
<
typename
T
>
bool
SortScorePairDescend
(
const
std
::
pair
<
float
,
T
>&
pair1
,
const
std
::
pair
<
float
,
T
>&
pair2
)
{
return
pair1
.
first
>
pair2
.
first
;
}
// template <>
// bool SortScorePairDescend(const std::pair<float, NormalizedBBox>& pair1,
// const std::pair<float, NormalizedBBox>& pair2) {
// return pair1.first > pair2.first;
// }
}
// namespace math
}
// namespace operators
}
// namespace paddle
python/paddle/v2/fluid/tests/test_detection_map_op.py
浏览文件 @
26f03ea1
...
...
@@ -10,14 +10,14 @@ class TestDetectionMAPOp(OpTest):
def
set_data
(
self
):
self
.
init_test_case
()
self
.
mAP
=
[
self
.
calc_map
(
self
.
tf_pos
)]
self
.
mAP
=
[
self
.
calc_map
(
self
.
tf_pos
,
self
.
tf_pos_lod
)]
self
.
label
=
np
.
array
(
self
.
label
).
astype
(
'float32'
)
self
.
detect
=
np
.
array
(
self
.
detect
).
astype
(
'float32'
)
self
.
mAP
=
np
.
array
(
self
.
mAP
).
astype
(
'float32'
)
self
.
inputs
=
{
'Label'
:
(
self
.
label
,
self
.
label_lod
),
'Detect
'
:
self
.
detect
'Detect
ion'
:
(
self
.
detect
,
self
.
detect_lod
)
}
self
.
attrs
=
{
...
...
@@ -31,29 +31,29 @@ class TestDetectionMAPOp(OpTest):
def
init_test_case
(
self
):
self
.
overlap_threshold
=
0.3
self
.
evaluate_difficult
=
True
self
.
ap_type
=
"
I
ntegral"
self
.
ap_type
=
"
i
ntegral"
self
.
label_lod
=
[[
0
,
2
,
4
]]
# label
xmin ymin xmax ymax difficult
self
.
label
=
[[
1
,
0
.1
,
0.1
,
0.3
,
0.3
,
0
],
[
1
,
0.6
,
0.6
,
0.8
,
0.8
,
1
],
[
2
,
0
.3
,
0.3
,
0.6
,
0.5
,
0
],
[
1
,
0.7
,
0.1
,
0.9
,
0.3
,
0
]]
# label
difficult xmin ymin xmax ymax
self
.
label
=
[[
1
,
0
,
0.1
,
0.1
,
0.3
,
0.3
],
[
1
,
1
,
0.6
,
0.6
,
0.8
,
0.8
],
[
2
,
0
,
0.3
,
0.3
,
0.6
,
0.5
],
[
1
,
0
,
0.7
,
0.1
,
0.9
,
0.3
]]
# image_id label score xmin ymin xmax ymax difficult
# label score xmin ymin xmax ymax difficult
self
.
detect_lod
=
[[
0
,
3
,
7
]]
self
.
detect
=
[
[
0
,
1
,
0.3
,
0.1
,
0.0
,
0.4
,
0.3
],
[
0
,
1
,
0.7
,
0.0
,
0.1
,
0.2
,
0.3
],
[
0
,
1
,
0.9
,
0.7
,
0.6
,
0.8
,
0.8
],
[
1
,
2
,
0.8
,
0.2
,
0.1
,
0.4
,
0.4
],
[
1
,
2
,
0.1
,
0.4
,
0.3
,
0.7
,
0.5
],
[
1
,
1
,
0.2
,
0.8
,
0.1
,
1.0
,
0.3
],
[
1
,
3
,
0.2
,
0.8
,
0.1
,
1.0
,
0.3
]
[
1
,
0.3
,
0.1
,
0.0
,
0.4
,
0.3
],
[
1
,
0.7
,
0.0
,
0.1
,
0.2
,
0.3
],
[
1
,
0.9
,
0.7
,
0.6
,
0.8
,
0.8
],
[
2
,
0.8
,
0.2
,
0.1
,
0.4
,
0.4
],
[
2
,
0.1
,
0.4
,
0.3
,
0.7
,
0.5
],
[
1
,
0.2
,
0.8
,
0.1
,
1.0
,
0.3
],
[
3
,
0.2
,
0.8
,
0.1
,
1.0
,
0.3
]
]
# image_id label score false_pos false_pos
# [-1, 1, 3, -1, -1],
# [-1, 2, 1, -1, -1]
self
.
tf_pos
=
[[
0
,
1
,
0.9
,
1
,
0
],
[
0
,
1
,
0.7
,
1
,
0
],
[
0
,
1
,
0.3
,
0
,
1
],
[
1
,
1
,
0.2
,
1
,
0
],
[
1
,
2
,
0.8
,
0
,
1
],
[
1
,
2
,
0.1
,
1
,
0
],
[
1
,
3
,
0.2
,
0
,
1
]]
# label score true_pos false_pos
self
.
tf_pos_lod
=
[[
0
,
3
,
7
]]
self
.
tf_pos
=
[[
1
,
0.9
,
1
,
0
],
[
1
,
0.7
,
1
,
0
],
[
1
,
0.3
,
0
,
1
],
[
1
,
0.2
,
1
,
0
],
[
2
,
0.8
,
0
,
1
],
[
2
,
0.1
,
1
,
0
],
[
3
,
0.2
,
0
,
1
]]
def
calc_map
(
self
,
tf_pos
):
def
calc_map
(
self
,
tf_pos
,
tf_pos_lod
):
mAP
=
0.0
count
=
0
...
...
@@ -71,7 +71,7 @@ class TestDetectionMAPOp(OpTest):
return
accu_list
label_count
=
collections
.
Counter
()
for
(
label
,
xmin
,
ymin
,
xmax
,
ymax
,
difficult
)
in
self
.
label
:
for
(
label
,
difficult
,
xmin
,
ymin
,
xmax
,
ymax
)
in
self
.
label
:
if
self
.
evaluate_difficult
:
label_count
[
label
]
+=
1
elif
not
difficult
:
...
...
@@ -79,7 +79,7 @@ class TestDetectionMAPOp(OpTest):
true_pos
=
collections
.
defaultdict
(
list
)
false_pos
=
collections
.
defaultdict
(
list
)
for
(
image_id
,
label
,
score
,
tp
,
fp
)
in
tf_pos
:
for
(
label
,
score
,
tp
,
fp
)
in
tf_pos
:
true_pos
[
label
].
append
([
score
,
tp
])
false_pos
[
label
].
append
([
score
,
fp
])
...
...
@@ -103,22 +103,22 @@ class TestDetectionMAPOp(OpTest):
recall
.
append
(
float
(
accu_tp_sum
[
i
])
/
label_pos_num
)
if
self
.
ap_type
==
"11point"
:
max_precisions
=
[
11.0
,
0.0
]
max_precisions
=
[
0.0
]
*
11
start_idx
=
len
(
accu_tp_sum
)
-
1
for
j
in
range
(
10
,
0
,
-
1
):
for
i
in
range
(
start_idx
,
0
,
-
1
):
if
recall
[
i
]
<
j
/
10.0
:
for
j
in
range
(
10
,
-
1
,
-
1
):
for
i
in
range
(
start_idx
,
-
1
,
-
1
):
if
recall
[
i
]
<
float
(
j
)
/
10.0
:
start_idx
=
i
if
j
>
0
:
max_precisions
[
j
-
1
]
=
max_precisions
[
j
]
break
else
:
if
max_precisions
[
j
]
<
accu_
precision
[
i
]:
max_precisions
[
j
]
=
accu_
precision
[
i
]
for
j
in
range
(
10
,
0
,
-
1
):
else
:
if
max_precisions
[
j
]
<
precision
[
i
]:
max_precisions
[
j
]
=
precision
[
i
]
for
j
in
range
(
10
,
-
1
,
-
1
):
mAP
+=
max_precisions
[
j
]
/
11
count
+=
1
elif
self
.
ap_type
==
"
I
ntegral"
:
elif
self
.
ap_type
==
"
i
ntegral"
:
average_precisions
=
0.0
prev_recall
=
0.0
for
i
in
range
(
len
(
accu_tp_sum
)):
...
...
@@ -147,8 +147,17 @@ class TestDetectionMAPOpSkipDiff(TestDetectionMAPOp):
self
.
evaluate_difficult
=
False
self
.
tf_pos
=
[[
0
,
1
,
0.7
,
1
,
0
],
[
0
,
1
,
0.3
,
0
,
1
],
[
1
,
1
,
0.2
,
1
,
0
],
[
1
,
2
,
0.8
,
0
,
1
],
[
1
,
2
,
0.1
,
1
,
0
],
[
1
,
3
,
0.2
,
0
,
1
]]
self
.
tf_pos_lod
=
[[
0
,
2
,
6
]]
# label score true_pos false_pos
self
.
tf_pos
=
[[
1
,
0.7
,
1
,
0
],
[
1
,
0.3
,
0
,
1
],
[
1
,
0.2
,
1
,
0
],
[
2
,
0.8
,
0
,
1
],
[
2
,
0.1
,
1
,
0
],
[
3
,
0.2
,
0
,
1
]]
class
TestDetectionMAPOp11Point
(
TestDetectionMAPOp
):
def
init_test_case
(
self
):
super
(
TestDetectionMAPOp11Point
,
self
).
init_test_case
()
self
.
ap_type
=
"11point"
if
__name__
==
'__main__'
:
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录