Files
2026-07-13 12:40:42 +08:00

261 lines
9.0 KiB
C++

// Copyright (c) 2021 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
#include <math.h>
#include <algorithm>
#include <deque>
#include <fstream>
#include <future>
#include <iostream>
#include <numeric>
#include <string>
#include <thread>
#include <vector>
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/include/paddle_inference_api.h"
namespace paddle {
namespace test {
#define IS_TRT_VERSION_GE(version) \
((NV_TENSORRT_MAJOR * 1000 + NV_TENSORRT_MINOR * 100 + \
NV_TENSORRT_PATCH * 10 + NV_TENSORRT_BUILD) >= version)
#define IS_TRT_VERSION_LT(version) \
((NV_TENSORRT_MAJOR * 1000 + NV_TENSORRT_MINOR * 100 + \
NV_TENSORRT_PATCH * 10 + NV_TENSORRT_BUILD) < version)
#define TRT_VERSION \
NV_TENSORRT_MAJOR * 1000 + NV_TENSORRT_MINOR * 100 + \
NV_TENSORRT_PATCH * 10 + NV_TENSORRT_BUILD
class Record {
public:
std::vector<float> data;
std::vector<int32_t> shape;
paddle::PaddleDType type;
int label;
};
std::string read_file(std::string filename) {
std::ifstream file(filename);
return std::string((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
}
void SingleThreadPrediction(paddle_infer::Predictor *predictor,
std::map<std::string, Record> *input_data_map,
std::map<std::string, Record> *output_data_map,
int repeat_times = 2) {
// prepare input tensor
auto input_names = predictor->GetInputNames();
for (const auto &[key, value] : *input_data_map) {
switch (value.type) {
case paddle::PaddleDType::INT64: {
std::vector<int64_t> input_value =
std::vector<int64_t>(value.data.begin(), value.data.end());
auto input_tensor = predictor->GetInputHandle(key);
input_tensor->Reshape(value.shape);
input_tensor->CopyFromCpu(input_value.data());
break;
}
case paddle::PaddleDType::INT32: {
std::vector<int32_t> input_value =
std::vector<int32_t>(value.data.begin(), value.data.end());
auto input_tensor = predictor->GetInputHandle(key);
input_tensor->Reshape(value.shape);
input_tensor->CopyFromCpu(input_value.data());
break;
}
case paddle::PaddleDType::FLOAT32: {
std::vector<float> input_value =
std::vector<float>(value.data.begin(), value.data.end());
auto input_tensor = predictor->GetInputHandle(key);
input_tensor->Reshape(value.shape);
input_tensor->CopyFromCpu(input_value.data());
break;
}
}
}
// inference
for (size_t i = 0; i < repeat_times; ++i) {
ASSERT_TRUE(predictor->Run());
}
// get output data to Record
auto output_names = predictor->GetOutputNames();
for (auto &output_name : output_names) {
Record output_Record;
auto output_tensor = predictor->GetOutputHandle(output_name);
std::vector<int> output_shape = output_tensor->shape();
int out_num = std::accumulate(
output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
switch (output_tensor->type()) {
case paddle::PaddleDType::INT64: {
VLOG(1) << "output_tensor dtype: int64";
std::vector<int64_t> out_data;
output_Record.type = paddle::PaddleDType::INT64;
out_data.resize(out_num);
output_tensor->CopyToCpu(out_data.data());
output_Record.shape = output_shape;
std::vector<float> floatVec(out_data.begin(), out_data.end());
output_Record.data = floatVec;
(*output_data_map)[output_name] = output_Record;
break;
}
case paddle::PaddleDType::FLOAT32: {
VLOG(1) << "output_tensor dtype: float32";
std::vector<float> out_data;
output_Record.type = paddle::PaddleDType::FLOAT32;
out_data.resize(out_num);
output_tensor->CopyToCpu(out_data.data());
output_Record.shape = output_shape;
output_Record.data = out_data;
(*output_data_map)[output_name] = output_Record;
break;
}
case paddle::PaddleDType::INT32: {
VLOG(1) << "output_tensor dtype: int32";
std::vector<int32_t> out_data;
output_Record.type = paddle::PaddleDType::INT32;
out_data.resize(out_num);
output_tensor->CopyToCpu(out_data.data());
output_Record.shape = output_shape;
std::vector<float> floatVec(out_data.begin(), out_data.end());
output_Record.data = floatVec;
(*output_data_map)[output_name] = output_Record;
break;
}
}
}
}
void CompareRecord(std::map<std::string, Record> *truth_output_data,
std::map<std::string, Record> *infer_output_data,
float epsilon = 1e-5) {
for (const auto &[key, value] : *infer_output_data) {
auto truth_record = (*truth_output_data)[key];
VLOG(1) << "output name: " << key;
size_t numel = value.data.size() / sizeof(float);
EXPECT_EQ(value.data.size(), truth_record.data.size());
for (size_t i = 0; i < numel; ++i) {
VLOG(1) << "compare: " << value.data.data()[i] << ",\t"
<< truth_record.data.data()[i];
ASSERT_LT(fabs(value.data.data()[i] - truth_record.data.data()[i]),
epsilon);
}
}
}
// Timer, count in ms
class Timer {
public:
Timer() { reset(); }
void start() { start_t = std::chrono::high_resolution_clock::now(); }
void stop() {
auto end_t = std::chrono::high_resolution_clock::now();
typedef std::chrono::microseconds ms;
auto diff = end_t - start_t;
ms counter = std::chrono::duration_cast<ms>(diff);
total_time += counter.count();
}
void reset() { total_time = 0.; }
double report() { return total_time / 1000.0; }
private:
double total_time;
std::chrono::high_resolution_clock::time_point start_t;
};
// single thread inference benchmark, return double time in ms
double SingleThreadProfile(paddle_infer::Predictor *predictor,
std::map<std::string, Record> *input_data_map,
int repeat_times = 2) {
// prepare input tensor
auto input_names = predictor->GetInputNames();
for (const auto &[key, value] : *input_data_map) {
switch (value.type) {
case paddle::PaddleDType::INT64: {
std::vector<int64_t> input_value =
std::vector<int64_t>(value.data.begin(), value.data.end());
auto input_tensor = predictor->GetInputHandle(key);
input_tensor->Reshape(value.shape);
input_tensor->CopyFromCpu(input_value.data());
break;
}
case paddle::PaddleDType::INT32: {
std::vector<int32_t> input_value =
std::vector<int32_t>(value.data.begin(), value.data.end());
auto input_tensor = predictor->GetInputHandle(key);
input_tensor->Reshape(value.shape);
input_tensor->CopyFromCpu(input_value.data());
break;
}
case paddle::PaddleDType::FLOAT32: {
std::vector<float> input_value =
std::vector<float>(value.data.begin(), value.data.end());
auto input_tensor = predictor->GetInputHandle(key);
input_tensor->Reshape(value.shape);
input_tensor->CopyFromCpu(input_value.data());
break;
}
}
}
Timer timer; // init prediction timer
timer.start();
// inference
for (size_t i = 0; i < repeat_times; ++i) {
CHECK(predictor->Run());
auto output_names = predictor->GetOutputNames();
for (auto &output_name : output_names) {
auto output_tensor = predictor->GetOutputHandle(output_name);
std::vector<int> output_shape = output_tensor->shape();
int out_num = std::accumulate(
output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
switch (output_tensor->type()) {
case paddle::PaddleDType::INT64: {
std::vector<int64_t> out_data;
out_data.resize(out_num);
output_tensor->CopyToCpu(out_data.data());
break;
}
case paddle::PaddleDType::FLOAT32: {
std::vector<float> out_data;
out_data.resize(out_num);
output_tensor->CopyToCpu(out_data.data());
break;
}
case paddle::PaddleDType::INT32: {
std::vector<int32_t> out_data;
out_data.resize(out_num);
output_tensor->CopyToCpu(out_data.data());
break;
}
}
}
}
timer.stop();
return timer.report();
}
} // namespace test
} // namespace paddle