Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
s920243400
PaddleDetection
提交
d077c569
P
PaddleDetection
项目概览
s920243400
/
PaddleDetection
与 Fork 源项目一致
Fork自
PaddlePaddle / PaddleDetection
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleDetection
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
d077c569
编写于
11月 11, 2019
作者:
Y
Yang Zhang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add native implementation for soft nms
and refactor a bit
上级
17f7cbfa
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
260 addition
and
57 deletion
+260
-57
CMakeLists.txt
CMakeLists.txt
+31
-0
ppdet/modeling/ops.py
ppdet/modeling/ops.py
+70
-57
src/binding.cc
src/binding.cc
+74
-0
src/nms.cc
src/nms.cc
+85
-0
未找到文件。
CMakeLists.txt
0 → 100644
浏览文件 @
d077c569
cmake_minimum_required
(
VERSION 3.8 FATAL_ERROR
)
set
(
CMAKE_CXX_STANDARD 11
)
set
(
PYBIND11_CPP_STANDARD -std=c++11
)
include
(
FetchContent
)
FetchContent_Declare
(
pybind11
GIT_REPOSITORY
"https://github.com/pybind/pybind11.git"
)
FetchContent_GetProperties
(
pybind11
)
if
(
NOT pybind11_POPULATED
)
FetchContent_Populate
(
pybind11
)
add_subdirectory
(
${
pybind11_SOURCE_DIR
}
)
endif
()
set
(
nms_SOURCES src/binding.cc src/nms.cc
)
add_library
(
nms MODULE
${
nms_SOURCES
}
)
set_target_properties
(
nms PROPERTIES
CXX_VISIBILITY_PRESET
"hidden"
PREFIX
"
${
PYTHON_MODULE_PREFIX
}
"
SUFFIX
"
${
PYTHON_MODULE_EXTENSION
}
"
OUTPUT_NAME
"nms"
)
target_compile_options
(
nms BEFORE PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-g -O2 -fopenmp -mavx2>
)
target_link_libraries
(
nms PRIVATE -fopenmp
)
target_link_libraries
(
nms PRIVATE pybind11::module
)
execute_process
(
COMMAND
${
PYTHON_EXECUTABLE
}
"-c"
"import sysconfig; print(sysconfig.get_config_vars()['INCLUDEPY'])"
OUTPUT_VARIABLE PYTHON_INC_PATHS OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process
(
COMMAND
${
PYTHON_EXECUTABLE
}
"-c"
"import sysconfig; print(sysconfig.get_config_vars()['BLDLIBRARY'])"
OUTPUT_VARIABLE PYTHON_LIB_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process
(
COMMAND
${
PYTHON_EXECUTABLE
}
"-c"
"import sysconfig; print(sysconfig.get_config_vars().get('EXT_SUFFIX', 'so'))"
OUTPUT_VARIABLE EXT_SUFFIX OUTPUT_STRIP_TRAILING_WHITESPACE
)
install
(
TARGETS nms DESTINATION
${
CMAKE_HOME_DIRECTORY
}
/ppdet/modeling
)
ppdet/modeling/ops.py
浏览文件 @
d077c569
...
@@ -266,64 +266,82 @@ class MultiClassNMS(object):
...
@@ -266,64 +266,82 @@ class MultiClassNMS(object):
@
register
@
register
@
serializable
@
serializable
class
MultiClassSoftNMS
(
object
):
class
MultiClassSoftNMS
(
object
):
def
__init__
(
def
__init__
(
self
,
self
,
score_threshold
=
0.01
,
score_threshold
=
0.01
,
keep_top_k
=
300
,
keep_top_k
=
300
,
softnms_sigma
=
0.5
,
softnms_sigma
=
0.5
,
normalized
=
False
,
normalized
=
False
,
background_label
=
0
,
background_label
=
0
,
):
Nt
=
0.3
,
method
=
'gaussian'
,
use_cpp
=
False
):
super
(
MultiClassSoftNMS
,
self
).
__init__
()
super
(
MultiClassSoftNMS
,
self
).
__init__
()
self
.
score_threshold
=
score_threshold
self
.
score_threshold
=
score_threshold
self
.
keep_top_k
=
keep_top_k
self
.
keep_top_k
=
keep_top_k
self
.
softnms_sigma
=
softnms_sigma
self
.
softnms_sigma
=
softnms_sigma
self
.
normalized
=
normalized
self
.
normalized
=
normalized
self
.
background_label
=
background_label
self
.
background_label
=
background_label
self
.
Nt
=
Nt
methods
=
[
'gaussian'
,
'linear'
,
'hard'
]
assert
method
in
methods
,
"supported methods are "
+
str
(
methods
)
self
.
method
=
method
self
.
use_cpp
=
use_cpp
if
not
use_cpp
:
return
try
:
from
ppdet.modeling.nms
import
NMSMethod
,
soft_nms
self
.
method
=
getattr
(
NMSMethod
,
method
.
upper
())
self
.
soft_nms_native
=
soft_nms
except
ImportError
:
print
(
"nms native extension not found, please build it with"
+
"`cmake -B build . ; cmake --build build -t install`"
)
def
per_class_soft_nms
(
self
,
dets
):
"""soft_nms_for_cls"""
if
self
.
use_cpp
:
keep
,
_
=
self
.
soft_nms_native
(
dets
,
self
.
method
,
Nt
=
self
.
Nt
,
sigma
=
self
.
softnms_sigma
,
threshold
=
self
.
score_threshold
)
return
keep
dets_final
=
[]
while
len
(
dets
)
>
0
:
maxpos
=
np
.
argmax
(
dets
[:,
0
])
dets_final
.
append
(
dets
[
maxpos
].
copy
())
ts
,
tx1
,
ty1
,
tx2
,
ty2
=
dets
[
maxpos
]
scores
=
dets
[:,
0
]
# force remove bbox at maxpos
scores
[
maxpos
]
=
-
1
x1
=
dets
[:,
1
]
y1
=
dets
[:,
2
]
x2
=
dets
[:,
3
]
y2
=
dets
[:,
4
]
eta
=
0
if
self
.
normalized
else
1
areas
=
(
x2
-
x1
+
eta
)
*
(
y2
-
y1
+
eta
)
xx1
=
np
.
maximum
(
tx1
,
x1
)
yy1
=
np
.
maximum
(
ty1
,
y1
)
xx2
=
np
.
minimum
(
tx2
,
x2
)
yy2
=
np
.
minimum
(
ty2
,
y2
)
w
=
np
.
maximum
(
0.0
,
xx2
-
xx1
+
eta
)
h
=
np
.
maximum
(
0.0
,
yy2
-
yy1
+
eta
)
inter
=
w
*
h
ovr
=
inter
/
(
areas
+
areas
[
maxpos
]
-
inter
)
weight
=
np
.
exp
(
-
(
ovr
*
ovr
)
/
self
.
softnms_sigma
)
scores
=
scores
*
weight
idx_keep
=
np
.
where
(
scores
>=
self
.
score_threshold
)
dets
[:,
0
]
=
scores
dets
=
dets
[
idx_keep
]
dets_final
=
np
.
array
(
dets_final
).
reshape
(
-
1
,
5
)
return
dets_final
def
__call__
(
self
,
bboxes
,
scores
):
def
__call__
(
self
,
bboxes
,
scores
):
def
create_tmp_var
(
program
,
name
,
dtype
,
shape
,
lod_level
):
return
program
.
current_block
().
create_var
(
name
=
name
,
dtype
=
dtype
,
shape
=
shape
,
lod_level
=
lod_level
)
def
_soft_nms_for_cls
(
dets
,
sigma
,
thres
):
"""soft_nms_for_cls"""
dets_final
=
[]
while
len
(
dets
)
>
0
:
maxpos
=
np
.
argmax
(
dets
[:,
0
])
dets_final
.
append
(
dets
[
maxpos
].
copy
())
ts
,
tx1
,
ty1
,
tx2
,
ty2
=
dets
[
maxpos
]
scores
=
dets
[:,
0
]
# force remove bbox at maxpos
scores
[
maxpos
]
=
-
1
x1
=
dets
[:,
1
]
y1
=
dets
[:,
2
]
x2
=
dets
[:,
3
]
y2
=
dets
[:,
4
]
eta
=
0
if
self
.
normalized
else
1
areas
=
(
x2
-
x1
+
eta
)
*
(
y2
-
y1
+
eta
)
xx1
=
np
.
maximum
(
tx1
,
x1
)
yy1
=
np
.
maximum
(
ty1
,
y1
)
xx2
=
np
.
minimum
(
tx2
,
x2
)
yy2
=
np
.
minimum
(
ty2
,
y2
)
w
=
np
.
maximum
(
0.0
,
xx2
-
xx1
+
eta
)
h
=
np
.
maximum
(
0.0
,
yy2
-
yy1
+
eta
)
inter
=
w
*
h
ovr
=
inter
/
(
areas
+
areas
[
maxpos
]
-
inter
)
weight
=
np
.
exp
(
-
(
ovr
*
ovr
)
/
sigma
)
scores
=
scores
*
weight
idx_keep
=
np
.
where
(
scores
>=
thres
)
dets
[:,
0
]
=
scores
dets
=
dets
[
idx_keep
]
dets_final
=
np
.
array
(
dets_final
).
reshape
(
-
1
,
5
)
return
dets_final
def
_soft_nms
(
bboxes
,
scores
):
def
_soft_nms
(
bboxes
,
scores
):
bboxes
=
np
.
array
(
bboxes
)
bboxes
=
np
.
array
(
bboxes
)
scores
=
np
.
array
(
scores
)
scores
=
np
.
array
(
scores
)
class_nums
=
scores
.
shape
[
-
1
]
class_nums
=
scores
.
shape
[
-
1
]
softnms_thres
=
self
.
score_threshold
softnms_thres
=
self
.
score_threshold
softnms_sigma
=
self
.
softnms_sigma
keep_top_k
=
self
.
keep_top_k
keep_top_k
=
self
.
keep_top_k
cls_boxes
=
[[]
for
_
in
range
(
class_nums
)]
cls_boxes
=
[[]
for
_
in
range
(
class_nums
)]
...
@@ -339,10 +357,9 @@ class MultiClassSoftNMS(object):
...
@@ -339,10 +357,9 @@ class MultiClassSoftNMS(object):
cls_rank
=
np
.
argsort
(
-
dets_j
[:,
0
])
cls_rank
=
np
.
argsort
(
-
dets_j
[:,
0
])
dets_j
=
dets_j
[
cls_rank
]
dets_j
=
dets_j
[
cls_rank
]
cls_boxes
[
j
]
=
_soft_nms_for_cls
(
cls_boxes
[
j
]
=
self
.
per_class_soft_nms
(
dets_j
)
dets_j
,
sigma
=
softnms_sigma
,
thres
=
softnms_thres
)
cls_ids
[
j
]
=
np
.
array
(
cls_ids
[
j
]
=
np
.
array
([
j
]
*
cls_boxes
[
j
].
shape
[
0
]).
reshape
(
-
1
,
[
j
]
*
cls_boxes
[
j
].
shape
[
0
]).
reshape
(
-
1
,
1
)
1
)
cls_boxes
=
np
.
vstack
(
cls_boxes
[
start_idx
:])
cls_boxes
=
np
.
vstack
(
cls_boxes
[
start_idx
:])
cls_ids
=
np
.
vstack
(
cls_ids
[
start_idx
:])
cls_ids
=
np
.
vstack
(
cls_ids
[
start_idx
:])
...
@@ -360,17 +377,13 @@ class MultiClassSoftNMS(object):
...
@@ -360,17 +377,13 @@ class MultiClassSoftNMS(object):
if
pred_result
.
shape
[
0
]
==
0
:
if
pred_result
.
shape
[
0
]
==
0
:
pred_result
=
np
.
array
([[
1
]],
dtype
=
np
.
float32
)
pred_result
=
np
.
array
([[
1
]],
dtype
=
np
.
float32
)
res
.
set
(
pred_result
,
fluid
.
CPUPlace
())
res
.
set
(
pred_result
,
fluid
.
CPUPlace
())
return
res
return
res
pred_result
=
create_tmp_var
(
pred_result
=
fluid
.
default_main_program
().
current_block
().
create_var
(
fluid
.
default_main_program
(),
name
=
'softnms_pred_result'
,
dtype
=
'float32'
,
shape
=
[
6
],
name
=
'softnms_pred_result'
,
lod_leval
=
1
)
dtype
=
'float32'
,
fluid
.
layers
.
py_func
(
func
=
_soft_nms
,
shape
=
[
6
],
x
=
[
bboxes
,
scores
],
out
=
pred_result
)
lod_level
=
1
)
fluid
.
layers
.
py_func
(
func
=
_soft_nms
,
x
=
[
bboxes
,
scores
],
out
=
pred_result
)
return
pred_result
return
pred_result
...
...
src/binding.cc
0 → 100644
浏览文件 @
d077c569
#include <bits/stdc++.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
namespace
nms
{
enum
class
Method
:
uint32_t
{
LINEAR
=
0
,
GAUSSIAN
,
HARD
};
size_t
soft_nms
(
float
*
boxes
,
int32_t
*
index
,
size_t
count
,
Method
method
,
float
Nt
,
float
sigma
,
float
threshold
);
}
// namespace nms
namespace
binding
{
namespace
py
=
pybind11
;
using
namespace
pybind11
::
literals
;
py
::
tuple
py_soft_nms
(
py
::
array_t
<
float
,
py
::
array
::
c_style
>
boxes
,
nms
::
Method
method
=
nms
::
Method
::
GAUSSIAN
,
float
Nt
=
0.3
,
float
sigma
=
0.5
,
float
threshold
=
0.001
)
{
assert
(
boxes
.
ndim
()
==
2
&&
"Input should be 2-D NumPy array"
);
assert
(
boxes
.
shape
()[
1
]
==
5
&&
"Input should have size [N,5]"
);
auto
count
=
boxes
.
size
()
/
5
;
auto
i
=
new
int32_t
[
count
];
auto
b
=
new
float
[
boxes
.
size
()];
std
::
copy
(
boxes
.
data
(),
boxes
.
data
()
+
boxes
.
size
(),
b
);
auto
N
=
nms
::
soft_nms
(
b
,
i
,
count
,
method
,
Nt
,
sigma
,
threshold
);
std
::
vector
<
size_t
>
shape5
=
{
N
,
5
};
std
::
vector
<
size_t
>
shape1
=
{
N
};
std
::
vector
<
ssize_t
>
strides5
=
{
sizeof
(
float
)
*
5
,
sizeof
(
float
)};
std
::
vector
<
ssize_t
>
strides1
=
{
sizeof
(
float
)};
auto
cap_b
=
py
::
capsule
(
b
,
[](
void
*
v
)
{
delete
[]
reinterpret_cast
<
float
*>
(
v
);
});
auto
cap_i
=
py
::
capsule
(
i
,
[](
void
*
v
)
{
delete
[]
reinterpret_cast
<
int32_t
*>
(
v
);
});
auto
pyb
=
py
::
array
(
py
::
dtype
(
"float32"
),
shape5
,
strides5
,
b
,
cap_b
);
auto
pyi
=
py
::
array
(
py
::
dtype
(
"int32"
),
shape1
,
strides1
,
i
,
cap_i
);
return
py
::
make_tuple
(
pyb
,
pyi
);
}
PYBIND11_MODULE
(
nms
,
m
)
{
m
.
doc
()
=
"SoftNMS for object detection."
;
py
::
enum_
<
nms
::
Method
>
(
m
,
"NMSMethod"
)
.
value
(
"LINEAR"
,
nms
::
Method
::
LINEAR
)
.
value
(
"GAUSSIAN"
,
nms
::
Method
::
GAUSSIAN
)
.
value
(
"HARD"
,
nms
::
Method
::
HARD
)
.
export_values
();
m
.
def
(
"soft_nms"
,
&
py_soft_nms
,
"boxes"
_a
.
noconvert
(),
"method"
_a
=
nms
::
Method
::
GAUSSIAN
,
"Nt"
_a
=
0.3
,
"sigma"
_a
=
0.5
,
"threshold"
_a
=
0.001
);
}
}
/* namespace binding */
src/nms.cc
0 → 100644
浏览文件 @
d077c569
#include <bits/stdc++.h>
namespace
nms
{
struct
proposal
{
float
score
,
x1
,
y1
,
x2
,
y2
;
};
inline
static
bool
cmp
(
const
proposal
&
a
,
const
proposal
&
b
)
{
return
a
.
score
<
b
.
score
;
}
inline
static
float
iou
(
const
proposal
&
,
const
proposal
&
)
__attribute__
((
always_inline
));
static
float
iou
(
const
proposal
&
a
,
const
proposal
&
b
)
{
auto
overlap
=
0.
f
;
float
iw
=
std
::
min
(
b
.
x2
,
a
.
x2
)
-
std
::
max
(
b
.
x1
,
a
.
x1
)
+
1
;
if
(
iw
>
0
)
{
float
ih
=
std
::
min
(
b
.
y2
,
a
.
y2
)
-
std
::
max
(
b
.
y1
,
a
.
y1
)
+
1
;
if
(
ih
>
0
)
{
float
ab
=
(
b
.
x2
-
b
.
x1
+
1
)
*
(
b
.
y2
-
b
.
y1
+
1
);
float
aa
=
(
a
.
x2
-
a
.
x1
+
1
)
*
(
a
.
y2
-
a
.
y1
+
1
);
float
inter
=
iw
*
ih
;
overlap
=
inter
/
(
aa
+
ab
-
inter
);
}
}
return
overlap
;
}
enum
class
Method
:
uint32_t
{
LINEAR
=
0
,
GAUSSIAN
,
HARD
};
size_t
soft_nms
(
float
*
boxes
,
int32_t
*
index
,
size_t
count
,
Method
method
,
float
Nt
,
float
sigma
,
float
threshold
)
{
std
::
iota
(
index
,
index
+
count
,
0
);
// np.arange()
auto
p
=
reinterpret_cast
<
proposal
*>
(
boxes
);
auto
N
=
count
;
for
(
size_t
i
=
0
;
i
<
N
;
++
i
)
{
auto
max
=
std
::
max_element
(
p
+
i
,
p
+
N
,
cmp
);
std
::
swap
(
p
[
i
],
*
max
);
std
::
swap
(
index
[
i
],
index
[
max
-
p
]);
auto
j
=
i
+
1
;
auto
weight
=
0.
f
;
while
(
j
<
N
)
{
auto
ov
=
iou
(
p
[
i
],
p
[
j
]);
switch
(
method
)
{
case
Method
::
LINEAR
:
weight
=
ov
>
Nt
?
1.
f
-
ov
:
1.
f
;
break
;
case
Method
::
GAUSSIAN
:
weight
=
std
::
exp
(
-
(
ov
*
ov
)
/
sigma
);
break
;
case
Method
::
HARD
:
weight
=
ov
>
Nt
?
0.
f
:
1.
f
;
break
;
}
p
[
j
].
score
*=
weight
;
if
(
p
[
j
].
score
<
threshold
)
{
N
--
;
std
::
swap
(
p
[
j
],
p
[
N
]);
std
::
swap
(
index
[
j
],
index
[
N
]);
j
--
;
}
j
++
;
}
};
return
N
;
}
}
/* namespace nms */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录