Skip to content

Commit 18e9c48

Browse files
authored
Merge pull request PaddlePaddle#366 from graphcore/yzx-0804-mv
[IPU] update docs and custom ops demo
2 parents 98f1192 + 15eb65e commit 18e9c48

File tree

13 files changed

+898
-2
lines changed

13 files changed

+898
-2
lines changed

c++/ipu/custom_ops/CMakeLists.txt

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
cmake_minimum_required(VERSION 3.0)
2+
project(cpp_inference_demo CXX C)
3+
option(WITH_IPU "Compile demo with IPU/CPU, default use CPU." OFF)
4+
option(CUSTOM_OPERATOR_FILES "List of file names for custom operators" "")
5+
6+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
7+
8+
if(NOT WITH_STATIC_LIB)
9+
add_definitions("-DPADDLE_WITH_SHARED_LIB")
10+
else()
11+
# PD_INFER_DECL is mainly used to set the dllimport/dllexport attribute in dynamic library mode.
12+
# Set it to empty in static library mode to avoid compilation issues.
13+
add_definitions("/DPD_INFER_DECL=")
14+
endif()
15+
16+
macro(safe_set_static_flag)
17+
foreach(flag_var
18+
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
19+
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
20+
if(${flag_var} MATCHES "/MD")
21+
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
22+
endif(${flag_var} MATCHES "/MD")
23+
endforeach(flag_var)
24+
endmacro()
25+
26+
if(NOT DEFINED PADDLE_LIB)
27+
message(FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/path/paddle/lib")
28+
endif()
29+
if(NOT DEFINED DEMO_NAME)
30+
message(FATAL_ERROR "please set DEMO_NAME with -DDEMO_NAME=demo_name")
31+
endif()
32+
33+
include_directories("${PADDLE_LIB}/")
34+
set(PADDLE_LIB_THIRD_PARTY_PATH "${PADDLE_LIB}/third_party/install/")
35+
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/include")
36+
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/include")
37+
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/include")
38+
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/include")
39+
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/include")
40+
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/include")
41+
42+
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/lib")
43+
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/lib")
44+
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/lib")
45+
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/lib")
46+
link_directories("${PADDLE_LIB}/paddle/lib")
47+
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib")
48+
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib")
49+
50+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
51+
if(WITH_IPU)
52+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DONNX_NAMESPACE=onnx")
53+
endif()
54+
55+
set(DEPS ${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_SHARED_LIBRARY_SUFFIX})
56+
set(EXTERNAL_LIB "-lrt -ldl -lpthread")
57+
set(DEPS ${DEPS}
58+
glog gflags protobuf xxhash
59+
${EXTERNAL_LIB})
60+
61+
add_library(pd_infer_custom_op SHARED ${CUSTOM_OPERATOR_FILES})
62+
add_executable(${DEMO_NAME} ${DEMO_NAME}.cc)
63+
set(DEPS ${DEPS} pd_infer_custom_op)
64+
target_link_libraries(${DEMO_NAME} ${DEPS})

c++/ipu/custom_ops/README.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# 自定义算子模型构建运行示例
2+
3+
## 一:获取本样例中的自定义算子模型
4+
下载地址:https://paddle-inference-dist.bj.bcebos.com/inference_demo/custom_operator/custom_relu_infer_model.tgz
5+
6+
执行 `tar zxvf custom_relu_infer_model.tgz` 将模型文件解压至当前目录。
7+
8+
## 二:**样例编译**
9+
10+
文件 `custom_relu_op.cc``custom_relu_op_ipu.cc` 为自定义算子源文件,自定义算子编写方式请参考[飞桨官网文档](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/index_cn.html)
11+
注意:自定义算子目前需要与飞桨预测库 `libpaddle_inference.so` 联合构建,启用 IPU 功能需要使用 IPU 版本的飞浆预测库。
12+
13+
文件`custom_op_test.cc` 为预测的样例程序。
14+
文件`CMakeLists.txt` 为编译构建文件。
15+
脚本`compile.sh` 包含了第三方库、预编译库的信息配置。
16+
17+
我们首先需要对脚本`compile.sh` 文件中的配置进行修改。
18+
19+
1)**修改`compile.sh`**
20+
21+
打开`compile.sh`,我们对以下的几处信息进行修改:
22+
23+
```shell
24+
# 根据预编译库中的version.txt信息判断是否将以下标记打开
25+
WITH_IPU=ON
26+
27+
# 配置预测库的根目录
28+
LIB_DIR=${work_path}/../lib/paddle_inference
29+
```
30+
31+
运行 `bash compile.sh`, 会在目录下产生build目录。
32+
33+
34+
2) **运行样例**
35+
36+
```shell
37+
# 运行样例
38+
./build/custom_op_test
39+
```
40+
41+
运行结束后,程序会将模型结果打印到屏幕,说明运行成功。

c++/ipu/custom_ops/compile.sh

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/bash
2+
set +x
3+
set -e
4+
5+
work_path=$(dirname $(readlink -f $0))
6+
7+
# 1. check paddle_inference exists
8+
if [ ! -d "${work_path}/../../lib/paddle_inference" ]; then
9+
echo "Please download paddle_inference lib and move it in Paddle-Inference-Demo/c++/lib"
10+
exit 1
11+
fi
12+
13+
# 2. compile
14+
mkdir -p build
15+
cd build
16+
17+
DEMO_NAME=custom_op_test
18+
19+
WITH_IPU=ON
20+
21+
LIB_DIR=${work_path}/../../lib/paddle_inference
22+
23+
24+
cmake .. -DPADDLE_LIB=${LIB_DIR} \
25+
-DDEMO_NAME=${DEMO_NAME} \
26+
-DWITH_IPU=${WITH_IPU} \
27+
-DWITH_STATIC_LIB=OFF \
28+
-DCUSTOM_OPERATOR_FILES="custom_relu_op.cc;custom_relu_op_ipu.cc"
29+
30+
make -j

c++/ipu/custom_ops/custom_op_test.cc

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
#include <numeric>
16+
#include <gflags/gflags.h>
17+
#include <glog/logging.h>
18+
19+
#include "paddle/include/paddle_inference_api.h"
20+
21+
using paddle_infer::Config;
22+
using paddle_infer::Predictor;
23+
using paddle_infer::CreatePredictor;
24+
25+
void run(Predictor *predictor, const std::vector<float> &input,
26+
const std::vector<int> &input_shape, std::vector<float> *out_data) {
27+
auto input_names = predictor->GetInputNames();
28+
auto input_t = predictor->GetInputHandle(input_names[0]);
29+
input_t->Reshape(input_shape);
30+
input_t->CopyFromCpu(input.data());
31+
32+
CHECK(predictor->Run());
33+
34+
auto output_names = predictor->GetOutputNames();
35+
auto output_t = predictor->GetOutputHandle(output_names[0]);
36+
std::vector<int> output_shape = output_t->shape();
37+
int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1,
38+
std::multiplies<int>());
39+
40+
out_data->resize(out_num);
41+
output_t->CopyToCpu(out_data->data());
42+
}
43+
44+
int main() {
45+
paddle::AnalysisConfig config;
46+
config.SetModel("./custom_relu_infer_model/custom_relu.pdmodel",
47+
"./custom_relu_infer_model/custom_relu.pdiparams");
48+
config.EnableIpu();
49+
std::vector<std::vector<std::string>> custom_ops_info {
50+
{"custom_relu", "Relu", "custom.ops", "1"}};
51+
config.SetIpuCustomInfo(custom_ops_info);
52+
auto predictor{paddle_infer::CreatePredictor(config)};
53+
std::vector<int> input_shape = {1, 1, 28, 28};
54+
std::vector<float> input_data(1 * 1 * 28 * 28, 1);
55+
std::vector<float> out_data;
56+
run(predictor.get(), input_data, input_shape, &out_data);
57+
for (auto e : out_data) {
58+
LOG(INFO) << e << '\n';
59+
}
60+
return 0;
61+
}

c++/ipu/custom_ops/custom_relu_op.cc

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <iostream>
16+
#include <vector>
17+
18+
#include "paddle/include/experimental/ext_all.h"
19+
20+
template <typename data_t>
21+
void relu_cpu_forward_kernel(const data_t* x_data,
22+
data_t* out_data,
23+
int64_t x_numel) {
24+
for (int i = 0; i < x_numel; ++i) {
25+
out_data[i] = std::max(static_cast<data_t>(0.), x_data[i]);
26+
}
27+
}
28+
29+
template <typename data_t>
30+
void relu_cpu_backward_kernel(const data_t* grad_out_data,
31+
const data_t* out_data,
32+
data_t* grad_x_data,
33+
int64_t out_numel) {
34+
for (int i = 0; i < out_numel; ++i) {
35+
grad_x_data[i] =
36+
grad_out_data[i] * (out_data[i] > static_cast<data_t>(0) ? 1. : 0.);
37+
}
38+
}
39+
40+
std::vector<paddle::Tensor> relu_cpu_forward(const paddle::Tensor& x) {
41+
auto out = paddle::Tensor(paddle::PlaceType::kCPU, x.shape());
42+
43+
PD_DISPATCH_FLOATING_TYPES(
44+
x.type(), "relu_cpu_forward", ([&] {
45+
relu_cpu_forward_kernel<data_t>(
46+
x.data<data_t>(), out.mutable_data<data_t>(x.place()), x.size());
47+
}));
48+
49+
return {out};
50+
}
51+
52+
std::vector<paddle::Tensor> relu_cpu_backward(const paddle::Tensor& x,
53+
const paddle::Tensor& out,
54+
const paddle::Tensor& grad_out) {
55+
auto grad_x = paddle::Tensor(paddle::PlaceType::kCPU, x.shape());
56+
57+
PD_DISPATCH_FLOATING_TYPES(out.type(), "relu_cpu_backward", ([&] {
58+
relu_cpu_backward_kernel<data_t>(
59+
grad_out.data<data_t>(),
60+
out.data<data_t>(),
61+
grad_x.mutable_data<data_t>(x.place()),
62+
out.size());
63+
}));
64+
65+
return {grad_x};
66+
}
67+
68+
std::vector<paddle::Tensor> ReluForward(const paddle::Tensor& x) {
69+
return relu_cpu_forward(x);
70+
}
71+
72+
std::vector<paddle::Tensor> ReluBackward(const paddle::Tensor& x,
73+
const paddle::Tensor& out,
74+
const paddle::Tensor& grad_out) {
75+
return relu_cpu_backward(x, out, grad_out);
76+
}
77+
78+
PD_BUILD_OP(custom_relu)
79+
.Inputs({"X"})
80+
.Outputs({"Out"})
81+
.SetKernelFn(PD_KERNEL(ReluForward));
82+
83+
PD_BUILD_GRAD_OP(custom_relu)
84+
.Inputs({"X", "Out", paddle::Grad("Out")})
85+
.Outputs({paddle::Grad("X")})
86+
.SetKernelFn(PD_KERNEL(ReluBackward));

0 commit comments

Comments
 (0)