Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
PaddleSeg
提交
23a4a62d
P
PaddleSeg
项目概览
PaddlePaddle
/
PaddleSeg
通知
285
Star
8
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
53
列表
看板
标记
里程碑
合并请求
3
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleSeg
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
53
Issue
53
列表
看板
标记
里程碑
合并请求
3
合并请求
3
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
23a4a62d
编写于
8月 27, 2019
作者:
Z
zhoushunjie
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
first commit to github project
上级
8447ec77
变更
9
显示空白变更内容
内联
并排
Showing
9 changed file
with
374 addition
and
218 deletion
+374
-218
serving/COMPILE_GUIDE.md
serving/COMPILE_GUIDE.md
+3
-91
serving/README.md
serving/README.md
+160
-19
serving/UBUNTU.md
serving/UBUNTU.md
+76
-0
serving/seg-serving/conf/gflags.conf
serving/seg-serving/conf/gflags.conf
+3
-0
serving/seg-serving/conf/model_toolkit.prototxt
serving/seg-serving/conf/model_toolkit.prototxt
+1
-1
serving/seg-serving/op/image_seg_op.cpp
serving/seg-serving/op/image_seg_op.cpp
+18
-4
serving/seg-serving/op/reader_op.cpp
serving/seg-serving/op/reader_op.cpp
+2
-1
serving/seg-serving/op/write_json_op.cpp
serving/seg-serving/op/write_json_op.cpp
+2
-1
serving/tools/image_seg_client.py
serving/tools/image_seg_client.py
+109
-101
未找到文件。
serving/COMPILE_GUIDE.md
浏览文件 @
23a4a62d
# 源码编译安装及搭建服务流程
本文将介绍源码编译安装以及在服务搭建流程。
本文将介绍源码编译安装以及在服务搭建流程。
编译前确保PaddleServing的依赖项安装完毕。依赖安装教程请前往
[
PaddleSegServing 依赖安装
](
./README.md
)
.
## 1. 系统依赖项
依赖项 | 验证过的版本
-- | --
Linux | Centos 6.10 / 7
CMake | 3.0+
GCC | 4.8.2/5.4.0
Python| 2.7
GO编译器| 1.9.2
openssl| 1.0.1+
bzip2 | 1.0.6+
如果需要使用GPU预测,还需安装以下几个依赖库
GPU库 | 验证过的版本
-- | --
CUDA | 9.2
cuDNN | 7.1.4
nccl | 2.4.7
## 2. 安装依赖项
以下流程在百度云CentOS7.5+CUDA9.2环境下进行。
### 2.1. 安装openssl、Go编译器以及bzip2
```
bash
yum
-y
install
openssl openssl-devel golang bzip2-libs bzip2-devel
```
### 2.2. 安装GPU预测的依赖项(如果需要使用GPU预测,必须执行此步骤)
#### 2.2.1. 安装配置CUDA9.2以及cuDNN 7.1.4
该百度云机器已经安装CUDA以及cuDNN,仅需复制相关头文件与链接库
```
bash
# 看情况确定是否需要安装 cudnn
# 进入 cudnn 根目录
cd
/home/work/cudnn/cudnn7.1.4
# 拷贝头文件
cp
include/cudnn.h /usr/local/cuda/include/
# 拷贝链接库
cp
lib64/libcudnn
*
/usr/local/cuda/lib64/
# 修改头文件、链接库访问权限
chmod
a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn
*
```
#### 2.2.2. 安装nccl库
```
bash
# 下载文件 nccl-repo-rhel7-2.4.7-ga-cuda9.2-1-1.x86_64.rpm
wget
-c
https://paddlehub.bj.bcebos.com/serving/nccl-repo-rhel7-2.4.7-ga-cuda9.2-1-1.x86_64.rpm
# 安装nccl的repo
rpm
-i
nccl-repo-rhel7-2.4.7-ga-cuda9.2-1-1.x86_64.rpm
# 更新索引
yum
-y
update
# 安装包
yum
-y
install
libnccl-2.4.7-1+cuda9.2 libnccl-devel-2.4.7-1+cuda9.2 libnccl-static-2.4.7-1+cuda9.2
```
### 2.3. 安装 cmake 3.15
如果机器没有安装cmake或者已安装cmake的版本低于3.0,请执行以下步骤
```
bash
# 如果原来的已经安装低于3.0版本的cmake,请先卸载原有低版本 cmake
yum
-y
remove cmake
# 下载源代码并解压
wget
-c
https://github.com/Kitware/CMake/releases/download/v3.15.0/cmake-3.15.0.tar.gz
tar
xvfz cmake-3.15.0.tar.gz
# 编译cmake
cd
cmake-3.15.0
./configure
make
-j4
# 安装并检查cmake版本
make
install
cmake
--version
# 在cmake-3.15.0目录中,将相应的头文件目录(curl目录,为PaddleServing的依赖头文件目录)拷贝到系统include目录下
cp
-r
Utilities/cmcurl/include/curl/ /usr/include/
```
### 2.4. 为依赖库增加相应的软连接
现在Linux系统中大部分链接库的名称都以版本号作为后缀,如libcurl.so.4.3.0。这种命名方式最大的问题是,CMakeList.txt中find_library命令是无法识别使用这种命名方式的链接库,会导致CMake时候出错。由于本项目是用CMake构建,所以务必保证相应的链接库以 .so 或 .a为后缀命名。解决这个问题最简单的方式就是用创建一个软连接指向相应的链接库。在百度云的机器中,只有curl库的命名方式有问题。所以命令如下:(如果是其他库,解决方法也类似):
```
bash
ln
-s
/usr/lib64/libcurl.so.4.3.0 /usr/lib64/libcurl.so
```
### 2.5. 编译安装PaddleServing
## 1. 编译安装PaddleServing
下列步骤介绍CPU版本以及GPU版本的PaddleServing编译安装过程。
```
bash
...
...
@@ -134,7 +46,7 @@ serving
└── tools
```
##
# 2.6
. 安装PaddleSegServing
##
2
. 安装PaddleSegServing
```
bash
# Step 1. 在~目录下下载PaddleSeg代码
...
...
serving/README.md
浏览文件 @
23a4a62d
# PaddleSeg
Serving
# PaddleSegServing
## 1.简介
PaddleSegServing是基于PaddleSeg开发的实时图像分割服务的企业级解决方案。用户仅需关注模型本身,无需理解模型模型的加载、预测以及GPU/CPU资源的并发调度等细节操作,通过设置不同的参数配置,即可根据自身的业务需求定制化不同图像分割服务。目前,PaddleSegServing支持人脸分割、城市道路分割、宠物外形分割模型。本文将通过一个人脸分割服务的搭建示例,展示PaddleSeg服务通用的搭建流程。
## 2.预编译版本安装及搭建服务流程
### 2.1. 下载预编译的PaddleSegServing
运行PaddleSegServing需要依赖其他的链接库,请保证在下载安装前系统环境已经具有相应的依赖项。
安装以及搭建服务的流程均在Centos和Ubuntu系统上验证。以下是Centos系统上的搭建流程,Ubuntu版本的依赖项安装流程介绍在
[
Ubuntu系统下依赖项的安装教程
](
UBUNTU.md
)
。
### 2.1. 系统依赖项
依赖项 | 验证过的版本
-- | --
Linux | Centos 6.10 / 7, Ubuntu16.07
CMake | 3.0+
GCC | 4.8.2
Python| 2.7
GO编译器| 1.9.2
openssl| 1.0.1+
bzip2 | 1.0.6+
如果需要使用GPU预测,还需安装以下几个依赖库
GPU库 | 验证过的版本
-- | --
CUDA | 9.2
cuDNN | 7.1.4
nccl | 2.4.7
### 2.2. 安装依赖项
#### 2.2.1. 安装openssl、Go编译器以及bzip2
```
bash
yum
-y
install
openssl openssl-devel golang bzip2-libs bzip2-devel
```
#### 2.2.2. 安装GPU预测的依赖项(如果需要使用GPU预测,必须执行此步骤)
#### 2.2.2.1. 安装配置CUDA9.2以及cuDNN 7.1.4
该百度云机器已经安装CUDA以及cuDNN,仅需复制相关头文件与链接库(具体目录以自己测试的机器为准) 。
```
bash
# 看情况确定是否需要安装 cudnn
# 进入 cudnn 根目录
cd
/home/work/cudnn/cudnn7.1.4
# 拷贝头文件
cp
include/cudnn.h /usr/local/cuda/include/
# 拷贝链接库
cp
lib64/libcudnn
*
/usr/local/cuda/lib64/
# 修改头文件、链接库访问权限
chmod
a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn
*
```
#### 2.2.2.2. 安装nccl库
```
bash
# 下载文件 nccl-repo-rhel7-2.4.7-ga-cuda9.2-1-1.x86_64.rpm
wget
-c
https://paddlehub.bj.bcebos.com/serving/nccl-repo-rhel7-2.4.7-ga-cuda9.2-1-1.x86_64.rpm
# 安装nccl的repo
rpm
-i
nccl-repo-rhel7-2.4.7-ga-cuda9.2-1-1.x86_64.rpm
# 更新索引
yum
-y
update
# 安装包
yum
-y
install
libnccl-2.4.7-1+cuda9.2 libnccl-devel-2.4.7-1+cuda9.2 libnccl-static-2.4.7-1+cuda9.2
```
### 2.2.3. 安装 cmake 3.15
如果机器没有安装cmake或者已安装cmake的版本低于3.0,请执行以下步骤
```
bash
# 如果原来的已经安装低于3.0版本的cmake,请先卸载原有低版本 cmake
yum
-y
remove cmake
# 下载源代码并解压
wget
-c
https://github.com/Kitware/CMake/releases/download/v3.15.0/cmake-3.15.0.tar.gz
tar
xvfz cmake-3.15.0.tar.gz
# 编译cmake
cd
cmake-3.15.0
./configure
make
-j4
# 安装并检查cmake版本
make
install
cmake
--version
# 在cmake-3.15.0目录中,将相应的头文件目录(curl目录,为PaddleServing的依赖头文件目录)拷贝到系统include目录下
cp
-r
Utilities/cmcurl/include/curl/ /usr/include/
```
### 2.2.4. 为依赖库增加相应的软连接
现在Linux系统中大部分链接库的名称都以版本号作为后缀,如libcurl.so.4.3.0。这种命名方式最大的问题是,CMakeList.txt中find_library命令是无法识别使用这种命名方式的链接库,会导致CMake时候出错。由于本项目是用CMake构建,所以务必保证相应的链接库以 .so 或 .a为后缀命名。解决这个问题最简单的方式就是用创建一个软连接指向相应的链接库。在百度云的机器中,只有curl库的命名方式有问题。所以命令如下:(如果是其他库,解决方法也类似):
```
bash
ln
-s
/usr/lib64/libcurl.so.4.3.0 /usr/lib64/libcurl.so
```
### 2.3. 下载预编译的PaddleSegServing
预编译版本在Centos7.6系统下编译,如果想快速体验PaddleSegServing,可在此系统下下载预编译版本进行安装。预编译版本有两个,一个是针对有GPU的机器,推荐安装GPU版本PaddleSegServing。另一个是CPU版本PaddleServing,针对无GPU的机器。
#### 2.
1
.1. 下载并解压GPU版本PaddleSegServing
#### 2.
3
.1. 下载并解压GPU版本PaddleSegServing
```
bash
# TODO:修改链接
cd
~
wget
-c
XXXX/PaddleSegServing.centos7.6_cuda9.2_gpu.tar.gz
tar
xvfz PaddleSegServing.centos7.6_cuda9.2_gpu.tar.gz
tar
xvfz PaddleSegServing.centos7.6_cuda9.2_gpu.tar.gz
seg-serving
```
#### 2.
1
.2. 下载并解压CPU版本PaddleSegServing
#### 2.
3
.2. 下载并解压CPU版本PaddleSegServing
```
bash
# TODO:修改链接
cd
~
wget
-c
XXXX/PaddleSegServing.centos7.6_cuda9.2_cpu.tar.gz
tar
xvfz PaddleSegServing.centos7.6_cuda9.2_gpu.tar.gz
tar
xvfz PaddleSegServing.centos7.6_cuda9.2_gpu.tar.gz
seg-serving
```
解压后的PaddleSegServing目录如下。
...
...
@@ -36,13 +124,22 @@ tar xvfz PaddleSegServing.centos7.6_cuda9.2_gpu.tar.gz
└── log
```
### 2.2. 运行PaddleSegServing
### 2.4 安装动态库
把 libiomp5.so, libmklml_gnu.so, libmklml_intel.so拷贝到/usr/lib。
```
bash
cd
seg-serving/bin/
cp
libiomp5.so libmklml_gnu.so libmklml_intel.so /usr/lib
```
### 2.5. 运行PaddleSegServing
本节将介绍如何运行以及测试PaddleSegServing。
#### 2.
2
.1. 搭建人脸分割服务
#### 2.
5
.1. 搭建人脸分割服务
搭建人脸分割服务只需完成一些配置文件的编写即可,其他分割服务的搭建流程类似。
##### 2.
2
.1.1. 下载人脸分割模型文件,并将其复制到相应目录。
##### 2.
5
.1.1. 下载人脸分割模型文件,并将其复制到相应目录。
```
bash
# 下载人脸分割模型
wget
-c
https://paddleseg.bj.bcebos.com/inference_model/deeplabv3p_xception65_humanseg.tgz
...
...
@@ -52,11 +149,7 @@ cp -r deeplabv3p_xception65_humanseg seg-serving/bin/data/model/paddle/fluid
```
##### 2.2.1.2. 配置参数文件
参数文件如,PaddleSegServing仅新增一个配置文件seg_conf.yaml,用来指定具体分割模型的一些参数,如均值、方差、图像尺寸等。该配置文件可在gflags.conf中通过--seg_conf_file指定。
其他配置文件的字段解释可参考以下链接:https://github.com/PaddlePaddle/Serving/blob/develop/doc/SERVING_CONFIGURE.md (TODO:介绍seg_conf.yaml中每个字段的含义)
##### 2.5.1.2. 配置参数文件。参数文件如下。PaddleSegServing仅新增一个配置文件seg_conf.yaml,用来指定具体分割模型的一些参数,如均值、方差、图像尺寸等。该配置文件可在gflags.conf中通过--seg_conf_file指定。其他配置文件的字段解释可参考以下链接:https://github.com/PaddlePaddle/Serving/blob/develop/doc/SERVING_CONFIGURE.md
```
bash
conf/
...
...
@@ -68,7 +161,28 @@ conf/
└── workflow.prototxt
```
#### 2.2.2 运行服务端程序
以下为seg_conf.yaml文件内容以及每一个配置项的内容。
```
bash
%YAML:1.0
# 输入到模型的图像的尺寸。会将任意图片resize到513*513尺寸的图像,再放入模型进行推测。
SIZE:
[
513, 513]
# 均值
MEAN:
[
104.008, 116.669, 122.675]
# 方差
STD:
[
1.0, 1.0, 1.0]
# 通道数
CHANNELS: 3
# 类别数量
CLASS_NUM: 2
# 加载的模型的名称,需要与model_toolkit.prototxt中对应模型的名称保持一致。
MODEL_NAME:
"human_segmentation"
```
#### 2.5.2 运行服务端程序
```
bash
# 1. 设置环境变量
...
...
@@ -77,9 +191,36 @@ export LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/lib64:$LD_LIBRARY_PATH
cd
~/serving/build/output/demo/seg-serving/bin/
./seg-serving
```
#### 2.2.3.运行客户端程序进行测试 (建议在windows、mac测试,可直接查看分割后的图像)
客户端程序是用Python3编写的,代码简洁易懂,可以通过运行客户端验证服务的正确性以及性能表现。
#### 2.5.3.运行客户端程序进行测试 (建议在windows、mac测试,可直接查看分割后的图像)
```
bash
以下为PaddleSeg的目录结构,客户端在PaddleSeg/serving/tools目录。
PaddleSeg
├── configs
├── contrib
├── dataset
├── docs
├── inference
├── pdseg
├── README.md
├── requirements.txt
├── scripts
├── serving
│ ├── COMPILE_GUIDE.md
│ ├── imgs
│ ├── README.md
│ ├── requirements.txt
│ ├── seg-serving
│ ├── tools
# 客户端目录
│ │ ├── images
# 测试的图像目录,可放置jpg格式或其他三通道格式的图像,以jpg或jpeg作为文件后缀名
│ │ │ ├── 1.jpg
│ │ │ ├── 2.jpg
│ │ │ └── 3.jpg
│ │ └── image_seg_client.py
# 客户端测试代码
│ └── UBUNTU.md
├──
test
└── test.md
```
客户端程序是用Python3编写的,代码简洁易懂,可以通过运行客户端验证服务的正确性以及性能表现。测试的图像放在images目录下,
```
bash
# 使用Python3.6,需要安装opencv-python、requests、numpy包(建议安装anaconda)
...
...
serving/UBUNTU.md
0 → 100644
浏览文件 @
23a4a62d
# Ubuntu系统下依赖项的安装教程
运行PaddleSegServing需要系统安装一些依赖库。在不同发行版本的Linux系统下,安装依赖项的具体命令略有不同,以下介绍在Ubuntu 16.07下安装依赖项的方法。
## 1. 安装ssl、go、python、bzip2、crypto.
```
bash
sudo
apt-get
install
golang-1.10 python2.7 libssl1.0.0 libssl-dev libssl-doc libcrypto++-dev libcrypto++-doc libcrypto++-utils libbz2-1.0 libbz2-dev
```
## 2. 为ssl、crypto、curl链接库添加软连接
```
bash
ln
-s
/lib/x86_64-linux-gnu/libssl.so.1.0.0 /usr/lib/x86_64-linux-gnu/libssl.so
ln
-s
/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 /usr/lib/x86_64-linux-gnu/libcrypto.so.10
ln
-s
/usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/lib/x86_64-linux-gnu/libcurl.so
```
## 3. 安装GPU依赖项(如果需要使用GPU预测,必须执行此步骤)
### 3.1. 安装配置CUDA9.2以及cuDNN 7.1.4
方法与
[
预编译安装流程
](
README.md
)
2.2.2.1节一样。
### 3.2. 安装nccl库
```
bash
# 下载nccl相关的deb包
wget
-c
xxx
sudo
apt-key add /var/nccl-repo-2.4.8-ga-cuda9.2/7fa2af80.pub
# 安装deb包
sudo
dpkg
-i
nccl-repo-ubuntu1604-2.4.8-ga-cuda9.2_1-1_amd64.deb
# 更新索引
sudo
apt update
# 安装nccl库
sudo
apt-get
install
libnccl2 libnccl-dev
```
## 4. 安装cmake 3.15
如果机器没有安装cmake或者已安装cmake的版本低于3.0,请执行以下步骤
```
bash
# 如果原来的已经安装低于3.0版本的cmake,请先卸载原有低版本 cmake
sudo
apt-get autoremove cmake
```
其余安装cmake的流程请参考以下链接
[
预编译安装流程
](
README.md
)
2.2.3节。
## 5. 安装PaddleSegServing
### 5.1. 下载并解压GPU版本PaddleSegServing
```
bash
# TODO:修改链接
cd
~
wget
-c
XXXX/PaddleSegServing.ubuntu16.07_cuda9.2_gpu.tar.gz
tar
xvfz PaddleSegServing.ubuntu16.07_cuda9.2_gpu.tar.gz seg-serving
```
### 5.2. 下载并解压CPU版本PaddleSegServing
```
bash
# TODO:修改链接
cd
~
wget
-c
XXXX/PaddleSegServing.ubuntu16.07_cuda9.2_cpu.tar.gz
tar
xvfz PaddleSegServing.ubuntu16.07_cuda9.2_gpu.tar.gz seg-serving
```
## 6. gcc版本问题
在Ubuntu 16.07系统中,默认的gcc版本为5.4.0。而目前PaddleSegServing仅支持gcc 4.8编译,所以如果测试的机器gcc版本为5.4,请先进行降级(无需卸载原有的gcc)。
```
bash
# 安装gcc 4.8
sudo
apt-get
install
gcc-4.8
# 查看是否成功安装gcc4.8
ls
/usr/bin/gcc
*
# 设置gcc4.8的优先级,使其能被gcc命令优先连接gcc4.8
sudo
update-alternatives
--install
/usr/bin/gcc gcc /usr/bin/gcc-4.8 100
# 查看设置结果(非必须)
sudo
update-alternatives
--config
gcc
```
serving/seg-serving/conf/gflags.conf
浏览文件 @
23a4a62d
--
enable_model_toolkit
--
seg_conf_file
=./
conf
/
seg_conf
.
yaml
--
num_threads
=
1
--
bthread_min_concurrency
=
4
--
bthread_concurrency
=
4
serving/seg-serving/conf/model_toolkit.prototxt
浏览文件 @
23a4a62d
engines {
name: "human_segmentation"
type: "FLUID_GPU_
NATIVE
"
type: "FLUID_GPU_
ANALYSIS
"
reloadable_meta: "./data/model/paddle/fluid_time_file"
reloadable_type: "timestamp_ne"
model_data_path: "./data/model/paddle/fluid/deeplabv3p_xception65_humanseg"
...
...
serving/seg-serving/op/image_seg_op.cpp
浏览文件 @
23a4a62d
...
...
@@ -128,16 +128,30 @@ int ImageSegOp::inference() {
mask_raw
[
di
]
=
label
;
}
//cv::Mat mask_mat = cv::Mat(height, width, CV_32FC1);
cv
::
Mat
mask_mat
=
cv
::
Mat
(
height
,
width
,
CV_8UC1
);
mask_mat
.
data
=
mask_raw
.
data
();
//scoremap
// mask_mat.data = reinterpret_cast<uchar *>(data + out_size);
//mask_mat.data = mask_raw.data();
std
::
vector
<
uchar
>
temp_mat
(
out_size
,
0
);
for
(
int
i
=
0
;
i
<
out_size
;
++
i
){
temp_mat
[
i
]
=
255
*
data
[
i
+
out_size
];
}
mask_mat
.
data
=
temp_mat
.
data
();
cv
::
Mat
mask_temp_mat
((
*
height_vec
)[
si
],
(
*
width_vec
)[
si
],
mask_mat
.
type
());
//Size(cols, rows)
cv
::
resize
(
mask_mat
,
mask_temp_mat
,
mask_temp_mat
.
size
());
// cv::resize(mask_mat, mask_temp_mat, cv::Size((*width_vec)[si], (*height_vec)[si]));
//debug
//for(int i = 0; i < (*height_vec)[si]; ++i){
// for(int j = 0; j < (*width_vec)[si]; ++j) {
// std::cout << mask_temp_mat.at<float>(i, j) << " ";
// }
// std::cout << std::endl;
//}
std
::
vector
<
uchar
>
mat_buff
;
cv
::
imencode
(
".png"
,
mask_temp_mat
,
mat_buff
);
ins
->
set_mask
(
mat_buff
.
data
(
),
mat_buff
.
size
());
ins
->
set_mask
(
reinterpret_cast
<
char
*>
(
mat_buff
.
data
()
),
mat_buff
.
size
());
}
// release out tensor object resource
...
...
serving/seg-serving/op/reader_op.cpp
浏览文件 @
23a4a62d
...
...
@@ -103,7 +103,8 @@ int ReaderOp::inference() {
const
ImageSegReqItem
&
ins
=
req
->
instances
(
si
);
// read dense image from request bytes
const
char
*
binary
=
ins
.
image_binary
().
c_str
();
size_t
length
=
ins
.
image_length
();
//size_t length = ins.image_length();
size_t
length
=
ins
.
image_binary
().
length
();
if
(
length
==
0
)
{
LOG
(
ERROR
)
<<
"Empty image, length is 0"
;
return
-
1
;
...
...
serving/seg-serving/op/write_json_op.cpp
浏览文件 @
23a4a62d
...
...
@@ -50,7 +50,7 @@ int WriteJsonOp::inference() {
std
::
string
err_string
;
uint32_t
batch_size
=
seg_out
->
item_size
();
LOG
(
INFO
)
<<
"batch_size = "
<<
batch_size
;
LOG
(
INFO
)
<<
seg_out
->
ShortDebugString
();
//
LOG(INFO) << seg_out->ShortDebugString();
for
(
uint32_t
si
=
0
;
si
<
batch_size
;
si
++
)
{
ResponseItem
*
ins
=
res
->
add_prediction
();
//LOG(INFO) << "Original image width = " << seg_out->width(si) << ", height = " << seg_out->height(si);
...
...
@@ -59,6 +59,7 @@ int WriteJsonOp::inference() {
return
-
1
;
}
std
::
string
*
text
=
ins
->
mutable_info
();
LOG
(
INFO
)
<<
seg_out
->
item
(
si
).
ShortDebugString
();
if
(
!
ProtoMessageToJson
(
seg_out
->
item
(
si
),
text
,
&
err_string
))
{
LOG
(
ERROR
)
<<
"Failed convert message["
<<
seg_out
->
item
(
si
).
ShortDebugString
()
...
...
serving/tools/image_seg_client.py
浏览文件 @
23a4a62d
# coding: utf-8
import
sys
import
os
import
cv2
import
requests
import
json
...
...
@@ -8,28 +7,68 @@ import base64
import
numpy
as
np
import
time
import
threading
import
re
#分割服务的地址
#IMAGE_SEG_URL = 'http://yq01-gpu-151-23-00.epc:8010/ImageSegService/inference'
#IMAGE_SEG_URL = 'http://106.12.25.202:8010/ImageSegService/inference'
IMAGE_SEG_URL
=
'http://180.76.118.53:8010/ImageSegService/inference'
# 请求预测服务
# input_img 要预测的图片列表
def
get_item_json
(
input_img
):
with
open
(
input_img
,
mode
=
"rb"
)
as
fp
:
# 使用 http 协议请求服务时, 请使用 base64 编码发送图片
item_binary_b64
=
str
(
base64
.
b64encode
(
fp
.
read
()),
'utf-8'
)
item_size
=
len
(
item_binary_b64
)
item_json
=
{
"image_length"
:
item_size
,
"image_binary"
:
item_binary_b64
}
return
item_json
IMAGE_SEG_URL
=
'http://xxx.xxx.xxx.xxx:8010/ImageSegService/inference'
class
ClientThread
(
threading
.
Thread
):
def
__init__
(
self
,
thread_id
,
image_data_repo
):
threading
.
Thread
.
__init__
(
self
)
self
.
__thread_id
=
thread_id
self
.
__image_data_repo
=
image_data_repo
def
run
(
self
):
self
.
__request_image_seg_service
()
def
__request_image_seg_service
(
self
):
# 持续发送150个请求
for
i
in
range
(
1
,
151
):
print
(
"Epoch %d, thread %d"
%
(
i
,
self
.
__thread_id
))
self
.
__benchmark_test
()
# benchmark test
def
__benchmark_test
(
self
):
start
=
time
.
time
()
for
image_filename
in
self
.
__image_data_repo
:
mask_mat_list
=
self
.
__request_predictor_server
(
image_filename
)
input_img
=
self
.
__image_data_repo
.
get_image_matrix
(
image_filename
)
# 将获得的mask matrix转换成可视化图像,并在当前目录下保存为图像文件
# 如果进行压测,可以把这句话注释掉
for
j
in
range
(
len
(
mask_mat_list
)):
self
.
__visualization
(
mask_mat_list
[
j
],
image_filename
,
2
,
input_img
)
latency
=
time
.
time
()
-
start
print
(
"total latency = %f s"
%
(
latency
))
# 对预测结果进行可视化
# input_raw_mask 是server返回的预测结果
# output_img 是可视化结果存储路径
def
__visualization
(
self
,
mask_mat
,
output_img
,
num_cls
,
input_img
):
# ColorMap for visualization more clearly
n
=
num_cls
color_map
=
[]
for
j
in
range
(
n
):
lab
=
j
a
=
b
=
c
=
0
color_map
.
append
([
a
,
b
,
c
])
i
=
0
while
lab
:
color_map
[
j
][
0
]
|=
(((
lab
>>
0
)
&
1
)
<<
(
7
-
i
))
color_map
[
j
][
1
]
|=
(((
lab
>>
1
)
&
1
)
<<
(
7
-
i
))
color_map
[
j
][
2
]
|=
(((
lab
>>
2
)
&
1
)
<<
(
7
-
i
))
i
+=
1
lab
>>=
3
im
=
cv2
.
imdecode
(
mask_mat
,
1
)
w
,
h
,
c
=
im
.
shape
im2
=
cv2
.
resize
(
im
,
(
w
,
h
))
im
=
im2
# I = aF + (1-a)B
a
=
im
/
255.0
im
=
a
*
input_img
+
(
1
-
a
)
*
[
255
,
255
,
255
]
cv2
.
imwrite
(
output_img
,
im
)
def
request_predictor_server
(
input_img_list
,
dir_name
):
data
=
{
"instances"
:
[
get_item_json
(
dir_name
+
input_img
)
for
input_img
in
input_img_list
]}
def
__request_predictor_server
(
self
,
input_img
):
data
=
{
"instances"
:
[
self
.
__get_item_json
(
input_img
)
]}
response
=
requests
.
post
(
IMAGE_SEG_URL
,
data
=
json
.
dumps
(
data
))
try
:
response
=
json
.
loads
(
response
.
text
)
...
...
@@ -37,86 +76,27 @@ def request_predictor_server(input_img_list, dir_name):
mask_response_list
=
[
mask_response
[
"info"
]
for
mask_response
in
prediction_list
]
mask_raw_list
=
[
json
.
loads
(
mask_response
)[
"mask"
]
for
mask_response
in
mask_response_list
]
except
Exception
as
err
:
print
(
"Exception[%s], server_message[%s]"
%
(
str
(
err
),
response
.
text
))
print
(
"Exception[%s], server_message[%s]"
%
(
str
(
err
),
response
.
text
))
return
None
# 使用 json 协议回复的包也是 base64 编码过的
mask_binary_list
=
[
base64
.
b64decode
(
mask_raw
)
for
mask_raw
in
mask_raw_list
]
m
=
[
np
.
fromstring
(
mask_binary
,
np
.
uint8
)
for
mask_binary
in
mask_binary_list
]
return
m
# 对预测结果进行可视化
# input_raw_mask 是server返回的预测结果
# output_img 是可视化结果存储路径
def
visualization
(
mask_mat
,
output_img
):
# ColorMap for visualization more clearly
color_map
=
[[
128
,
64
,
128
],
[
244
,
35
,
231
],
[
69
,
69
,
69
],
[
102
,
102
,
156
],
[
190
,
153
,
153
],
[
153
,
153
,
153
],
[
250
,
170
,
29
],
[
219
,
219
,
0
],
[
106
,
142
,
35
],
[
152
,
250
,
152
],
[
69
,
129
,
180
],
[
219
,
19
,
60
],
[
255
,
0
,
0
],
[
0
,
0
,
142
],
[
0
,
0
,
69
],
[
0
,
60
,
100
],
[
0
,
79
,
100
],
[
0
,
0
,
230
],
[
119
,
10
,
32
]]
im
=
cv2
.
imdecode
(
mask_mat
,
1
)
w
,
h
,
c
=
im
.
shape
im2
=
cv2
.
resize
(
im
,
(
w
,
h
))
im
=
im2
for
i
in
range
(
0
,
h
):
for
j
in
range
(
0
,
w
):
im
[
i
,
j
]
=
color_map
[
im
[
i
,
j
,
0
]]
cv2
.
imwrite
(
output_img
,
im
)
#benchmark test
def
benchmark_test
(
batch_size
,
img_list
):
start
=
time
.
time
()
total_size
=
len
(
img_list
)
for
i
in
range
(
0
,
total_size
,
batch_size
):
mask_mat_list
=
request_predictor_server
(
img_list
[
i
:
np
.
min
([
i
+
batch_size
,
total_size
])],
"images/"
)
# 将获得的mask matrix转换成可视化图像,并在当前目录下保存为图像文件
# 如果进行压测,可以把这句话注释掉
# for j in range(len(mask_mat_list)):
# visualization(mask_mat_list[j], img_list[j + i])
latency
=
time
.
time
()
-
start
print
(
"batch size = %d, total latency = %f s"
%
(
batch_size
,
latency
))
class
ClientThread
(
threading
.
Thread
):
def
__init__
(
self
,
thread_id
,
batch_size
):
threading
.
Thread
.
__init__
(
self
)
self
.
__thread_id
=
thread_id
self
.
__batch_size
=
batch_size
def
run
(
self
):
self
.
request_image_seg_service
(
3
)
def
request_image_seg_service
(
self
,
imgs_num
):
total_size
=
imgs_num
img_list
=
[
str
(
i
+
1
)
+
".jpg"
for
i
in
range
(
total_size
)]
# batch_size_list = [2**i for i in range(0, 4)]
# 持续发送150个请求
batch_size_list
=
[
self
.
__batch_size
]
*
150
i
=
1
for
batch_size
in
batch_size_list
:
print
(
"Epoch %d, thread %d"
%
(
i
,
self
.
__thread_id
))
i
+=
1
benchmark_test
(
batch_size
,
img_list
)
# 请求预测服务
# input_img 要预测的图片列表
def
__get_item_json
(
self
,
input_img
):
# 使用 http 协议请求服务时, 请使用 base64 编码发送图片
item_binary_b64
=
str
(
base64
.
b64encode
(
self
.
__image_data_repo
.
get_image_binary
(
input_img
)),
'utf-8'
)
item_size
=
len
(
item_binary_b64
)
item_json
=
{
"image_length"
:
item_size
,
"image_binary"
:
item_binary_b64
}
return
item_json
def
create_thread_pool
(
thread_num
,
batch_size
):
return
[
ClientThread
(
i
+
1
,
batch_size
)
for
i
in
range
(
thread_num
)]
def
create_thread_pool
(
thread_num
,
image_data_repo
):
return
[
ClientThread
(
i
+
1
,
image_data_repo
)
for
i
in
range
(
thread_num
)]
def
run_threads
(
thread_pool
):
...
...
@@ -126,7 +106,35 @@ def run_threads(thread_pool):
for
thread
in
thread_pool
:
thread
.
join
()
class
ImageDataRepo
:
def
__init__
(
self
,
dir_name
):
print
(
"Loading images data..."
)
self
.
__data
=
{}
pattern
=
re
.
compile
(
".+\.(jpg|jpeg)"
,
re
.
I
)
if
os
.
path
.
isdir
(
dir_name
):
for
image_filename
in
os
.
listdir
(
dir_name
):
if
pattern
.
match
(
image_filename
):
full_path
=
os
.
path
.
join
(
dir_name
,
image_filename
)
fp
=
open
(
full_path
,
mode
=
"rb"
)
image_binary_data
=
fp
.
read
()
image_mat_data
=
cv2
.
imread
(
full_path
)
self
.
__data
[
image_filename
]
=
(
image_binary_data
,
image_mat_data
)
else
:
raise
Exception
(
"Please use directory to initialize"
);
print
(
"Finish loading."
)
def
__iter__
(
self
):
for
filename
in
self
.
__data
:
yield
filename
def
get_image_binary
(
self
,
image_name
):
return
self
.
__data
[
image_name
][
0
]
def
get_image_matrix
(
self
,
image_name
):
return
self
.
__data
[
image_name
][
1
]
if
__name__
==
"__main__"
:
thread_pool
=
create_thread_pool
(
thread_num
=
2
,
batch_size
=
1
)
#preprocess
IDR
=
ImageDataRepo
(
"images"
)
thread_pool
=
create_thread_pool
(
thread_num
=
1
,
image_data_repo
=
IDR
)
run_threads
(
thread_pool
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录