Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
PaddleClas
提交
a1320ecf
P
PaddleClas
项目概览
PaddlePaddle
/
PaddleClas
1 年多 前同步成功
通知
116
Star
4999
Fork
1114
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
19
列表
看板
标记
里程碑
合并请求
6
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleClas
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
19
Issue
19
列表
看板
标记
里程碑
合并请求
6
合并请求
6
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
a1320ecf
编写于
3月 14, 2022
作者:
L
lubin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add faiss lib to do retrieval; upate reademe.md
上级
47c3b093
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
239 addition
and
32 deletion
+239
-32
deploy/lite_shitu/Makefile
deploy/lite_shitu/Makefile
+15
-4
deploy/lite_shitu/README.md
deploy/lite_shitu/README.md
+26
-13
deploy/lite_shitu/include/vector_search.h
deploy/lite_shitu/include/vector_search.h
+72
-0
deploy/lite_shitu/src/main.cc
deploy/lite_shitu/src/main.cc
+20
-15
deploy/lite_shitu/src/vector_search.cc
deploy/lite_shitu/src/vector_search.cc
+67
-0
deploy/lite_shitu/transform_id_map.py
deploy/lite_shitu/transform_id_map.py
+39
-0
未找到文件。
deploy/lite_shitu/Makefile
浏览文件 @
a1320ecf
...
...
@@ -30,6 +30,8 @@ OPENCV_LIBS = ${THIRD_PARTY_DIR}/${OPENCV_VERSION}/${ARM_PLAT}/libs/libopencv_im
${THIRD_PARTY_DIR}
/
${OPENCV_VERSION}
/
${ARM_PLAT}
/3rdparty/libs/libtbb.a
\
${THIRD_PARTY_DIR}
/
${OPENCV_VERSION}
/
${ARM_PLAT}
/3rdparty/libs/libcpufeatures.a
FAISS_VERSION
=
faiss1.5.3
FAISS_LIBS
=
${THIRD_PARTY_DIR}
/
${FAISS_VERSION}
/libs/
${ARM_PLAT}
/libfaiss.a
LITE_LIBS
=
-L
${LITE_ROOT}
/cxx/lib/
-lpaddle_light_api_shared
###############################################################
...
...
@@ -43,7 +45,7 @@ LITE_LIBS = -L${LITE_ROOT}/cxx/lib/ -lpaddle_light_api_shared
# 2. Undo comment below line using `libpaddle_api_light_bundled.a`
# LITE_LIBS = ${LITE_ROOT}/cxx/lib/libpaddle_api_light_bundled.a
CXX_LIBS
=
$(LITE_LIBS)
${OPENCV_LIBS}
$(SYSTEM_LIBS)
CXX_LIBS
=
$(LITE_LIBS)
${OPENCV_LIBS}
$
{FAISS_LIBS}
$
(SYSTEM_LIBS)
LOCAL_DIRSRCS
=
$(
wildcard
src/
*
.cc
)
LOCAL_SRCS
=
$(
notdir
$(LOCAL_DIRSRCS)
)
...
...
@@ -51,9 +53,17 @@ LOCAL_OBJS=$(patsubst %.cpp, %.o, $(patsubst %.cc, %.o, $(LOCAL_SRCS)))
JSON_OBJS
=
json_reader.o json_value.o json_writer.o
pp_shitu
:
$(LOCAL_OBJS) $(JSON_OBJS) fetch_opencv
pp_shitu
:
$(LOCAL_OBJS) $(JSON_OBJS) fetch_opencv
fetch_faiss
$(CC)
$(SYSROOT_LINK)
$(CXXFLAGS_LINK)
$(LOCAL_OBJS)
$(JSON_OBJS)
-o
pp_shitu
$(CXX_LIBS)
$(LDFLAGS)
fetch_faiss
:
@
test
-d
${THIRD_PARTY_DIR}
||
mkdir
${THIRD_PARTY_DIR}
@
test
-e
${THIRD_PARTY_DIR}
/
${FAISS_VERSION}
.tar.gz
||
\
(
echo
"fetch faiss libs"
&&
\
wget
-P
${THIRD_PARTY_DIR}
https://paddle-inference-dist.bj.bcebos.com/
${FAISS_VERSION}
.tar.gz
)
@
test
-d
${THIRD_PARTY_DIR}
/
${FAISS_VERSION}
||
\
tar
-xf
${THIRD_PARTY_DIR}
/
${FAISS_VERSION}
.tar.gz
-C
${THIRD_PARTY_DIR}
fetch_opencv
:
@
test
-d
${THIRD_PARTY_DIR}
||
mkdir
${THIRD_PARTY_DIR}
@
test
-e
${THIRD_PARTY_DIR}
/
${OPENCV_VERSION}
.tar.gz
||
\
...
...
@@ -72,11 +82,12 @@ fetch_json_code:
LOCAL_INCLUDES
=
-I
./
-Iinclude
OPENCV_INCLUDE
=
-I
${THIRD_PARTY_DIR}
/
${OPENCV_VERSION}
/
${ARM_PLAT}
/include
FAISS_INCLUDE
=
-I
${THIRD_PARTY_DIR}
/
${FAISS_VERSION}
/include
JSON_INCLUDE
=
-I
${THIRD_PARTY_DIR}
/jsoncpp_code/include
CXX_INCLUDES
=
${LOCAL_INCLUDES}
${INCLUDES}
${OPENCV_INCLUDE}
${JSON_INCLUDE}
-I
$(LITE_ROOT)
/cxx/include
CXX_INCLUDES
=
${LOCAL_INCLUDES}
${INCLUDES}
${OPENCV_INCLUDE}
${
FAISS_INCLUDE}
${
JSON_INCLUDE}
-I
$(LITE_ROOT)
/cxx/include
$(LOCAL_OBJS)
:
%.o: src/%.cc fetch_opencv fetch_json_code
$(LOCAL_OBJS)
:
%.o: src/%.cc fetch_opencv fetch_json_code
fetch_faiss
$(CC)
$(SYSROOT_COMPLILE)
$(CXX_DEFINES)
$(CXX_INCLUDES)
$(CXX_FLAGS)
-c
$<
-o
$@
$(JSON_OBJS)
:
%.o: ${THIRD_PARTY_DIR}/jsoncpp_code/%.cpp fetch_json_code
...
...
deploy/lite_shitu/README.md
浏览文件 @
a1320ecf
...
...
@@ -92,9 +92,9 @@ PaddleClas 提供了转换并优化后的推理模型,可以直接参考下方
```
shell
# 进入lite_ppshitu目录
cd
$PaddleClas
/deploy/lite_shitu
wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/lite/ppshitu_lite_models_v1.0.tar
tar
-xf
ppshitu_lite_models_v1.0.tar
rm
-f
ppshitu_lite_models_v1.0.tar
wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/lite/ppshitu_lite_models_v1.0.tar
.gz
tar
-xf
ppshitu_lite_models_v1.0.tar
.gz
rm
-f
ppshitu_lite_models_v1.0.tar
.gz
```
#### 2.1.2 使用其他模型
...
...
@@ -191,16 +191,28 @@ cd deploy/lite_shitu
```
shell
# 如果测试单张图像
python generate_json_config.py
--det_model_path
ppshitu_lite_models_v1.0/mainbody_PPLCNet_x2_5_640_quant_v1.0_lite.nb
--rec_model_path
ppshitu_lite_models_v1.0/general_PPLCNet_x2_5_
quant_v1.0_lite.nb
--rec_label_path
ppshitu_lite_models_v1.0/label.txt
--img_path
images/demo.jpg
python generate_json_config.py
--det_model_path
ppshitu_lite_models_v1.0/mainbody_PPLCNet_x2_5_640_quant_v1.0_lite.nb
--rec_model_path
ppshitu_lite_models_v1.0/general_PPLCNet_x2_5_
lite_v1.0_infer.nb
--img_path
images/demo.jpg
# or
# 如果测试多张图像
python generate_json_config.py
--det_model_path
ppshitu_lite_models_v1.0/mainbody_PPLCNet_x2_5_640_quant_v1.0_lite.nb
--rec_model_path
ppshitu_lite_models_v1.0/general_PPLCNet_x2_5_quant_v1.0_lite.nb
--rec_label_path
ppshitu_lite_models_v1.0/label.txt
--img_dir
images
python generate_json_config.py
--det_model_path
ppshitu_lite_models_v1.0/mainbody_PPLCNet_x2_5_640_quant_v1.0_lite.nb
--rec_model_path
ppshitu_lite_models_v1.0/general_PPLCNet_x2_5_lite_v1.0_infer.nb
--img_dir
images
# 执行完成后,会在lit_shitu下生成shitu_config.json配置文件
```
### 2.3 index字典转换
由于python的检索库字典,使用
`pickle`
进行的序列化存储,导致C++不方便读取,因此需要进行转换
```
shell
# 下载瓶装饮料数据集
wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/data/drink_dataset_v1.0.tar
&&
tar
-xf
drink_dataset_v1.0.tar
rm
-rf
drink_dataset_v1.0.tar
# 转化id_map.pkl为id_map.txt
python transform_id_map.py
-c
../configs/inference_drink.yaml
```
转换成功后,会在
`IndexProcess.index_dir`
目录下生成
`id_map.txt`
。
### 2.
3
与手机联调
### 2.
4
与手机联调
首先需要进行一些准备工作。
1.
准备一台arm8的安卓手机,如果编译的预测库是armv7,则需要arm7的手机,并修改Makefile中
`ARM_ABI=arm7`
。
...
...
@@ -252,6 +264,7 @@ make ARM_ABI=arm8
```
shell
mkdir
deploy
mv
ppshitu_lite_models_v1.0 deploy/
mv
drink_dataset_v1.0 deploy/
mv
images deploy/
mv
shitu_config.json deploy/
cp
pp_shitu deploy/
...
...
@@ -265,12 +278,12 @@ cp ../../../cxx/lib/libpaddle_light_api_shared.so deploy/
```
shell
deploy/
|-- ppshitu_lite_models_v1.0/
| |--mainbody_PPLCNet_x2_5_640_v1.0_lite.nb 优化后的主体检测模型文件
| |--general_PPLCNet_x2_5_quant_v1.0_lite.nb 优化后的识别模型文件
| |--label.txt 识别模型的label文件
| |--mainbody_PPLCNet_x2_5_lite_v1.0_infer.nb 优化后的主体检测模型文件
| |--general_PPLCNet_x2_5_quant_v1.0_lite.nb 优化后的识别模型文件
|-- images/
| |--demo.jpg 图片文件
| ... 图片文件
|-- drink_dataset_v1/ 瓶装饮料demo数据
| |--index 检索index目录
|-- pp_shitu 生成的移动端执行文件
|-- shitu_config.json 执行时参数配置文件
|-- libpaddle_light_api_shared.so Paddle-Lite库文件
...
...
@@ -298,8 +311,8 @@ chmod 777 pp_shitu
如果对代码做了修改,则需要重新编译并push到手机上。
运行效果如下:
![](
../../docs/images/ppshitu_lite_demo.png
)
```
```
`
## FAQ
Q1:如果想更换模型怎么办,需要重新按照流程走一遍吗?
...
...
deploy/lite_shitu/include/vector_search.h
0 → 100644
浏览文件 @
a1320ecf
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// 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
#ifdef WIN32
#define OS_PATH_SEP "\\"
#else
#define OS_PATH_SEP "/"
#endif
#include "json/json.h"
#include <cstring>
#include <faiss/Index.h>
#include <faiss/index_io.h>
#include <map>
namespace
PPShiTu
{
struct
SearchResult
{
std
::
vector
<
faiss
::
Index
::
idx_t
>
I
;
std
::
vector
<
float
>
D
;
int
return_k
;
};
class
VectorSearch
{
public:
explicit
VectorSearch
(
const
Json
::
Value
&
config
)
{
// IndexProcess
this
->
index_dir
=
config
[
"IndexProcess"
][
"index_dir"
].
as
<
std
::
string
>
();
this
->
return_k
=
config
[
"IndexProcess"
][
"return_k"
].
as
<
int
>
();
this
->
score_thres
=
config
[
"IndexProcess"
][
"score_thres"
].
as
<
float
>
();
this
->
max_query_number
=
config
[
"Global"
][
"max_det_results"
].
as
<
int
>
()
+
1
;
LoadIdMap
();
LoadIndexFile
();
this
->
I
.
resize
(
this
->
return_k
*
this
->
max_query_number
);
this
->
D
.
resize
(
this
->
return_k
*
this
->
max_query_number
);
};
void
LoadIdMap
();
void
LoadIndexFile
();
const
SearchResult
&
Search
(
float
*
feature
,
int
query_number
);
const
std
::
string
&
GetLabel
(
faiss
::
Index
::
idx_t
ind
);
const
float
&
GetThreshold
()
{
return
this
->
score_thres
;
}
private:
std
::
string
index_dir
;
int
return_k
=
5
;
float
score_thres
=
0.5
;
std
::
map
<
long
int
,
std
::
string
>
id_map
;
faiss
::
Index
*
index
;
int
max_query_number
=
6
;
std
::
vector
<
float
>
D
;
std
::
vector
<
faiss
::
Index
::
idx_t
>
I
;
SearchResult
sr
;
};
}
deploy/lite_shitu/src/main.cc
浏览文件 @
a1320ecf
...
...
@@ -24,9 +24,10 @@
#include <vector>
#include "include/config_parser.h"
#include "include/feature_extractor.h"
#include "include/object_detector.h"
#include "include/preprocess_op.h"
#include "include/
feature_extractor
.h"
#include "include/
vector_search
.h"
#include "json/json.h"
Json
::
Value
RT_Config
;
...
...
@@ -111,14 +112,18 @@ void DetPredictImage(const std::vector<cv::Mat> &batch_imgs,
}
}
void
PrintResult
(
const
std
::
string
&
image_path
,
std
::
vector
<
PPShiTu
::
ObjectResult
>
&
det_result
)
{
printf
(
"%s:
\n
"
,
image_path
.
c_str
());
void
PrintResult
(
std
::
string
&
img_path
,
std
::
vector
<
PPShiTu
::
ObjectResult
>
&
det_result
,
PPShiTu
::
VectorSearch
&
vector_search
,
PPShiTu
::
SearchResult
&
search_result
)
{
printf
(
"%s:
\n
"
,
img_path
.
c_str
());
for
(
int
i
=
0
;
i
<
det_result
.
size
();
++
i
)
{
int
t
=
i
;
printf
(
"
\t
result%d: bbox[%d, %d, %d, %d], score: %f, label: %s
\n
"
,
i
,
det_result
[
i
].
rect
[
0
],
det_result
[
i
].
rect
[
1
],
det_result
[
i
].
rect
[
2
],
det_result
[
i
].
rect
[
3
],
det_result
[
i
].
rec_result
[
0
].
score
,
det_result
[
i
].
rec_result
[
0
].
class_name
.
c_str
());
det_result
[
t
].
rect
[
0
],
det_result
[
t
].
rect
[
1
],
det_result
[
t
].
rect
[
2
],
det_result
[
t
].
rect
[
3
],
det_result
[
t
].
confidence
,
vector_search
.
GetLabel
(
search_result
.
I
[
search_result
.
return_k
*
t
])
.
c_str
());
}
}
...
...
@@ -160,12 +165,13 @@ int main(int argc, char **argv) {
RT_Config
[
"Global"
][
"batch_size"
].
as
<
int
>
());
// create rec model
PPShiTu
::
FeatureExtract
rec
(
RT_Config
);
PPShiTu
::
VectorSearch
searcher
(
RT_Config
);
// Do inference on input image
std
::
vector
<
PPShiTu
::
ObjectResult
>
det_result
;
std
::
vector
<
cv
::
Mat
>
batch_imgs
;
//for vector search
//
for vector search
std
::
vector
<
float
>
feature
;
std
::
vector
<
float
>
features
;
double
rec_time
;
...
...
@@ -182,8 +188,7 @@ int main(int argc, char **argv) {
return
-
1
;
}
}
else
{
cv
::
glob
(
img_dir
,
cv_all_img_paths
);
cv
::
glob
(
img_dir
,
cv_all_img_paths
);
for
(
const
auto
&
img_path
:
cv_all_img_paths
)
{
all_img_paths
.
push_back
(
img_path
);
}
...
...
@@ -208,6 +213,7 @@ int main(int argc, char **argv) {
det_result
.
push_back
(
result_whole_img
);
// get rec result
PPShiTu
::
SearchResult
search_result
;
for
(
int
j
=
0
;
j
<
det_result
.
size
();
++
j
)
{
int
w
=
det_result
[
j
].
rect
[
2
]
-
det_result
[
j
].
rect
[
0
];
int
h
=
det_result
[
j
].
rect
[
3
]
-
det_result
[
j
].
rect
[
1
];
...
...
@@ -217,11 +223,10 @@ int main(int argc, char **argv) {
features
.
insert
(
features
.
end
(),
feature
.
begin
(),
feature
.
end
());
}
std
::
cout
<<
"feature len is: "
<<
features
.
size
()
<<
std
::
endl
;
// rec nms
// PPShiTu::nms(det_result,
// RT_Config["Global"]["rec_nms_thresold"].as<float>(), true);
// PrintResult(img_path, det_result);
// do vectore search
search_result
=
searcher
.
Search
(
features
.
data
(),
det_result
.
size
());
PrintResult
(
img_path
,
det_result
,
searcher
,
search_result
);
batch_imgs
.
clear
();
det_result
.
clear
();
}
...
...
deploy/lite_shitu/src/vector_search.cc
0 → 100644
浏览文件 @
a1320ecf
// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// 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 "include/vector_search.h"
#include <cstdio>
#include <faiss/index_io.h>
#include <fstream>
#include <iostream>
#include <regex>
namespace
PPShiTu
{
// load the vector.index
void
VectorSearch
::
LoadIndexFile
()
{
std
::
string
file_path
=
this
->
index_dir
+
OS_PATH_SEP
+
"vector.index"
;
const
char
*
fname
=
file_path
.
c_str
();
this
->
index
=
faiss
::
read_index
(
fname
,
0
);
}
// load id_map.txt
void
VectorSearch
::
LoadIdMap
()
{
std
::
string
file_path
=
this
->
index_dir
+
OS_PATH_SEP
+
"id_map.txt"
;
std
::
ifstream
in
(
file_path
);
std
::
string
line
;
std
::
vector
<
std
::
string
>
m_vec
;
if
(
in
)
{
while
(
getline
(
in
,
line
))
{
std
::
regex
ws_re
(
"
\\
s+"
);
std
::
vector
<
std
::
string
>
v
(
std
::
sregex_token_iterator
(
line
.
begin
(),
line
.
end
(),
ws_re
,
-
1
),
std
::
sregex_token_iterator
());
if
(
v
.
size
()
!=
2
)
{
std
::
cout
<<
"The number of element for each line in : "
<<
file_path
<<
"must be 2, exit the program..."
<<
std
::
endl
;
exit
(
1
);
}
else
this
->
id_map
.
insert
(
std
::
pair
<
long
int
,
std
::
string
>
(
std
::
stol
(
v
[
0
],
nullptr
,
10
),
v
[
1
]));
}
}
}
// doing search
const
SearchResult
&
VectorSearch
::
Search
(
float
*
feature
,
int
query_number
)
{
this
->
D
.
resize
(
this
->
return_k
*
query_number
);
this
->
I
.
resize
(
this
->
return_k
*
query_number
);
this
->
index
->
search
(
query_number
,
feature
,
return_k
,
D
.
data
(),
I
.
data
());
this
->
sr
.
return_k
=
this
->
return_k
;
this
->
sr
.
D
=
this
->
D
;
this
->
sr
.
I
=
this
->
I
;
return
this
->
sr
;
}
const
std
::
string
&
VectorSearch
::
GetLabel
(
faiss
::
Index
::
idx_t
ind
)
{
return
this
->
id_map
.
at
(
ind
);
}
}
\ No newline at end of file
deploy/lite_shitu/transform_id_map.py
0 → 100644
浏览文件 @
a1320ecf
import
argparse
import
os
import
pickle
import
yaml
def
parse_args
():
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'-c'
,
'--config'
,
type
=
str
,
required
=
True
)
args
=
parser
.
parse_args
()
return
args
def
main
():
args
=
parse_args
()
with
open
(
args
.
config
)
as
fd
:
config
=
yaml
.
load
(
fd
.
read
(),
yaml
.
FullLoader
)
index_dir
=
""
try
:
index_dir
=
config
[
"IndexProcess"
][
"index_dir"
]
except
Exception
as
e
:
print
(
"The IndexProcess.index_dir in config_file dose not exist"
)
exit
(
1
)
id_map_path
=
os
.
path
.
join
(
index_dir
,
"id_map.pkl"
)
assert
os
.
path
.
exists
(
id_map_path
),
"The id_map file dose not exist: {}"
.
format
(
id_map_path
)
with
open
(
id_map_path
,
"rb"
)
as
fd
:
ids
=
pickle
.
load
(
fd
)
with
open
(
os
.
path
.
join
(
index_dir
,
"id_map.txt"
),
"w"
)
as
fd
:
for
k
,
v
in
ids
.
items
():
v
=
v
.
split
(
"
\t
"
)[
1
]
fd
.
write
(
str
(
k
)
+
" "
+
v
+
"
\n
"
)
print
(
'Transform id_map sucess'
)
if
__name__
==
"__main__"
:
main
()
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录