chore: import upstream snapshot with attribution
This commit is contained in:
Executable
+94
@@ -0,0 +1,94 @@
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=pessimizing-move")
|
||||
endif()
|
||||
|
||||
add_subdirectory(details)
|
||||
|
||||
cc_library(
|
||||
paddle_infer_contrib
|
||||
SRCS paddle_infer_contrib.cc
|
||||
DEPS zero_copy_tensor)
|
||||
cc_library(
|
||||
paddle_pass_builder
|
||||
SRCS paddle_pass_builder.cc
|
||||
DEPS framework_proto)
|
||||
|
||||
set(paddle_inference_api_deps
|
||||
reset_tensor_array
|
||||
paddle_infer_contrib
|
||||
paddle_pass_builder
|
||||
zero_copy_tensor
|
||||
trainer_desc_proto
|
||||
custom_operator
|
||||
lod_tensor
|
||||
scope
|
||||
drr)
|
||||
|
||||
if(WITH_CRYPTO)
|
||||
list(APPEND paddle_inference_api_deps framework_io)
|
||||
endif()
|
||||
if(WITH_CUSTOM_DEVICE)
|
||||
set(paddle_inference_api_deps ${paddle_inference_api_deps} phi common)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
cc_library(
|
||||
paddle_inference_api
|
||||
SRCS api.cc api_impl.cc helper.cc
|
||||
DEPS executor ${paddle_inference_api_deps})
|
||||
else()
|
||||
cc_library(
|
||||
paddle_inference_api
|
||||
SRCS api.cc api_impl.cc helper.cc
|
||||
DEPS executor paddle_inference_io ${paddle_inference_api_deps})
|
||||
endif()
|
||||
|
||||
cc_library(
|
||||
analysis_config
|
||||
SRCS analysis_config.cc
|
||||
DEPS paddle_inference_api paddle_pass_builder table_printer utf8proc)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(paddle_inference_api phi common)
|
||||
endif()
|
||||
|
||||
set(inference_deps
|
||||
${analysis_deps}
|
||||
paddle_inference_api
|
||||
analysis
|
||||
analysis_config
|
||||
naive_executor
|
||||
${GLOB_PASS_LIB}
|
||||
pir_transforms)
|
||||
|
||||
if(WITH_GPU AND TENSORRT_FOUND)
|
||||
set(inference_deps ${inference_deps} tensorrt_engine tensorrt_converter)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENVINO)
|
||||
set(inference_deps ${inference_deps} openvino_engine)
|
||||
endif()
|
||||
|
||||
set(ANALYSIS_PREDICTOR_SRCS analysis_predictor.cc resource_manager.cc
|
||||
infer_context.cc)
|
||||
set(ANALYSIS_PREDICTOR_DEPS ${inference_deps} zero_copy_tensor ir_pass_manager
|
||||
infer_io_utils model_utils)
|
||||
|
||||
if(WITH_ONNXRUNTIME)
|
||||
set(ANALYSIS_PREDICTOR_SRCS ${ANALYSIS_PREDICTOR_SRCS}
|
||||
onnxruntime_predictor.cc)
|
||||
set(ANALYSIS_PREDICTOR_DEPS ${ANALYSIS_PREDICTOR_DEPS} onnxruntime
|
||||
paddle2onnx)
|
||||
elseif(WITH_CINN)
|
||||
set(ANALYSIS_PREDICTOR_DEPS ${ANALYSIS_PREDICTOR_DEPS} add_cinn_pass)
|
||||
endif()
|
||||
cc_library(
|
||||
analysis_predictor
|
||||
SRCS ${ANALYSIS_PREDICTOR_SRCS}
|
||||
DEPS ${ANALYSIS_PREDICTOR_DEPS})
|
||||
|
||||
if(WITH_ONNXRUNTIME AND WIN32)
|
||||
# Copy onnxruntime for some c++ test in Windows, since the test will
|
||||
# be build only in CI, so suppose the generator in Windows is Ninja.
|
||||
copy_onnx(test_paddle_inference_api)
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,569 @@
|
||||
// Copyright (c) 2018 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 <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/fluid/framework/naive_executor.h"
|
||||
#include "paddle/fluid/inference/analysis/analyzer.h"
|
||||
#include "paddle/fluid/inference/api/api_impl.h"
|
||||
#include "paddle/fluid/inference/api/details/reset_tensor_array.h"
|
||||
#include "paddle/fluid/inference/api/helper.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/fluid/inference/api/resource_manager.h"
|
||||
#include "paddle/phi/common/bfloat16.h"
|
||||
#include "paddle/phi/common/float16.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_types.h"
|
||||
#include "paddle/utils/string/printf.h"
|
||||
|
||||
#ifdef PADDLE_WITH_TESTING
|
||||
#include <gtest/gtest.h>
|
||||
#include <gtest/gtest_prod.h>
|
||||
#endif
|
||||
|
||||
#include "paddle/phi/common/data_type.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/pir/include/core/operation.h"
|
||||
#include "paddle/pir/include/core/program.h"
|
||||
|
||||
namespace paddle_infer {
|
||||
namespace experimental {
|
||||
class InternalUtils;
|
||||
};
|
||||
} // namespace paddle_infer
|
||||
///
|
||||
/// \file analysis_predictor.h
|
||||
///
|
||||
/// \brief Compared to NativePredictor, AnalysisPredictor is a high-performance
|
||||
/// predictor that includes many optimizations
|
||||
///
|
||||
/// \author paddle-infer@baidu.com
|
||||
/// \date 2020-01-01
|
||||
/// \since 1.7.0
|
||||
///
|
||||
|
||||
namespace paddle {
|
||||
|
||||
using framework::NaiveExecutor;
|
||||
using framework::proto::ProgramDesc;
|
||||
using inference::analysis::Analyzer;
|
||||
using inference::analysis::Argument;
|
||||
|
||||
///
|
||||
/// \class AnalysisPredictor
|
||||
///
|
||||
/// \brief The analysis predictor is based on the original native predictor with
|
||||
/// IR and Analysis support. It will optimize IR and Parameters in the runtime.
|
||||
///
|
||||
/// The predictor has the following typical uses:
|
||||
///
|
||||
/// Get predictor
|
||||
/// \code{cpp}
|
||||
/// auto predictor = CreatePaddlePredictor(config);
|
||||
/// \endcode
|
||||
///
|
||||
/// Get input or output names
|
||||
/// \code{cpp}
|
||||
/// auto input_names = predictor->GetInputNames();
|
||||
/// auto output_names = predictor->GetOutputNames();
|
||||
/// \endcode
|
||||
///
|
||||
/// Get input or output tensors
|
||||
/// \code{cpp}
|
||||
/// auto input_t = predictor->GetInputTensor(input_names[0]);
|
||||
/// auto output_t = predictor->GetOutputTensor(output_names[0]);
|
||||
/// \endcode
|
||||
///
|
||||
/// Run predictor
|
||||
/// \code{cpp}
|
||||
/// predictor->ZeroCopyRun();
|
||||
/// \endcode
|
||||
///
|
||||
class AnalysisPredictor : public PaddlePredictor {
|
||||
public:
|
||||
///
|
||||
/// \brief Construct a new Analysis Predictor object
|
||||
///
|
||||
/// \param[in] AnalysisConfig config
|
||||
///
|
||||
explicit AnalysisPredictor(const AnalysisConfig &config);
|
||||
///
|
||||
/// \brief Destroy the Analysis Predictor object
|
||||
///
|
||||
~AnalysisPredictor();
|
||||
|
||||
///
|
||||
/// \brief Initialize predictor
|
||||
///
|
||||
/// Initializing predictor mainly includes the following tasks:
|
||||
/// preparing scope, creating executor, preparing program, initializing the
|
||||
/// variables required by the executor, getting the feed_target_names and
|
||||
/// fetch_target_names, etc.
|
||||
///
|
||||
/// \param[in] parent_scope parent scope
|
||||
/// \param[in] program program
|
||||
/// \return Whether the init function executed successfully
|
||||
///
|
||||
bool Init(const std::shared_ptr<framework::Scope> &parent_scope,
|
||||
const std::shared_ptr<framework::ProgramDesc> &program = nullptr);
|
||||
|
||||
///
|
||||
/// \brief Run the prediction engine. Deprecated. Please refer to ZeroCopyRun
|
||||
///
|
||||
/// \param[in] inputs input tensors
|
||||
/// \param[out] output_data output tensors
|
||||
/// \param[in] batch_size data's batch size
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool Run(const std::vector<PaddleTensor> &inputs,
|
||||
std::vector<PaddleTensor> *output_data,
|
||||
int batch_size = -1) override;
|
||||
|
||||
///
|
||||
/// \brief Run the prediction engine (Recommended).
|
||||
///
|
||||
/// \param[in] inputs input tensors
|
||||
/// \param[out] outputs output tensors
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool Run(const std::vector<paddle::Tensor> &inputs,
|
||||
std::vector<paddle::Tensor> *outputs) override;
|
||||
|
||||
///
|
||||
/// \brief Get the input names
|
||||
///
|
||||
/// \return input names
|
||||
///
|
||||
std::vector<std::string> GetInputNames() override;
|
||||
///
|
||||
/// \brief Get the output names
|
||||
///
|
||||
/// \return output names
|
||||
///
|
||||
std::vector<std::string> GetOutputNames() override;
|
||||
|
||||
///
|
||||
/// \brief Get the value really need place, only for pir
|
||||
///
|
||||
/// \return phi::place
|
||||
///
|
||||
phi::Place GetTensorPlace(const pir::Value &value);
|
||||
///
|
||||
/// \brief Get the Input Tensor object
|
||||
///
|
||||
/// \param[in] name input name
|
||||
/// \return input tensor
|
||||
///
|
||||
std::unique_ptr<ZeroCopyTensor> GetInputTensor(
|
||||
const std::string &name) override;
|
||||
///
|
||||
/// \brief Get the Output Tensor object
|
||||
///
|
||||
/// \param[in] name output name
|
||||
/// \return output tensor
|
||||
///
|
||||
std::unique_ptr<ZeroCopyTensor> GetOutputTensor(
|
||||
const std::string &name) override;
|
||||
///
|
||||
/// \brief Get all input names and their corresponding shapes
|
||||
///
|
||||
/// \return the map of input names and shapes
|
||||
///
|
||||
std::map<std::string, std::vector<int64_t>> GetInputTensorShape() override;
|
||||
///
|
||||
/// \brief Get all input names and their corresponding type
|
||||
///
|
||||
/// \return the map of input names and type
|
||||
///
|
||||
std::map<std::string, paddle_infer::DataType> GetInputTypes() override;
|
||||
///
|
||||
/// \brief Get all output names and their corresponding shapes
|
||||
///
|
||||
/// \return the map of output names and shapes
|
||||
///
|
||||
std::map<std::string, std::vector<int64_t>> GetOutputTensorShape() override;
|
||||
///
|
||||
/// \brief Get all output names and their corresponding type
|
||||
///
|
||||
/// \return the map of output names and type
|
||||
///
|
||||
std::map<std::string, paddle_infer::DataType> GetOutputTypes() override;
|
||||
|
||||
///
|
||||
/// \brief Run the prediction engine
|
||||
///
|
||||
/// \param switch_stream Whether the stream is switched
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool ZeroCopyRun(bool switch_stream = false) override;
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
// Note: Can only be used under thread_local semantics.
|
||||
bool ExpRunWithExternalStream(const gpuStream_t stream);
|
||||
#endif
|
||||
|
||||
// Note: Can only be used under thread_local semantics.
|
||||
bool ExpRunWithExternalStream(void *stream);
|
||||
|
||||
// Note: Can only be used under thread_local semantics.
|
||||
bool ExpRunWithRuntimeConfig(void *config);
|
||||
|
||||
///
|
||||
/// \brief Get the execution stream on devices with a concept of stream,
|
||||
/// otherwise returns nullptr.
|
||||
///
|
||||
/// \return The execution stream or nullptr (CPU).
|
||||
///
|
||||
void *GetExecStream() const override;
|
||||
|
||||
///
|
||||
/// \brief Create feed fetch variables
|
||||
///
|
||||
/// \param[in] scope Scope needed to create variables
|
||||
///
|
||||
void CreateFeedFetchVar(framework::Scope *scope);
|
||||
///
|
||||
/// \brief Determine the model's inputs and outputs based on the program's
|
||||
/// feed fetch op
|
||||
///
|
||||
void PrepareFeedFetch();
|
||||
|
||||
///
|
||||
/// \brief Set predictor's argument according to config, which mainly includes
|
||||
/// execution information and graph optimization related pass information
|
||||
///
|
||||
void PrepareArgument();
|
||||
///
|
||||
/// \brief According to argument information, execute the relevant pass
|
||||
/// to get the optimized model program
|
||||
///
|
||||
void OptimizeInferenceProgram();
|
||||
///
|
||||
/// \brief According to argument information, execute the relevant pass
|
||||
/// to get the optimized model program
|
||||
///
|
||||
void OptimizeInferencePirProgram();
|
||||
///
|
||||
/// \brief Clear the intermediate tensors of the predictor
|
||||
///
|
||||
///
|
||||
void ClearIntermediateTensor() override;
|
||||
|
||||
///
|
||||
/// \brief Release all tmp tensor to compress the size of the memory pool.
|
||||
/// The memory pool is considered to be composed of a list of chunks, if
|
||||
/// the chunk is not occupied, it can be released.
|
||||
///
|
||||
/// \return Number of bytes released. It may be smaller than the actual
|
||||
/// released memory, because part of the memory is not managed by the
|
||||
/// MemoryPool.
|
||||
///
|
||||
uint64_t TryShrinkMemory() override;
|
||||
|
||||
///
|
||||
/// \brief Get the argument used by predictor
|
||||
///
|
||||
/// \return the argument obtained by config
|
||||
///
|
||||
Argument &analysis_argument() { return *argument_; }
|
||||
///
|
||||
/// \brief Clone to get the new predictor. thread safe.
|
||||
///
|
||||
/// \return get a new predictor
|
||||
///
|
||||
std::unique_ptr<PaddlePredictor> Clone(void *stream = nullptr) override;
|
||||
///
|
||||
/// \brief Get the scope used by predictor
|
||||
///
|
||||
/// \return scope
|
||||
///
|
||||
framework::Scope *scope() { return scope_.get(); }
|
||||
///
|
||||
/// \brief Get the inference program
|
||||
///
|
||||
/// \return the inference program
|
||||
///
|
||||
framework::ProgramDesc &program() { return *inference_program_; }
|
||||
|
||||
///
|
||||
/// \brief Get the serialized program
|
||||
///
|
||||
/// \return the serialized program
|
||||
///
|
||||
std::string GetSerializedProgram() const override;
|
||||
|
||||
///
|
||||
/// \brief Get the fusion_statis_t
|
||||
///
|
||||
/// \return the fusion_statis_t
|
||||
///
|
||||
Argument::fusion_statis_t fusion_statis() { return fusion_statis_; }
|
||||
|
||||
///
|
||||
/// \brief Register a output hook function to operate the intermediate tensor
|
||||
/// of op output. when using this function, memory reuse should be turned off.
|
||||
/// The hook function signature is void(const std::string&, const
|
||||
/// std::string&, const paddle::Tensor&>). Here, the first parameter is op's
|
||||
/// type, the second param is output var name of the op, and the third
|
||||
/// parameter is output tensor with the var name.
|
||||
///
|
||||
void RegisterOutputHook(const OutputTensorHookFunc &hookfunc) override;
|
||||
|
||||
/// \brief Same as RegisterOutputHook
|
||||
void RegisterInputHook(const InputTensorHookFunc &hookfunc) override;
|
||||
|
||||
///
|
||||
/// \brief Initialize onednn quantizer and execute onednn quantization pass
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool MkldnnQuantize();
|
||||
|
||||
protected:
|
||||
///
|
||||
/// \brief Prepare predictor's required programs, including loading model
|
||||
/// information, graph optimization, and executor creation variables, etc.
|
||||
///
|
||||
/// \param[in] program paddle program
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool PrepareProgram(const std::shared_ptr<framework::ProgramDesc> &program);
|
||||
///
|
||||
/// \brief Prepare predictor's required programs, including loading model
|
||||
/// information, graph optimization, and executor creation variables, etc.
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool PreparePirProgram();
|
||||
///
|
||||
/// \brief Prepare scope environment, each predictor has its own scope
|
||||
///
|
||||
/// \param[in] parent_scope The scope of the predictor to be cloned, or null
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool PrepareScope(const std::shared_ptr<framework::Scope> &parent_scope);
|
||||
///
|
||||
/// \brief Create an Executor object
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool CreateExecutor();
|
||||
///
|
||||
/// \brief According to the model's program, the executor creates ops
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool PrepareExecutor();
|
||||
|
||||
///
|
||||
/// \brief Load model program.
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool LoadProgramDesc();
|
||||
///
|
||||
/// \brief Load model parameters.
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool LoadParameters();
|
||||
|
||||
///
|
||||
/// \brief Save or Load pir model parameters.
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool SaveOrLoadPirParameters(bool for_save);
|
||||
|
||||
///
|
||||
/// \brief Prepare input data, only used in Run()
|
||||
///
|
||||
/// \param[in] input_datas input tensors
|
||||
/// \param[in] scope the scope used by predictor
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool SetFeed(const std::vector<PaddleTensor> &input_datas,
|
||||
framework::Scope *scope);
|
||||
|
||||
///
|
||||
/// \brief Prepare input data, only used in Run()
|
||||
///
|
||||
/// \param[in] inputs input tensors
|
||||
/// \param[in] scope the scope used by predictor
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool SetFeed(const std::vector<paddle::Tensor> &inputs,
|
||||
framework::Scope *scope);
|
||||
|
||||
///
|
||||
/// \brief Get the output data, only used in Run()
|
||||
///
|
||||
/// \param[out] output_data output tensors
|
||||
/// \param[in] scope the scope used by predictor
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool GetFetch(std::vector<PaddleTensor> *output_data,
|
||||
framework::Scope *scope);
|
||||
|
||||
///
|
||||
/// \brief Get the output data, only used in Run()
|
||||
///
|
||||
/// \param[out] outputs output tensors
|
||||
/// \param[in] scope the scope used by predictor
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool GetFetch(std::vector<paddle::Tensor> *outputs, framework::Scope *scope);
|
||||
|
||||
///
|
||||
/// \brief Get the output data, only used in GetFetch()
|
||||
///
|
||||
/// \param[in] tensor for fetch op
|
||||
/// \param[out] output_data output tensor
|
||||
///
|
||||
template <typename T>
|
||||
void GetFetchOne(const phi::DenseTensor &fetches, PaddleTensor *output_data);
|
||||
///
|
||||
/// \brief PreSet for Mkldnn multi-thread and dynamic shape input.
|
||||
///
|
||||
/// Used in AnalysisPredictor::Run(), do not support
|
||||
/// AnalysisPredictor::ZeroCopyRun() now.
|
||||
///
|
||||
/// \param[in] inputs tensors
|
||||
///
|
||||
void MkldnnPreSet(const std::vector<PaddleTensor> &inputs);
|
||||
///
|
||||
/// \brief PreSet for Mkldnn multi-thread and dynamic shape input.
|
||||
///
|
||||
/// Used in AnalysisPredictor::Run().
|
||||
///
|
||||
/// \param[in] inputs tensors
|
||||
///
|
||||
void MkldnnPreSet(const std::vector<paddle::Tensor> &inputs);
|
||||
|
||||
///
|
||||
/// \brief PreSet for Mkldnn multi-thread and dynamic shape input.
|
||||
///
|
||||
/// Used in AnalysisPredictor::Run(), do not support
|
||||
/// AnalysisPredictor::ZeroCopyRun() now.
|
||||
///
|
||||
/// \param[in] inputs tensor shape
|
||||
///
|
||||
void MkldnnPreSet(const std::vector<std::vector<int>> &inputs_shape);
|
||||
|
||||
///
|
||||
/// \brief PostReset for Mkldnn multi-thread and dynamic shape input.
|
||||
///
|
||||
/// Used in AnalysisPredictor::Run(), do not support
|
||||
/// AnalysisPredictor::ZeroCopyRun() now.
|
||||
///
|
||||
void MkldnnPostReset();
|
||||
|
||||
#ifdef PADDLE_WITH_TENSORRT
|
||||
///
|
||||
/// \brief save calibration table
|
||||
///
|
||||
/// When we use Paddle-TRT INT8 engine, we need to generate calibration table
|
||||
/// data first,
|
||||
/// the calibration table contains the range for each op's input and output,
|
||||
/// this whole process can be divided into several steps:
|
||||
/// 1. Builds a 32-bit engine, runs it on the calibration set, and records a
|
||||
/// histogram for each tensor of the distribution of activation values.
|
||||
/// 2. Builds a calibration table from the histograms.
|
||||
/// After step 2, we need to store the calibration table on disk.
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool SaveTrtCalibToDisk();
|
||||
#endif
|
||||
|
||||
// Some more detailed tests, they are made the friends of the predictor, so that
|
||||
// the all the details can be tested.
|
||||
#if PADDLE_WITH_TESTING
|
||||
FRIEND_TEST(AnalysisPredictor, analysis_off);
|
||||
FRIEND_TEST(AnalysisPredictor, analysis_on);
|
||||
FRIEND_TEST(AnalysisPredictor, with_gpu);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
const void *GetDeviceContexts() const override;
|
||||
|
||||
private:
|
||||
void StatisticShapeRangeInfo();
|
||||
void HookCollectShapeRangeInfo();
|
||||
void InitPlace();
|
||||
void InitDeviceContexts();
|
||||
void InitResourceManager(void *stream);
|
||||
std::string GetOptimizedModelPath();
|
||||
void ClearExtraParams();
|
||||
|
||||
private:
|
||||
AnalysisConfig config_;
|
||||
std::unique_ptr<Argument> argument_ = nullptr;
|
||||
Argument::fusion_statis_t fusion_statis_;
|
||||
std::unique_ptr<NaiveExecutor> executor_;
|
||||
phi::Place place_;
|
||||
std::shared_ptr<framework::Scope> scope_;
|
||||
framework::Scope *sub_scope_{nullptr};
|
||||
std::shared_ptr<framework::ProgramDesc> inference_program_;
|
||||
std::shared_ptr<pir::Program> pir_program_;
|
||||
bool load_pir_model_{false};
|
||||
std::vector<framework::OpDesc *> feeds_;
|
||||
std::vector<pir::Operation *> pir_feeds_;
|
||||
std::map<std::string, size_t> feed_names_;
|
||||
// Sorted according to the idx.
|
||||
std::map<size_t, std::string> idx2feeds_;
|
||||
std::map<std::string, std::vector<int64_t>> feed_name2shapes_;
|
||||
std::vector<framework::OpDesc *> fetches_;
|
||||
std::vector<pir::Operation *> pir_fetches_;
|
||||
std::map<size_t, std::string> idx2fetches_;
|
||||
std::map<std::string, std::vector<int64_t>> fetch_name2shapes_;
|
||||
|
||||
phi::DataType model_precision_{phi::DataType::FLOAT32};
|
||||
|
||||
// Memory buffer for feed inputs. The temporary DenseTensor will cause serious
|
||||
// concurrency problems, wrong results and memory leak, so cache them.
|
||||
std::vector<phi::DenseTensor> feed_tensors_;
|
||||
details::TensorArrayBatchCleaner tensor_array_batch_cleaner_;
|
||||
// A mutex help to make Clone thread safe.
|
||||
std::mutex clone_mutex_;
|
||||
static int clone_num_;
|
||||
|
||||
int predictor_id_;
|
||||
int root_predictor_id_{-1};
|
||||
|
||||
private:
|
||||
std::once_flag register_input_hook_flag_;
|
||||
std::once_flag register_output_hook_flag_;
|
||||
std::vector<OutputTensorHookFunc> output_hookfuncs_;
|
||||
std::vector<InputTensorHookFunc> input_hookfuncs_;
|
||||
// Some status here that help to determine the status inside the predictor.
|
||||
bool status_is_cloned_{false};
|
||||
|
||||
std::map<std::string, std::vector<std::vector<int32_t>>> shape_info_;
|
||||
std::map<std::string, std::vector<std::vector<int32_t>>> shape_tensor_value_;
|
||||
|
||||
bool private_context_{false};
|
||||
void *predictor_stream_{nullptr};
|
||||
std::map<phi::Place, std::shared_future<std::unique_ptr<phi::DeviceContext>>>
|
||||
device_contexts_;
|
||||
|
||||
friend class paddle_infer::experimental::InternalUtils;
|
||||
};
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2018 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 <sstream>
|
||||
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/fluid/framework/commit.h"
|
||||
#include "paddle/fluid/framework/lod_tensor.h"
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/fluid/inference/api/paddle_pass_builder.h"
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
|
||||
namespace paddle {
|
||||
|
||||
int PaddleDtypeSize(PaddleDType dtype) {
|
||||
switch (dtype) {
|
||||
case PaddleDType::FLOAT32:
|
||||
return sizeof(float);
|
||||
case PaddleDType::BFLOAT16:
|
||||
return sizeof(uint16_t);
|
||||
case PaddleDType::INT64:
|
||||
return sizeof(int64_t);
|
||||
case PaddleDType::INT32:
|
||||
return sizeof(int32_t);
|
||||
case PaddleDType::UINT8:
|
||||
return sizeof(uint8_t);
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
PaddleBuf::PaddleBuf(PaddleBuf &&other) noexcept
|
||||
: data_(other.data_),
|
||||
length_(other.length_),
|
||||
memory_owned_(other.memory_owned_) {
|
||||
other.memory_owned_ = false;
|
||||
other.data_ = nullptr;
|
||||
other.length_ = 0;
|
||||
}
|
||||
|
||||
PaddleBuf::PaddleBuf(const PaddleBuf &other) { *this = other; }
|
||||
|
||||
PaddleBuf &PaddleBuf::operator=(const PaddleBuf &other) {
|
||||
if (this == &other) return *this;
|
||||
if (!other.memory_owned_) {
|
||||
data_ = other.data_;
|
||||
length_ = other.length_;
|
||||
memory_owned_ = other.memory_owned_;
|
||||
} else {
|
||||
Resize(other.length());
|
||||
// if other.length() == 0 or other.data() == nullptr, then the memcpy
|
||||
// behavior is undefined
|
||||
if (other.length() && other.data())
|
||||
memcpy(data_, other.data(), other.length());
|
||||
else if (other.length())
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"Invalid argument, null pointer data with length %u is passed",
|
||||
other.length()));
|
||||
|
||||
length_ = other.length();
|
||||
memory_owned_ = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
PaddleBuf &PaddleBuf::operator=(PaddleBuf &&other) noexcept {
|
||||
// only the buffer with external memory can be copied
|
||||
data_ = other.data_;
|
||||
length_ = other.length_;
|
||||
memory_owned_ = other.memory_owned_;
|
||||
other.data_ = nullptr;
|
||||
other.length_ = 0;
|
||||
other.memory_owned_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PaddleBuf::Resize(size_t length) {
|
||||
// Only the owned memory can be reset, the external memory can't be changed.
|
||||
if (length_ >= length) return;
|
||||
if (memory_owned_) {
|
||||
Free();
|
||||
data_ = new char[length];
|
||||
length_ = length;
|
||||
memory_owned_ = true;
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::PreconditionNotMet(
|
||||
"The memory is allocated externally, can not Resized"));
|
||||
}
|
||||
}
|
||||
|
||||
void PaddleBuf::Reset(void *data, size_t length) {
|
||||
Free();
|
||||
memory_owned_ = false;
|
||||
data_ = data;
|
||||
length_ = length;
|
||||
}
|
||||
|
||||
void PaddleBuf::Free() {
|
||||
if (memory_owned_ && data_) {
|
||||
PADDLE_ENFORCE_GT(
|
||||
length_,
|
||||
0UL,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The memory used in PaddleBuf %d should be greater than 0",
|
||||
length_));
|
||||
delete[] static_cast<char *>(data_);
|
||||
data_ = nullptr;
|
||||
length_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NativeConfig::NativeConfig() {
|
||||
LOG(WARNING) << "The paddle::NativeConfig interface is going to be "
|
||||
"deprecated in the next release, please use the latest "
|
||||
"paddle_infer::Config instead.";
|
||||
}
|
||||
|
||||
std::string get_version() {
|
||||
std::stringstream ss;
|
||||
ss << "version: " << framework::paddle_version() << "\n";
|
||||
ss << "commit: " << framework::paddle_commit() << "\n";
|
||||
ss << "branch: " << framework::paddle_compile_branch() << "\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void UpdateDllFlag(const char *name, const char *value) {
|
||||
std::string ret;
|
||||
LOG(WARNING)
|
||||
<< "The function \"UpdateDllFlag\" is only used to update the flag "
|
||||
"on the Windows shared library";
|
||||
bool success = paddle::flags::SetFlagValue(name, value);
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
success,
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"Fail to update flag: %s, please make sure the flag exists.", name));
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_CRYPTO
|
||||
std::shared_ptr<framework::Cipher> MakeCipher(const std::string &config_file) {
|
||||
return framework::CipherFactory::CreateCipher(config_file);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace paddle
|
||||
|
||||
#ifdef PADDLE_WITH_CUSTOM_DEVICE
|
||||
#include "paddle/phi/capi/capi.h"
|
||||
#endif
|
||||
@@ -0,0 +1,403 @@
|
||||
/* Copyright (c) 2018 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 "paddle/fluid/inference/api/api_impl.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "paddle/fluid/framework/feed_fetch_method.h"
|
||||
#include "paddle/fluid/inference/api/helper.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/cpu_helper.h"
|
||||
#include "paddle/phi/core/platform/profiler.h"
|
||||
|
||||
PD_DEFINE_bool(profile, false, "Turn on profiler for fluid"); // NOLINT
|
||||
|
||||
namespace paddle {
|
||||
namespace {
|
||||
using paddle::inference::Timer;
|
||||
|
||||
template <class T>
|
||||
std::string num2str(T a) {
|
||||
std::stringstream istr;
|
||||
istr << a;
|
||||
return istr.str();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void NativePaddlePredictor::PrepareFeedFetch() {
|
||||
for (auto *op : inference_program_->Block(0).AllOps()) {
|
||||
if (op->Type() == "feed") {
|
||||
int idx = PADDLE_GET_CONST(int, op->GetAttr("col"));
|
||||
if (feeds_.size() <= static_cast<size_t>(idx)) {
|
||||
feeds_.resize(idx + 1);
|
||||
}
|
||||
feeds_[idx] = op;
|
||||
feed_names_[op->Output("Out")[0]] = idx;
|
||||
} else if (op->Type() == "fetch") {
|
||||
int idx = PADDLE_GET_CONST(int, op->GetAttr("col"));
|
||||
if (fetches_.size() <= static_cast<size_t>(idx)) {
|
||||
fetches_.resize(idx + 1);
|
||||
}
|
||||
fetches_[idx] = op;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NativePaddlePredictor::Init(
|
||||
std::shared_ptr<framework::Scope> parent_scope) {
|
||||
VLOG(3) << "Predictor::init()";
|
||||
if (FLAGS_profile) {
|
||||
LOG(WARNING) << "Profiler is activated, might affect the performance";
|
||||
LOG(INFO) << "You can turn off by set gflags '-profile false'";
|
||||
|
||||
auto tracking_device = config_.use_gpu ? platform::ProfilerState::kAll
|
||||
: platform::ProfilerState::kCPU;
|
||||
platform::EnableProfiler(tracking_device);
|
||||
}
|
||||
|
||||
// no matter with or without OneDNN
|
||||
paddle::platform::SetNumThreads(config_.cpu_math_library_num_threads());
|
||||
|
||||
if (config_.use_gpu) {
|
||||
PADDLE_ENFORCE_EQ(config_.use_xpu,
|
||||
false,
|
||||
common::errors::InvalidArgument(
|
||||
"Only one choice can be made between CPU and XPU."));
|
||||
place_ = phi::GPUPlace(config_.device);
|
||||
} else if (config_.use_xpu) {
|
||||
place_ = phi::XPUPlace(config_.device);
|
||||
} else {
|
||||
place_ = phi::CPUPlace();
|
||||
}
|
||||
if (parent_scope) {
|
||||
scope_ = parent_scope;
|
||||
sub_scope_ = &(parent_scope->NewScope());
|
||||
PADDLE_ENFORCE_NOT_NULL(sub_scope_,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The sub_scope should not be nullptr."));
|
||||
} else {
|
||||
paddle::framework::InitMemoryMethod();
|
||||
paddle::framework::InitDevices();
|
||||
paddle::framework::InitDefaultKernelSignatureMap();
|
||||
scope_ = std::make_unique<paddle::framework::Scope>();
|
||||
}
|
||||
|
||||
executor_ = std::make_unique<paddle::framework::Executor>(place_);
|
||||
|
||||
// Initialize the inference program
|
||||
if (!config_.model_dir.empty()) { // NOLINT
|
||||
// Parameters are saved in separate files sited in
|
||||
// the specified `dirname`.
|
||||
inference_program_ = paddle::inference::Load(
|
||||
executor_.get(), scope_.get(), config_.model_dir);
|
||||
} else if (!config_.prog_file.empty() && !config_.param_file.empty()) {
|
||||
// All parameters are saved in a single file.
|
||||
// The file names should be consistent with that used
|
||||
// in Python API `fluid.io.save_inference_model`.
|
||||
inference_program_ = paddle::inference::Load(
|
||||
executor_.get(), scope_.get(), config_.prog_file, config_.param_file);
|
||||
} else {
|
||||
LOG(ERROR) << "fail to load inference model from " << config_.model_dir;
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx_ = executor_->Prepare(*inference_program_, 0);
|
||||
executor_->CreateVariables(
|
||||
*inference_program_, sub_scope_ ? sub_scope_ : scope_.get(), 0);
|
||||
|
||||
// Get the feed_target_names and fetch_target_names
|
||||
PrepareFeedFetch();
|
||||
return true;
|
||||
}
|
||||
|
||||
NativePaddlePredictor::~NativePaddlePredictor() {
|
||||
if (FLAGS_profile) {
|
||||
platform::DisableProfiler(platform::EventSortingKey::kTotal,
|
||||
"./profile.log");
|
||||
}
|
||||
if (sub_scope_) {
|
||||
scope_->DeleteScope(sub_scope_);
|
||||
}
|
||||
}
|
||||
|
||||
bool NativePaddlePredictor::Run(const std::vector<PaddleTensor> &inputs,
|
||||
std::vector<PaddleTensor> *output_data,
|
||||
int batch_size) {
|
||||
#ifndef PADDLE_ON_INFERENCE
|
||||
LOG_FIRST_N(WARNING, 5) << "The NaiveExecutor can not work properly if the "
|
||||
"cmake flag ON_INFER is not set.";
|
||||
LOG_FIRST_N(WARNING, 5) << "Unlike the training phase, all the scopes and "
|
||||
"variables will be reused to save the allocation "
|
||||
"overhead.";
|
||||
LOG_FIRST_N(WARNING, 5) << "Please re-compile the inference library by "
|
||||
"setting the cmake flag ON_INFER=ON if you are "
|
||||
"running Paddle Inference";
|
||||
#endif // PADDLE_ON_INFERENCE
|
||||
if (UNLIKELY(config_.cpu_math_library_num_threads() > 1)) {
|
||||
paddle::platform::SetNumThreads(config_.cpu_math_library_num_threads());
|
||||
}
|
||||
VLOG(3) << "Predictor::predict";
|
||||
Timer timer;
|
||||
timer.tic();
|
||||
// set feed variable
|
||||
framework::Scope *scope = sub_scope_ != nullptr ? sub_scope_ : scope_.get();
|
||||
if (!SetFeed(inputs, scope)) {
|
||||
LOG(ERROR) << "fail to set feed";
|
||||
return false;
|
||||
}
|
||||
// Run the inference program
|
||||
// if share variables, we need not create variables
|
||||
VLOG(4) << "Run prepared context";
|
||||
executor_->RunPreparedContext(ctx_.get(),
|
||||
scope,
|
||||
false, /* don't create local scope each time*/
|
||||
false /* don't create variable each time */);
|
||||
VLOG(4) << "Finish prepared context";
|
||||
// get fetch variable
|
||||
if (!GetFetch(output_data, scope)) {
|
||||
LOG(ERROR) << "fail to get fetches";
|
||||
return false;
|
||||
}
|
||||
VLOG(3) << "predict cost: " << timer.toc() << "ms";
|
||||
|
||||
// For some other vector like containers not cleaned after each batch.
|
||||
tensor_array_batch_cleaner_.CollectNoTensorVars(scope_.get());
|
||||
tensor_array_batch_cleaner_.ResetNoTensorVars();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<PaddlePredictor> NativePaddlePredictor::Clone(void *stream) {
|
||||
std::lock_guard<std::mutex> lk(clone_mutex_);
|
||||
VLOG(3) << "Predictor::clone";
|
||||
std::unique_ptr<PaddlePredictor> cls(new NativePaddlePredictor(config_));
|
||||
// Hot fix the bug that result diff in multi-thread.
|
||||
// TODO(Superjomn) re-implement a real clone here.
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
dynamic_cast<NativePaddlePredictor *>(cls.get()),
|
||||
common::errors::PreconditionNotMet(
|
||||
"Dynamic_cast from PaddlePredictor to NativePaddlePredictor failed"));
|
||||
if (!dynamic_cast<NativePaddlePredictor *>(cls.get())->Init(nullptr)) {
|
||||
LOG(ERROR) << "fail to call Init";
|
||||
return nullptr;
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
|
||||
bool NativePaddlePredictor::SetFeed(const std::vector<PaddleTensor> &inputs,
|
||||
framework::Scope *scope) {
|
||||
VLOG(3) << "Predictor::set_feed";
|
||||
if (inputs.size() != feeds_.size()) {
|
||||
LOG(ERROR) << "wrong feed input size, need " << feeds_.size() << " but get "
|
||||
<< inputs.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache the inputs memory for better concurrency performance.
|
||||
feed_tensors_.resize(inputs.size());
|
||||
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
auto &input = feed_tensors_[i];
|
||||
phi::DDim ddim = common::make_ddim(inputs[i].shape);
|
||||
void *input_ptr = nullptr;
|
||||
if (inputs[i].dtype == PaddleDType::INT64) {
|
||||
input_ptr = input.mutable_data<int64_t>(ddim, place_);
|
||||
} else if (inputs[i].dtype == PaddleDType::FLOAT32) {
|
||||
input_ptr = input.mutable_data<float>(ddim, place_);
|
||||
} else if (inputs[i].dtype == PaddleDType::INT32) {
|
||||
input_ptr = input.mutable_data<int32_t>(ddim, place_);
|
||||
} else if (inputs[i].dtype == PaddleDType::BFLOAT16) {
|
||||
input_ptr = input.mutable_data<bfloat16>(ddim, place_);
|
||||
} else {
|
||||
LOG(ERROR) << "unsupported feed type " << inputs[i].dtype;
|
||||
return false;
|
||||
}
|
||||
|
||||
PADDLE_ENFORCE_NOT_NULL(input_ptr,
|
||||
common::errors::InvalidArgument(
|
||||
"The input_ptr should not be nullptr."));
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
inputs[i].data.data(),
|
||||
common::errors::InvalidArgument(
|
||||
"The data of input tensor should not be null."));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
inputs[i].data.length(),
|
||||
input.numel() * phi::SizeOf(input.dtype()),
|
||||
common::errors::InvalidArgument(
|
||||
"The data contained in the input PaddleTensor had wrong length."));
|
||||
|
||||
if (phi::is_cpu_place(place_)) {
|
||||
// TODO(panyx0718): Init DenseTensor from existing memcpy to save a copy.
|
||||
std::memcpy(static_cast<void *>(input_ptr),
|
||||
inputs[i].data.data(),
|
||||
inputs[i].data.length());
|
||||
} else if (phi::is_gpu_place(place_)) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
phi::is_xpu_place(place_),
|
||||
false,
|
||||
common::errors::InvalidArgument(
|
||||
"Only one choice can be made between CPU and XPU."));
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
|
||||
auto *dev_ctx = static_cast<const phi::GPUContext *>(pool.Get(place_));
|
||||
auto dst_gpu_place = place_;
|
||||
memory::Copy(dst_gpu_place,
|
||||
static_cast<void *>(input_ptr),
|
||||
phi::CPUPlace(),
|
||||
inputs[i].data.data(),
|
||||
inputs[i].data.length(),
|
||||
dev_ctx->stream());
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Not compile with CUDA, should not reach here."));
|
||||
#endif
|
||||
} else if (phi::is_xpu_place(place_)) {
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
auto dst_xpu_place = place_;
|
||||
memory::Copy(dst_xpu_place,
|
||||
static_cast<void *>(input_ptr),
|
||||
phi::CPUPlace(),
|
||||
inputs[i].data.data(),
|
||||
inputs[i].data.length());
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Not compile with XPU, should not reach here."));
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO(Superjomn) Low performance, need optimization for heavy LoD copy.
|
||||
phi::LegacyLoD lod;
|
||||
for (auto &level : inputs[i].lod) {
|
||||
lod.emplace_back(level);
|
||||
}
|
||||
input.set_lod(lod);
|
||||
int idx = -1;
|
||||
if (config_.specify_input_name) { // NOLINT
|
||||
idx = static_cast<int>(feed_names_[inputs[i].name]);
|
||||
} else {
|
||||
idx = PADDLE_GET_CONST(int, feeds_[i]->GetAttr("col"));
|
||||
}
|
||||
framework::SetFeedVariable(scope, input, "feed", idx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
void NativePaddlePredictor::GetFetchOne(const phi::DenseTensor &fetch,
|
||||
PaddleTensor *output) {
|
||||
// set shape.
|
||||
auto shape = common::vectorize(fetch.dims());
|
||||
output->shape.assign(shape.begin(), shape.end());
|
||||
// set data.
|
||||
const T *data = fetch.data<T>();
|
||||
int num_elems = inference::VecReduceToInt(shape);
|
||||
output->data.Resize(num_elems * sizeof(T));
|
||||
// The fetched tensor output by fetch op, should always in CPU memory, so just
|
||||
// copy.
|
||||
memcpy(output->data.data(), data, num_elems * sizeof(T));
|
||||
// set lod
|
||||
output->lod.clear();
|
||||
for (auto &level : fetch.lod()) {
|
||||
output->lod.emplace_back(level.begin(), level.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool NativePaddlePredictor::GetFetch(std::vector<PaddleTensor> *outputs,
|
||||
framework::Scope *scope) {
|
||||
VLOG(3) << "Predictor::get_fetch";
|
||||
outputs->resize(fetches_.size());
|
||||
for (size_t i = 0; i < fetches_.size(); ++i) {
|
||||
int idx = PADDLE_GET_CONST(int, fetches_[i]->GetAttr("col"));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
static_cast<size_t>(idx),
|
||||
i,
|
||||
common::errors::InvalidArgument(
|
||||
"Fetch op's col attr(%d) should be equal to the index(%d)",
|
||||
idx,
|
||||
i));
|
||||
framework::FetchType &fetch_var =
|
||||
framework::GetFetchVariable(*scope, "fetch", idx);
|
||||
auto fetch = PADDLE_GET_CONST(phi::DenseTensor, fetch_var);
|
||||
auto type = framework::TransToProtoVarType(fetch.dtype());
|
||||
auto output = &(outputs->at(i));
|
||||
output->name = fetches_[idx]->Input("X")[0];
|
||||
if (type == framework::DataTypeTrait<float>::DataType()) {
|
||||
GetFetchOne<float>(fetch, output);
|
||||
output->dtype = PaddleDType::FLOAT32;
|
||||
} else if (type == framework::DataTypeTrait<int64_t>::DataType()) {
|
||||
GetFetchOne<int64_t>(fetch, output);
|
||||
output->dtype = PaddleDType::INT64;
|
||||
} else if (type == framework::DataTypeTrait<int32_t>::DataType()) {
|
||||
GetFetchOne<int32_t>(fetch, output);
|
||||
output->dtype = PaddleDType::INT32;
|
||||
} else {
|
||||
LOG(ERROR) << "unknown type, only support float32, int64 and int32 now.";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<NativeConfig, PaddleEngineKind::kNative>(
|
||||
const NativeConfig &config) {
|
||||
// TODO(NHZlX): Should add the link to the doc of
|
||||
// paddle_infer::CreatePredictor<paddle_infer::Config>
|
||||
VLOG(3) << "create NativePaddlePredictor";
|
||||
if (config.use_gpu) {
|
||||
// 1. GPU memory
|
||||
PADDLE_ENFORCE_GE(config.fraction_of_gpu_memory,
|
||||
0.f,
|
||||
common::errors::InvalidArgument(
|
||||
"fraction_of_gpu_memory in the config should be set "
|
||||
"to range (0., 1.]"));
|
||||
PADDLE_ENFORCE_GE(config.device,
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Invalid device id %d, the device id should be "
|
||||
"greater than or equal to 0.",
|
||||
config.device));
|
||||
std::vector<std::string> flags;
|
||||
if (config.fraction_of_gpu_memory >= 0.0f ||
|
||||
config.fraction_of_gpu_memory <= 0.95f) {
|
||||
std::string flag = "--fraction_of_gpu_memory_to_use=" +
|
||||
num2str<float>(config.fraction_of_gpu_memory);
|
||||
flags.push_back(flag);
|
||||
VLOG(3) << "set flag: " << flag;
|
||||
framework::InitGflags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PaddlePredictor> predictor(new NativePaddlePredictor(config));
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
dynamic_cast<NativePaddlePredictor *>(predictor.get()),
|
||||
common::errors::PreconditionNotMet(
|
||||
"Dynamic_cast from PaddlePredictor to NativePaddlePredictor failed"));
|
||||
if (!dynamic_cast<NativePaddlePredictor *>(predictor.get())->Init(nullptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return predictor;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<PaddlePredictor> CreatePaddlePredictor<NativeConfig>(
|
||||
const NativeConfig &config) {
|
||||
LOG(WARNING) << "Deprecated. Please use CreatePredictor instead.";
|
||||
return CreatePaddlePredictor<NativeConfig, PaddleEngineKind::kNative>(config);
|
||||
}
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright (c) 2018 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 <glog/logging.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/ddim.h"
|
||||
#include "paddle/fluid/framework/dense_tensor_array.h"
|
||||
#include "paddle/fluid/framework/lod_tensor.h"
|
||||
#include "paddle/fluid/framework/naive_executor.h"
|
||||
#include "paddle/fluid/inference/api/details/reset_tensor_array.h"
|
||||
#include "paddle/fluid/inference/api/paddle_api.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/fluid/inference/io.h"
|
||||
#include "paddle/fluid/platform/init.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/profiler.h"
|
||||
|
||||
namespace paddle {
|
||||
|
||||
namespace framework {
|
||||
class Scope;
|
||||
} // namespace framework
|
||||
|
||||
class NativePaddlePredictor : public PaddlePredictor {
|
||||
public:
|
||||
explicit NativePaddlePredictor(const NativeConfig &config)
|
||||
: config_(config) {}
|
||||
|
||||
// will only create sub scope if have global scope
|
||||
bool Init(std::shared_ptr<framework::Scope> parent_scope);
|
||||
|
||||
bool Run(const std::vector<PaddleTensor> &inputs,
|
||||
std::vector<PaddleTensor> *output_data,
|
||||
int batch_size = -1) override;
|
||||
|
||||
std::unique_ptr<PaddlePredictor> Clone(void *stream = nullptr) override;
|
||||
|
||||
~NativePaddlePredictor() override;
|
||||
|
||||
framework::Scope *scope() { return sub_scope_ ? sub_scope_ : scope_.get(); }
|
||||
|
||||
protected:
|
||||
bool SetFeed(const std::vector<PaddleTensor> &input_datas,
|
||||
framework::Scope *scope);
|
||||
bool GetFetch(std::vector<PaddleTensor> *output_data,
|
||||
framework::Scope *scope);
|
||||
template <typename T>
|
||||
void GetFetchOne(const phi::DenseTensor &fetches, PaddleTensor *output_data);
|
||||
void PrepareFeedFetch();
|
||||
|
||||
NativeConfig config_;
|
||||
phi::Place place_;
|
||||
std::unique_ptr<framework::Executor> executor_;
|
||||
std::shared_ptr<framework::Scope> scope_;
|
||||
std::unique_ptr<framework::ExecutorPrepareContext> ctx_;
|
||||
std::unique_ptr<framework::ProgramDesc> inference_program_;
|
||||
std::vector<framework::OpDesc *> feeds_;
|
||||
std::map<std::string, size_t> feed_names_;
|
||||
std::vector<framework::OpDesc *> fetches_;
|
||||
// Memory buffer for feed inputs. The temporary DenseTensor will cause serious
|
||||
// concurrency problems, wrong results and memory leak, so cache them.
|
||||
std::vector<phi::DenseTensor> feed_tensors_;
|
||||
// Do not use unique_ptr, use parent scope to delete
|
||||
framework::Scope *sub_scope_{nullptr};
|
||||
details::TensorArrayBatchCleaner tensor_array_batch_cleaner_;
|
||||
// A mutex to make Clone thread safe.
|
||||
std::mutex clone_mutex_;
|
||||
};
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1 @@
|
||||
data
|
||||
@@ -0,0 +1,356 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(cpp_inference_demo CXX C)
|
||||
option(WITH_MKL "Compile demo with MKL/OpenBlas support, default use MKL." ON)
|
||||
option(WITH_GPU "Compile demo with GPU/CPU, default use CPU." OFF)
|
||||
option(WITH_STATIC_LIB
|
||||
"Compile demo with static/shared library, default use static." ON)
|
||||
option(USE_TENSORRT "Compile demo with TensorRT." OFF)
|
||||
option(WITH_ONNXRUNTIME "Compile demo with ONNXRuntime" OFF)
|
||||
option(WITH_SHARED_PHI "Compile demo with phi shared lib" ON)
|
||||
option(CUSTOM_OPERATOR_FILES "List of file names for custom operators" "")
|
||||
option(CUSTOM_PASS_FILES "List of file names for custom passes" "")
|
||||
|
||||
if(NOT WITH_STATIC_LIB)
|
||||
add_definitions("-DPADDLE_WITH_SHARED_LIB")
|
||||
else()
|
||||
# PD_INFER_DECL is mainly used to set the dllimport/dllexport attribute in dynamic library mode.
|
||||
# Set it to empty in static library mode to avoid compilation issues.
|
||||
add_definitions("/DPD_INFER_DECL=")
|
||||
endif()
|
||||
|
||||
macro(safe_set_static_flag)
|
||||
foreach(flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if(${flag_var} MATCHES "/MD")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
if(NOT DEFINED PADDLE_LIB)
|
||||
message(
|
||||
FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/path/paddle/lib")
|
||||
endif()
|
||||
if(NOT DEFINED DEMO_NAME)
|
||||
message(FATAL_ERROR "please set DEMO_NAME with -DDEMO_NAME=demo_name")
|
||||
endif()
|
||||
|
||||
include_directories("${PADDLE_LIB}/paddle/include")
|
||||
set(PADDLE_LIB_THIRD_PARTY_PATH "${PADDLE_LIB}/third_party/install/")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}utf8proc/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}yaml-cpp/include")
|
||||
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}protobuf/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}glog/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}utf8proc/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}gflags/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}xxhash/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}cryptopp/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}yaml-cpp/lib")
|
||||
link_directories("${PADDLE_LIB}/paddle/lib")
|
||||
|
||||
if(WITH_ONNXRUNTIME)
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/include")
|
||||
include_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/include")
|
||||
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib")
|
||||
link_directories("${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_definitions("/DGOOGLE_GLOG_DLL_DECL=")
|
||||
option(MSVC_STATIC_CRT "use static C Runtime library by default" ON)
|
||||
if(MSVC_STATIC_CRT)
|
||||
if(WITH_MKL)
|
||||
set(FLAG_OPENMP "/openmp")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4244 /wd4251 /wd4267 /wd4305")
|
||||
set(CMAKE_C_FLAGS_DEBUG
|
||||
"${CMAKE_C_FLAGS_DEBUG} /bigobj /MTd ${FLAG_OPENMP}")
|
||||
set(CMAKE_C_FLAGS_RELEASE
|
||||
"${CMAKE_C_FLAGS_RELEASE} /bigobj /MT ${FLAG_OPENMP}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /wd4251 /wd4267 /wd4305")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} /bigobj /MTd ${FLAG_OPENMP}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} /bigobj /MT ${FLAG_OPENMP}")
|
||||
safe_set_static_flag()
|
||||
if(WITH_STATIC_LIB)
|
||||
add_definitions(-DSTATIC_LIB)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(WITH_MKL)
|
||||
set(FLAG_OPENMP "-fopenmp")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 ${FLAG_OPENMP}")
|
||||
endif()
|
||||
|
||||
if(WITH_GPU)
|
||||
if(NOT WIN32)
|
||||
set(CUDA_LIB
|
||||
"/usr/local/cuda/lib64/"
|
||||
CACHE STRING "CUDA Library")
|
||||
else()
|
||||
set(CUDA_LIB
|
||||
""
|
||||
CACHE STRING "CUDA_LIB")
|
||||
if("${CUDA_LIB}" STREQUAL "")
|
||||
if(DEFINED ENV{CUDA_PATH})
|
||||
set(CUDA_LIB "$ENV{CUDA_PATH}\\lib\\x64")
|
||||
else()
|
||||
set(CUDA_LIB
|
||||
"C:\\Program\ Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v10.2\\lib\\x64"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Current CUDA lib path: ${CUDA_LIB}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_TENSORRT AND WITH_GPU)
|
||||
set(TENSORRT_ROOT
|
||||
""
|
||||
CACHE STRING "The root directory of TensorRT library")
|
||||
if("${TENSORRT_ROOT}" STREQUAL "")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"The TENSORRT_ROOT is empty, you must assign it a value with CMake command. Such as: -DTENSORRT_ROOT=TENSORRT_ROOT_PATH "
|
||||
)
|
||||
endif()
|
||||
set(TENSORRT_INCLUDE_DIR ${TENSORRT_ROOT}/include)
|
||||
set(TENSORRT_LIB_DIR ${TENSORRT_ROOT}/lib)
|
||||
file(READ ${TENSORRT_INCLUDE_DIR}/NvInfer.h TENSORRT_VERSION_FILE_CONTENTS)
|
||||
string(REGEX MATCH "define NV_TENSORRT_MAJOR +([0-9]+)"
|
||||
TENSORRT_MAJOR_VERSION "${TENSORRT_VERSION_FILE_CONTENTS}")
|
||||
if("${TENSORRT_MAJOR_VERSION}" STREQUAL "")
|
||||
file(READ ${TENSORRT_INCLUDE_DIR}/NvInferVersion.h
|
||||
TENSORRT_VERSION_FILE_CONTENTS)
|
||||
string(REGEX MATCH "define NV_TENSORRT_MAJOR +([0-9]+)"
|
||||
TENSORRT_MAJOR_VERSION "${TENSORRT_VERSION_FILE_CONTENTS}")
|
||||
endif()
|
||||
if("${TENSORRT_MAJOR_VERSION}" STREQUAL "")
|
||||
message(SEND_ERROR "Failed to detect TensorRT version.")
|
||||
endif()
|
||||
string(REGEX REPLACE "define NV_TENSORRT_MAJOR +([0-9]+)" "\\1"
|
||||
TENSORRT_MAJOR_VERSION "${TENSORRT_MAJOR_VERSION}")
|
||||
message(
|
||||
STATUS "Current TensorRT header is ${TENSORRT_INCLUDE_DIR}/NvInfer.h. "
|
||||
"Current TensorRT version is v${TENSORRT_MAJOR_VERSION}. ")
|
||||
include_directories("${TENSORRT_INCLUDE_DIR}")
|
||||
link_directories("${TENSORRT_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
if(WITH_MKL)
|
||||
set(MATH_LIB_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}mklml")
|
||||
include_directories("${MATH_LIB_PATH}/include")
|
||||
if(WIN32)
|
||||
set(MATH_LIB ${MATH_LIB_PATH}/lib/mklml${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
${MATH_LIB_PATH}/lib/libiomp5md${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
else()
|
||||
set(MATH_LIB
|
||||
${MATH_LIB_PATH}/lib/libmklml_intel${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
${MATH_LIB_PATH}/lib/libiomp5${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
set(ONEDNN_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}onednn")
|
||||
if(EXISTS ${ONEDNN_PATH})
|
||||
include_directories("${ONEDNN_PATH}/include")
|
||||
if(WIN32)
|
||||
set(ONEDNN_LIB ${ONEDNN_PATH}/lib/mkldnn.lib)
|
||||
else()
|
||||
set(ONEDNN_LIB ${ONEDNN_PATH}/lib/libdnnl.so.3)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(OPENBLAS_LIB_PATH "${PADDLE_LIB_THIRD_PARTY_PATH}openblas")
|
||||
include_directories("${OPENBLAS_LIB_PATH}/include/openblas")
|
||||
if(WIN32)
|
||||
set(MATH_LIB
|
||||
${OPENBLAS_LIB_PATH}/lib/openblas${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
else()
|
||||
set(MATH_LIB
|
||||
${OPENBLAS_LIB_PATH}/lib/libopenblas${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_STATIC_LIB)
|
||||
set(DEPS
|
||||
${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
)
|
||||
else()
|
||||
if(WIN32)
|
||||
set(DEPS
|
||||
${PADDLE_LIB}/paddle/lib/paddle_inference${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
else()
|
||||
set(DEPS
|
||||
${PADDLE_LIB}/paddle/lib/libpaddle_inference${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ONNXRUNTIME)
|
||||
set(DEPS ${DEPS} onnxruntime paddle2onnx)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
set(EXTERNAL_LIB "-lrt -ldl -lpthread")
|
||||
set(DEPS
|
||||
${DEPS}
|
||||
${MATH_LIB}
|
||||
${ONEDNN_LIB}
|
||||
glog
|
||||
gflags
|
||||
protobuf
|
||||
xxhash
|
||||
cryptopp
|
||||
utf8proc
|
||||
${PADDLE_LIB_THIRD_PARTY_PATH}yaml-cpp/lib/libyaml-cpp.a
|
||||
${EXTERNAL_LIB})
|
||||
if(WITH_SHARED_PHI)
|
||||
set(DEPS
|
||||
${DEPS} ${PADDLE_LIB}/paddle/lib/libphi${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
${PADDLE_LIB}/paddle/lib/libphi_core${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
${PADDLE_LIB}/paddle/lib/libcommon${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
if(WITH_GPU OR WITH_ROCM)
|
||||
set(DEPS
|
||||
${DEPS}
|
||||
${PADDLE_LIB}/paddle/lib/libphi_gpu${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(DEPS
|
||||
${DEPS}
|
||||
${MATH_LIB}
|
||||
${ONEDNN_LIB}
|
||||
phi
|
||||
glog
|
||||
gflags_static
|
||||
libprotobuf
|
||||
xxhash
|
||||
cryptopp-static
|
||||
utf8proc_static
|
||||
${EXTERNAL_LIB})
|
||||
set(DEPS ${DEPS} shlwapi.lib
|
||||
${PADDLE_LIB_THIRD_PARTY_PATH}yaml-cpp/lib/yaml-cpp.lib)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
set(DEPS ${DEPS} stdc++fs)
|
||||
endif()
|
||||
|
||||
if(WITH_GPU)
|
||||
if(NOT WIN32)
|
||||
if(USE_TENSORRT)
|
||||
set(DEPS ${DEPS}
|
||||
${TENSORRT_LIB_DIR}/libnvinfer${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(DEPS
|
||||
${DEPS}
|
||||
${TENSORRT_LIB_DIR}/libnvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
set(DEPS ${DEPS} ${CUDA_LIB}/libcudart${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
else()
|
||||
if(USE_TENSORRT)
|
||||
set(DEPS ${DEPS}
|
||||
${TENSORRT_LIB_DIR}/nvinfer${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set(DEPS ${DEPS}
|
||||
${TENSORRT_LIB_DIR}/nvinfer_plugin${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
set(DEPS ${DEPS} ${CUDA_LIB}/cudart${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set(DEPS ${DEPS} ${CUDA_LIB}/cublas${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set(DEPS ${DEPS} ${CUDA_LIB}/cudnn${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CUSTOM_OPERATOR_FILES)
|
||||
if(WITH_GPU AND NOT APPLE)
|
||||
add_definitions("-DPADDLE_WITH_CUDA")
|
||||
enable_language(CUDA)
|
||||
find_package(CUDA REQUIRED)
|
||||
include_directories("${CUDA_INCLUDE_DIRS}")
|
||||
endif()
|
||||
add_library(pd_infer_custom_op SHARED ${CUSTOM_OPERATOR_FILES})
|
||||
set(DEPS ${DEPS} pd_infer_custom_op)
|
||||
endif()
|
||||
|
||||
if(CUSTOM_PASS_FILES)
|
||||
add_library(pd_infer_custom_pass SHARED ${CUSTOM_PASS_FILES})
|
||||
set(DEPS ${DEPS} pd_infer_custom_pass)
|
||||
endif()
|
||||
|
||||
add_executable(${DEMO_NAME} ${DEMO_NAME}.cc)
|
||||
target_link_libraries(${DEMO_NAME} ${DEPS})
|
||||
if(WIN32)
|
||||
if("${CMAKE_GENERATOR}" MATCHES "Ninja")
|
||||
set(LIB_PATH ${CMAKE_BINARY_DIR})
|
||||
else()
|
||||
set(LIB_PATH ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
if(USE_TENSORRT)
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy
|
||||
${TENSORRT_LIB_DIR}/nvinfer${CMAKE_SHARED_LIBRARY_SUFFIX} ${LIB_PATH}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy
|
||||
${TENSORRT_LIB_DIR}/nvinfer_plugin${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
${LIB_PATH})
|
||||
endif()
|
||||
if(WITH_SHARED_PHI)
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${PADDLE_LIB}/paddle/lib/common.dll
|
||||
${LIB_PATH})
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${PADDLE_LIB}/paddle/lib/phi.dll
|
||||
${LIB_PATH})
|
||||
endif()
|
||||
if(WITH_MKL)
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${MATH_LIB_PATH}/lib/mklml.dll
|
||||
${LIB_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${MATH_LIB_PATH}/lib/libiomp5md.dll
|
||||
${LIB_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${ONEDNN_PATH}/lib/mkldnn.dll
|
||||
${LIB_PATH})
|
||||
else()
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${OPENBLAS_LIB_PATH}/lib/openblas.dll
|
||||
${LIB_PATH})
|
||||
endif()
|
||||
if(WITH_ONNXRUNTIME)
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy
|
||||
${PADDLE_LIB_THIRD_PARTY_PATH}onnxruntime/lib/onnxruntime.dll
|
||||
${LIB_PATH}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy
|
||||
${PADDLE_LIB_THIRD_PARTY_PATH}paddle2onnx/lib/paddle2onnx.dll
|
||||
${LIB_PATH})
|
||||
endif()
|
||||
if(NOT WITH_STATIC_LIB)
|
||||
add_custom_command(
|
||||
TARGET ${DEMO_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${PADDLE_LIB}/paddle/lib/paddle_inference.dll" ${LIB_PATH})
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,26 @@
|
||||
# Inference Demos
|
||||
|
||||
There are several demos:
|
||||
|
||||
- simple_on_word2vec:
|
||||
- Follow the C++ codes is in `simple_on_word2vec.cc`.
|
||||
- It is suitable for word2vec model.
|
||||
- vis_demo:
|
||||
- Follow the C++ codes is in `vis_demo.cc`.
|
||||
- It is suitable for mobilenet, se_resnext50 and ocr three models.
|
||||
- Input data format:
|
||||
- Each line contains a single record
|
||||
- Each record's format is
|
||||
```
|
||||
<space split floats as data>\t<space split ints as shape>
|
||||
```
|
||||
|
||||
To build and execute the demos, simply run
|
||||
```
|
||||
./run.sh $PADDLE_ROOT $TURN_ON_MKL $TEST_GPU_CPU
|
||||
```
|
||||
- It will build and execute the demos in both static and shared library.
|
||||
- `$PADDLE_ROOT`: paddle library path
|
||||
- `$TURN_ON_MKL`: use MKL or Openblas
|
||||
- `$TEST_GPU_CPU`: test both GPU/CPU mode or only CPU mode
|
||||
- NOTE: for simple_on_word2vec, must run `ctest -R test_word2vec -R` to obtain word2vec model at first.
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
set -x
|
||||
cd `dirname $0`
|
||||
rm -rf build/ data/
|
||||
set +x
|
||||
@@ -0,0 +1,65 @@
|
||||
/* Copyright (c) 2024 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 <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <numeric>
|
||||
|
||||
#include "paddle_inference_api.h" //NOLINT
|
||||
|
||||
DEFINE_string(modeldir, "", "Directory of the inference model.");
|
||||
|
||||
using paddle_infer::Config;
|
||||
using paddle_infer::CreatePredictor;
|
||||
using paddle_infer::Predictor;
|
||||
|
||||
void run(Predictor *predictor,
|
||||
const std::vector<float> &input,
|
||||
const std::vector<int> &input_shape,
|
||||
std::vector<float> *out_data) {
|
||||
auto input_names = predictor->GetInputNames();
|
||||
auto input_t = predictor->GetInputHandle(input_names[0]);
|
||||
input_t->Reshape(input_shape);
|
||||
input_t->CopyFromCpu(input.data());
|
||||
|
||||
CHECK(predictor->Run());
|
||||
|
||||
auto output_names = predictor->GetOutputNames();
|
||||
auto output_t = predictor->GetOutputHandle(output_names[0]);
|
||||
std::vector<int> output_shape = output_t->shape();
|
||||
int out_num = std::accumulate(
|
||||
output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
|
||||
|
||||
out_data->resize(out_num);
|
||||
output_t->CopyToCpu(out_data->data());
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
Config config;
|
||||
config.EnableUseGpu(100, 0);
|
||||
config.SetModel(FLAGS_modeldir + "/custom_relu.pdmodel",
|
||||
FLAGS_modeldir + "/custom_relu.pdiparams");
|
||||
config.EnableNewExecutor(true);
|
||||
config.EnableNewIR(true);
|
||||
auto predictor = CreatePredictor(config);
|
||||
std::vector<int> input_shape = {1, 1, 28, 28};
|
||||
std::vector<float> input_data(1 * 1 * 28 * 28, 1);
|
||||
std::vector<float> out_data;
|
||||
run(predictor.get(), input_data, input_shape, &out_data);
|
||||
for (auto e : out_data) {
|
||||
LOG(INFO) << e << '\n';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright (c) 2024 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 <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
#include "paddle/extension.h"
|
||||
#include "paddle_inference_api.h" //NOLINT
|
||||
|
||||
DEFINE_string(modeldir, "", "Directory of the inference model.");
|
||||
|
||||
using paddle_infer::Config;
|
||||
using paddle_infer::CreatePredictor;
|
||||
using paddle_infer::Predictor;
|
||||
|
||||
std::shared_ptr<Predictor> InitPredictor(bool use_custom_pass) {
|
||||
Config config;
|
||||
config.EnableUseGpu(100, 0);
|
||||
config.SetModel(FLAGS_modeldir + "/inference.pdmodel",
|
||||
FLAGS_modeldir + "/inference.pdiparams");
|
||||
config.EnableNewExecutor(true);
|
||||
config.EnableNewIR(true);
|
||||
// config.SwitchIrDebug(true);
|
||||
if (use_custom_pass) {
|
||||
config.EnableCustomPasses({"relu_replace_pass"});
|
||||
}
|
||||
|
||||
return CreatePredictor(config);
|
||||
}
|
||||
|
||||
std::vector<float> GetOutputData(const std::shared_ptr<Predictor> &predictor) {
|
||||
auto input_names = predictor->GetInputNames();
|
||||
auto input_shapes = predictor->GetInputTensorShape();
|
||||
|
||||
for (const auto &input_name : input_names) {
|
||||
// update input shape's batch size
|
||||
input_shapes[input_name][0] = 1;
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> inputs, outputs;
|
||||
for (const auto &input_name : input_names) {
|
||||
auto input_tensor = paddle::full(input_shapes[input_name],
|
||||
0.5,
|
||||
paddle::DataType::FLOAT32,
|
||||
paddle::GPUPlace{});
|
||||
input_tensor.set_name(input_name);
|
||||
inputs.emplace_back(std::move(input_tensor));
|
||||
}
|
||||
PADDLE_ENFORCE_EQ(
|
||||
predictor->Run(inputs, &outputs),
|
||||
true,
|
||||
common::errors::ExecutionTimeout("Sorry, predictor run failed"));
|
||||
PADDLE_ENFORCE_EQ(outputs[0].place(),
|
||||
paddle::GPUPlace{},
|
||||
common::errors::InvalidArgument(
|
||||
"Sorry, output tensor place is not GPUPlace"));
|
||||
PADDLE_ENFORCE_EQ(outputs[0].dtype(),
|
||||
paddle::DataType::FLOAT32,
|
||||
common::errors::InvalidArgument(
|
||||
"Sorry, output tensor dtype is not FLOAT32"));
|
||||
auto output = outputs[0].copy_to(paddle::CPUPlace{}, true);
|
||||
|
||||
std::vector<float> output_data;
|
||||
for (int64_t i = 0; i < output.numel(); i++) {
|
||||
output_data.push_back(output.data<float>()[i]);
|
||||
}
|
||||
return output_data;
|
||||
}
|
||||
|
||||
bool AreEqual(const std::vector<float> &vec1,
|
||||
const std::vector<float> &vec2,
|
||||
float epsilon) {
|
||||
if (vec1.size() != vec2.size()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < vec1.size(); ++i) {
|
||||
if (std::fabs(vec1[i] - vec2[i]) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
auto base_data = GetOutputData(InitPredictor(false));
|
||||
auto custom_data = GetOutputData(InitPredictor(true));
|
||||
|
||||
PADDLE_ENFORCE_EQ(AreEqual(base_data, custom_data, 1e-3),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"Sorry, base_data and custom_data are not equal"));
|
||||
return 0;
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// 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.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/extension.h"
|
||||
|
||||
template <typename data_t>
|
||||
void relu_cpu_forward_kernel(const data_t* x_data,
|
||||
data_t* out_data,
|
||||
int64_t x_numel) {
|
||||
for (int i = 0; i < x_numel; ++i) {
|
||||
out_data[i] = std::max(static_cast<data_t>(0.), x_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename data_t>
|
||||
void relu_cpu_backward_kernel(const data_t* grad_out_data,
|
||||
const data_t* out_data,
|
||||
data_t* grad_x_data,
|
||||
int64_t out_numel) {
|
||||
for (int i = 0; i < out_numel; ++i) {
|
||||
grad_x_data[i] =
|
||||
grad_out_data[i] * (out_data[i] > static_cast<data_t>(0) ? 1. : 0.);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> relu_cpu_forward(const paddle::Tensor& x) {
|
||||
auto out = paddle::empty_like(x);
|
||||
PD_DISPATCH_FLOATING_TYPES(
|
||||
x.type(), "relu_cpu_forward", ([&] {
|
||||
relu_cpu_forward_kernel<data_t>(
|
||||
x.data<data_t>(), out.data<data_t>(), x.size());
|
||||
}));
|
||||
|
||||
return {out};
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> relu_cpu_backward(const paddle::Tensor& x,
|
||||
const paddle::Tensor& out,
|
||||
const paddle::Tensor& grad_out) {
|
||||
auto grad_x = paddle::empty_like(x);
|
||||
|
||||
PD_DISPATCH_FLOATING_TYPES(out.type(), "relu_cpu_backward", ([&] {
|
||||
relu_cpu_backward_kernel<data_t>(
|
||||
grad_out.data<data_t>(),
|
||||
out.data<data_t>(),
|
||||
grad_x.data<data_t>(),
|
||||
out.size());
|
||||
}));
|
||||
|
||||
return {grad_x};
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> relu_cuda_forward(const paddle::Tensor& x);
|
||||
std::vector<paddle::Tensor> relu_cuda_backward(const paddle::Tensor& x,
|
||||
const paddle::Tensor& out,
|
||||
const paddle::Tensor& grad_out);
|
||||
|
||||
std::vector<paddle::Tensor> ReluForward(const paddle::Tensor& x) {
|
||||
// TODO(chenweihang): Check Input
|
||||
if (x.is_cpu()) {
|
||||
return relu_cpu_forward(x);
|
||||
} else if (x.is_gpu()) {
|
||||
return relu_cuda_forward(x);
|
||||
} else {
|
||||
throw std::runtime_error("Not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> ReluBackward(const paddle::Tensor& x,
|
||||
const paddle::Tensor& out,
|
||||
const paddle::Tensor& grad_out) {
|
||||
// TODO(chenweihang): Check Input
|
||||
if (x.is_cpu()) {
|
||||
return relu_cpu_backward(x, out, grad_out);
|
||||
} else if (x.is_gpu()) {
|
||||
return relu_cuda_backward(x, out, grad_out);
|
||||
} else {
|
||||
throw std::runtime_error("Not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
PD_BUILD_OP(custom_relu)
|
||||
.Inputs({"X"})
|
||||
.Outputs({"Out"})
|
||||
.SetKernelFn(PD_KERNEL(ReluForward));
|
||||
|
||||
PD_BUILD_GRAD_OP(custom_relu)
|
||||
.Inputs({"X", "Out", paddle::Grad("Out")})
|
||||
.Outputs({paddle::Grad("X")})
|
||||
.SetKernelFn(PD_KERNEL(ReluBackward));
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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.
|
||||
|
||||
#include "paddle/extension.h"
|
||||
|
||||
template <typename data_t>
|
||||
__global__ void relu_cuda_forward_kernel(const data_t* x,
|
||||
data_t* y,
|
||||
const int num) {
|
||||
int gid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
for (int i = gid; i < num; i += blockDim.x * gridDim.x) {
|
||||
y[i] = max(x[i], static_cast<data_t>(0.));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename data_t>
|
||||
__global__ void relu_cuda_backward_kernel(const data_t* dy,
|
||||
const data_t* y,
|
||||
data_t* dx,
|
||||
const int num) {
|
||||
int gid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
for (int i = gid; i < num; i += blockDim.x * gridDim.x) {
|
||||
dx[i] = dy[i] * (y[i] > 0 ? 1. : 0.);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> relu_cuda_forward(const paddle::Tensor& x) {
|
||||
auto out = paddle::empty_like(x);
|
||||
|
||||
int numel = x.size();
|
||||
int block = 512;
|
||||
int grid = (numel + block - 1) / block;
|
||||
PD_DISPATCH_FLOATING_TYPES(
|
||||
x.type(), "relu_cuda_forward_kernel", ([&] {
|
||||
relu_cuda_forward_kernel<data_t><<<grid, block, 0, x.stream()>>>(
|
||||
x.data<data_t>(), out.data<data_t>(), numel);
|
||||
}));
|
||||
|
||||
return {out};
|
||||
}
|
||||
|
||||
std::vector<paddle::Tensor> relu_cuda_backward(const paddle::Tensor& x,
|
||||
const paddle::Tensor& out,
|
||||
const paddle::Tensor& grad_out) {
|
||||
auto grad_x = paddle::empty_like(x);
|
||||
|
||||
int numel = out.size();
|
||||
int block = 512;
|
||||
int grid = (numel + block - 1) / block;
|
||||
PD_DISPATCH_FLOATING_TYPES(out.type(), "relu_cuda_backward_kernel", ([&] {
|
||||
relu_cuda_backward_kernel<data_t>
|
||||
<<<grid, block, 0, x.stream()>>>(
|
||||
grad_out.data<data_t>(),
|
||||
out.data<data_t>(),
|
||||
grad_x.data<data_t>(),
|
||||
numel);
|
||||
}));
|
||||
|
||||
return {grad_x};
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* Copyright (c) 2024 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 "paddle/extension.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class ReluReplacePattern : public paddle::drr::DrrPatternBase {
|
||||
public:
|
||||
std::string name() const override { return "ReluReplacePattern"; }
|
||||
|
||||
void operator()(paddle::drr::DrrPatternContext *ctx) const override {
|
||||
paddle::drr::SourcePattern pat = ctx->SourcePattern();
|
||||
const auto &relu = pat.Op("pd_op.relu");
|
||||
relu({&pat.Tensor("in")}, {&pat.Tensor("out")});
|
||||
|
||||
paddle::drr::ResultPattern res = pat.ResultPattern();
|
||||
const auto &custom_relu = res.Op("custom_op.custom_relu");
|
||||
custom_relu({&res.Tensor("in")}, {&res.Tensor("out")});
|
||||
}
|
||||
};
|
||||
|
||||
class ReluReplacePass : public pir::PatternRewritePass {
|
||||
public:
|
||||
ReluReplacePass() : pir::PatternRewritePass("relu_replace_pass", 2) {}
|
||||
|
||||
pir::RewritePatternSet InitializePatterns(pir::IrContext *context) override {
|
||||
pir::RewritePatternSet ps(context);
|
||||
ps.Add(paddle::drr::Create<ReluReplacePattern>(context));
|
||||
return ps;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
REGISTER_IR_PASS(relu_replace_pass, ReluReplacePass);
|
||||
@@ -0,0 +1,103 @@
|
||||
/* Copyright (c) 2022 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. */
|
||||
|
||||
/*
|
||||
* This file contains demo of mobilenet for onnxruntime backend.
|
||||
*/
|
||||
#include <glog/logging.h> // use glog instead of CHECK to avoid importing other paddle header files.
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "utils.h" // NOLINT
|
||||
|
||||
DEFINE_string(modeldir, "", "Directory of the inference model.");
|
||||
DEFINE_string(data, "", "path of data");
|
||||
|
||||
namespace paddle {
|
||||
namespace demo {
|
||||
|
||||
/*
|
||||
* Use the onnxruntime engine to inference the demo.
|
||||
*/
|
||||
void Main() {
|
||||
paddle::AnalysisConfig config;
|
||||
config.EnableONNXRuntime();
|
||||
config.SetModel(FLAGS_modeldir + "/inference.pdmodel",
|
||||
FLAGS_modeldir + "/inference.pdiparams");
|
||||
auto predictor = paddle_infer::CreatePredictor(config);
|
||||
|
||||
// Inference.
|
||||
LOG(INFO) << "--- prepare input data ----";
|
||||
std::vector<int> input_shape = {1, 3, 224, 224};
|
||||
std::vector<float> input_data;
|
||||
std::string line;
|
||||
std::ifstream file(FLAGS_data);
|
||||
std::getline(file, line);
|
||||
file.close();
|
||||
std::vector<std::string> data_strs;
|
||||
split(line, ' ', &data_strs);
|
||||
int input_num = 0;
|
||||
for (auto& d : data_strs) {
|
||||
input_num += 1;
|
||||
input_data.push_back(std::stof(d));
|
||||
}
|
||||
|
||||
std::vector<float> out_data;
|
||||
out_data.resize(1000);
|
||||
auto input_names = predictor->GetInputNames();
|
||||
auto output_names = predictor->GetOutputNames();
|
||||
auto input_tensor = predictor->GetInputHandle(input_names[0]);
|
||||
input_tensor->Reshape(input_shape);
|
||||
auto output_tensor = predictor->GetOutputHandle(output_names[0]);
|
||||
|
||||
input_tensor->CopyFromCpu(input_data.data());
|
||||
predictor->Run();
|
||||
output_tensor->CopyToCpu(out_data.data());
|
||||
|
||||
std::vector<int> out_index(out_data.size());
|
||||
std::iota(out_index.begin(), out_index.end(), 0);
|
||||
std::sort(
|
||||
out_index.begin(), out_index.end(), [&out_data](int index1, int index2) {
|
||||
return out_data[index1] > out_data[index2];
|
||||
});
|
||||
LOG(INFO) << "output.size " << out_data.size()
|
||||
<< " max_index:" << out_index[0];
|
||||
PADDLE_ENFORCE_EQ(out_data.size(),
|
||||
1000,
|
||||
common::errors::InvalidArgument(
|
||||
"Required out_data.size() should be equal to 1000. "));
|
||||
int max_index = out_index[0];
|
||||
PADDLE_ENFORCE_EQ(max_index,
|
||||
13,
|
||||
common::errors::InvalidArgument(
|
||||
"Required max_index should be equal to 13. "));
|
||||
float max_score = out_data[max_index];
|
||||
PADDLE_ENFORCE_LE(fabs(max_score - 0.99981),
|
||||
1e-4,
|
||||
common::errors::InvalidArgument(
|
||||
"Required fabs(max_score - 0.99981) should "
|
||||
"be less than or equal to 1e-4. "));
|
||||
}
|
||||
|
||||
} // namespace demo
|
||||
} // namespace paddle
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
paddle::demo::Main();
|
||||
return 0;
|
||||
}
|
||||
Executable
+272
@@ -0,0 +1,272 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
set -x
|
||||
PADDLE_ROOT=$1
|
||||
TURN_ON_MKL=$2 # use MKL or Openblas
|
||||
TEST_GPU_CPU=$3 # test both GPU/CPU mode or only CPU mode
|
||||
DATA_DIR=$4 # dataset
|
||||
USE_TENSORRT=$5
|
||||
TENSORRT_ROOT_DIR=$6 # TensorRT root dir, default to /usr
|
||||
WITH_ONNXRUNTIME=$7
|
||||
MSVC_STATIC_CRT=$8
|
||||
CUDA_LIB=$9/lib/x64
|
||||
inference_install_dir=${PADDLE_ROOT}/build/paddle_inference_install_dir
|
||||
WIN_DETECT=$(echo `uname` | grep "Win") # detect current platform
|
||||
|
||||
cd `dirname $0`
|
||||
current_dir=`pwd`
|
||||
|
||||
if [ $2 == ON ]; then
|
||||
# You can export yourself if move the install path
|
||||
MKL_LIB=${inference_install_dir}/third_party/install/mklml/lib
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${MKL_LIB}
|
||||
fi
|
||||
if [ $3 == ON ]; then
|
||||
use_gpu_list='true false'
|
||||
else
|
||||
use_gpu_list='false'
|
||||
fi
|
||||
|
||||
mkdir -p $DATA_DIR
|
||||
cd $DATA_DIR
|
||||
|
||||
if [ $7 == ON ]; then
|
||||
ONNXRUNTIME_LIB=${inference_install_dir}/third_party/install/onnxruntime/lib
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${ONNXRUNTIME_LIB}
|
||||
PADDLE2ONNX_LIB=${inference_install_dir}/third_party/install/paddle2onnx/lib
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${PADDLE2ONNX_LIB}
|
||||
#download model
|
||||
mkdir -p MobileNetV2
|
||||
cd MobileNetV2
|
||||
if [[ -e "MobileNetV2.inference.model.tar.gz" ]]; then
|
||||
rm -rf MobileNetV2.inference.model.tar.gz
|
||||
fi
|
||||
# echo "MobileNetV2.inference.model.tar.gz has been downloaded."
|
||||
# else
|
||||
if [ $WIN_DETECT != "" ]; then
|
||||
wget -q -Y off http://paddle-inference-dist.bj.bcebos.com/MobileNetV2.inference.model.tar.gz
|
||||
else
|
||||
wget -q --no-proxy http://paddle-inference-dist.bj.bcebos.com/MobileNetV2.inference.model.tar.gz
|
||||
fi
|
||||
tar xzf *.tar.gz
|
||||
# fi
|
||||
cd ..
|
||||
fi
|
||||
|
||||
PREFIX=inference-vis-demos%2F
|
||||
URL_ROOT=http://paddlemodels.bj.bcebos.com/${PREFIX}
|
||||
|
||||
# download vis_demo data
|
||||
function download() {
|
||||
dir_name=$1
|
||||
mkdir -p $dir_name
|
||||
cd $dir_name
|
||||
if [[ -e "${PREFIX}${dir_name}.tar.gz" ]]; then
|
||||
echo "${PREFIX}${dir_name}.tar.gz has been downloaded."
|
||||
else
|
||||
if [ $WIN_DETECT != "" ]; then
|
||||
wget -q -Y off ${URL_ROOT}$dir_name.tar.gz
|
||||
else
|
||||
wget -q --no-proxy ${URL_ROOT}$dir_name.tar.gz
|
||||
fi
|
||||
tar xzf *.tar.gz
|
||||
fi
|
||||
cd ..
|
||||
}
|
||||
|
||||
vis_demo_list='se_resnext50 ocr mobilenet'
|
||||
for vis_demo_name in $vis_demo_list; do
|
||||
download $vis_demo_name
|
||||
done
|
||||
|
||||
# download word2vec data
|
||||
mkdir -p word2vec
|
||||
cd word2vec
|
||||
if [[ -e "word2vec.inference.model.tar.gz" ]]; then
|
||||
echo "word2vec.inference.model.tar.gz has been downloaded."
|
||||
else
|
||||
wget -q http://paddle-inference-dist.bj.bcebos.com/word2vec.inference.model.tar.gz
|
||||
tar xzf *.tar.gz
|
||||
fi
|
||||
cd ..
|
||||
|
||||
#download custom_op_demo data
|
||||
mkdir -p custom_op
|
||||
cd custom_op
|
||||
if [[ -e "custom_relu_infer_model.tgz" ]]; then
|
||||
echo "custom_relu_infer_model.tgz has been downloaded."
|
||||
else
|
||||
wget -q https://paddle-inference-dist.bj.bcebos.com/inference_demo/custom_operator/custom_relu_infer_model.tgz
|
||||
tar xzf *.tgz
|
||||
fi
|
||||
cd ..
|
||||
|
||||
#download custom_pass_demo data
|
||||
mkdir -p custom_pass
|
||||
cd custom_pass
|
||||
if [ ! -d resnet50 ]; then
|
||||
wget https://paddle-inference-dist.bj.bcebos.com/Paddle-Inference-Demo/resnet50.tgz
|
||||
tar xzf resnet50.tgz
|
||||
fi
|
||||
|
||||
# compile and test the demo
|
||||
cd $current_dir
|
||||
mkdir -p build
|
||||
cd build
|
||||
rm -rf *
|
||||
|
||||
# run all test cases before exit
|
||||
EXIT_CODE=0
|
||||
|
||||
for WITH_STATIC_LIB in ON OFF; do
|
||||
if [ $(echo `uname` | grep "Win") != "" ]; then
|
||||
# TODO(wilber, T8T9): Do we still need to support windows gpu static library
|
||||
if [ $TEST_GPU_CPU == ON ] && [ $WITH_STATIC_LIB == ON ]; then
|
||||
continue
|
||||
fi
|
||||
# -----simple_on_word2vec on windows-----
|
||||
cmake .. -GNinja -DPADDLE_LIB=${inference_install_dir} \
|
||||
-DWITH_MKL=$TURN_ON_MKL \
|
||||
-DDEMO_NAME=simple_on_word2vec \
|
||||
-DWITH_GPU=$TEST_GPU_CPU \
|
||||
-DWITH_STATIC_LIB=$WITH_STATIC_LIB \
|
||||
-DMSVC_STATIC_CRT=$MSVC_STATIC_CRT \
|
||||
-DWITH_ONNXRUNTIME=$WITH_ONNXRUNTIME \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCUDA_LIB="$CUDA_LIB"
|
||||
ninja
|
||||
for use_gpu in $use_gpu_list; do
|
||||
./simple_on_word2vec.exe \
|
||||
--dirname=$DATA_DIR/word2vec/word2vec.inference.model \
|
||||
--use_gpu=$use_gpu
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "simple_on_word2vec use_gpu:${use_gpu} runs failed " > ${current_dir}/test_summary.txt
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
done
|
||||
|
||||
# --------tensorrt mobilenet on windows------
|
||||
if [ $USE_TENSORRT == ON -a $TEST_GPU_CPU == ON ]; then
|
||||
rm -rf *
|
||||
fi
|
||||
else
|
||||
# -----simple_on_word2vec on linux/mac-----
|
||||
rm -rf *
|
||||
cmake .. -DPADDLE_LIB=${inference_install_dir} \
|
||||
-DWITH_MKL=$TURN_ON_MKL \
|
||||
-DDEMO_NAME=simple_on_word2vec \
|
||||
-DWITH_GPU=$TEST_GPU_CPU \
|
||||
-DWITH_STATIC_LIB=$WITH_STATIC_LIB \
|
||||
-DWITH_ONNXRUNTIME=$WITH_ONNXRUNTIME
|
||||
make -j$(nproc)
|
||||
word2vec_model=$DATA_DIR'/word2vec/word2vec.inference.model'
|
||||
if [ -d $word2vec_model ]; then
|
||||
for use_gpu in $use_gpu_list; do
|
||||
./simple_on_word2vec \
|
||||
--dirname=$DATA_DIR/word2vec/word2vec.inference.model \
|
||||
--use_gpu=$use_gpu
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "simple_on_word2vec use_gpu:${use_gpu} runs failed " >> ${current_dir}/test_summary.txt
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# --------onnxruntime mobilenetv2 on linux/mac------
|
||||
if [ $WITH_ONNXRUNTIME == ON ]; then
|
||||
rm -rf *
|
||||
cmake .. -DPADDLE_LIB=${inference_install_dir} \
|
||||
-DWITH_MKL=$TURN_ON_MKL \
|
||||
-DDEMO_NAME=onnxruntime_mobilenet_demo \
|
||||
-DWITH_GPU=$TEST_GPU_CPU \
|
||||
-DWITH_STATIC_LIB=$WITH_STATIC_LIB \
|
||||
-DUSE_TENSORRT=$USE_TENSORRT \
|
||||
-DTENSORRT_ROOT=$TENSORRT_ROOT_DIR \
|
||||
-DWITH_ONNXRUNTIME=$WITH_ONNXRUNTIME
|
||||
make -j$(nproc)
|
||||
./onnxruntime_mobilenet_demo \
|
||||
--modeldir=$DATA_DIR/MobileNetV2/MobileNetV2 \
|
||||
--data=$DATA_DIR/MobileNetV2/MobileNetV2/data.txt
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "onnxruntime_mobilenet_demo runs failed " >> ${current_dir}/test_summary.txt
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --------custom op demo on linux/mac------
|
||||
if [ $TEST_GPU_CPU == ON -a $WITH_STATIC_LIB == OFF ]; then
|
||||
rm -rf *
|
||||
CUSTOM_OPERATOR_FILES="custom_relu_op.cc;custom_relu_op.cu"
|
||||
cmake .. -DPADDLE_LIB=${inference_install_dir} \
|
||||
-DWITH_MKL=$TURN_ON_MKL \
|
||||
-DDEMO_NAME=custom_op_demo \
|
||||
-DWITH_GPU=$TEST_GPU_CPU \
|
||||
-DWITH_STATIC_LIB=OFF \
|
||||
-DUSE_TENSORRT=$USE_TENSORRT \
|
||||
-DTENSORRT_ROOT=$TENSORRT_ROOT_DIR \
|
||||
-DCUSTOM_OPERATOR_FILES=$CUSTOM_OPERATOR_FILES \
|
||||
-DWITH_ONNXRUNTIME=$WITH_ONNXRUNTIME
|
||||
make -j$(nproc)
|
||||
./custom_op_demo \
|
||||
--modeldir=$DATA_DIR/custom_op/custom_relu_infer_model
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "custom_op_demo runs failed " >> ${current_dir}/test_summary.txt
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --------custom pass demo on linux/mac------
|
||||
if [ $TEST_GPU_CPU == ON -a $WITH_STATIC_LIB == OFF ]; then
|
||||
rm -rf *
|
||||
CUSTOM_OPERATOR_FILES="custom_relu_op.cc;custom_relu_op.cu"
|
||||
CUSTOM_PASS_FILES="custom_relu_pass.cc"
|
||||
cmake .. -DPADDLE_LIB=${inference_install_dir} \
|
||||
-DWITH_MKL=$TURN_ON_MKL \
|
||||
-DDEMO_NAME=custom_pass_demo \
|
||||
-DWITH_GPU=$TEST_GPU_CPU \
|
||||
-DWITH_STATIC_LIB=OFF \
|
||||
-DUSE_TENSORRT=$USE_TENSORRT \
|
||||
-DTENSORRT_ROOT=$TENSORRT_ROOT_DIR \
|
||||
-DCUSTOM_OPERATOR_FILES=$CUSTOM_OPERATOR_FILES \
|
||||
-DCUSTOM_PASS_FILES=${CUSTOM_PASS_FILES} \
|
||||
-DWITH_ONNXRUNTIME=$WITH_ONNXRUNTIME
|
||||
make -j$(nproc)
|
||||
./custom_pass_demo \
|
||||
--modeldir=$DATA_DIR/custom_pass/resnet50
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "custom_pass_demo runs failed " >> ${current_dir}/test_summary.txt
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
set +x
|
||||
|
||||
if [[ -f ${current_dir}/test_summary.txt ]];then
|
||||
echo " "
|
||||
echo "Summary demo_ci Failed Tests ..."
|
||||
echo "=====================test summary======================"
|
||||
echo "The following tests Failed: "
|
||||
cat ${current_dir}/test_summary.txt
|
||||
echo "========================================================"
|
||||
echo " "
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
exit ${EXIT_CODE}
|
||||
@@ -0,0 +1,248 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set source_path=%~dp0
|
||||
set build_path=%~dp0\build
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
rem set gpu_inference
|
||||
SET /P gpu_inference="Use GPU_inference_lib or not(Y/N), default: N =======>"
|
||||
IF /i "%gpu_inference%"=="y" (
|
||||
SET gpu_inference=Y
|
||||
) else (
|
||||
SET gpu_inference=N
|
||||
)
|
||||
|
||||
SET /P use_mkl="Use MKL or not (Y/N), default: Y =======>"
|
||||
if /i "%use_mkl%"=="N" (
|
||||
set use_mkl=N
|
||||
) else (
|
||||
set use_mkl=Y
|
||||
)
|
||||
|
||||
:set_paddle_inference_lib
|
||||
SET /P paddle_inference_lib="Please input the path of paddle inference library, such as D:\paddle_inference_install_dir =======>"
|
||||
set tmp_var=!paddle_inference_lib!
|
||||
call:remove_space
|
||||
set paddle_inference_lib=!tmp_var!
|
||||
IF NOT EXIST "%paddle_inference_lib%" (
|
||||
echo "------------%paddle_inference_lib% not exist------------"
|
||||
goto set_paddle_inference_lib
|
||||
)
|
||||
|
||||
IF "%use_mkl%"=="N" (
|
||||
IF NOT EXIST "%paddle_inference_lib%\third_party\install\openblas" (
|
||||
echo "------------It's not a OpenBlas inference library------------"
|
||||
goto:eof
|
||||
)
|
||||
) else (
|
||||
IF NOT EXIST "%paddle_inference_lib%\third_party\install\mklml" (
|
||||
echo "------------It's not a MKL inference library------------"
|
||||
goto:eof
|
||||
)
|
||||
)
|
||||
|
||||
:set_path_cuda
|
||||
if /i "!gpu_inference!"=="Y" (
|
||||
SET /P cuda_lib_dir="Please input the path of cuda libraries, such as D:\cuda\lib\x64 =======>"
|
||||
set tmp_var=!cuda_lib_dir!
|
||||
call:remove_space
|
||||
set cuda_lib_dir=!tmp_var!
|
||||
IF NOT EXIST "!cuda_lib_dir!" (
|
||||
echo "------------!cuda_lib_dir!not exist------------"
|
||||
goto set_path_cuda
|
||||
)
|
||||
)
|
||||
|
||||
rem set_use_gpu
|
||||
if /i "!gpu_inference!"=="Y" (
|
||||
SET /P use_gpu="Use GPU or not(Y/N), default: N =======>"
|
||||
)
|
||||
|
||||
if /i "%use_gpu%"=="Y" (
|
||||
set use_gpu=Y
|
||||
) else (
|
||||
set use_gpu=N
|
||||
)
|
||||
|
||||
rem set_path_vs_command_prompt
|
||||
:set_vcvarsall_dir
|
||||
SET /P vcvarsall_dir="Please input the path of visual studio command Prompt, such as C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat =======>"
|
||||
set tmp_var=!vcvarsall_dir!
|
||||
call:remove_space
|
||||
set vcvarsall_dir=!tmp_var!
|
||||
IF NOT EXIST "%vcvarsall_dir%" (
|
||||
echo "------------%vcvarsall_dir% not exist------------"
|
||||
goto set_vcvarsall_dir
|
||||
)
|
||||
|
||||
rem set_demo_name
|
||||
:set_demo_name
|
||||
SET /P demo_name="Please input the demo name, default: windows_mobilenet =======>"
|
||||
if "%demo_name%"=="" set demo_name=windows_mobilenet
|
||||
IF NOT EXIST "%source_path%\%demo_name%.cc" (
|
||||
echo "------------%source_path%\%demo_name%.cc not exist------------"
|
||||
goto set_demo_name
|
||||
)
|
||||
if "%demo_name%"=="windows_mobilenet" set model_name=mobilenet
|
||||
if "%demo_name%"=="vis_demo" set model_name=mobilenet
|
||||
if "%demo_name%"=="simple_on_word2vec" set model_name=word2vec.inference.model
|
||||
if "%demo_name%"=="trt_mobilenet_demo" set model_name=mobilenet
|
||||
|
||||
rem download model
|
||||
if NOT EXIST "%source_path%\%model_name%.tar.gz" (
|
||||
if "%model_name%"=="mobilenet" (
|
||||
call:download_model_mobilenet
|
||||
)
|
||||
if "%model_name%"=="word2vec.inference.model" (
|
||||
call:download_model_word2vec
|
||||
)
|
||||
)
|
||||
|
||||
if EXIST "%source_path%\%model_name%.tar.gz" (
|
||||
if NOT EXIST "%source_path%\%model_name%" (
|
||||
SET /P python_path="Please input the path of python.exe, such as C:\Python37\python.exe =======>"
|
||||
set tmp_var=!python_path!
|
||||
call:remove_space
|
||||
set python_path=!tmp_var!
|
||||
if "!python_path!"=="" (
|
||||
set python_path=python.exe
|
||||
) else (
|
||||
if NOT exist "!python_path!" (
|
||||
echo "------------!python_path! not exist------------"
|
||||
goto:eof
|
||||
)
|
||||
)
|
||||
md %source_path%\%model_name%
|
||||
!python_path! %source_path%\untar_model.py %source_path%\%model_name%.tar.gz %source_path%\%model_name%
|
||||
|
||||
SET error_code=N
|
||||
if "%model_name%"=="mobilenet" (
|
||||
if NOT EXIST "%source_path%\%model_name%\model" set error_code=Y
|
||||
) else (
|
||||
if NOT EXIST "%source_path%\%model_name%\%model_name%" set error_code=Y
|
||||
)
|
||||
if "!error_code!"=="Y" (
|
||||
echo "========= Unzip %model_name%.tar.gz failed ======="
|
||||
del /f /s /q "%source_path%\%model_name%\*.*" >nul 2>&1
|
||||
rd /s /q "%source_path%\%model_name%" >nul 2>&1
|
||||
goto:eof
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
echo "=================================================================="
|
||||
echo.
|
||||
echo "use_gpu_inference=%gpu_inference%"
|
||||
echo.
|
||||
echo "use_mkl=%use_mkl%"
|
||||
echo.
|
||||
echo "use_gpu=%use_gpu%"
|
||||
echo.
|
||||
echo "paddle_inference_lib=%paddle_inference_lib%"
|
||||
echo.
|
||||
IF /i "%gpu_inference%"=="y" (
|
||||
echo "cuda_lib_dir=%cuda_lib_dir%"
|
||||
echo.
|
||||
)
|
||||
echo "vs_vcvarsall_dir=%vcvarsall_dir%"
|
||||
echo.
|
||||
echo "demo_name=%demo_name%"
|
||||
echo.
|
||||
if NOT "!python_path!"=="" (
|
||||
echo "python_path=!python_path!"
|
||||
echo.
|
||||
)
|
||||
echo "===================================================================="
|
||||
pause
|
||||
|
||||
|
||||
rem compile and run demo
|
||||
|
||||
if NOT EXIST "%build_path%" (
|
||||
md %build_path%
|
||||
cd %build_path%
|
||||
) else (
|
||||
del /f /s /q "%build_path%\*.*" >nul 2>&1
|
||||
rd /s /q "%build_path%" >nul 2>&1
|
||||
md %build_path%
|
||||
cd %build_path%
|
||||
)
|
||||
|
||||
if /i "%use_mkl%"=="N" (
|
||||
set use_mkl=OFF
|
||||
) else (
|
||||
set use_mkl=ON
|
||||
)
|
||||
|
||||
if /i "%gpu_inference%"=="Y" (
|
||||
if "%demo_name%"=="trt_mobilenet_demo" (
|
||||
cmake .. -G "Visual Studio 15 2017 Win64" -T host=x64 -DWITH_GPU=ON ^
|
||||
-DWITH_MKL=%use_mkl% -DWITH_STATIC_LIB=ON -DCMAKE_BUILD_TYPE=Release -DDEMO_NAME=%demo_name% ^
|
||||
-DPADDLE_LIB="%paddle_inference_lib%" -DMSVC_STATIC_CRT=ON -DCUDA_LIB="%cuda_lib_dir%" -DUSE_TENSORRT=ON
|
||||
) else (
|
||||
cmake .. -G "Visual Studio 15 2017 Win64" -T host=x64 -DWITH_GPU=ON ^
|
||||
-DWITH_MKL=%use_mkl% -DWITH_STATIC_LIB=ON -DCMAKE_BUILD_TYPE=Release -DDEMO_NAME=%demo_name% ^
|
||||
-DPADDLE_LIB="%paddle_inference_lib%" -DMSVC_STATIC_CRT=ON -DCUDA_LIB="%cuda_lib_dir%"
|
||||
)
|
||||
) else (
|
||||
cmake .. -G "Visual Studio 15 2017 Win64" -T host=x64 -DWITH_GPU=OFF ^
|
||||
-DWITH_MKL=%use_mkl% -DWITH_STATIC_LIB=ON -DCMAKE_BUILD_TYPE=Release -DDEMO_NAME=%demo_name% ^
|
||||
-DPADDLE_LIB="%paddle_inference_lib%" -DMSVC_STATIC_CRT=ON
|
||||
)
|
||||
|
||||
call "%vcvarsall_dir%" amd64
|
||||
msbuild /m /p:Configuration=Release %demo_name%.vcxproj
|
||||
|
||||
if /i "%use_gpu%"=="Y" (
|
||||
SET use_gpu=true
|
||||
) else (
|
||||
SET use_gpu=false
|
||||
)
|
||||
|
||||
if exist "%build_path%\Release\%demo_name%.exe" (
|
||||
cd %build_path%\Release
|
||||
set GLOG_v=4
|
||||
if "%demo_name%"=="simple_on_word2vec" (
|
||||
%demo_name%.exe --dirname="%source_path%\%model_name%\%model_name%" --use_gpu="%use_gpu%"
|
||||
) else (
|
||||
if "%demo_name%"=="windows_mobilenet" (
|
||||
%demo_name%.exe --modeldir="%source_path%\%model_name%\model" --use_gpu="%use_gpu%"
|
||||
) else (
|
||||
if "%demo_name%"=="trt_mobilenet_demo" (
|
||||
%demo_name%.exe --modeldir="%source_path%\%model_name%\model" --data=%source_path%\%model_name%\data.txt ^
|
||||
--refer=%source_path%\%model_name%\result.txt
|
||||
) else (
|
||||
%demo_name%.exe --modeldir="%source_path%\%model_name%\model" --data=%source_path%\%model_name%\data.txt ^
|
||||
--refer=%source_path%\%model_name%\result.txt --use_gpu="%use_gpu%"
|
||||
)
|
||||
)
|
||||
)
|
||||
) else (
|
||||
echo "=========compilation fails!!=========="
|
||||
)
|
||||
echo.&pause&goto:eof
|
||||
|
||||
:download_model_mobilenet
|
||||
powershell.exe (new-object System.Net.WebClient).DownloadFile('http://paddlemodels.bj.bcebos.com//inference-vis-demos/mobilenet.tar.gz', ^
|
||||
'%source_path%\mobilenet.tar.gz')
|
||||
goto:eof
|
||||
|
||||
:download_model_word2vec
|
||||
powershell.exe (new-object System.Net.WebClient).DownloadFile('http://paddle-inference-dist.bj.bcebos.com/word2vec.inference.model.tar.gz', ^
|
||||
'%source_path%\word2vec.inference.model.tar.gz')
|
||||
goto:eof
|
||||
|
||||
:remove_space
|
||||
:remove_left_space
|
||||
if "%tmp_var:~0,1%"==" " (
|
||||
set "tmp_var=%tmp_var:~1%"
|
||||
goto remove_left_space
|
||||
)
|
||||
|
||||
:remove_right_space
|
||||
if "%tmp_var:~-1%"==" " (
|
||||
set "tmp_var=%tmp_var:~0,-1%"
|
||||
goto remove_left_space
|
||||
)
|
||||
goto:eof
|
||||
@@ -0,0 +1,146 @@
|
||||
/* Copyright (c) 2018 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. */
|
||||
|
||||
/*
|
||||
* This file contains a simple demo for how to take a model for inference.
|
||||
*/
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <thread> //NOLINT
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "utils.h" // NOLINT
|
||||
|
||||
DEFINE_string(dirname, "", "Directory of the inference model.");
|
||||
DEFINE_bool(use_gpu, false, "Whether use gpu.");
|
||||
|
||||
namespace paddle {
|
||||
namespace demo {
|
||||
|
||||
void Main(bool use_gpu) {
|
||||
//# 1. Create PaddlePredictor with a config.
|
||||
NativeConfig config;
|
||||
if (FLAGS_dirname.empty()) {
|
||||
LOG(INFO) << "Usage: ./simple_on_word2vec --dirname=path/to/your/model";
|
||||
exit(1);
|
||||
}
|
||||
config.model_dir = FLAGS_dirname;
|
||||
config.use_gpu = use_gpu;
|
||||
config.fraction_of_gpu_memory = 0.15;
|
||||
config.device = 0;
|
||||
auto predictor = CreatePaddlePredictor<NativeConfig>(config);
|
||||
|
||||
for (int batch_id = 0; batch_id < 3; batch_id++) {
|
||||
//# 2. Prepare input.
|
||||
int64_t data[4] = {1, 2, 3, 4};
|
||||
|
||||
PaddleTensor tensor;
|
||||
tensor.shape = std::vector<int>({4, 1});
|
||||
tensor.data = PaddleBuf(data, sizeof(data));
|
||||
tensor.dtype = PaddleDType::INT64;
|
||||
|
||||
// For simplicity, we set all the slots with the same data.
|
||||
std::vector<PaddleTensor> slots(4, tensor);
|
||||
|
||||
//# 3. Run
|
||||
std::vector<PaddleTensor> outputs;
|
||||
CHECK(predictor->Run(slots, &outputs));
|
||||
|
||||
//# 4. Get output.
|
||||
CHECK_EQ(outputs.size(), 1UL);
|
||||
// Check the output buffer size and result of each tid.
|
||||
CHECK_EQ(outputs.front().data.length(), 33168UL);
|
||||
float result[5] = {
|
||||
0.00129761, 0.00151112, 0.000423564, 0.00108815, 0.000932706};
|
||||
const size_t num_elements = outputs.front().data.length() / sizeof(float);
|
||||
// The outputs' buffers are in CPU memory.
|
||||
for (size_t i = 0; i < std::min(static_cast<size_t>(5), num_elements);
|
||||
i++) {
|
||||
CHECK_NEAR(static_cast<float*>(outputs.front().data.data())[i],
|
||||
result[i],
|
||||
0.001);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainThreads(int num_threads, bool use_gpu) {
|
||||
// Multi-threads only support on CPU
|
||||
// 0. Create PaddlePredictor with a config.
|
||||
NativeConfig config;
|
||||
config.model_dir = FLAGS_dirname;
|
||||
config.use_gpu = use_gpu;
|
||||
config.fraction_of_gpu_memory = 0.15;
|
||||
config.device = 0;
|
||||
auto main_predictor = CreatePaddlePredictor<NativeConfig>(config);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int tid = 0; tid < num_threads; ++tid) {
|
||||
threads.emplace_back([&, tid]() {
|
||||
// 1. clone a predictor which shares the same parameters
|
||||
auto predictor = main_predictor->Clone();
|
||||
constexpr int num_batches = 3;
|
||||
for (int batch_id = 0; batch_id < num_batches; ++batch_id) {
|
||||
// 2. Dummy Input Data
|
||||
int64_t data[4] = {1, 2, 3, 4};
|
||||
PaddleTensor tensor;
|
||||
tensor.shape = std::vector<int>({4, 1});
|
||||
tensor.data = PaddleBuf(data, sizeof(data));
|
||||
tensor.dtype = PaddleDType::INT64;
|
||||
|
||||
std::vector<PaddleTensor> inputs(4, tensor);
|
||||
std::vector<PaddleTensor> outputs;
|
||||
// 3. Run
|
||||
CHECK(predictor->Run(inputs, &outputs));
|
||||
|
||||
// 4. Get output.
|
||||
CHECK_EQ(outputs.size(), 1UL);
|
||||
// Check the output buffer size and result of each tid.
|
||||
CHECK_EQ(outputs.front().data.length(), 33168UL);
|
||||
float result[5] = {
|
||||
0.00129761, 0.00151112, 0.000423564, 0.00108815, 0.000932706};
|
||||
const size_t num_elements =
|
||||
outputs.front().data.length() / sizeof(float);
|
||||
// The outputs' buffers are in CPU memory.
|
||||
for (size_t i = 0; i < std::min(static_cast<size_t>(5), num_elements);
|
||||
i++) {
|
||||
CHECK_NEAR(static_cast<float*>(outputs.front().data.data())[i],
|
||||
result[i],
|
||||
0.001);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (int i = 0; i < num_threads; ++i) {
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace demo
|
||||
} // namespace paddle
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
paddle::demo::Main(false /* use_gpu*/);
|
||||
paddle::demo::MainThreads(1, false /* use_gpu*/);
|
||||
paddle::demo::MainThreads(4, false /* use_gpu*/);
|
||||
if (FLAGS_use_gpu) {
|
||||
paddle::demo::Main(true /*use_gpu*/);
|
||||
paddle::demo::MainThreads(1, true /*use_gpu*/);
|
||||
paddle::demo::MainThreads(4, true /*use_gpu*/);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* Copyright (c) 2018 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. */
|
||||
|
||||
/*
|
||||
* This file contains demo of mobilenet for tensorrt.
|
||||
*/
|
||||
|
||||
#include <glog/logging.h> // use glog instead of CHECK to avoid importing other paddle header files.
|
||||
#include "gflags/gflags.h"
|
||||
#include "utils.h" // NOLINT
|
||||
|
||||
DEFINE_string(modeldir, "", "Directory of the inference model.");
|
||||
DEFINE_string(refer, "", "path to reference result for comparison.");
|
||||
DEFINE_string(data,
|
||||
"",
|
||||
"path of data; each line is a record, format is "
|
||||
"'<space split floats as data>\t<space split ints as shape'");
|
||||
|
||||
namespace paddle {
|
||||
namespace demo {
|
||||
|
||||
/*
|
||||
* Use the tensorrt fluid engine to inference the demo.
|
||||
*/
|
||||
void Main() {
|
||||
std::unique_ptr<PaddlePredictor> predictor;
|
||||
paddle::AnalysisConfig config;
|
||||
config.EnableUseGpu(100, 0);
|
||||
config.SetModel(FLAGS_modeldir + "/__model__",
|
||||
FLAGS_modeldir + "/__params__");
|
||||
config.EnableTensorRtEngine();
|
||||
predictor = CreatePaddlePredictor(config);
|
||||
|
||||
VLOG(3) << "begin to process data";
|
||||
// Just a single batch of data.
|
||||
std::string line;
|
||||
std::ifstream file(FLAGS_data);
|
||||
std::getline(file, line);
|
||||
auto record = ProcessALine(line);
|
||||
file.close();
|
||||
|
||||
// Inference.
|
||||
PaddleTensor input;
|
||||
input.shape = record.shape;
|
||||
input.data =
|
||||
PaddleBuf(record.data.data(), record.data.size() * sizeof(float));
|
||||
input.dtype = PaddleDType::FLOAT32;
|
||||
|
||||
VLOG(3) << "run executor";
|
||||
std::vector<PaddleTensor> output;
|
||||
predictor->Run({input}, &output, 1);
|
||||
|
||||
VLOG(3) << "output.size " << output.size();
|
||||
auto& tensor = output.front();
|
||||
VLOG(3) << "output: " << SummaryTensor(tensor);
|
||||
|
||||
// compare with reference result
|
||||
CheckOutput(FLAGS_refer, tensor);
|
||||
}
|
||||
|
||||
} // namespace demo
|
||||
} // namespace paddle
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
paddle::demo::Main();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2019 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.
|
||||
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
|
||||
def untar(fname, dirs):
|
||||
"""
|
||||
extract the tar.gz file
|
||||
:param fname: the name of tar.gz file
|
||||
:param dirs: the path of decompressed file
|
||||
:return: bool
|
||||
"""
|
||||
try:
|
||||
t = tarfile.open(name=fname, mode='r:gz')
|
||||
t.extractall(path=dirs)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
|
||||
untar(sys.argv[1], sys.argv[2])
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) 2018 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 <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/extension.h" // For pr test!
|
||||
#include "paddle_inference_api.h" // NOLINT
|
||||
|
||||
namespace paddle {
|
||||
namespace demo {
|
||||
|
||||
struct Record {
|
||||
std::vector<float> data;
|
||||
std::vector<int32_t> shape;
|
||||
};
|
||||
|
||||
static void split(const std::string& str,
|
||||
char sep,
|
||||
std::vector<std::string>* pieces) {
|
||||
pieces->clear();
|
||||
if (str.empty()) {
|
||||
return;
|
||||
}
|
||||
size_t pos = 0;
|
||||
size_t next = str.find(sep, pos);
|
||||
while (next != std::string::npos) {
|
||||
pieces->push_back(str.substr(pos, next - pos));
|
||||
pos = next + 1;
|
||||
next = str.find(sep, pos);
|
||||
}
|
||||
if (!str.substr(pos).empty()) {
|
||||
pieces->push_back(str.substr(pos));
|
||||
}
|
||||
}
|
||||
|
||||
Record ProcessALine(const std::string& line) {
|
||||
VLOG(3) << "process a line";
|
||||
std::vector<std::string> columns;
|
||||
split(line, '\t', &columns);
|
||||
CHECK_EQ(columns.size(), 2UL)
|
||||
<< "data format error, should be <data>\t<shape>";
|
||||
|
||||
Record record;
|
||||
std::vector<std::string> data_strs;
|
||||
split(columns[0], ' ', &data_strs);
|
||||
for (auto& d : data_strs) {
|
||||
record.data.push_back(std::stof(d));
|
||||
}
|
||||
|
||||
std::vector<std::string> shape_strs;
|
||||
split(columns[1], ' ', &shape_strs);
|
||||
for (auto& s : shape_strs) {
|
||||
record.shape.push_back(std::stoi(s));
|
||||
}
|
||||
VLOG(3) << "data size " << record.data.size();
|
||||
VLOG(3) << "data shape size " << record.shape.size();
|
||||
return record;
|
||||
}
|
||||
|
||||
void CheckOutput(const std::string& referfile,
|
||||
const PaddleTensor& output,
|
||||
float threshold = 1e-5) {
|
||||
std::string line;
|
||||
std::ifstream file(referfile);
|
||||
std::getline(file, line);
|
||||
auto refer = ProcessALine(line);
|
||||
file.close();
|
||||
|
||||
paddle::Tensor dummy;
|
||||
|
||||
size_t numel = output.data.length() / PaddleDtypeSize(output.dtype);
|
||||
VLOG(3) << "predictor output numel " << numel;
|
||||
VLOG(3) << "reference output numel " << refer.data.size();
|
||||
CHECK_EQ(numel, refer.data.size());
|
||||
switch (output.dtype) {
|
||||
case PaddleDType::INT64: {
|
||||
for (size_t i = 0; i < numel; ++i) {
|
||||
CHECK_EQ(static_cast<int64_t*>(output.data.data())[i], refer.data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PaddleDType::FLOAT32: {
|
||||
for (size_t i = 0; i < numel; ++i) {
|
||||
CHECK_LT(
|
||||
fabs(static_cast<float*>(output.data.data())[i] - refer.data[i]),
|
||||
threshold);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PaddleDType::INT32: {
|
||||
for (size_t i = 0; i < numel; ++i) {
|
||||
CHECK_EQ(static_cast<int32_t*>(output.data.data())[i], refer.data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a summary of a PaddleTensor content.
|
||||
*/
|
||||
static std::string SummaryTensor(const PaddleTensor& tensor) {
|
||||
std::stringstream ss;
|
||||
int num_elems = tensor.data.length() / PaddleDtypeSize(tensor.dtype);
|
||||
|
||||
ss << "data[:10]\t";
|
||||
switch (tensor.dtype) {
|
||||
case PaddleDType::INT64: {
|
||||
for (int i = 0; i < std::min(num_elems, 10); i++) {
|
||||
ss << static_cast<int64_t*>(tensor.data.data())[i] << " ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PaddleDType::FLOAT32: {
|
||||
for (int i = 0; i < std::min(num_elems, 10); i++) {
|
||||
ss << static_cast<float*>(tensor.data.data())[i] << " ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PaddleDType::INT32: {
|
||||
for (int i = 0; i < std::min(num_elems, 10); i++) {
|
||||
ss << static_cast<int32_t*>(tensor.data.data())[i] << " ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace demo
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright (c) 2018 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. */
|
||||
|
||||
/*
|
||||
* This file contains demo for mobilenet, se-resnext50 and ocr.
|
||||
*/
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "utils.h" // NOLINT
|
||||
|
||||
DEFINE_string(modeldir, "", "Directory of the inference model.");
|
||||
DEFINE_string(refer, "", "path to reference result for comparison.");
|
||||
DEFINE_string(data,
|
||||
"",
|
||||
"path of data; each line is a record, format is "
|
||||
"'<space split floats as data>\t<space split ints as shape'");
|
||||
DEFINE_bool(use_gpu, false, "Whether use gpu.");
|
||||
|
||||
namespace paddle {
|
||||
namespace demo {
|
||||
|
||||
/*
|
||||
* Use the native and analysis fluid engine to inference the demo.
|
||||
*/
|
||||
void Main(bool use_gpu) {
|
||||
std::unique_ptr<PaddlePredictor> predictor, analysis_predictor;
|
||||
AnalysisConfig config;
|
||||
if (use_gpu) {
|
||||
config.EnableUseGpu(100, 0);
|
||||
}
|
||||
config.SetModel(FLAGS_modeldir + "/__model__",
|
||||
FLAGS_modeldir + "/__params__");
|
||||
|
||||
predictor = CreatePaddlePredictor<NativeConfig>(config.ToNativeConfig());
|
||||
analysis_predictor = CreatePaddlePredictor(config);
|
||||
|
||||
// Just a single batch of data.
|
||||
std::string line;
|
||||
std::ifstream file(FLAGS_data);
|
||||
std::getline(file, line);
|
||||
auto record = ProcessALine(line);
|
||||
file.close();
|
||||
|
||||
// Inference.
|
||||
PaddleTensor input;
|
||||
input.shape = record.shape;
|
||||
input.data =
|
||||
PaddleBuf(record.data.data(), record.data.size() * sizeof(float));
|
||||
input.dtype = PaddleDType::FLOAT32;
|
||||
|
||||
std::vector<PaddleTensor> output, analysis_output;
|
||||
predictor->Run({input}, &output, 1);
|
||||
|
||||
auto& tensor = output.front();
|
||||
|
||||
// compare with reference result
|
||||
CheckOutput(FLAGS_refer, tensor, 1e-4);
|
||||
|
||||
// the analysis_output has some diff with native_output,
|
||||
// TODO(luotao): add CheckOutput for analysis_output later.
|
||||
analysis_predictor->Run({input}, &analysis_output, 1);
|
||||
}
|
||||
|
||||
} // namespace demo
|
||||
} // namespace paddle
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
if (FLAGS_use_gpu) {
|
||||
paddle::demo::Main(true /*use_gpu*/);
|
||||
} else {
|
||||
paddle::demo::Main(false /*use_gpu*/);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# windows inference
|
||||
本文介绍windows inference,目前只提供了静态编译,编译出paddle_inference.lib,包含了除openblas.dll之外的所有第三方依赖库。
|
||||
|
||||
1. 下载最新的paddle_inference.lib和openblas.dll,并把它们放在同一个目录下。
|
||||
|
||||
2. 准备预训练好的模型文件,例如models中的模型,可以将模型用safe_inference_model接口保存下来。将模型文件放到该目录下
|
||||
|
||||
3. 进入Paddle/paddle/fluid/inference/api/demo_ci目录,新建build目录,然后使用cmake生成vs2015的solution文件。
|
||||
其中PADDLE_LIB是前面的paddle_inference.lib对应文件夹, CUDA_LIB指定为x64格式下的cuda系统库目录文件夹。
|
||||
```shell
|
||||
cmake .. -G "Visual Studio 15 2017 Win64" -T host=x64 -DWITH_GPU=ON -DWITH_MKL=OFF -DWITH_STATIC_LIB=ON -DCMAKE_BUILD_TYPE=Release -DDEMO_NAME=inference_icnet -DPADDLE_LIB=D:\to_the_paddle_inference.lib -DCUDA_LIB=D:\tools\v8.0\lib\x64
|
||||
```
|
||||
然后用vs2015打开对应的项目文件,注意使用静态链接 "/MT",生成对应的exe。将openblas.dll放到exe所在目录。
|
||||
|
||||
4. 该exe即为项目生成文件,可绑定运行。
|
||||
|
||||
## FAQ
|
||||
1. cmake需要您手动下载,并添加到系统路径里
|
||||
2. 路径中的不要包含空格,例如发现CUDA_LIB路径是Program Files(x86)可能会出错。可以将CUDA拷贝到一个新位置。
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2019 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 <glog/logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "paddle_inference_api.h" // NOLINT
|
||||
|
||||
DEFINE_string(modeldir, "", "Directory of the inference model.");
|
||||
DEFINE_bool(use_gpu, false, "Whether use gpu.");
|
||||
|
||||
namespace paddle {
|
||||
namespace demo {
|
||||
|
||||
void RunAnalysis() {
|
||||
// 1. create AnalysisConfig
|
||||
AnalysisConfig config;
|
||||
if (FLAGS_modeldir.empty()) {
|
||||
LOG(INFO) << "Usage: path\\mobilenet --modeldir=path/to/your/model";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// CreateConfig(&config);
|
||||
if (FLAGS_use_gpu) {
|
||||
config.EnableUseGpu(100, 0);
|
||||
}
|
||||
config.SetModel(FLAGS_modeldir + "/__model__",
|
||||
FLAGS_modeldir + "/__params__");
|
||||
|
||||
// 2. create predictor, prepare input data
|
||||
std::unique_ptr<PaddlePredictor> predictor = CreatePaddlePredictor(config);
|
||||
int batch_size = 1;
|
||||
int channels = 3;
|
||||
int height = 300;
|
||||
int width = 300;
|
||||
int nums = batch_size * channels * height * width;
|
||||
|
||||
float* input = new float[nums];
|
||||
for (int i = 0; i < nums; ++i) input[i] = 0;
|
||||
|
||||
// 3. create input tensor, use ZeroCopyTensor
|
||||
auto input_names = predictor->GetInputNames();
|
||||
auto input_t = predictor->GetInputTensor(input_names[0]);
|
||||
input_t->Reshape({batch_size, channels, height, width});
|
||||
input_t->copy_from_cpu(input);
|
||||
|
||||
// 4. run predictor
|
||||
predictor->ZeroCopyRun();
|
||||
|
||||
// 5. get out put
|
||||
std::vector<float> out_data;
|
||||
auto output_names = predictor->GetOutputNames();
|
||||
auto output_t = predictor->GetOutputTensor(output_names[0]);
|
||||
std::vector<int> output_shape = output_t->shape();
|
||||
int out_num = std::accumulate(
|
||||
output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
|
||||
|
||||
out_data.resize(out_num);
|
||||
output_t->copy_to_cpu(out_data.data());
|
||||
delete[] input;
|
||||
}
|
||||
|
||||
} // namespace demo
|
||||
} // namespace paddle
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
paddle::demo::RunAnalysis();
|
||||
std::cout << "=========================Runs successfully===================="
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2016 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.
|
||||
#
|
||||
|
||||
cc_library(
|
||||
reset_tensor_array
|
||||
SRCS reset_tensor_array.cc
|
||||
DEPS lod_tensor scope)
|
||||
if(WITH_ONNXRUNTIME)
|
||||
cc_library(
|
||||
zero_copy_tensor
|
||||
SRCS zero_copy_tensor.cc
|
||||
DEPS scope lod_tensor phi onnxruntime common)
|
||||
cc_library(
|
||||
zero_copy_tensor_dummy
|
||||
SRCS zero_copy_tensor_dummy.cc
|
||||
DEPS onnxruntime phi common)
|
||||
else()
|
||||
cc_library(
|
||||
zero_copy_tensor
|
||||
SRCS zero_copy_tensor.cc
|
||||
DEPS scope lod_tensor phi common)
|
||||
cc_library(
|
||||
zero_copy_tensor_dummy
|
||||
SRCS zero_copy_tensor_dummy.cc
|
||||
DEPS phi common)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
cc_test(
|
||||
zero_copy_tensor_test
|
||||
SRCS zero_copy_tensor_test.cc
|
||||
DEPS paddle_inference_api)
|
||||
endif()
|
||||
|
||||
if(WITH_ONNXRUNTIME AND WIN32)
|
||||
# Copy onnxruntime for some c++ test in Windows, since the test will
|
||||
# be build only in CI, so suppose the generator in Windows is Ninja.
|
||||
copy_onnx(zero_copy_tensor_test)
|
||||
endif()
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2018 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 "paddle/fluid/inference/api/details/reset_tensor_array.h"
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
namespace paddle::framework {
|
||||
class Scope;
|
||||
} // namespace paddle::framework
|
||||
|
||||
namespace paddle::details {
|
||||
|
||||
// Should be called after the parameters are loaded.
|
||||
void TensorArrayBatchCleaner::CollectTensorArrays(framework::Scope *scope) {
|
||||
if (flag_) {
|
||||
for (auto &var_name : scope->LocalVarNames()) {
|
||||
auto *var = scope->FindVar(var_name);
|
||||
// TODO(Superjomn) should avoid the case when a TensorArray is a
|
||||
// parameter.
|
||||
if (var_name == "feed" || var_name == "fetch") continue;
|
||||
if (var->IsType<phi::TensorArray>()) {
|
||||
VLOG(4) << "collect " << var_name;
|
||||
arrays_.push_back(var->GetMutable<phi::TensorArray>());
|
||||
}
|
||||
}
|
||||
for (auto *kid : scope->kids()) {
|
||||
CollectTensorArrays(kid);
|
||||
}
|
||||
|
||||
VLOG(3) << "Collect " << arrays_.size() << " arrays";
|
||||
flag_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Should be called when `Run` finished.
|
||||
void TensorArrayBatchCleaner::ResetTensorArray() {
|
||||
for (auto *arr : arrays_) {
|
||||
arr->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TensorArrayBatchCleaner::CollectNoTensorVars(framework::Scope *scope) {
|
||||
if (no_tensor_flag_) {
|
||||
for (auto &var_name : scope->LocalVarNames()) {
|
||||
auto *var = scope->FindVar(var_name);
|
||||
if (!var->IsInitialized()) continue;
|
||||
if (!valid_types_.count(var->Type())) {
|
||||
no_tensor_vars_.insert(var);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto *kid : scope->kids()) {
|
||||
CollectTensorArrays(kid);
|
||||
}
|
||||
no_tensor_flag_ = false; // Only collect one time.
|
||||
}
|
||||
}
|
||||
|
||||
void TensorArrayBatchCleaner::ResetNoTensorVars() {
|
||||
for (auto *var : no_tensor_vars_) {
|
||||
var->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace paddle::details
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2018 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 <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/fluid/framework/dense_tensor_array.h"
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/framework/variable.h"
|
||||
|
||||
namespace phi {
|
||||
class DenseTensor;
|
||||
} // namespace phi
|
||||
|
||||
namespace paddle {
|
||||
namespace framework {
|
||||
class Scope;
|
||||
class SelectedRows;
|
||||
} // namespace framework
|
||||
} // namespace paddle
|
||||
|
||||
namespace paddle {
|
||||
namespace details {
|
||||
|
||||
// Clean the TensorArray each batch to make the behavior the same with the
|
||||
// training phase.
|
||||
struct TensorArrayBatchCleaner {
|
||||
TensorArrayBatchCleaner() {
|
||||
constexpr auto kTensorId = framework::VarTypeTrait<phi::DenseTensor>::kId;
|
||||
constexpr auto kDenseTensorId =
|
||||
framework::VarTypeTrait<phi::DenseTensor>::kId;
|
||||
constexpr auto kSelectedRowsId =
|
||||
framework::VarTypeTrait<phi::SelectedRows>::kId;
|
||||
constexpr auto kFetchListId =
|
||||
framework::VarTypeTrait<framework::FetchList>::kId;
|
||||
valid_types_.insert(kTensorId);
|
||||
valid_types_.insert(kDenseTensorId);
|
||||
valid_types_.insert(kSelectedRowsId);
|
||||
valid_types_.insert(kFetchListId);
|
||||
}
|
||||
// Collect the variables that are not Tensor or DenseTensor, and reset them to
|
||||
// a bool(trick), because some of them are containers, and some operators just
|
||||
// keep inserting new items without clearing the containers first; So the
|
||||
// memory grow larger and larger in inference service deployed online.
|
||||
void CollectNoTensorVars(framework::Scope *scope);
|
||||
void ResetNoTensorVars();
|
||||
|
||||
// Fix the tensor array not clear in the inference scenarios.
|
||||
void CollectTensorArrays(framework::Scope *scope);
|
||||
void ResetTensorArray();
|
||||
|
||||
private:
|
||||
bool flag_{true};
|
||||
bool no_tensor_flag_{true};
|
||||
std::vector<phi::TensorArray *> arrays_;
|
||||
|
||||
std::unordered_set<int> valid_types_;
|
||||
std::unordered_set<framework::Variable *> no_tensor_vars_;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,984 @@
|
||||
// Copyright (c) 2018 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 "paddle/fluid/framework/convert_utils.h"
|
||||
#include "paddle/fluid/framework/data_layout_transform.h"
|
||||
#include "paddle/fluid/framework/lod_tensor.h"
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/fluid/inference/api/paddle_tensor.h"
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
#include "paddle/phi/common/bfloat16.h"
|
||||
#include "paddle/phi/common/float16.h"
|
||||
#include "paddle/phi/core/allocator.h"
|
||||
#include "paddle/phi/core/memory/memcpy.h"
|
||||
#include "paddle/phi/core/vocab/string_array.h"
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
#include "onnxruntime_c_api.h" // NOLINT
|
||||
#include "onnxruntime_cxx_api.h" // NOLINT
|
||||
#endif
|
||||
|
||||
namespace paddle_infer {
|
||||
|
||||
using float16 = phi::dtype::float16;
|
||||
using bfloat16 = phi::dtype::bfloat16;
|
||||
|
||||
void Tensor::Reshape(const std::vector<int> &shape) {
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
if (is_ort_tensor_) {
|
||||
shape_.assign(shape.begin(), shape.end());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
name_.empty(),
|
||||
false,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Need to SetName first, so that the corresponding tensor can "
|
||||
"be retrieved."));
|
||||
PADDLE_ENFORCE_EQ(input_or_output_,
|
||||
true,
|
||||
common::errors::PermissionDenied(
|
||||
"Can't reshape the output tensor, it is readonly"));
|
||||
auto *scope = static_cast<paddle::framework::Scope *>(scope_);
|
||||
auto *var = scope->FindVar(name_);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
var,
|
||||
common::errors::PreconditionNotMet(
|
||||
"No tensor called [%s] in the runtime scope", name_));
|
||||
auto *tensor = var->GetMutable<phi::DenseTensor>();
|
||||
tensor->Resize(common::make_ddim(shape));
|
||||
}
|
||||
|
||||
void Tensor::ReshapeStrings(const size_t &shape) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
name_.empty(),
|
||||
false,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Need to SetName first, so that the corresponding tensor can "
|
||||
"be retrieved."));
|
||||
PADDLE_ENFORCE_EQ(input_or_output_,
|
||||
true,
|
||||
common::errors::PermissionDenied(
|
||||
"Can't reshape the output tensor, it is readonly"));
|
||||
auto *scope = static_cast<paddle::framework::Scope *>(scope_);
|
||||
auto *var = scope->FindVar(name_);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
var,
|
||||
common::errors::PreconditionNotMet(
|
||||
"No tensor called [%s] in the runtime scope", name_));
|
||||
phi::Strings *tensor = var->GetMutable<phi::Strings>();
|
||||
tensor->resize(shape);
|
||||
}
|
||||
|
||||
#define EAGER_GET_TENSOR(tensor_type) \
|
||||
if (!tensor_) { \
|
||||
tensor_ = FindTensor<tensor_type>(); \
|
||||
} \
|
||||
auto *tensor = static_cast<tensor_type *>(tensor_);
|
||||
|
||||
template <typename T>
|
||||
T *Tensor::mutable_data(PlaceType place) {
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
if (is_ort_tensor_) {
|
||||
return ORTGetMutableData<T>();
|
||||
}
|
||||
#endif
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
PADDLE_ENFORCE_GT(
|
||||
tensor->numel(),
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"You should call Tensor::Reshape(const std::vector<int> "
|
||||
"&shape)"
|
||||
"function before retrieving mutable_data from input tensor."));
|
||||
switch (static_cast<int>(place)) {
|
||||
case static_cast<int>(PlaceType::kCPU): {
|
||||
return tensor->mutable_data<T>(phi::CPUPlace());
|
||||
}
|
||||
case static_cast<int>(PlaceType::kGPU): {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
phi::GPUPlace gpu_place(device_);
|
||||
auto *dev_ctxs = reinterpret_cast<const std::map<
|
||||
phi::Place,
|
||||
std::shared_future<std::unique_ptr<phi::DeviceContext>>> *>(
|
||||
device_contexts_);
|
||||
auto *dev_ctx =
|
||||
static_cast<phi::GPUContext *>(dev_ctxs->at(gpu_place).get().get());
|
||||
return dev_ctx->Alloc<T>(tensor, tensor->numel() * sizeof(T));
|
||||
#else
|
||||
return tensor->mutable_data<T>(phi::GPUPlace(device_));
|
||||
#endif
|
||||
}
|
||||
case static_cast<int>(PlaceType::kXPU): {
|
||||
return tensor->mutable_data<T>(phi::XPUPlace(device_));
|
||||
}
|
||||
case static_cast<int>(PlaceType::kCUSTOM): {
|
||||
return tensor->mutable_data<T>(phi::CustomPlace(device_type_, device_));
|
||||
}
|
||||
default:
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Only CPU / CUDA / XPU places is supported. The place `%d` is "
|
||||
"not supported.",
|
||||
static_cast<int>(place)));
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *Tensor::data(PlaceType *place, int *size) const {
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
auto *res = tensor->data<T>();
|
||||
|
||||
if (phi::is_cpu_place(tensor->place())) {
|
||||
*place = PlaceType::kCPU;
|
||||
} else if (phi::is_gpu_place(tensor->place())) {
|
||||
*place = PlaceType::kGPU;
|
||||
} else if (phi::is_xpu_place(tensor->place())) {
|
||||
*place = PlaceType::kXPU;
|
||||
} else if (phi::is_custom_place(tensor->place())) {
|
||||
*place = PlaceType::kCUSTOM;
|
||||
} else {
|
||||
*place = PlaceType::kUNK;
|
||||
}
|
||||
|
||||
*size = static_cast<int>(tensor->numel());
|
||||
return res;
|
||||
}
|
||||
|
||||
DataType Tensor::type() const {
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
if (is_ort_tensor_) {
|
||||
return dtype_;
|
||||
}
|
||||
#endif
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
auto type = paddle::framework::TransToProtoVarType(tensor->dtype());
|
||||
if (type == paddle::framework::proto::VarType::FP64) {
|
||||
return DataType::FLOAT64;
|
||||
} else if (type == paddle::framework::proto::VarType::FP32) {
|
||||
return DataType::FLOAT32;
|
||||
} else if (type == paddle::framework::proto::VarType::FP16) {
|
||||
return DataType::FLOAT16;
|
||||
} else if (type == paddle::framework::proto::VarType::BF16) {
|
||||
return DataType::BFLOAT16;
|
||||
} else if (type == paddle::framework::proto::VarType::INT64) {
|
||||
return DataType::INT64;
|
||||
} else if (type == paddle::framework::proto::VarType::INT32) {
|
||||
return DataType::INT32;
|
||||
} else if (type == paddle::framework::proto::VarType::UINT8) {
|
||||
return DataType::UINT8;
|
||||
} else if (type == paddle::framework::proto::VarType::INT8) {
|
||||
return DataType::INT8;
|
||||
} else if (type == paddle::framework::proto::VarType::BOOL) {
|
||||
return DataType::BOOL;
|
||||
}
|
||||
return DataType::FLOAT32;
|
||||
}
|
||||
|
||||
PlaceType Tensor::place() const { return place_; }
|
||||
|
||||
template <typename T>
|
||||
void Tensor::CopyFromCpu(const T *data) {
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
PADDLE_ENFORCE_GE(tensor->numel(),
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"You should call Tensor::Reshape(const "
|
||||
"std::vector<int> &shape)"
|
||||
"function before copying data from cpu."));
|
||||
size_t ele_size = tensor->numel() * sizeof(T);
|
||||
|
||||
if (place_ == PlaceType::kCPU) {
|
||||
auto *t_data = tensor->mutable_data<T>(phi::CPUPlace());
|
||||
std::memcpy(static_cast<void *>(t_data), data, ele_size);
|
||||
} else if (place_ == PlaceType::kGPU) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
|
||||
phi::GPUPlace gpu_place(device_);
|
||||
auto *dev_ctxs = reinterpret_cast<const std::map<
|
||||
phi::Place,
|
||||
std::shared_future<std::unique_ptr<phi::DeviceContext>>> *>(
|
||||
device_contexts_);
|
||||
auto *dev_ctx =
|
||||
static_cast<phi::GPUContext *>(dev_ctxs->at(gpu_place).get().get());
|
||||
auto *t_data = dev_ctx->Alloc<T>(tensor, tensor->numel() * sizeof(T));
|
||||
|
||||
paddle::memory::Copy(gpu_place,
|
||||
static_cast<void *>(t_data),
|
||||
phi::CPUPlace(),
|
||||
data,
|
||||
ele_size,
|
||||
dev_ctx->stream());
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with CUDA place because paddle is not compiled "
|
||||
"with CUDA."));
|
||||
#endif
|
||||
} else if (place_ == PlaceType::kXPU) {
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
phi::XPUPlace xpu_place(device_);
|
||||
auto *t_data = tensor->mutable_data<T>(xpu_place);
|
||||
paddle::memory::Copy(xpu_place,
|
||||
static_cast<void *>(t_data),
|
||||
phi::CPUPlace(),
|
||||
data,
|
||||
ele_size);
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with XPU place because paddle is not compiled "
|
||||
"with XPU."));
|
||||
#endif
|
||||
} else if (place_ == PlaceType::kCUSTOM) {
|
||||
#ifdef PADDLE_WITH_CUSTOM_DEVICE
|
||||
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
|
||||
phi::CustomPlace custom_place(device_type_, device_);
|
||||
auto *t_data = tensor->mutable_data<T>(custom_place);
|
||||
auto *dev_ctx =
|
||||
static_cast<const phi::CustomContext *>(pool.Get(custom_place));
|
||||
paddle::memory::Copy(custom_place,
|
||||
static_cast<void *>(t_data),
|
||||
phi::CPUPlace(),
|
||||
data,
|
||||
ele_size,
|
||||
dev_ctx->stream());
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with Custom place because paddle is not "
|
||||
"compiled "
|
||||
"with XPU."));
|
||||
#endif
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"The analysis predictor supports CPU, GPU, XPU and CUSTOM_DEVICE "
|
||||
"now."));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct DataTypeInfo;
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<double> {
|
||||
phi::DataType TYPE = phi::DataType::FLOAT64;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<float> {
|
||||
phi::DataType TYPE = phi::DataType::FLOAT32;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<float16> {
|
||||
phi::DataType TYPE = phi::DataType::FLOAT16;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<bfloat16> {
|
||||
phi::DataType TYPE = phi::DataType::BFLOAT16;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<int64_t> {
|
||||
phi::DataType TYPE = phi::DataType::INT64;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<int8_t> {
|
||||
phi::DataType TYPE = phi::DataType::INT8;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<uint8_t> {
|
||||
phi::DataType TYPE = phi::DataType::UINT8;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<int32_t> {
|
||||
phi::DataType TYPE = phi::DataType::INT32;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DataTypeInfo<bool> {
|
||||
phi::DataType TYPE = phi::DataType::BOOL;
|
||||
};
|
||||
|
||||
phi::DataLayout LayoutConvert(DataLayout layout) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
layout,
|
||||
DataLayout::kNCHW,
|
||||
common::errors::InvalidArgument("Only NCHW is supported now."));
|
||||
return phi::DataLayout::NCHW;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Tensor::ShareExternalData(const T *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout) {
|
||||
EAGER_GET_TENSOR(phi::DenseTensor)
|
||||
size_t size =
|
||||
std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<int>()) *
|
||||
sizeof(T);
|
||||
phi::DenseTensorMeta meta(
|
||||
DataTypeInfo<T>().TYPE, common::make_ddim(shape), LayoutConvert(layout));
|
||||
if (place == PlaceType::kCPU) {
|
||||
phi::DenseTensor dtensor(std::make_shared<phi::Allocation>(
|
||||
const_cast<T *>(data), size, phi::CPUPlace()),
|
||||
meta);
|
||||
*tensor = std::move(dtensor);
|
||||
} else if (place == PlaceType::kGPU) {
|
||||
phi::DenseTensor dtensor(
|
||||
std::make_shared<phi::Allocation>(
|
||||
const_cast<T *>(data), size, phi::GPUPlace(device_)),
|
||||
meta);
|
||||
*tensor = std::move(dtensor);
|
||||
} else if (place == PlaceType::kXPU) {
|
||||
phi::DenseTensor dtensor(
|
||||
std::make_shared<phi::Allocation>(
|
||||
const_cast<T *>(data), size, phi::XPUPlace(device_)),
|
||||
meta);
|
||||
*tensor = std::move(dtensor);
|
||||
} else if (place == PlaceType::kCUSTOM) {
|
||||
phi::DenseTensor dtensor(std::make_shared<phi::Allocation>(
|
||||
const_cast<T *>(data),
|
||||
size,
|
||||
phi::CustomPlace(device_type_, device_)),
|
||||
meta);
|
||||
*tensor = std::move(dtensor);
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"PlaceType must be one of [PlaceType::kCPU, PlaceType::kGPU, "
|
||||
"PlaceType::kXPU]."));
|
||||
}
|
||||
}
|
||||
|
||||
void Tensor::CopyStringsFromCpu(const paddle_infer::Strings *data) {
|
||||
EAGER_GET_TENSOR(phi::Strings);
|
||||
PADDLE_ENFORCE_GE(tensor->size(),
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"You should call Tensor::Reshape(const "
|
||||
"std::size_t &shape) function before copying "
|
||||
"the string data from cpu."));
|
||||
*tensor = *data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Tensor::CopyToCpuImpl(T *data,
|
||||
void *exec_stream,
|
||||
CallbackFunc cb,
|
||||
void *cb_params) const {
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
auto ele_num = tensor->numel();
|
||||
auto *t_data = tensor->data<T>();
|
||||
auto t_place = tensor->place();
|
||||
|
||||
if (phi::is_cpu_place(t_place)) {
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (tensor->layout() == phi::DataLayout::ONEDNN) {
|
||||
phi::DenseTensor out;
|
||||
auto mem_allocation =
|
||||
std::make_shared<paddle::memory::allocation::Allocation>(
|
||||
static_cast<void *>(data), ele_num * sizeof(T), phi::CPUPlace());
|
||||
out.ResetHolder(mem_allocation);
|
||||
phi::funcs::TransDataLayoutFromOneDNN(
|
||||
tensor->layout(),
|
||||
phi::OneDNNContext::tls().get_cur_paddle_data_layout(),
|
||||
*tensor,
|
||||
&out,
|
||||
phi::CPUPlace(),
|
||||
true);
|
||||
} else {
|
||||
std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
|
||||
}
|
||||
#else
|
||||
std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
|
||||
#endif
|
||||
} else if (phi::is_ipu_place(t_place)) {
|
||||
#ifdef PADDLE_WITH_IPU
|
||||
std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with IPU place because paddle is not compiled "
|
||||
"with IPU."));
|
||||
#endif
|
||||
} else if (place_ == PlaceType::kGPU) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
auto gpu_place = t_place;
|
||||
auto *dev_ctxs = reinterpret_cast<const std::map<
|
||||
phi::Place,
|
||||
std::shared_future<std::unique_ptr<phi::DeviceContext>>> *>(
|
||||
device_contexts_);
|
||||
auto *dev_ctx =
|
||||
static_cast<phi::GPUContext *>(dev_ctxs->at(gpu_place).get().get());
|
||||
paddle::memory::Copy(phi::CPUPlace(),
|
||||
static_cast<void *>(data),
|
||||
gpu_place,
|
||||
t_data,
|
||||
ele_num * sizeof(T),
|
||||
dev_ctx->stream());
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipStreamSynchronize(dev_ctx->stream());
|
||||
#else
|
||||
// async, return stream
|
||||
if (nullptr != exec_stream) {
|
||||
*(static_cast<cudaStream_t *>(exec_stream)) = dev_ctx->stream();
|
||||
// async with callback
|
||||
} else if (cb) {
|
||||
cudaLaunchHostFunc(dev_ctx->stream(), cb, cb_params);
|
||||
// sync
|
||||
} else {
|
||||
cudaStreamSynchronize(dev_ctx->stream());
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with CUDA place because paddle is not compiled "
|
||||
"with CUDA."));
|
||||
#endif
|
||||
} else if (place_ == PlaceType::kXPU) {
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
auto xpu_place = t_place;
|
||||
paddle::memory::Copy(phi::CPUPlace(),
|
||||
static_cast<void *>(data),
|
||||
xpu_place,
|
||||
t_data,
|
||||
ele_num * sizeof(T));
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with XPU place because paddle is not compiled "
|
||||
"with XPU."));
|
||||
#endif
|
||||
} else {
|
||||
#ifdef PADDLE_WITH_CUSTOM_DEVICE
|
||||
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
|
||||
auto custom_place = t_place;
|
||||
auto *dev_ctx =
|
||||
static_cast<const phi::CustomContext *>(pool.Get(custom_place));
|
||||
paddle::memory::Copy(phi::CPUPlace(),
|
||||
static_cast<void *>(data),
|
||||
custom_place,
|
||||
t_data,
|
||||
ele_num * sizeof(T),
|
||||
dev_ctx->stream());
|
||||
dev_ctx->GetStream()->Synchronize();
|
||||
#else
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"The analysis predictor supports CPU, GPU and XPU now."));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Tensor::CopyToCpu(T *data) const {
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
if (is_ort_tensor_) {
|
||||
ORTCopyToCpu<T>(data);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
CopyToCpuImpl<T>(data, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Tensor::CopyToCpuAsync(T *data, void *exec_stream) const {
|
||||
CopyToCpuImpl<T>(data, exec_stream, nullptr, nullptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Tensor::CopyToCpuAsync(T *data, CallbackFunc cb, void *cb_params) const {
|
||||
CopyToCpuImpl<T>(data, nullptr, cb, cb_params);
|
||||
}
|
||||
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<double>(const double *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<float>(const float *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<int64_t>(const int64_t *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<int32_t>(const int32_t *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<uint8_t>(const uint8_t *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<int8_t>(const int8_t *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<float16>(const float16 *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<bfloat16>(const bfloat16 *data);
|
||||
template PD_INFER_DECL void Tensor::CopyFromCpu<bool>(const bool *data);
|
||||
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<double>(
|
||||
const double *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<float>(
|
||||
const float *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<int64_t>(
|
||||
const int64_t *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<int32_t>(
|
||||
const int32_t *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<uint8_t>(
|
||||
const uint8_t *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<int8_t>(
|
||||
const int8_t *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<float16>(
|
||||
const float16 *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<bfloat16>(
|
||||
const bfloat16 *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
template PD_INFER_DECL void Tensor::ShareExternalData<bool>(
|
||||
const bool *data,
|
||||
const std::vector<int> &shape,
|
||||
PlaceType place,
|
||||
DataLayout layout);
|
||||
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<double>(double *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<float>(float *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<int64_t>(int64_t *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<int32_t>(int32_t *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<uint8_t>(uint8_t *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<int8_t>(int8_t *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<float16>(float16 *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<bfloat16>(bfloat16 *data) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpu<bool>(bool *data) const;
|
||||
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<double>(
|
||||
double *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<float>(float *data,
|
||||
void *exec_stream,
|
||||
CallbackFunc cb,
|
||||
void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<int64_t>(
|
||||
int64_t *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<int32_t>(
|
||||
int32_t *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<uint8_t>(
|
||||
uint8_t *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<int8_t>(
|
||||
int8_t *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<float16>(
|
||||
float16 *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<bfloat16>(
|
||||
bfloat16 *data, void *exec_stream, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuImpl<bool>(bool *data,
|
||||
void *exec_stream,
|
||||
CallbackFunc cb,
|
||||
void *cb_params) const;
|
||||
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<double>(
|
||||
double *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<float>(
|
||||
float *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<int64_t>(
|
||||
int64_t *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<int32_t>(
|
||||
int32_t *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<uint8_t>(
|
||||
uint8_t *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<int8_t>(
|
||||
int8_t *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<float16>(
|
||||
float16 *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<bfloat16>(
|
||||
bfloat16 *data, void *exec_stream) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<bool>(
|
||||
bool *data, void *exec_stream) const;
|
||||
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<double>(
|
||||
double *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<float>(
|
||||
float *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<int64_t>(
|
||||
int64_t *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<int32_t>(
|
||||
int32_t *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<uint8_t>(
|
||||
uint8_t *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<int8_t>(
|
||||
int8_t *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<float16>(
|
||||
float16 *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<bfloat16>(
|
||||
bfloat16 *data, CallbackFunc cb, void *cb_params) const;
|
||||
template PD_INFER_DECL void Tensor::CopyToCpuAsync<bool>(bool *data,
|
||||
CallbackFunc cb,
|
||||
void *cb_params) const;
|
||||
|
||||
template PD_INFER_DECL double *Tensor::data<double>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL float *Tensor::data<float>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL int64_t *Tensor::data<int64_t>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL int32_t *Tensor::data<int32_t>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL uint8_t *Tensor::data<uint8_t>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL int8_t *Tensor::data<int8_t>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL float16 *Tensor::data<float16>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL bfloat16 *Tensor::data<bfloat16>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL bool *Tensor::data<bool>(PlaceType *place,
|
||||
int *size) const;
|
||||
|
||||
template PD_INFER_DECL double *Tensor::mutable_data<double>(PlaceType place);
|
||||
template PD_INFER_DECL float *Tensor::mutable_data<float>(PlaceType place);
|
||||
template PD_INFER_DECL int64_t *Tensor::mutable_data<int64_t>(PlaceType place);
|
||||
template PD_INFER_DECL int32_t *Tensor::mutable_data<int32_t>(PlaceType place);
|
||||
template PD_INFER_DECL uint8_t *Tensor::mutable_data<uint8_t>(PlaceType place);
|
||||
template PD_INFER_DECL int8_t *Tensor::mutable_data<int8_t>(PlaceType place);
|
||||
template PD_INFER_DECL float16 *Tensor::mutable_data<float16>(PlaceType place);
|
||||
template PD_INFER_DECL bfloat16 *Tensor::mutable_data<bfloat16>(
|
||||
PlaceType place);
|
||||
template PD_INFER_DECL bool *Tensor::mutable_data<bool>(PlaceType place);
|
||||
|
||||
Tensor::Tensor(void *scope, const void *device_contexts)
|
||||
: dtype_(DataType::FLOAT16),
|
||||
input_or_output_(false),
|
||||
scope_{scope},
|
||||
device_contexts_(device_contexts),
|
||||
place_(PlaceType::kCPU),
|
||||
device_(0) {}
|
||||
|
||||
template <typename T>
|
||||
void *Tensor::FindTensor() const {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
name_.empty(),
|
||||
false,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Need to SetName first, so that the corresponding tensor can "
|
||||
"be retrieved."));
|
||||
auto *scope = static_cast<paddle::framework::Scope *>(scope_);
|
||||
auto *var = scope->FindVar(name_);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
var,
|
||||
common::errors::PreconditionNotMet(
|
||||
"No tensor called [%s] in the runtime scope", name_));
|
||||
auto *tensor = var->GetMutable<T>();
|
||||
return tensor;
|
||||
}
|
||||
|
||||
std::vector<int> Tensor::shape() const {
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
if (is_ort_tensor_) {
|
||||
std::vector<int> shape;
|
||||
// input handle
|
||||
if (idx_ < 0) {
|
||||
shape.assign(shape_.begin(), shape_.end());
|
||||
} else { // output handle
|
||||
auto binding = binding_.lock();
|
||||
PADDLE_ENFORCE_NOT_NULL(binding,
|
||||
common::errors::PreconditionNotMet(
|
||||
"output tensor [%s] no binding ptr", name_));
|
||||
std::vector<Ort::Value> outputs = binding->GetOutputValues();
|
||||
Ort::Value &value = outputs[idx_];
|
||||
auto info = value.GetTensorTypeAndShapeInfo();
|
||||
auto ort_shape = info.GetShape();
|
||||
shape.assign(ort_shape.begin(), ort_shape.end());
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
#endif
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
tensor_,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Not found tensor called %s in the scope", name_));
|
||||
// oneDNN may does layout transform internally, so need to reorder before
|
||||
// return
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (tensor->layout() == phi::DataLayout::ONEDNN) {
|
||||
phi::DataLayout out_layout =
|
||||
phi::OneDNNContext::tls().get_cur_paddle_data_layout();
|
||||
// Set default as NCHW in case not specified
|
||||
out_layout = out_layout == phi::DataLayout::kAnyLayout
|
||||
? phi::DataLayout::kNCHW
|
||||
: out_layout;
|
||||
// In these data layouts, channel dimension is either on 2nd position: nChw
|
||||
// or
|
||||
// at last nhwC, so for dim==2 these layouts are the same and nothing should
|
||||
// be done. Similarly for dim==1 when you have just one possible
|
||||
// combination.
|
||||
if (tensor->dims().size() < 3)
|
||||
return common::vectorize<int>(tensor->dims());
|
||||
if (out_layout == phi::DataLayout::NHWC ||
|
||||
out_layout == phi::DataLayout::NDHWC) {
|
||||
auto dims = common::vectorize<int>(tensor->dims());
|
||||
std::rotate(dims.begin() + 1, dims.begin() + 2, dims.end());
|
||||
return dims;
|
||||
} else {
|
||||
return common::vectorize<int>(tensor->dims());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return common::vectorize<int>(tensor->dims());
|
||||
}
|
||||
|
||||
void Tensor::SetLoD(const std::vector<std::vector<size_t>> &x) {
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
phi::LegacyLoD lod;
|
||||
for (auto &level : x) {
|
||||
lod.emplace_back(level);
|
||||
}
|
||||
tensor->set_lod(lod);
|
||||
}
|
||||
|
||||
std::vector<std::vector<size_t>> Tensor::lod() const {
|
||||
EAGER_GET_TENSOR(phi::DenseTensor);
|
||||
std::vector<std::vector<size_t>> res;
|
||||
for (auto &level : tensor->lod()) {
|
||||
res.emplace_back(level);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Tensor::SetName(const std::string &name) { name_ = name; }
|
||||
|
||||
const std::string &Tensor::name() const { return name_; }
|
||||
|
||||
void Tensor::SetPlace(PlaceType place,
|
||||
int device,
|
||||
const std::string device_type) {
|
||||
place_ = place;
|
||||
device_ = device;
|
||||
device_type_ = device_type;
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
void Tensor::SetOrtMark(bool is_ort_tensor) { is_ort_tensor_ = is_ort_tensor; }
|
||||
|
||||
void Tensor::SetOrtBinding(const std::shared_ptr<Ort::IoBinding> binding) {
|
||||
binding_ = binding;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *Tensor::ORTGetMutableData() {
|
||||
auto binding = binding_.lock();
|
||||
PADDLE_ENFORCE_NOT_NULL(binding,
|
||||
common::errors::PreconditionNotMet(
|
||||
"output tensor [%s] no binding ptr", name_));
|
||||
std::vector<Ort::Value> outputs = binding->GetOutputValues();
|
||||
Ort::Value &value = outputs[idx_];
|
||||
return value.GetTensorMutableData<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Tensor::ORTCopyToCpu(T *data) const {
|
||||
auto binding = binding_.lock();
|
||||
PADDLE_ENFORCE_NOT_NULL(binding,
|
||||
common::errors::PreconditionNotMet(
|
||||
"output tensor [%s] no binding ptr", name_));
|
||||
std::vector<Ort::Value> outputs = binding->GetOutputValues();
|
||||
Ort::Value &value = outputs[idx_];
|
||||
auto info = value.GetTensorTypeAndShapeInfo();
|
||||
size_t size = info.GetElementCount() * sizeof(T);
|
||||
|
||||
if (place_ == PlaceType::kCPU) {
|
||||
std::memcpy(static_cast<void *>(data), value.GetTensorData<void *>(), size);
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"CopyToCpu error.The current ONNXRuntime backend doesn't support "
|
||||
"GPU."));
|
||||
}
|
||||
}
|
||||
|
||||
template void Tensor::ORTCopyToCpu<float>(float *data) const;
|
||||
template void Tensor::ORTCopyToCpu<int32_t>(int32_t *data) const;
|
||||
template void Tensor::ORTCopyToCpu<uint8_t>(uint8_t *data) const;
|
||||
template void Tensor::ORTCopyToCpu<int8_t>(int8_t *data) const;
|
||||
template void Tensor::ORTCopyToCpu<float16>(float16 *data) const;
|
||||
template void Tensor::ORTCopyToCpu<bfloat16>(bfloat16 *data) const;
|
||||
#endif
|
||||
|
||||
namespace experimental {
|
||||
template <typename T>
|
||||
void InternalUtils::CopyFromCpuWithIoStream(paddle_infer::Tensor *t,
|
||||
const T *data,
|
||||
cudaStream_t stream) {
|
||||
if (t->tensor_ == nullptr) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
t->name_.empty(),
|
||||
false,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Need to SetName first, so that the corresponding tensor can "
|
||||
"be retrieved."));
|
||||
auto *scope = static_cast<paddle::framework::Scope *>(t->scope_);
|
||||
auto *var = scope->FindVar(t->name_);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
var,
|
||||
common::errors::PreconditionNotMet(
|
||||
"No tensor called [%s] in the runtime scope", t->name_));
|
||||
auto *tensor = var->GetMutable<phi::DenseTensor>();
|
||||
t->tensor_ = tensor;
|
||||
}
|
||||
|
||||
auto *tensor = static_cast<phi::DenseTensor *>(t->tensor_);
|
||||
PADDLE_ENFORCE_GE(tensor->numel(),
|
||||
0,
|
||||
common::errors::PreconditionNotMet(
|
||||
"You should call Tensor::Reshape(const "
|
||||
"std::vector<int> &shape)"
|
||||
"function before copying data from cpu."));
|
||||
size_t ele_size = tensor->numel() * sizeof(T);
|
||||
if (t->place_ == PlaceType::kCPU) {
|
||||
auto *t_data = tensor->mutable_data<T>(phi::CPUPlace());
|
||||
std::memcpy(static_cast<void *>(t_data), data, ele_size);
|
||||
} else if (t->place_ == PlaceType::kGPU) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
phi::GPUPlace gpu_place(t->device_);
|
||||
auto *t_data = tensor->mutable_data<T>(gpu_place);
|
||||
paddle::memory::Copy(gpu_place,
|
||||
static_cast<void *>(t_data),
|
||||
phi::CPUPlace(),
|
||||
data,
|
||||
ele_size,
|
||||
stream);
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with CUDA place because paddle is not compiled "
|
||||
"with CUDA."));
|
||||
#endif
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"CopyFromCpuWithIoStream only supports CPU and GPU now."));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void InternalUtils::CopyToCpuWithIoStream(paddle_infer::Tensor *t,
|
||||
T *data,
|
||||
cudaStream_t stream) {
|
||||
if (t->tensor_ == nullptr) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
t->name_.empty(),
|
||||
false,
|
||||
common::errors::PreconditionNotMet(
|
||||
"Need to SetName first, so that the corresponding tensor can "
|
||||
"be retrieved."));
|
||||
auto *scope = static_cast<paddle::framework::Scope *>(t->scope_);
|
||||
auto *var = scope->FindVar(t->name_);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
var,
|
||||
common::errors::PreconditionNotMet(
|
||||
"No tensor called [%s] in the runtime scope", t->name_));
|
||||
auto *tensor = var->GetMutable<phi::DenseTensor>();
|
||||
t->tensor_ = tensor;
|
||||
}
|
||||
|
||||
auto *tensor = static_cast<phi::DenseTensor *>(t->tensor_);
|
||||
auto ele_num = tensor->numel();
|
||||
auto *t_data = tensor->data<T>();
|
||||
auto t_place = tensor->place();
|
||||
|
||||
if (phi::is_cpu_place(t_place)) {
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (tensor->layout() == phi::DataLayout::ONEDNN) {
|
||||
phi::DenseTensor out;
|
||||
auto mem_allocation =
|
||||
std::make_shared<paddle::memory::allocation::Allocation>(
|
||||
static_cast<void *>(data), ele_num * sizeof(T), phi::CPUPlace());
|
||||
out.ResetHolder(mem_allocation);
|
||||
phi::funcs::TransDataLayoutFromOneDNN(
|
||||
tensor->layout(),
|
||||
phi::OneDNNContext::tls().get_cur_paddle_data_layout(),
|
||||
*tensor,
|
||||
&out,
|
||||
phi::CPUPlace(),
|
||||
true);
|
||||
} else {
|
||||
std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
|
||||
}
|
||||
#else
|
||||
std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
|
||||
#endif
|
||||
} else if (t->place_ == PlaceType::kGPU) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
paddle::memory::Copy(phi::CPUPlace(),
|
||||
static_cast<void *>(data),
|
||||
t_place,
|
||||
t_data,
|
||||
ele_num * sizeof(T),
|
||||
stream);
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not create tensor with CUDA place because paddle is not compiled "
|
||||
"with CUDA."));
|
||||
#endif
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"CopyToCpuWithIoStream only supports CPU and GPU now."));
|
||||
}
|
||||
}
|
||||
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<double>(
|
||||
paddle_infer::Tensor *t, const double *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<float>(
|
||||
paddle_infer::Tensor *t, const float *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<int64_t>(
|
||||
paddle_infer::Tensor *t, const int64_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<int32_t>(
|
||||
paddle_infer::Tensor *t, const int32_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<uint8_t>(
|
||||
paddle_infer::Tensor *t, const uint8_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<int8_t>(
|
||||
paddle_infer::Tensor *t, const int8_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<float16>(
|
||||
paddle_infer::Tensor *t, const float16 *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<bfloat16>(
|
||||
paddle_infer::Tensor *t, const bfloat16 *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyFromCpuWithIoStream<bool>(
|
||||
paddle_infer::Tensor *t, const bool *data, cudaStream_t stream);
|
||||
|
||||
template void InternalUtils::CopyToCpuWithIoStream<double>(
|
||||
paddle_infer::Tensor *t, double *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<float>(
|
||||
paddle_infer::Tensor *t, float *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<int64_t>(
|
||||
paddle_infer::Tensor *t, int64_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<int32_t>(
|
||||
paddle_infer::Tensor *t, int32_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<uint8_t>(
|
||||
paddle_infer::Tensor *t, uint8_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<int8_t>(
|
||||
paddle_infer::Tensor *t, int8_t *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<float16>(
|
||||
paddle_infer::Tensor *t, float16 *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<bfloat16>(
|
||||
paddle_infer::Tensor *t, bfloat16 *data, cudaStream_t stream);
|
||||
template void InternalUtils::CopyToCpuWithIoStream<bool>(
|
||||
paddle_infer::Tensor *t, bool *data, cudaStream_t stream);
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2018 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 "paddle/fluid/inference/api/paddle_api.h"
|
||||
#include "paddle/fluid/inference/api/paddle_infer_declare.h"
|
||||
|
||||
namespace paddle_infer {
|
||||
|
||||
void Tensor::Reshape(const std::vector<int> &shape) {}
|
||||
|
||||
template <typename T>
|
||||
T *Tensor::mutable_data(PlaceType place) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *Tensor::data(PlaceType *place, int *size) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template PD_INFER_DECL float *Tensor::data<float>(PlaceType *place,
|
||||
int *size) const;
|
||||
template PD_INFER_DECL int64_t *Tensor::data<int64_t>(PlaceType *place,
|
||||
int *size) const;
|
||||
template float *Tensor::mutable_data(PlaceType place);
|
||||
template int64_t *Tensor::mutable_data(PlaceType place);
|
||||
|
||||
template <typename T>
|
||||
void *Tensor::FindTensor() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<int> Tensor::shape() const { return {}; }
|
||||
|
||||
void Tensor::SetLoD(const std::vector<std::vector<size_t>> &x) {}
|
||||
|
||||
std::vector<std::vector<size_t>> Tensor::lod() const {
|
||||
return std::vector<std::vector<size_t>>();
|
||||
}
|
||||
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,155 @@
|
||||
// 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.
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
#include "paddle/fluid/framework/data_type.h"
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/inference/api/helper.h"
|
||||
#include "paddle/fluid/inference/api/paddle_tensor.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/platform/device_context.h"
|
||||
|
||||
namespace paddle_infer {
|
||||
|
||||
struct TensorWrapper : public Tensor {
|
||||
TensorWrapper(
|
||||
paddle_infer::PlaceType place,
|
||||
paddle::framework::Scope* scope,
|
||||
const std::map<phi::Place,
|
||||
std::shared_future<std::unique_ptr<phi::DeviceContext>>>*
|
||||
dev_ctxs,
|
||||
const std::string& name)
|
||||
: Tensor{static_cast<void*>(scope), dev_ctxs} {
|
||||
SetPlace(place, 0 /*device_id*/);
|
||||
SetName(name);
|
||||
input_or_output_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Tensor> CreateTensor(paddle_infer::PlaceType place,
|
||||
paddle::framework::Scope* scope,
|
||||
const std::string& name) {
|
||||
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
|
||||
const auto& dev_ctxs = pool.device_contexts();
|
||||
return std::unique_ptr<Tensor>(
|
||||
new TensorWrapper{place, scope, &dev_ctxs, name});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct RandomGenerator {
|
||||
RandomGenerator(
|
||||
double min = static_cast<double>((std::numeric_limits<T>::min)()),
|
||||
double max = static_cast<double>((std::numeric_limits<T>::max)()))
|
||||
: dist_{min, max} {}
|
||||
T operator()() { return static_cast<T>(dist_(random_engine_)); }
|
||||
|
||||
private:
|
||||
std::mt19937_64 random_engine_{std::random_device()()};
|
||||
std::uniform_real_distribution<double> dist_;
|
||||
};
|
||||
|
||||
template <typename T, template <typename> class G>
|
||||
bool FillRandomDataAndCheck(PlaceType place,
|
||||
size_t length,
|
||||
G<T>&& generator,
|
||||
float threshold = 10e-5) {
|
||||
std::vector<T> data_in(length);
|
||||
std::generate(data_in.begin(), data_in.end(), std::forward<G<T>>(generator));
|
||||
paddle::framework::Scope scope;
|
||||
const std::string name{"name"};
|
||||
scope.Var(name);
|
||||
auto tensor = CreateTensor(place, &scope, name);
|
||||
tensor->CopyFromCpu<T>(data_in.data());
|
||||
if (tensor->type() != paddle::inference::ConvertToPaddleDType(
|
||||
paddle::framework::DataTypeTrait<T>::DataType())) {
|
||||
return false;
|
||||
}
|
||||
std::vector<T> data_out(length);
|
||||
tensor->CopyToCpu<T>(data_out.data());
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (std::abs(data_out[i] - data_out[i]) > threshold) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SetPlaceAndCheck(PlaceType place, size_t length) {
|
||||
paddle::framework::Scope scope;
|
||||
const std::string name{"name"};
|
||||
const std::vector<std::vector<size_t>> lod{{0, length}};
|
||||
scope.Var(name);
|
||||
auto tensor = CreateTensor(place, &scope, name);
|
||||
std::vector<int> shape{static_cast<int>(length)};
|
||||
tensor->Reshape(shape);
|
||||
tensor->mutable_data<T>(place);
|
||||
tensor->SetLoD(lod);
|
||||
|
||||
PlaceType place_out{PlaceType::kUNK};
|
||||
int length_out{-1};
|
||||
tensor->data<T>(&place_out, &length_out);
|
||||
if (length_out != static_cast<int>(length) || place_out != place) {
|
||||
return false;
|
||||
}
|
||||
if (tensor->name() != name || tensor->lod() != lod) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillRandomDataAndCheck(PlaceType place) {
|
||||
const size_t length{RandomGenerator<size_t>{1, 1000}()};
|
||||
VLOG(3) << "FillRandomDataAndCheck: length = " << length;
|
||||
return FillRandomDataAndCheck<float>(
|
||||
place, length, RandomGenerator<float>{}) &&
|
||||
FillRandomDataAndCheck<int64_t>(
|
||||
place, length, RandomGenerator<int64_t>{}) &&
|
||||
FillRandomDataAndCheck<int32_t>(
|
||||
place, length, RandomGenerator<int32_t>{}) &&
|
||||
FillRandomDataAndCheck<uint8_t>(
|
||||
place, length, RandomGenerator<uint8_t>{});
|
||||
}
|
||||
|
||||
bool SetPlaceAndCheck(PlaceType place) {
|
||||
const size_t length{RandomGenerator<size_t>{1, 1000}()};
|
||||
VLOG(3) << "SetPlaceAndCheck: length = " << length;
|
||||
return SetPlaceAndCheck<float>(place, length) &&
|
||||
SetPlaceAndCheck<int64_t>(place, length) &&
|
||||
SetPlaceAndCheck<int32_t>(place, length) &&
|
||||
SetPlaceAndCheck<uint8_t>(place, length);
|
||||
}
|
||||
|
||||
TEST(Tensor, FillRandomDataAndCheck) {
|
||||
ASSERT_TRUE(FillRandomDataAndCheck(PlaceType::kCPU));
|
||||
ASSERT_TRUE(SetPlaceAndCheck(PlaceType::kCPU));
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
ASSERT_TRUE(FillRandomDataAndCheck(PlaceType::kGPU));
|
||||
ASSERT_TRUE(SetPlaceAndCheck(PlaceType::kGPU));
|
||||
#endif
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
ASSERT_TRUE(FillRandomDataAndCheck(PlaceType::kXPU));
|
||||
ASSERT_TRUE(SetPlaceAndCheck(PlaceType::kXPU));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,448 @@
|
||||
// Copyright (c) 2018 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 "paddle/fluid/inference/api/helper.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/common/errors.h"
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/fluid/framework/custom_operator.h"
|
||||
#include "paddle/fluid/framework/custom_operator_utils.h"
|
||||
#include "paddle/fluid/framework/operator.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/ir/op_type.h"
|
||||
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
|
||||
#include "paddle/fluid/pir/drr/src/ir_operation_factory.h"
|
||||
#include "paddle/fluid/platform/init.h"
|
||||
#include "paddle/phi/api/ext/op_meta_info.h"
|
||||
#include "paddle/phi/core/enforce.h"
|
||||
#include "paddle/pir/include/core/builtin_attribute.h"
|
||||
#include "paddle/pir/include/core/builtin_type.h"
|
||||
#include "paddle/pir/include/core/ir_context.h"
|
||||
#include "paddle/pir/include/core/operation.h"
|
||||
#include "paddle/pir/include/core/value.h"
|
||||
|
||||
namespace paddle::inference {
|
||||
|
||||
template <>
|
||||
std::string to_string<std::vector<float>>(
|
||||
const std::vector<std::vector<float>> &vec) {
|
||||
std::stringstream ss;
|
||||
for (const auto &piece : vec) {
|
||||
ss << to_string(piece) << "\n";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string to_string<std::vector<std::vector<float>>>(
|
||||
const std::vector<std::vector<std::vector<float>>> &vec) {
|
||||
std::stringstream ss;
|
||||
for (const auto &line : vec) {
|
||||
for (const auto &rcd : line) {
|
||||
ss << to_string(rcd) << ";\t";
|
||||
}
|
||||
ss << '\n';
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void RegisterAllCustomOperator(bool use_pir) {
|
||||
const auto &meta_info_map = OpMetaInfoMap::Instance().GetMap();
|
||||
for (auto &pair : meta_info_map) {
|
||||
if (use_pir) {
|
||||
auto *custom_dialect =
|
||||
::pir::IrContext::Instance()
|
||||
->GetOrRegisterDialect<paddle::dialect::CustomOpDialect>();
|
||||
if (custom_dialect->HasRegistered(pair.first)) {
|
||||
VLOG(3) << "The operator `" << pair.first
|
||||
<< "` has been registered. "
|
||||
"Therefore, we will not repeat the registration here.";
|
||||
continue;
|
||||
}
|
||||
for (const auto &meta_info : pair.second) {
|
||||
VLOG(3) << "register pir custom op: " << pair.first;
|
||||
custom_dialect->RegisterCustomOp(meta_info);
|
||||
}
|
||||
|
||||
std::string pir_op_name =
|
||||
paddle::framework::kCustomDialectPrefix + pair.first;
|
||||
paddle::drr::OperationFactory::Instance().RegisterOperationCreator(
|
||||
pir_op_name,
|
||||
[pair, pir_op_name](
|
||||
const std::vector<::pir::Value> &inputs,
|
||||
const ::pir::AttributeMap &attrs,
|
||||
::pir::PatternRewriter &rewriter) mutable -> ::pir::Operation * {
|
||||
const auto &meta_inputs =
|
||||
paddle::OpMetaInfoHelper::GetInputs(pair.second[0]);
|
||||
const auto &meta_attrs =
|
||||
paddle::OpMetaInfoHelper::GetAttrs(pair.second[0]);
|
||||
const auto &meta_outputs =
|
||||
paddle::OpMetaInfoHelper::GetOutputs(pair.second[0]);
|
||||
const auto &inplace_map =
|
||||
paddle::OpMetaInfoHelper::GetInplaceMap(pair.second[0]);
|
||||
const auto &inplace_reverse_map =
|
||||
paddle::OpMetaInfoHelper::GetInplaceReverseMap(pair.second[0]);
|
||||
auto infershape_func =
|
||||
OpMetaInfoHelper::GetInferShapeFn(pair.second[0]);
|
||||
auto inferdtype_func =
|
||||
OpMetaInfoHelper::GetInferDtypeFn(pair.second[0]);
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
meta_inputs.size(),
|
||||
inputs.size(),
|
||||
common::errors::InvalidArgument(
|
||||
"The number of inputs for the custom operator [%s] given "
|
||||
"in the Pattern needs to be consistent with the number at "
|
||||
"implementation time.",
|
||||
pir_op_name));
|
||||
PADDLE_ENFORCE_EQ(
|
||||
meta_attrs.size(),
|
||||
attrs.size(),
|
||||
common::errors::InvalidArgument(
|
||||
"The number of attrs for the custom operator [%s] given "
|
||||
"in the Pattern needs to be consistent with the number at "
|
||||
"implementation time.",
|
||||
pir_op_name));
|
||||
|
||||
if (!inplace_map.empty()) {
|
||||
pir_op_name += "_";
|
||||
}
|
||||
::pir::OperationArgument argument(
|
||||
rewriter.ir_context()->GetRegisteredOpInfo(pir_op_name));
|
||||
argument.attributes = attrs;
|
||||
argument.inputs = inputs;
|
||||
|
||||
std::vector<pir::Type> argument_outputs;
|
||||
std::vector<std::vector<int64_t>> input_shapes;
|
||||
std::vector<DataType> input_dtypes;
|
||||
std::unordered_map<std::string, int> input_name2id_map;
|
||||
std::vector<std::vector<std::vector<int64_t>>> vec_input_shapes;
|
||||
std::vector<std::vector<DataType>> vec_input_dtypes;
|
||||
std::unordered_map<std::string, int> vec_input_name2id_map;
|
||||
std::vector<paddle::any> custom_attrs;
|
||||
int input_index = 0;
|
||||
int vec_input_index = 0;
|
||||
|
||||
for (size_t i = 0; i < meta_inputs.size(); ++i) {
|
||||
const auto &meta_input = meta_inputs.at(i);
|
||||
if (!inputs[i]) {
|
||||
VLOG(6) << "Add un-initialized tensor because the optional "
|
||||
"input is None.";
|
||||
if (paddle::framework::detail::IsDuplicableVar(meta_input)) {
|
||||
std::vector<std::vector<int64_t>> vec_input_shape;
|
||||
std::vector<DataType> vec_input_dtype;
|
||||
vec_input_shapes.emplace_back(vec_input_shape);
|
||||
vec_input_dtypes.emplace_back(vec_input_dtype);
|
||||
vec_input_name2id_map[meta_inputs[i]] = vec_input_index;
|
||||
vec_input_index++;
|
||||
} else {
|
||||
std::vector<int64_t> input_shape;
|
||||
DataType input_dtype = DataType::UNDEFINED;
|
||||
input_shapes.emplace_back(input_shape);
|
||||
input_dtypes.emplace_back(input_dtype);
|
||||
input_name2id_map[meta_inputs[i]] = input_index;
|
||||
input_index++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (paddle::framework::detail::IsDuplicableVar(meta_input)) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
inputs[i].type().isa<::pir::VectorType>(),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"The [%d] input of the custom operator [%s] "
|
||||
"should be a pir::VectorType.",
|
||||
i,
|
||||
pir_op_name));
|
||||
std::vector<std::vector<int64_t>> tmp_input_shapes;
|
||||
std::vector<phi::DataType> tmp_input_dtypes;
|
||||
vec_input_name2id_map[meta_inputs[i]] = vec_input_index;
|
||||
vec_input_index++;
|
||||
auto input_value_types =
|
||||
inputs[i].type().dyn_cast<::pir::VectorType>().data();
|
||||
for (auto &input_value_type : input_value_types) {
|
||||
auto input_tensor =
|
||||
input_value_type
|
||||
.dyn_cast<paddle::dialect::DenseTensorType>();
|
||||
tmp_input_shapes.push_back(
|
||||
phi::vectorize(input_tensor.dims()));
|
||||
tmp_input_dtypes.push_back(
|
||||
paddle::dialect::TransToPhiDataType(
|
||||
input_tensor.dtype()));
|
||||
}
|
||||
vec_input_shapes.push_back(tmp_input_shapes);
|
||||
vec_input_dtypes.push_back(tmp_input_dtypes);
|
||||
} else {
|
||||
input_name2id_map[meta_inputs[i]] = input_index;
|
||||
input_index++;
|
||||
auto input_tensor =
|
||||
inputs[i]
|
||||
.type()
|
||||
.dyn_cast<paddle::dialect::DenseTensorType>();
|
||||
input_shapes.push_back(phi::vectorize(input_tensor.dims()));
|
||||
input_dtypes.push_back(
|
||||
paddle::dialect::TransToPhiDataType(input_tensor.dtype()));
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &meta_attr : meta_attrs) {
|
||||
auto attr_name_and_type = paddle::ParseAttrStr(meta_attr);
|
||||
auto attr_name = attr_name_and_type[0];
|
||||
auto attr_type = attr_name_and_type[1];
|
||||
PADDLE_ENFORCE_EQ(attrs.count(attr_name),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"The attr [%s] in the custom operator [%s] "
|
||||
"specified in the Pattern needs to be "
|
||||
"consistent with the implementation",
|
||||
attr_name,
|
||||
pir_op_name));
|
||||
VLOG(6) << "Custom operator add attrs " << attr_name
|
||||
<< " to CustomOpKernelContext. Attribute type = "
|
||||
<< attr_type;
|
||||
if (attr_type == "bool") {
|
||||
auto bool_attr =
|
||||
attrs.at(attr_name).dyn_cast<::pir::BoolAttribute>().data();
|
||||
custom_attrs.emplace_back(bool_attr);
|
||||
} else if (attr_type == "int") {
|
||||
int int_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::Int32Attribute>()
|
||||
.data();
|
||||
custom_attrs.emplace_back(int_attr);
|
||||
} else if (attr_type == "float") {
|
||||
float float_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::FloatAttribute>()
|
||||
.data();
|
||||
custom_attrs.emplace_back(float_attr);
|
||||
} else if (attr_type == "int64_t") {
|
||||
int64_t long_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::Int64Attribute>()
|
||||
.data();
|
||||
custom_attrs.emplace_back(long_attr);
|
||||
} else if (attr_type == "std::string") {
|
||||
std::string str_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::StrAttribute>()
|
||||
.AsString();
|
||||
custom_attrs.emplace_back(str_attr);
|
||||
} else if (attr_type == "std::vector<int>") {
|
||||
auto vec_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::ArrayAttribute>()
|
||||
.AsVector();
|
||||
std::vector<int> vec_int_attr;
|
||||
for (const auto &int_attr : vec_attr) {
|
||||
vec_int_attr.push_back(
|
||||
int_attr.dyn_cast<::pir::Int32Attribute>().data());
|
||||
}
|
||||
custom_attrs.emplace_back(vec_int_attr);
|
||||
} else if (attr_type == "std::vector<float>") {
|
||||
auto vec_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::ArrayAttribute>()
|
||||
.AsVector();
|
||||
std::vector<float> vec_float_attr;
|
||||
for (const auto &float_attr : vec_attr) {
|
||||
vec_float_attr.push_back(
|
||||
float_attr.dyn_cast<::pir::FloatAttribute>().data());
|
||||
}
|
||||
custom_attrs.emplace_back(vec_float_attr);
|
||||
} else if (attr_type == "std::vector<int64_t>") {
|
||||
auto vec_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::ArrayAttribute>()
|
||||
.AsVector();
|
||||
std::vector<int64_t> vec_long_attr;
|
||||
for (const auto &long_attr : vec_attr) {
|
||||
vec_long_attr.push_back(
|
||||
long_attr.dyn_cast<::pir::Int64Attribute>().data());
|
||||
}
|
||||
custom_attrs.emplace_back(vec_long_attr);
|
||||
} else if (attr_type == "std::vector<std::string>") {
|
||||
auto vec_attr = attrs.at(attr_name)
|
||||
.dyn_cast<::pir::ArrayAttribute>()
|
||||
.AsVector();
|
||||
std::vector<std::string> vec_string_attr;
|
||||
for (const auto &string_attr : vec_attr) {
|
||||
vec_string_attr.push_back(
|
||||
string_attr.dyn_cast<::pir::StrAttribute>().AsString());
|
||||
}
|
||||
custom_attrs.emplace_back(vec_string_attr);
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported `%s` type value as custom attribute now. "
|
||||
"Supported data types include `bool`, `int`, `float`, "
|
||||
"`int64_t`, `std::string`, `std::vector<int>`, "
|
||||
"`std::vector<float>`, `std::vector<int64_t>`, "
|
||||
"`std::vector<std::string>`, Please check whether "
|
||||
"the attribute data type and data type string are matched.",
|
||||
attr_type));
|
||||
}
|
||||
}
|
||||
|
||||
paddle::framework::CheckDefaultInferShapeDtype(
|
||||
infershape_func, inferdtype_func, pair.second[0]);
|
||||
std::vector<std::vector<int64_t>> output_shapes =
|
||||
paddle::framework::RunInferShape(infershape_func,
|
||||
pair.second[0],
|
||||
input_shapes,
|
||||
input_name2id_map,
|
||||
vec_input_shapes,
|
||||
vec_input_name2id_map,
|
||||
custom_attrs);
|
||||
std::vector<phi::DataType> output_dtypes =
|
||||
paddle::framework::RunInferDtype(inferdtype_func,
|
||||
pair.second[0],
|
||||
input_dtypes,
|
||||
input_name2id_map,
|
||||
vec_input_dtypes,
|
||||
vec_input_name2id_map,
|
||||
custom_attrs);
|
||||
|
||||
size_t all_values_num = 0;
|
||||
// output name -> value num (that output should hold)
|
||||
std::unordered_map<std::string, size_t> output_name2value_num;
|
||||
for (const auto &output : meta_outputs) {
|
||||
if (paddle::framework::detail::IsDuplicableVar(output)) {
|
||||
PADDLE_ENFORCE_NE(inplace_reverse_map.find(output),
|
||||
inplace_reverse_map.end(),
|
||||
common::errors::InvalidArgument(
|
||||
"Only support vector output that is set "
|
||||
"for inplace, Please use "
|
||||
"`SetInplaceMap` in your output when "
|
||||
"registry custom operator."));
|
||||
const auto &input = inplace_reverse_map.at(output);
|
||||
auto index = vec_input_name2id_map[input];
|
||||
auto &vec_input_shape = vec_input_shapes[index];
|
||||
output_name2value_num[output] = vec_input_shape.size();
|
||||
} else {
|
||||
if (inplace_reverse_map.find(output) !=
|
||||
inplace_reverse_map.end()) {
|
||||
const auto &input = inplace_reverse_map.at(output);
|
||||
auto index = input_name2id_map[input];
|
||||
// input_shapes[index] is dim of tensor, if the dim doesn't
|
||||
// have element, it must be a optional tensor that is None in
|
||||
// custom operator
|
||||
output_name2value_num[output] =
|
||||
input_shapes[index].empty() ? 0 : 1;
|
||||
} else {
|
||||
output_name2value_num[output]++;
|
||||
}
|
||||
}
|
||||
all_values_num += output_name2value_num[output];
|
||||
}
|
||||
|
||||
PADDLE_ENFORCE_EQ(output_shapes.size(),
|
||||
all_values_num,
|
||||
common::errors::InvalidArgument(
|
||||
"The number of output shapes "
|
||||
"after running custom operator's "
|
||||
"InferShapeFunc is wrong, "
|
||||
"expected contains %d Tensors' "
|
||||
"shape, but actually contains %d "
|
||||
"Tensors' shape",
|
||||
all_values_num,
|
||||
output_shapes.size()));
|
||||
|
||||
PADDLE_ENFORCE_EQ(output_dtypes.size(),
|
||||
all_values_num,
|
||||
common::errors::InvalidArgument(
|
||||
"The number of output dtypes "
|
||||
"after running custom operator's "
|
||||
"InferDtypeFunc is wrong, "
|
||||
"expected contains %d Tensors' "
|
||||
"dtype, but actually contains %d "
|
||||
"Tensors' dtype",
|
||||
all_values_num,
|
||||
output_dtypes.size()));
|
||||
|
||||
size_t value_index = 0;
|
||||
for (const auto &output : meta_outputs) {
|
||||
auto value_num = output_name2value_num[output];
|
||||
if (value_num == 0) {
|
||||
// Optional value condition
|
||||
pir::Type out_type;
|
||||
argument_outputs.push_back(out_type);
|
||||
continue;
|
||||
}
|
||||
if (paddle::framework::detail::IsDuplicableVar(output)) {
|
||||
auto value_num = output_name2value_num[output];
|
||||
std::vector<pir::Type> out_types;
|
||||
for (size_t j = 0; j < value_num; ++j) {
|
||||
auto ddims = phi::make_ddim(output_shapes[value_index]);
|
||||
auto dtype = output_dtypes[value_index];
|
||||
phi::DataLayout layout{DataLayout::NCHW};
|
||||
phi::LegacyLoD lod;
|
||||
out_types.push_back(paddle::dialect::DenseTensorType::get(
|
||||
pir::IrContext::Instance(),
|
||||
paddle::dialect::TransToIrDataType(dtype),
|
||||
ddims,
|
||||
layout,
|
||||
lod,
|
||||
0));
|
||||
value_index++;
|
||||
}
|
||||
pir::Type out_vector_type =
|
||||
pir::VectorType::get(pir::IrContext::Instance(), out_types);
|
||||
argument_outputs.push_back(out_vector_type);
|
||||
} else {
|
||||
auto ddims = phi::make_ddim(output_shapes[value_index]);
|
||||
auto dtype = output_dtypes[value_index];
|
||||
phi::DataLayout layout{DataLayout::NCHW};
|
||||
phi::LegacyLoD lod;
|
||||
auto out_type = paddle::dialect::DenseTensorType::get(
|
||||
pir::IrContext::Instance(),
|
||||
paddle::dialect::TransToIrDataType(dtype),
|
||||
ddims,
|
||||
layout,
|
||||
lod,
|
||||
0);
|
||||
argument_outputs.push_back(out_type);
|
||||
value_index++;
|
||||
}
|
||||
}
|
||||
|
||||
argument.AddOutputs(argument_outputs.begin(),
|
||||
argument_outputs.end());
|
||||
::pir::PassStopGradientsDefaultly(argument);
|
||||
return rewriter.Build(std::move(argument));
|
||||
});
|
||||
}
|
||||
const auto &all_op_kernels{framework::OperatorWithKernel::AllOpKernels()};
|
||||
if (all_op_kernels.find(pair.first) == all_op_kernels.end()) {
|
||||
framework::RegisterOperatorWithMetaInfo(pair.second);
|
||||
} else {
|
||||
VLOG(3) << "The operator `" << pair.first
|
||||
<< "` has been registered. Therefore, we will not repeat the "
|
||||
"registration here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitGflagsFromEnv() {
|
||||
// support set gflags from environment.
|
||||
std::vector<std::string> gflags;
|
||||
const phi::ExportedFlagInfoMap &env_map = phi::GetExportedFlagInfoMap();
|
||||
std::ostringstream os;
|
||||
for (auto &pair : env_map) {
|
||||
os << pair.second.name << ",";
|
||||
}
|
||||
std::string tryfromenv_str = os.str();
|
||||
if (!tryfromenv_str.empty()) {
|
||||
tryfromenv_str.pop_back();
|
||||
tryfromenv_str = "--tryfromenv=" + tryfromenv_str;
|
||||
gflags.push_back(tryfromenv_str);
|
||||
}
|
||||
framework::InitGflags(gflags);
|
||||
}
|
||||
|
||||
} // namespace paddle::inference
|
||||
@@ -0,0 +1,518 @@
|
||||
// Copyright (c) 2018 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 <glog/logging.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#endif
|
||||
#include <fstream>
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <chrono> // NOLINT
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/fluid/framework/data_type.h"
|
||||
#include "paddle/fluid/inference/api/paddle_analysis_config.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/common/port.h"
|
||||
#include "paddle/phi/core/memory/stats.h"
|
||||
#include "paddle/utils/string/printf.h"
|
||||
|
||||
extern std::string paddle::framework::DataTypeToString(
|
||||
const framework::proto::VarType::Type type);
|
||||
|
||||
namespace paddle {
|
||||
namespace inference {
|
||||
|
||||
template <typename T>
|
||||
constexpr PaddleDType PaddleTensorGetDType();
|
||||
|
||||
template <>
|
||||
constexpr PaddleDType PaddleTensorGetDType<int32_t>() {
|
||||
return PaddleDType::INT32;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr PaddleDType PaddleTensorGetDType<int64_t>() {
|
||||
return PaddleDType::INT64;
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr PaddleDType PaddleTensorGetDType<float>() {
|
||||
return PaddleDType::FLOAT32;
|
||||
}
|
||||
|
||||
inline PaddleDType ConvertToPaddleDType(
|
||||
paddle::framework::proto::VarType::Type type) {
|
||||
if (type == paddle::framework::proto::VarType::FP32) {
|
||||
return PaddleDType::FLOAT32;
|
||||
} else if (type == paddle::framework::proto::VarType::INT64) {
|
||||
return PaddleDType::INT64;
|
||||
} else if (type == paddle::framework::proto::VarType::INT32) {
|
||||
return PaddleDType::INT32;
|
||||
} else if (type == paddle::framework::proto::VarType::UINT8) {
|
||||
return PaddleDType::UINT8;
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"The paddle dtype convert function only supports FLOAT32, INT64, INT32 "
|
||||
"and UINT8 now. But "
|
||||
"we get %d here.",
|
||||
static_cast<int>(type)));
|
||||
return PaddleDType::FLOAT32;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsFloatVar(framework::proto::VarType::Type t) {
|
||||
if (t == framework::proto::VarType::FP16 ||
|
||||
t == framework::proto::VarType::FP32 ||
|
||||
t == framework::proto::VarType::FP64 ||
|
||||
t == framework::proto::VarType::BF16)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
using paddle::framework::DataTypeToString;
|
||||
|
||||
// Timer for timer
|
||||
class Timer {
|
||||
public:
|
||||
std::chrono::high_resolution_clock::time_point start;
|
||||
std::chrono::high_resolution_clock::time_point startu;
|
||||
|
||||
void tic() { start = std::chrono::high_resolution_clock::now(); }
|
||||
double toc() {
|
||||
startu = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> time_span =
|
||||
std::chrono::duration_cast<std::chrono::duration<double>>(startu -
|
||||
start);
|
||||
double used_time_ms = static_cast<double>(time_span.count()) * 1000.0;
|
||||
return used_time_ms;
|
||||
}
|
||||
};
|
||||
|
||||
static int GetUniqueId() {
|
||||
static int id = 0;
|
||||
return id++;
|
||||
}
|
||||
|
||||
static void split(const std::string &str,
|
||||
char sep,
|
||||
std::vector<std::string> *pieces,
|
||||
bool ignore_null = true) {
|
||||
pieces->clear();
|
||||
if (str.empty()) {
|
||||
if (!ignore_null) {
|
||||
pieces->push_back(str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
size_t pos = 0;
|
||||
size_t next = str.find(sep, pos);
|
||||
while (next != std::string::npos) {
|
||||
pieces->push_back(str.substr(pos, next - pos));
|
||||
pos = next + 1;
|
||||
next = str.find(sep, pos);
|
||||
}
|
||||
if (!str.substr(pos).empty()) {
|
||||
pieces->push_back(str.substr(pos));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T convert(const std::string &item,
|
||||
std::function<T(const std::string &item)> func) {
|
||||
T res;
|
||||
try {
|
||||
res = func(item);
|
||||
} catch (std::invalid_argument &e) {
|
||||
std::string message =
|
||||
"invalid_argument exception when try to convert : " + item;
|
||||
LOG(ERROR) << message;
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"invalid_argument exception when try to convert %s.", item));
|
||||
} catch (std::out_of_range &e) {
|
||||
std::string message =
|
||||
"out_of_range exception when try to convert : " + item;
|
||||
LOG(ERROR) << message;
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"out_of_range exception when try to convert %s.", item));
|
||||
} catch (...) {
|
||||
std::string message = "unexpected exception when try to convert " + item;
|
||||
LOG(ERROR) << message;
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"unexpected exception when try to convert %s.", item));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void split_to_float(const std::string &str,
|
||||
char sep,
|
||||
std::vector<float> *fs) {
|
||||
std::vector<std::string> pieces;
|
||||
split(str, sep, &pieces);
|
||||
std::transform(pieces.begin(),
|
||||
pieces.end(),
|
||||
std::back_inserter(*fs),
|
||||
[](const std::string &v) {
|
||||
return convert<float>(v, [](const std::string &item) {
|
||||
return std::stof(item);
|
||||
});
|
||||
});
|
||||
}
|
||||
static void split_to_int64(const std::string &str,
|
||||
char sep,
|
||||
std::vector<int64_t> *is) {
|
||||
std::vector<std::string> pieces;
|
||||
split(str, sep, &pieces);
|
||||
std::transform(pieces.begin(),
|
||||
pieces.end(),
|
||||
std::back_inserter(*is),
|
||||
[](const std::string &v) {
|
||||
return convert<int64_t>(v, [](const std::string &item) {
|
||||
return std::stoll(item);
|
||||
});
|
||||
});
|
||||
}
|
||||
static void split_to_int(const std::string &str,
|
||||
char sep,
|
||||
std::vector<int> *is) {
|
||||
std::vector<std::string> pieces;
|
||||
split(str, sep, &pieces);
|
||||
std::transform(pieces.begin(),
|
||||
pieces.end(),
|
||||
std::back_inserter(*is),
|
||||
[](const std::string &v) {
|
||||
return convert<int>(v, [](const std::string &item) {
|
||||
return std::stoi(item);
|
||||
});
|
||||
});
|
||||
}
|
||||
template <typename T>
|
||||
std::string to_string(const std::vector<T> &vec) {
|
||||
std::stringstream ss;
|
||||
for (const auto &c : vec) {
|
||||
ss << c << " ";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
template <>
|
||||
std::string to_string<std::vector<float>>(
|
||||
const std::vector<std::vector<float>> &vec);
|
||||
|
||||
template <>
|
||||
std::string to_string<std::vector<std::vector<float>>>(
|
||||
const std::vector<std::vector<std::vector<float>>> &vec);
|
||||
|
||||
template <typename T>
|
||||
int VecReduceToInt(const std::vector<T> &v) {
|
||||
return std::accumulate(v.begin(), v.end(), 1, [](T a, T b) { return a * b; });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CheckAssignedData(const std::vector<std::vector<T>> &data,
|
||||
const int num_elems) {
|
||||
int num = 0;
|
||||
for (auto it = data.begin(); it != data.end(); ++it) {
|
||||
num += (*it).size();
|
||||
}
|
||||
PADDLE_ENFORCE_EQ(
|
||||
num,
|
||||
num_elems,
|
||||
common::errors::OutOfRange(
|
||||
"The number of elements out of bounds. "
|
||||
"Expected number of elements = %d. But received %d. Suggested Fix: "
|
||||
"If the tensor is expected to assign %d elements, check the number "
|
||||
"of elements of your 'infer_data'.",
|
||||
num_elems,
|
||||
num,
|
||||
num_elems));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void TensorAssignData(PaddleTensor *tensor,
|
||||
const std::vector<std::vector<T>> &data) {
|
||||
// Assign buffer
|
||||
int num_elems = VecReduceToInt(tensor->shape);
|
||||
CheckAssignedData(data, num_elems);
|
||||
tensor->data.Resize(sizeof(T) * num_elems);
|
||||
int c = 0;
|
||||
for (const auto &f : data) {
|
||||
for (T v : f) {
|
||||
static_cast<T *>(tensor->data.data())[c++] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void TensorAssignData(PaddleTensor *tensor,
|
||||
const std::vector<std::vector<T>> &data,
|
||||
const std::vector<size_t> &lod) {
|
||||
int size = lod[lod.size() - 1];
|
||||
tensor->shape.assign({size, 1});
|
||||
tensor->lod.assign({lod});
|
||||
TensorAssignData(tensor, data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void ZeroCopyTensorAssignData(ZeroCopyTensor *tensor,
|
||||
const std::vector<std::vector<T>> &data) {
|
||||
auto *ptr = tensor->mutable_data<T>(PaddlePlace::kCPU);
|
||||
int c = 0;
|
||||
for (const auto &f : data) {
|
||||
for (T v : f) {
|
||||
ptr[c++] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void ZeroCopyTensorAssignData(ZeroCopyTensor *tensor,
|
||||
const PaddleBuf &data) {
|
||||
auto *ptr = tensor->mutable_data<T>(PaddlePlace::kCPU);
|
||||
for (size_t i = 0; i < data.length() / sizeof(T); i++) {
|
||||
ptr[i] = *(reinterpret_cast<T *>(data.data()) + i);
|
||||
}
|
||||
}
|
||||
|
||||
static bool CompareTensor(const PaddleTensor &a, const PaddleTensor &b) {
|
||||
if (a.dtype != b.dtype) {
|
||||
LOG(ERROR) << "dtype not match";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.lod.size() != b.lod.size()) {
|
||||
LOG(ERROR) << "lod not match";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < a.lod.size(); i++) {
|
||||
if (a.lod[i].size() != b.lod[i].size()) {
|
||||
LOG(ERROR) << "lod not match";
|
||||
return false;
|
||||
}
|
||||
for (size_t j = 0; j < a.lod[i].size(); j++) {
|
||||
if (a.lod[i][j] != b.lod[i][j]) {
|
||||
LOG(ERROR) << "lod not match";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a.shape.size() != b.shape.size()) {
|
||||
LOG(INFO) << "shape not match";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < a.shape.size(); i++) {
|
||||
if (a.shape[i] != b.shape[i]) {
|
||||
LOG(ERROR) << "shape not match";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto *adata = static_cast<float *>(a.data.data());
|
||||
auto *bdata = static_cast<float *>(b.data.data());
|
||||
for (int i = 0; i < VecReduceToInt(a.shape); i++) {
|
||||
if (adata[i] != bdata[i]) {
|
||||
LOG(ERROR) << "data not match";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string DescribeTensor(const PaddleTensor &tensor,
|
||||
int max_num_of_data UNUSED = 15) {
|
||||
std::stringstream os;
|
||||
os << "Tensor [" << tensor.name << "]\n";
|
||||
os << " - type: ";
|
||||
switch (tensor.dtype) {
|
||||
case PaddleDType::FLOAT32:
|
||||
os << "float32";
|
||||
break;
|
||||
case PaddleDType::INT64:
|
||||
os << "int64";
|
||||
break;
|
||||
case PaddleDType::INT32:
|
||||
os << "int32";
|
||||
break;
|
||||
default:
|
||||
os << "unset";
|
||||
}
|
||||
os << '\n';
|
||||
|
||||
os << " - shape: " << to_string(tensor.shape) << '\n';
|
||||
os << " - lod: ";
|
||||
for (auto &l : tensor.lod) {
|
||||
os << to_string(l) << "; ";
|
||||
}
|
||||
os << "\n";
|
||||
os << " - memory length: " << tensor.data.length();
|
||||
os << "\n";
|
||||
|
||||
os << " - data: ";
|
||||
int dim = VecReduceToInt(tensor.shape);
|
||||
float *pdata = static_cast<float *>(tensor.data.data());
|
||||
for (int i = 0; i < dim; i++) {
|
||||
os << pdata[i] << " ";
|
||||
}
|
||||
os << '\n';
|
||||
return os.str();
|
||||
}
|
||||
|
||||
static std::string DescribeZeroCopyTensor(const ZeroCopyTensor &tensor) {
|
||||
std::stringstream os;
|
||||
os << "Tensor [" << tensor.name() << "]\n";
|
||||
|
||||
os << " - shape: " << to_string(tensor.shape()) << '\n';
|
||||
os << " - lod: ";
|
||||
for (auto &l : tensor.lod()) {
|
||||
os << to_string(l) << "; ";
|
||||
}
|
||||
os << "\n";
|
||||
PaddlePlace place;
|
||||
int size;
|
||||
const auto *data = tensor.data<float>(&place, &size);
|
||||
os << " - numel: " << size;
|
||||
os << "\n";
|
||||
os << " - data: ";
|
||||
for (int i = 0; i < size; i++) {
|
||||
os << data[i] << " ";
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
static void PrintTime(int batch_size,
|
||||
int repeat,
|
||||
int num_threads,
|
||||
int tid,
|
||||
double batch_latency,
|
||||
int epoch = 1,
|
||||
const framework::proto::VarType::Type data_type =
|
||||
framework::proto::VarType::FP32) {
|
||||
PADDLE_ENFORCE_GT(
|
||||
batch_size,
|
||||
0,
|
||||
common::errors::InvalidArgument("Non-positive batch size."));
|
||||
double sample_latency = batch_latency / batch_size;
|
||||
LOG(INFO) << "====== threads: " << num_threads << ", thread id: " << tid
|
||||
<< " ======";
|
||||
LOG(INFO) << "====== batch size: " << batch_size << ", iterations: " << epoch
|
||||
<< ", repetitions: " << repeat << " ======";
|
||||
LOG(INFO) << "====== batch latency: " << batch_latency
|
||||
<< "ms, number of samples: " << batch_size * epoch
|
||||
<< ", sample latency: " << sample_latency
|
||||
<< "ms, fps: " << 1000.f / sample_latency
|
||||
<< ", data type: " << DataTypeToString(data_type) << " ======";
|
||||
}
|
||||
|
||||
static bool IsFileExists(const std::string &path) {
|
||||
#ifdef _WIN32
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring wpath = converter.from_bytes(path);
|
||||
std::ifstream file(wpath, std::ios::binary);
|
||||
#else
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
#endif
|
||||
bool exists = file.is_open();
|
||||
file.close();
|
||||
return exists;
|
||||
}
|
||||
|
||||
static bool IsDirectory(const std::string &path) {
|
||||
#ifdef _WIN32
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring wpath = converter.from_bytes(path);
|
||||
DWORD attr = GetFileAttributesW(wpath.c_str());
|
||||
if (attr == INVALID_FILE_ATTRIBUTES) return false;
|
||||
return (attr & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
struct stat info;
|
||||
if (stat(path.c_str(), &info) != 0) {
|
||||
return false;
|
||||
} else if (info.st_mode & S_IFDIR) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RegisterAllCustomOperator(bool use_pir);
|
||||
|
||||
void InitGflagsFromEnv();
|
||||
|
||||
static inline double ToMegaBytes(size_t bytes) {
|
||||
return static_cast<double>(bytes) / (1 << 20);
|
||||
}
|
||||
|
||||
static inline void DisplayMemoryInfo(phi::Place place,
|
||||
const std::string &hint) {
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
// size_t free, total;
|
||||
// cudaSetDevice(place.GetDeviceId());
|
||||
// cudaMemGetInfo(&free, &total);
|
||||
// VLOG(1) << "[" << ToMegaBytes(total - free) << "MB/" << ToMegaBytes(total)
|
||||
// << "MB]";
|
||||
|
||||
VLOG(1) << hint << " : [gpu current allocated memory: "
|
||||
<< ToMegaBytes(paddle::memory::DeviceMemoryStatCurrentValue(
|
||||
"Allocated", place.GetDeviceId()))
|
||||
<< "MB], [gpu current reserved memory: "
|
||||
<< ToMegaBytes(paddle::memory::DeviceMemoryStatCurrentValue(
|
||||
"Reserved", place.GetDeviceId()))
|
||||
<< "MB], [gpu peak allocated memory: "
|
||||
<< ToMegaBytes(paddle::memory::DeviceMemoryStatPeakValue(
|
||||
"Allocated", place.GetDeviceId()))
|
||||
<< "MB], [gpu peak reserved memory: "
|
||||
<< ToMegaBytes(paddle::memory::DeviceMemoryStatPeakValue(
|
||||
"Reserved", place.GetDeviceId()))
|
||||
<< "MB]";
|
||||
#endif
|
||||
VLOG(1)
|
||||
<< hint << " : [cpu current allocated memory: "
|
||||
<< ToMegaBytes(paddle::memory::HostMemoryStatCurrentValue("Allocated", 0))
|
||||
<< "MB], [cpu current reserved memory: "
|
||||
<< ToMegaBytes(paddle::memory::HostMemoryStatCurrentValue("Reserved", 0))
|
||||
<< "MB], [cpu peak allocated memory: "
|
||||
<< ToMegaBytes(paddle::memory::HostMemoryStatPeakValue("Allocated", 0))
|
||||
<< "MB], [cpu peak reserved memory: "
|
||||
<< ToMegaBytes(paddle::memory::HostMemoryStatPeakValue("Reserved", 0))
|
||||
<< "MB]";
|
||||
}
|
||||
|
||||
static std::string Precision2String(AnalysisConfig::Precision precision) {
|
||||
if (precision == AnalysisConfig::Precision::kFloat32)
|
||||
return "fp32";
|
||||
else if (precision == AnalysisConfig::Precision::kHalf)
|
||||
return "fp16";
|
||||
else if (precision == AnalysisConfig::Precision::kInt8)
|
||||
return "int8";
|
||||
else if (precision == AnalysisConfig::Precision::kBf16)
|
||||
return "bf16";
|
||||
else
|
||||
return "none";
|
||||
}
|
||||
|
||||
} // namespace inference
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,290 @@
|
||||
// Copyright (c) 2022 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 "paddle/fluid/inference/api/infer_context.h"
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
#include "xpu/runtime.h"
|
||||
#endif
|
||||
#include "glog/logging.h"
|
||||
|
||||
namespace paddle {
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
InferGPUContext::InferGPUContext(const phi::Place& place)
|
||||
: phi::GPUContext(place, false) {}
|
||||
#endif
|
||||
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
InferXPUContext::InferXPUContext(const phi::Place& place, int context_gm_size)
|
||||
: phi::XPUContext(place) {
|
||||
if (context_gm_size >= 0) {
|
||||
x_context()->set_option("XPUAPI_DEFAULT_SIZE",
|
||||
std::to_string(context_gm_size).c_str());
|
||||
} else {
|
||||
x_context()->set_option("XPUAPI_DEFAULT_SIZE", "");
|
||||
}
|
||||
}
|
||||
|
||||
void* InferXPUContext::Alloc(phi::TensorBase* tensor,
|
||||
phi::DataType dtype,
|
||||
size_t requested_size,
|
||||
bool pinned,
|
||||
bool fake_alloc) const {
|
||||
size_t size = tensor->numel() * phi::SizeOf(tensor->dtype());
|
||||
if (l3_autotune_size_ > 0 && holder_map_.empty()) {
|
||||
void* data_ptr =
|
||||
DeviceContext::Alloc(tensor, dtype, requested_size, pinned, fake_alloc);
|
||||
phi::XPUL3CacheBlock* l3_block = nullptr;
|
||||
phi::Allocation* holder =
|
||||
reinterpret_cast<phi::DenseTensor*>(tensor)->Holder().get();
|
||||
if (holder_l3_blocks_.count(holder) == 0) {
|
||||
l3_block = new phi::XPUL3CacheBlock();
|
||||
holder_l3_blocks_[holder] = l3_block;
|
||||
l3_blocks_.push_back(l3_block);
|
||||
} else {
|
||||
l3_block = holder_l3_blocks_[holder];
|
||||
}
|
||||
l3_block->Record(size);
|
||||
return data_ptr;
|
||||
} else if (l3_autotune_size_ > 0 && !holder_map_.empty()) {
|
||||
phi::Allocation* holder =
|
||||
reinterpret_cast<phi::DenseTensor*>(tensor)->Holder().get();
|
||||
auto holder_iter = holder_map_.find(holder);
|
||||
if (holder_iter != holder_map_.end()) {
|
||||
auto& holder_pair = holder_iter->second;
|
||||
auto* swap_holder = holder_pair.first;
|
||||
bool& swap_holder_is_l3 = holder_pair.second;
|
||||
if (swap_holder_is_l3 && swap_holder->size() >= size) {
|
||||
swap(*holder, *swap_holder);
|
||||
swap_holder_is_l3 = false;
|
||||
} else if (!swap_holder_is_l3 && holder->size() < size) {
|
||||
swap(*holder, *swap_holder);
|
||||
swap_holder_is_l3 = true;
|
||||
}
|
||||
}
|
||||
return DeviceContext::Alloc(
|
||||
tensor, dtype, requested_size, pinned, fake_alloc);
|
||||
} else {
|
||||
return DeviceContext::Alloc(
|
||||
tensor, dtype, requested_size, pinned, fake_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
void InferXPUContext::SetXContext(xpu::Context* x_context) {
|
||||
auto* old_x_context = this->x_context();
|
||||
if (old_x_context != x_context) {
|
||||
if (l3_owned_ && l3_size_ > 0 &&
|
||||
(x_context->_l3_mgr.get_size() != l3_size_ ||
|
||||
x_context->_l3_mgr.get_ptr() != l3_ptr_)) {
|
||||
xpu_free(l3_ptr_);
|
||||
}
|
||||
old_x_context->_l3_mgr.set(nullptr, 0);
|
||||
l3_size_ = x_context->_l3_mgr.get_size();
|
||||
l3_ptr_ = x_context->_l3_mgr.get_ptr();
|
||||
l3_owned_ = false;
|
||||
phi::XPUContext::SetXContext(x_context);
|
||||
}
|
||||
}
|
||||
|
||||
void InferXPUContext::SetL3Info(size_t l3_size,
|
||||
void* l3_ptr,
|
||||
size_t l3_autotune_size,
|
||||
const phi::Place& place) {
|
||||
phi::backends::xpu::XPUDeviceGuard guard(place.GetDeviceId());
|
||||
if (l3_ptr == nullptr) {
|
||||
if (l3_size_ != l3_size) {
|
||||
if (l3_owned_) {
|
||||
xpu_free(l3_ptr_);
|
||||
}
|
||||
if (l3_size > 0) {
|
||||
xpu_malloc(&l3_ptr_, l3_size, XPU_MEM_L3);
|
||||
if (l3_ptr_ != nullptr) {
|
||||
VLOG(3) << "remalloc l3(" << l3_size << ") success.";
|
||||
l3_size_ = l3_size;
|
||||
l3_owned_ = true;
|
||||
l3_autotune_size_ = l3_autotune_size;
|
||||
} else {
|
||||
VLOG(3) << "malloc l3(" << l3_size << ") failed. No l3 will be used.";
|
||||
l3_size_ = 0;
|
||||
l3_owned_ = false;
|
||||
l3_autotune_size_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (l3_owned_) {
|
||||
xpu_free(l3_ptr_);
|
||||
}
|
||||
l3_ptr_ = l3_ptr;
|
||||
l3_size_ = l3_size;
|
||||
l3_autotune_size_ = l3_autotune_size;
|
||||
}
|
||||
if (l3_autotune_size_ == 0) {
|
||||
x_context()->_l3_mgr.set(l3_ptr_, l3_size_);
|
||||
}
|
||||
}
|
||||
|
||||
void InferXPUContext::SetConvAutotuneInfo(std::string conv_autotune_file,
|
||||
int conv_autotune_level,
|
||||
bool conv_autotune_file_writeback,
|
||||
const phi::Place& place) {
|
||||
phi::backends::xpu::XPUDeviceGuard guard(place.GetDeviceId());
|
||||
|
||||
VLOG(5) << "XPU conv autotune level:" << conv_autotune_level;
|
||||
VLOG(5) << "XPU conv autotune file:" << conv_autotune_file;
|
||||
VLOG(5) << "XPU conv autotune file writeback:"
|
||||
<< conv_autotune_file_writeback;
|
||||
|
||||
if (!conv_autotune_file.empty()) {
|
||||
int ret;
|
||||
ret = x_context()->set_option("XPU_CONV_AUTOTUNE_FILE",
|
||||
conv_autotune_file.c_str());
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ret,
|
||||
0,
|
||||
common::errors::Unavailable("Failed to set XPU conv autotune file %s.",
|
||||
conv_autotune_file));
|
||||
}
|
||||
if (conv_autotune_level > 0) {
|
||||
int ret;
|
||||
ret = x_context()->set_option(
|
||||
"XPU_CONV_AUTOTUNE", (std::to_string(conv_autotune_level)).c_str());
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ret,
|
||||
0,
|
||||
common::errors::Unavailable("Failed to set XPU conv autotune %d.",
|
||||
conv_autotune_level));
|
||||
}
|
||||
if (conv_autotune_file_writeback) {
|
||||
int ret;
|
||||
ret = x_context()->set_option(
|
||||
"XPU_AUTOTUNE_WRITEBACK",
|
||||
(std::to_string(conv_autotune_file_writeback)).c_str());
|
||||
PADDLE_ENFORCE_EQ(ret,
|
||||
0,
|
||||
common::errors::Unavailable(
|
||||
"Failed to set XPU conv autotune writeback %d.",
|
||||
conv_autotune_file_writeback));
|
||||
}
|
||||
}
|
||||
void InferXPUContext::SetContextOption(const char* name, const char* value) {
|
||||
phi::backends::xpu::XPUDeviceGuard guard(GetPlace().GetDeviceId());
|
||||
VLOG(5) << "XPU Set Option name:" << name << " value:" << value;
|
||||
int ret;
|
||||
ret = x_context()->set_option(name, value);
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ret,
|
||||
0,
|
||||
common::errors::Unavailable("Failed to set XPU option %s.", name));
|
||||
}
|
||||
|
||||
void InferXPUContext::SetFcAutotuneInfo(std::string fc_autotune_file,
|
||||
int fc_autotune_level,
|
||||
bool fc_autotune_file_writeback,
|
||||
const phi::Place& place) {
|
||||
phi::backends::xpu::XPUDeviceGuard guard(place.GetDeviceId());
|
||||
|
||||
VLOG(5) << "XPU fc autotune level:" << fc_autotune_level;
|
||||
VLOG(5) << "XPU fc autotune file:" << fc_autotune_file;
|
||||
VLOG(5) << "XPU fc autotune file writeback:" << fc_autotune_file_writeback;
|
||||
|
||||
if (!fc_autotune_file.empty()) {
|
||||
int ret;
|
||||
ret = x_context()->set_option("XPU_FC_AUTOTUNE_FILE",
|
||||
fc_autotune_file.c_str());
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ret,
|
||||
0,
|
||||
common::errors::Unavailable("Failed to set XPU fc autotune file %s.",
|
||||
fc_autotune_file));
|
||||
}
|
||||
if (fc_autotune_level > 0) {
|
||||
int ret;
|
||||
ret = x_context()->set_option("XPU_FC_AUTOTUNE",
|
||||
(std::to_string(fc_autotune_level)).c_str());
|
||||
PADDLE_ENFORCE_EQ(
|
||||
ret,
|
||||
0,
|
||||
common::errors::Unavailable("Failed to set XPU fc autotune %d.",
|
||||
fc_autotune_level));
|
||||
}
|
||||
if (fc_autotune_file_writeback) {
|
||||
int ret;
|
||||
ret = x_context()->set_option(
|
||||
"XPU_FC_AUTOTUNE_WRITEBACK",
|
||||
(std::to_string(fc_autotune_file_writeback)).c_str());
|
||||
PADDLE_ENFORCE_EQ(ret,
|
||||
0,
|
||||
common::errors::Unavailable(
|
||||
"Failed to set XPU fc autotune writeback %d.",
|
||||
fc_autotune_file_writeback));
|
||||
}
|
||||
}
|
||||
|
||||
void InferXPUContext::L3CacheAutotune() {
|
||||
if (l3_autotune_size_ == 0) return;
|
||||
if (holder_map_.empty()) {
|
||||
bool ret = l3_plan_.RunAutotune(l3_blocks_, l3_size_);
|
||||
if (!ret) {
|
||||
return;
|
||||
}
|
||||
auto* plan = l3_plan_.plan();
|
||||
int8_t* cur_l3_ptr = reinterpret_cast<int8_t*>(l3_ptr_);
|
||||
for (size_t i = 0; i < l3_blocks_.size(); i++) {
|
||||
size_t block_size = plan->at(i);
|
||||
if (block_size > 0) {
|
||||
l3_blocks_[i]->Set(cur_l3_ptr, block_size);
|
||||
cur_l3_ptr += block_size;
|
||||
}
|
||||
}
|
||||
x_context()->_l3_mgr.set(
|
||||
reinterpret_cast<int8_t*>(l3_ptr_) + l3_size_ - plan->back(),
|
||||
plan->back());
|
||||
|
||||
for (auto holder_l3_block : holder_l3_blocks_) {
|
||||
auto* l3_block = holder_l3_block.second;
|
||||
if (l3_block->size() > 0) {
|
||||
auto* holder = holder_l3_block.first;
|
||||
auto place = holder->place();
|
||||
phi::Allocation* l3_holder =
|
||||
new phi::Allocation(l3_block->data(), l3_block->size(), place);
|
||||
holder_map_[holder] = std::make_pair(l3_holder, true);
|
||||
|
||||
if (output_holder_set_.find(holder) != output_holder_set_.end()) {
|
||||
VLOG(4) << "Insert output tensor's l3 holder:" << l3_holder->ptr();
|
||||
SetOutHolder(l3_holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& holders : holder_map_) {
|
||||
auto* holder = holders.first;
|
||||
auto& holder_pair = holders.second;
|
||||
if (!holder_pair.second &&
|
||||
output_holder_set_.find(holder) == output_holder_set_.end()) {
|
||||
swap(*holder, *(holder_pair.first));
|
||||
holder_pair.second = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InferXPUContext::SetOutHolder(phi::Allocation* holder) {
|
||||
output_holder_set_.insert(holder);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2022 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 "paddle/phi/backends/all_context.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
#include "paddle/phi/backends/xpu/xpu_l3_strategy.h"
|
||||
#endif
|
||||
#include <unordered_set>
|
||||
|
||||
namespace paddle {
|
||||
|
||||
class InferCPUContext : public phi::CPUContext {
|
||||
public:
|
||||
using phi::CPUContext::SetEigenDevice;
|
||||
};
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
class InferGPUContext : public phi::GPUContext {
|
||||
public:
|
||||
explicit InferGPUContext(const phi::Place& place);
|
||||
using phi::GPUContext::SetBlasHandle;
|
||||
using phi::GPUContext::SetBlasTensorCoreHandle;
|
||||
using phi::GPUContext::SetBlasTF32Handle;
|
||||
using phi::GPUContext::SetDnnHandle;
|
||||
using phi::GPUContext::SetEigenDevice;
|
||||
using phi::GPUContext::SetSolverHandle;
|
||||
using phi::GPUContext::SetSparseHandle;
|
||||
using phi::GPUContext::SetStream;
|
||||
// using phi::GPUContext::SetDnnWorkspaceHandle;
|
||||
using phi::GPUContext::SetComputeCapability;
|
||||
using phi::GPUContext::SetDriverVersion;
|
||||
using phi::GPUContext::SetMaxGridDimSize;
|
||||
using phi::GPUContext::SetMaxThreadsPerBlock;
|
||||
using phi::GPUContext::SetMaxThreadsPerMultiProcessor;
|
||||
using phi::GPUContext::SetMultiProcessors;
|
||||
using phi::GPUContext::SetRuntimeVersion;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef PADDLE_WITH_XPU
|
||||
class InferXPUContext : public phi::XPUContext {
|
||||
public:
|
||||
explicit InferXPUContext(const phi::Place& place, int context_gm_size = -1);
|
||||
|
||||
void* Alloc(phi::TensorBase* tensor,
|
||||
phi::DataType dtype,
|
||||
size_t requested_size = 0,
|
||||
bool pinned = false,
|
||||
bool fake_alloc = false) const override;
|
||||
|
||||
void SetXContext(xpu::Context* x_context);
|
||||
|
||||
void SetL3Info(size_t l3_size,
|
||||
void* l3_ptr,
|
||||
size_t l3_autotune_size,
|
||||
const phi::Place& place);
|
||||
|
||||
void L3CacheAutotune();
|
||||
|
||||
void SetConvAutotuneInfo(std::string conv_autotune_file,
|
||||
int conv_autotune_level,
|
||||
bool conv_autotune_file_writeback,
|
||||
const phi::Place& place);
|
||||
|
||||
void SetFcAutotuneInfo(std::string fc_autotune_file,
|
||||
int fc_autotune_level,
|
||||
bool fc_autotune_file_writeback,
|
||||
const phi::Place& place);
|
||||
void SetContextOption(const char* name, const char* value);
|
||||
|
||||
void SetOutHolder(phi::Allocation* holder);
|
||||
|
||||
private:
|
||||
size_t l3_size_{0};
|
||||
void* l3_ptr_{nullptr};
|
||||
bool l3_owned_{false};
|
||||
size_t l3_autotune_size_{0};
|
||||
mutable std::vector<phi::XPUL3CacheBlock*> l3_blocks_;
|
||||
mutable std::unordered_map<phi::Allocation*, phi::XPUL3CacheBlock*>
|
||||
holder_l3_blocks_;
|
||||
mutable std::unordered_map<phi::Allocation*,
|
||||
std::pair<phi::Allocation*, bool>>
|
||||
holder_map_;
|
||||
|
||||
mutable std::unordered_set<phi::Allocation*> output_holder_set_;
|
||||
phi::XPUL3Planner l3_plan_;
|
||||
};
|
||||
#endif
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,389 @@
|
||||
// Copyright (c) 2022 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 "paddle/fluid/inference/api/onnxruntime_predictor.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/framework/var_type_traits.h"
|
||||
#include "paddle/fluid/framework/variable_helper.h"
|
||||
#include "paddle/fluid/inference/analysis/helper.h"
|
||||
#include "paddle/fluid/inference/api/helper.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_pass.h"
|
||||
#include "paddle/fluid/inference/utils/io_utils.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/memory/memcpy.h"
|
||||
#include "paddle/phi/core/platform/cpu_helper.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_info.h"
|
||||
#include "paddle/phi/core/platform/profiler.h"
|
||||
|
||||
namespace paddle {
|
||||
|
||||
paddle_infer::DataType ConvertONNXType(ONNXTensorElementDataType type) {
|
||||
switch (type) {
|
||||
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT:
|
||||
return paddle_infer::DataType::FLOAT32;
|
||||
case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16:
|
||||
return paddle_infer::DataType::FLOAT16;
|
||||
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8:
|
||||
return paddle_infer::DataType::INT8;
|
||||
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32:
|
||||
return paddle_infer::DataType::INT32;
|
||||
case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64:
|
||||
return paddle_infer::DataType::INT64;
|
||||
case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8:
|
||||
return paddle_infer::DataType::UINT8;
|
||||
default:
|
||||
LOG(ERROR) << "unsupported ONNX Tensor Type: " << static_cast<int>(type);
|
||||
return paddle_infer::DataType::FLOAT32;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckConvertToONNX(const AnalysisConfig &config) {
|
||||
if (!config.model_dir().empty()) {
|
||||
LOG(ERROR) << "Paddle2ONNX not support model_dir config";
|
||||
// TODO(heliqi jiangjiajun): Paddle2ONNX not support
|
||||
// config.model_dir() + "/__model__"
|
||||
// config.model_dir() + var_name
|
||||
return false;
|
||||
} else if (config.prog_file().empty() || config.params_file().empty()) {
|
||||
LOG(ERROR) << string::Sprintf(
|
||||
"not valid model path '%s' or program path '%s' or params path '%s'.",
|
||||
config.model_dir(),
|
||||
config.prog_file(),
|
||||
config.params_file());
|
||||
return false;
|
||||
}
|
||||
if (config.model_from_memory()) {
|
||||
return paddle2onnx::IsExportable(config.prog_file().data(),
|
||||
config.prog_file().size(),
|
||||
config.params_file().data(),
|
||||
config.params_file().size());
|
||||
} else {
|
||||
return paddle2onnx::IsExportable(config.prog_file().c_str(),
|
||||
config.params_file().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool ONNXRuntimePredictor::InitBinding() {
|
||||
// Now ONNXRuntime only support CPU
|
||||
const char *device_name = config_.use_gpu() ? "Cuda" : "Cpu";
|
||||
if (config_.use_gpu()) {
|
||||
place_ = phi::GPUPlace(config_.gpu_device_id());
|
||||
} else {
|
||||
place_ = phi::CPUPlace();
|
||||
}
|
||||
scope_.reset(new paddle::framework::Scope());
|
||||
|
||||
binding_ = std::make_shared<Ort::IoBinding>(*session_);
|
||||
Ort::MemoryInfo memory_info(
|
||||
device_name, OrtDeviceAllocator, place_.GetDeviceId(), OrtMemTypeDefault);
|
||||
Ort::Allocator allocator(*session_, memory_info);
|
||||
|
||||
size_t n_inputs = session_->GetInputCount();
|
||||
framework::proto::VarType::Type proto_type =
|
||||
framework::proto::VarType::DENSE_TENSOR;
|
||||
for (size_t i = 0; i < n_inputs; ++i) {
|
||||
auto input_name = session_->GetInputName(i, allocator);
|
||||
auto type_info = session_->GetInputTypeInfo(i);
|
||||
std::vector<int64_t> shape =
|
||||
type_info.GetTensorTypeAndShapeInfo().GetShape();
|
||||
ONNXTensorElementDataType data_type =
|
||||
type_info.GetTensorTypeAndShapeInfo().GetElementType();
|
||||
input_desc_.emplace_back(ONNXDesc{input_name, shape, data_type});
|
||||
|
||||
auto *ptr = scope_->Var(input_name);
|
||||
framework::InitializeVariable(ptr, proto_type);
|
||||
|
||||
allocator.Free(input_name);
|
||||
}
|
||||
|
||||
size_t n_outputs = session_->GetOutputCount();
|
||||
for (size_t i = 0; i < n_outputs; ++i) {
|
||||
auto output_name = session_->GetOutputName(i, allocator);
|
||||
auto type_info = session_->GetOutputTypeInfo(i);
|
||||
std::vector<int64_t> shape =
|
||||
type_info.GetTensorTypeAndShapeInfo().GetShape();
|
||||
ONNXTensorElementDataType data_type =
|
||||
type_info.GetTensorTypeAndShapeInfo().GetElementType();
|
||||
output_desc_.emplace_back(ONNXDesc{output_name, shape, data_type});
|
||||
|
||||
Ort::MemoryInfo out_memory_info(device_name,
|
||||
OrtDeviceAllocator,
|
||||
place_.GetDeviceId(),
|
||||
OrtMemTypeDefault);
|
||||
binding_->BindOutput(output_name, out_memory_info);
|
||||
|
||||
allocator.Free(output_name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ONNXRuntimePredictor::Init() {
|
||||
VLOG(3) << "ONNXRuntime Predictor::init()";
|
||||
|
||||
char *onnx_proto = nullptr;
|
||||
int out_size;
|
||||
if (config_.model_from_memory()) {
|
||||
paddle2onnx::Export(config_.prog_file().data(),
|
||||
config_.prog_file().size(),
|
||||
config_.params_file().data(),
|
||||
config_.params_file().size(),
|
||||
&onnx_proto,
|
||||
&out_size);
|
||||
} else {
|
||||
paddle2onnx::Export(config_.prog_file().c_str(),
|
||||
config_.params_file().c_str(),
|
||||
&onnx_proto,
|
||||
&out_size);
|
||||
}
|
||||
|
||||
Ort::SessionOptions session_options;
|
||||
if (config_.ort_optimization_enabled()) {
|
||||
session_options.SetGraphOptimizationLevel(
|
||||
GraphOptimizationLevel::ORT_ENABLE_ALL);
|
||||
}
|
||||
// Turn optimization off first, and then turn it on when it's stable
|
||||
// session_options.SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
|
||||
// session_options.EnableCpuMemArena();
|
||||
// session_options.EnableMemPattern();
|
||||
// session_options.SetInterOpNumThreads(config_.cpu_math_library_num_threads());
|
||||
session_options.SetIntraOpNumThreads(config_.cpu_math_library_num_threads());
|
||||
VLOG(2) << "ONNXRuntime threads " << config_.cpu_math_library_num_threads();
|
||||
if (config_.profile_enabled()) {
|
||||
LOG(WARNING) << "ONNXRuntime Profiler is activated, which might affect the "
|
||||
"performance";
|
||||
#if defined(_WIN32)
|
||||
session_options.EnableProfiling(L"ONNX");
|
||||
#else
|
||||
session_options.EnableProfiling("ONNX");
|
||||
#endif
|
||||
} else {
|
||||
VLOG(2) << "ONNXRuntime Profiler is deactivated, and no profiling report "
|
||||
"will be "
|
||||
"generated.";
|
||||
}
|
||||
session_ = std::make_shared<Ort::Session>(
|
||||
*env_, onnx_proto, static_cast<size_t>(out_size), session_options);
|
||||
InitBinding();
|
||||
paddle::framework::InitMemoryMethod();
|
||||
delete onnx_proto;
|
||||
onnx_proto = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<AnalysisConfig, PaddleEngineKind::kONNXRuntime>(
|
||||
const AnalysisConfig &config) {
|
||||
if (config.glog_info_disabled()) {
|
||||
FLAGS_logtostderr = true;
|
||||
FLAGS_minloglevel = 2; // GLOG_ERROR
|
||||
}
|
||||
|
||||
PADDLE_ENFORCE_EQ(
|
||||
config.is_valid(),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"Note: Each config can only be used for one predictor."));
|
||||
|
||||
VLOG(3) << "create ONNXRuntimePredictor";
|
||||
|
||||
std::unique_ptr<PaddlePredictor> predictor(new ONNXRuntimePredictor(config));
|
||||
// Each config can only be used for one predictor.
|
||||
config.SetInValid();
|
||||
auto predictor_p = dynamic_cast<ONNXRuntimePredictor *>(predictor.get());
|
||||
|
||||
if (!predictor_p->Init()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return predictor;
|
||||
}
|
||||
|
||||
std::vector<std::string> ONNXRuntimePredictor::GetInputNames() {
|
||||
std::vector<std::string> input_names;
|
||||
for (auto input_desc : input_desc_) {
|
||||
input_names.push_back(input_desc.name);
|
||||
}
|
||||
return input_names;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<int64_t>>
|
||||
ONNXRuntimePredictor::GetInputTensorShape() {
|
||||
std::map<std::string, std::vector<int64_t>> input_shapes;
|
||||
for (auto input_desc : input_desc_) {
|
||||
input_shapes[input_desc.name] = input_desc.shape;
|
||||
}
|
||||
return input_shapes;
|
||||
}
|
||||
|
||||
std::vector<std::string> ONNXRuntimePredictor::GetOutputNames() {
|
||||
std::vector<std::string> output_names;
|
||||
for (auto output_desc : output_desc_) {
|
||||
output_names.push_back(output_desc.name);
|
||||
}
|
||||
return output_names;
|
||||
}
|
||||
|
||||
bool ONNXRuntimePredictor::FindONNXDesc(const std::string &name,
|
||||
bool is_input) {
|
||||
if (is_input) {
|
||||
for (auto i : input_desc_)
|
||||
if (i.name == name) return true;
|
||||
} else {
|
||||
for (auto i : output_desc_)
|
||||
if (i.name == name) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<ZeroCopyTensor> ONNXRuntimePredictor::GetInputTensor(
|
||||
const std::string &name) {
|
||||
PADDLE_ENFORCE_NOT_NULL(scope_->FindVar(name),
|
||||
common::errors::PreconditionNotMet(
|
||||
"The in variable named %s is not found in the "
|
||||
"ONNXPredictor.",
|
||||
name));
|
||||
std::unique_ptr<ZeroCopyTensor> res(
|
||||
new ZeroCopyTensor(static_cast<void *>(scope_.get()), this));
|
||||
res->input_or_output_ = true;
|
||||
res->SetName(name);
|
||||
if (phi::is_cpu_place(place_)) {
|
||||
res->SetPlace(PaddlePlace::kCPU);
|
||||
} else {
|
||||
auto gpu_place = place_;
|
||||
res->SetPlace(PaddlePlace::kGPU, gpu_place.GetDeviceId());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::unique_ptr<ZeroCopyTensor> ONNXRuntimePredictor::GetOutputTensor(
|
||||
const std::string &name) {
|
||||
PADDLE_ENFORCE_EQ(FindONNXDesc(name, false),
|
||||
true,
|
||||
common::errors::PreconditionNotMet(
|
||||
"The out variable named %s is not found in the "
|
||||
"ONNXPredictor.",
|
||||
name));
|
||||
std::unique_ptr<ZeroCopyTensor> res(new ZeroCopyTensor(nullptr, this));
|
||||
res->input_or_output_ = false;
|
||||
res->SetName(name);
|
||||
if (phi::is_cpu_place(place_)) {
|
||||
res->SetPlace(PaddlePlace::kCPU);
|
||||
} else {
|
||||
auto gpu_place = place_;
|
||||
res->SetPlace(PaddlePlace::kGPU, gpu_place.GetDeviceId());
|
||||
}
|
||||
res->SetOrtMark(true);
|
||||
res->SetOrtBinding(binding_);
|
||||
int size = output_desc_.size();
|
||||
for (int i = 0; i < size; ++i)
|
||||
if (output_desc_[i].name == name) {
|
||||
res->idx_ = i;
|
||||
res->dtype_ = ConvertONNXType(output_desc_[i].dtype);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Ort::Value ONNXRuntimePredictor::GetOrtValue(const ONNXDesc &desc,
|
||||
const char *device_name) {
|
||||
Ort::MemoryInfo memory_info(
|
||||
device_name, OrtDeviceAllocator, place_.GetDeviceId(), OrtMemTypeDefault);
|
||||
auto *var = scope_->FindVar(desc.name);
|
||||
auto *tensor = var->GetMutable<phi::DenseTensor>();
|
||||
size_t size =
|
||||
tensor->numel() *
|
||||
framework::SizeOfType(framework::TransToProtoVarType(tensor->dtype()));
|
||||
std::vector<int64_t> shape = common::vectorize<int64_t>(tensor->dims());
|
||||
return Ort::Value::CreateTensor(memory_info,
|
||||
static_cast<void *>(tensor->data()),
|
||||
size,
|
||||
shape.data(),
|
||||
shape.size(),
|
||||
desc.dtype);
|
||||
}
|
||||
|
||||
bool ONNXRuntimePredictor::Run(const std::vector<PaddleTensor> &inputs,
|
||||
std::vector<PaddleTensor> *output_data,
|
||||
int batch_size) {
|
||||
LOG(ERROR) << "Not support Run";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ONNXRuntimePredictor::ZeroCopyRun(bool switch_stream) {
|
||||
try {
|
||||
const char *device_name = phi::is_cpu_place(place_) ? "Cpu" : "Cuda";
|
||||
std::vector<Ort::Value> inputs;
|
||||
inputs.reserve(input_desc_.size());
|
||||
for (auto desc : input_desc_) {
|
||||
inputs.push_back(GetOrtValue(desc, device_name));
|
||||
binding_->BindInput(desc.name.c_str(), inputs.back());
|
||||
}
|
||||
for (auto output : output_desc_) {
|
||||
Ort::MemoryInfo out_memory_info(device_name,
|
||||
OrtDeviceAllocator,
|
||||
place_.GetDeviceId(),
|
||||
OrtMemTypeDefault);
|
||||
binding_->BindOutput(output.name.c_str(), out_memory_info);
|
||||
}
|
||||
session_->Run({}, *(binding_.get()));
|
||||
} catch (const std::exception &e) {
|
||||
LOG(ERROR) << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<PaddlePredictor> ONNXRuntimePredictor::Clone(void *stream) {
|
||||
std::lock_guard<std::mutex> lk(clone_mutex_);
|
||||
auto *x = new ONNXRuntimePredictor(config_, env_, session_);
|
||||
x->InitBinding();
|
||||
return std::unique_ptr<PaddlePredictor>(x);
|
||||
}
|
||||
|
||||
uint64_t ONNXRuntimePredictor::TryShrinkMemory() {
|
||||
return paddle::memory::Release(place_);
|
||||
}
|
||||
|
||||
ONNXRuntimePredictor::~ONNXRuntimePredictor() {
|
||||
binding_->ClearBoundInputs();
|
||||
binding_->ClearBoundOutputs();
|
||||
|
||||
memory::Release(place_);
|
||||
}
|
||||
|
||||
const void *ONNXRuntimePredictor::GetDeviceContexts() const {
|
||||
// TODO(inference): Support private device contexts.
|
||||
phi::DeviceContextPool &pool = phi::DeviceContextPool::Instance();
|
||||
const auto &dev_ctxs = pool.device_contexts();
|
||||
return &const_cast<
|
||||
std::map<phi::Place,
|
||||
std::shared_future<std::unique_ptr<phi::DeviceContext>>> &>(
|
||||
dev_ctxs);
|
||||
}
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,247 @@
|
||||
// Copyright (c) 2022 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 <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "onnxruntime_c_api.h" // NOLINT
|
||||
#include "onnxruntime_cxx_api.h" // NOLINT
|
||||
#include "paddle/fluid/inference/analysis/analyzer.h"
|
||||
#include "paddle/fluid/inference/api/api_impl.h"
|
||||
#include "paddle/fluid/inference/api/details/reset_tensor_array.h"
|
||||
#include "paddle/fluid/inference/api/helper.h"
|
||||
#include "paddle/fluid/inference/api/paddle_inference_api.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_types.h"
|
||||
#include "paddle/utils/string/printf.h"
|
||||
#include "paddle2onnx/converter.h"
|
||||
|
||||
#ifdef PADDLE_WITH_TESTING
|
||||
#include <gtest/gtest.h>
|
||||
#include <gtest/gtest_prod.h>
|
||||
#endif
|
||||
|
||||
///
|
||||
/// \file onnxruntime_predictor.h
|
||||
///
|
||||
/// \brief A predictor using ONNXRuntime
|
||||
///
|
||||
/// \author heliqi@baidu.com
|
||||
/// \date 2022-02-14
|
||||
/// \since 2.3.0
|
||||
///
|
||||
|
||||
namespace paddle {
|
||||
|
||||
bool CheckConvertToONNX(const AnalysisConfig &config);
|
||||
|
||||
struct ONNXDesc {
|
||||
std::string name;
|
||||
std::vector<int64_t> shape;
|
||||
ONNXTensorElementDataType dtype;
|
||||
};
|
||||
|
||||
///
|
||||
/// \class ONNXRuntimePredictor
|
||||
///
|
||||
/// \brief The ONNXRuntimePredictor using ONNXRuntime for inference
|
||||
///
|
||||
/// The predictor has the following typical uses:
|
||||
///
|
||||
/// Get predictor
|
||||
/// \code{cpp}
|
||||
/// auto predictor = CreatePaddlePredictor(config);
|
||||
/// \endcode
|
||||
///
|
||||
/// Get input or output names
|
||||
/// \code{cpp}
|
||||
/// auto input_names = predictor->GetInputNames();
|
||||
/// auto output_names = predictor->GetOutputNames();
|
||||
/// \endcode
|
||||
///
|
||||
/// Get input or output tensors
|
||||
/// \code{cpp}
|
||||
/// auto input_t = predictor->GetInputTensor(input_names[0]);
|
||||
/// auto output_t = predictor->GetOutputTensor(output_names[0]);
|
||||
/// \endcode
|
||||
///
|
||||
/// Run predictor
|
||||
/// \code{cpp}
|
||||
/// predictor->ZeroCopyRun();
|
||||
/// \endcode
|
||||
///
|
||||
class ONNXRuntimePredictor : public PaddlePredictor {
|
||||
public:
|
||||
///
|
||||
/// \brief Construct a new ONNXRuntime Predictor object
|
||||
///
|
||||
/// \param[in] AnalysisConfig config
|
||||
///
|
||||
explicit ONNXRuntimePredictor(const AnalysisConfig &config)
|
||||
: env_(std::make_shared<Ort::Env>(ORT_LOGGING_LEVEL_WARNING,
|
||||
"paddle-ort")),
|
||||
session_(nullptr),
|
||||
binding_(nullptr),
|
||||
config_(config) {
|
||||
predictor_id_ = inference::GetUniqueId();
|
||||
}
|
||||
///
|
||||
/// \brief Clone a ONNXRuntime Predictor object
|
||||
///
|
||||
/// \param[in] AnalysisConfig config
|
||||
///
|
||||
explicit ONNXRuntimePredictor(const AnalysisConfig &config,
|
||||
std::shared_ptr<Ort::Env> env,
|
||||
std::shared_ptr<Ort::Session> session)
|
||||
: env_(env), session_(session), binding_(nullptr), config_(config) {
|
||||
predictor_id_ = inference::GetUniqueId();
|
||||
}
|
||||
///
|
||||
/// \brief Destroy the ONNXRuntime Predictor object
|
||||
///
|
||||
~ONNXRuntimePredictor();
|
||||
|
||||
///
|
||||
/// \brief Initialize ORT Binding
|
||||
///
|
||||
/// \return Whether the init function executed successfully
|
||||
///
|
||||
bool InitBinding();
|
||||
|
||||
///
|
||||
/// \brief Initialize predictor
|
||||
///
|
||||
/// \return Whether the init function executed successfully
|
||||
///
|
||||
bool Init();
|
||||
|
||||
///
|
||||
/// \brief Get the input names
|
||||
///
|
||||
/// \return input names
|
||||
///
|
||||
std::vector<std::string> GetInputNames();
|
||||
|
||||
///
|
||||
/// \brief Get the output names
|
||||
///
|
||||
/// \return output names
|
||||
///
|
||||
std::vector<std::string> GetOutputNames();
|
||||
|
||||
///
|
||||
/// \brief Get the Input Tensor object
|
||||
///
|
||||
/// \param[in] name input name
|
||||
/// \return input tensor
|
||||
///
|
||||
std::unique_ptr<ZeroCopyTensor> GetInputTensor(
|
||||
const std::string &name) override;
|
||||
|
||||
///
|
||||
/// \brief Get the Output Tensor object
|
||||
///
|
||||
/// \param[in] name output name
|
||||
/// \return output tensor
|
||||
///
|
||||
std::unique_ptr<ZeroCopyTensor> GetOutputTensor(
|
||||
const std::string &name) override;
|
||||
///
|
||||
/// \brief Get all input names and their corresponding shapes
|
||||
///
|
||||
/// \return the map of input names and shapes
|
||||
///
|
||||
std::map<std::string, std::vector<int64_t>> GetInputTensorShape() override;
|
||||
|
||||
/// Not support
|
||||
bool Run(const std::vector<PaddleTensor> &inputs,
|
||||
std::vector<PaddleTensor> *output_data,
|
||||
int batch_size = -1) override;
|
||||
|
||||
///
|
||||
/// \brief Run the prediction engine
|
||||
///
|
||||
/// \param switch_stream Whether the stream is switched
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool ZeroCopyRun(bool switch_stream = false) override;
|
||||
|
||||
///
|
||||
/// \brief Release all tmp tensor to compress the size of the memory pool.
|
||||
/// The memory pool is considered to be composed of a list of chunks, if
|
||||
/// the chunk is not occupied, it can be released.
|
||||
///
|
||||
/// \return Number of bytes released. It may be smaller than the actual
|
||||
/// released memory, because part of the memory is not managed by the
|
||||
/// MemoryPool.
|
||||
///
|
||||
uint64_t TryShrinkMemory() override;
|
||||
///
|
||||
/// \brief Clone to get the new predictor. thread safe.
|
||||
///
|
||||
/// \return get a new predictor
|
||||
///
|
||||
std::unique_ptr<PaddlePredictor> Clone(void *stream = nullptr) override;
|
||||
|
||||
std::shared_ptr<framework::Scope> scope_;
|
||||
|
||||
protected:
|
||||
const void *GetDeviceContexts() const override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// \brief Whether to find in/out by name.
|
||||
///
|
||||
/// \param[in] name input or output name
|
||||
///
|
||||
/// \param[in] is_input input(true) or output(false)
|
||||
///
|
||||
/// \return Whether to find by name
|
||||
///
|
||||
bool FindONNXDesc(const std::string &name, bool is_input);
|
||||
|
||||
/// \brief get the Ort Value(input Tensor).
|
||||
///
|
||||
/// \param[in] desc ONNXDesc(name、shape、dtype)
|
||||
///
|
||||
/// \param[in] device_name "cpu" or "gpu" of device
|
||||
///
|
||||
/// \return get a Ort::Value
|
||||
///
|
||||
Ort::Value GetOrtValue(const ONNXDesc &desc, const char *device_name);
|
||||
|
||||
private:
|
||||
// ONNXRuntime
|
||||
std::shared_ptr<Ort::Env> env_;
|
||||
std::shared_ptr<Ort::Session> session_{nullptr};
|
||||
std::shared_ptr<Ort::IoBinding> binding_;
|
||||
|
||||
AnalysisConfig config_;
|
||||
std::mutex clone_mutex_;
|
||||
phi::Place place_;
|
||||
std::vector<ONNXDesc> input_desc_;
|
||||
std::vector<ONNXDesc> output_desc_;
|
||||
int predictor_id_;
|
||||
|
||||
// Some more detailed tests, they are made the friends of the predictor, so that
|
||||
// the all the details can be tested.
|
||||
#if PADDLE_WITH_TESTING
|
||||
FRIEND_TEST(ONNXRuntimePredictor, onnxruntime_on);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace paddle
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,541 @@
|
||||
// Copyright (c) 2018 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
|
||||
|
||||
/*! \file paddle_api.h
|
||||
*/
|
||||
|
||||
/*! \mainpage Paddle Inference APIs
|
||||
* \section intro_sec Introduction
|
||||
* The Paddle inference library aims to offer an high performance inference SDK
|
||||
* for Paddle users.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "crypto/cipher.h"
|
||||
#include "paddle_infer_declare.h" // NOLINT
|
||||
#include "paddle_tensor.h" // NOLINT
|
||||
/*! \namespace paddle
|
||||
*/
|
||||
#define ONEDNN_UPDATE_WARNING(api) \
|
||||
"Warning: The api is deprecated since version 3.x, please use onednn " \
|
||||
"api " #api "."
|
||||
namespace paddle {
|
||||
|
||||
using PaddleDType = paddle_infer::DataType;
|
||||
using PaddlePlace = paddle_infer::PlaceType;
|
||||
using PaddleDataLayout = paddle_infer::DataLayout;
|
||||
using paddle_infer::InputTensorHookFunc;
|
||||
using paddle_infer::OutputTensorHookFunc;
|
||||
|
||||
/// \brief Memory manager for PaddleTensor.
|
||||
///
|
||||
/// The PaddleBuf holds a buffer for data input or output. The memory can be
|
||||
/// allocated by user or by PaddleBuf itself, but in any case, the PaddleBuf
|
||||
/// should be reused for better performance.
|
||||
///
|
||||
/// For user allocated memory, the following API can be used:
|
||||
/// - PaddleBuf(void* data, size_t length) to set an external memory by
|
||||
/// specifying the memory address and length.
|
||||
/// - Reset(void* data, size_t length) to reset the PaddleBuf with an external
|
||||
/// memory.
|
||||
/// ATTENTION, for user allocated memory, deallocation should be done by users
|
||||
/// externally after the program finished. The PaddleBuf won't do any allocation
|
||||
/// or deallocation.
|
||||
///
|
||||
/// To have the PaddleBuf allocate and manage the memory:
|
||||
/// - PaddleBuf(size_t length) will allocate a memory of size `length`.
|
||||
/// - Resize(size_t length) resize the memory to no less than `length`,
|
||||
/// ATTENTION
|
||||
/// if the allocated memory is larger than `length`, nothing will done.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// Let PaddleBuf manage the memory internally.
|
||||
/// \code{cpp}
|
||||
/// const int num_elements = 128;
|
||||
/// PaddleBuf buf(num_elements/// sizeof(float));
|
||||
/// \endcode
|
||||
///
|
||||
/// Or
|
||||
/// \code{cpp}
|
||||
/// PaddleBuf buf;
|
||||
/// buf.Resize(num_elements/// sizeof(float));
|
||||
/// \endcode
|
||||
/// Works the exactly the same.
|
||||
///
|
||||
/// One can also make the `PaddleBuf` use the external memory.
|
||||
/// \code{cpp}
|
||||
/// PaddleBuf buf;
|
||||
/// void* external_memory = new float[num_elements];
|
||||
/// buf.Reset(external_memory, num_elements*sizeof(float));
|
||||
/// ...
|
||||
/// delete[] external_memory; // manage the memory lifetime outside.
|
||||
/// \endcode
|
||||
///
|
||||
class PD_INFER_DECL PaddleBuf {
|
||||
public:
|
||||
///
|
||||
/// \brief PaddleBuf allocate memory internally, and manage it.
|
||||
///
|
||||
/// \param[in] length The length of data.
|
||||
///
|
||||
explicit PaddleBuf(size_t length)
|
||||
: data_(new char[length]), length_(length), memory_owned_(true) {}
|
||||
///
|
||||
/// \brief Set external memory, the PaddleBuf won't manage it.
|
||||
///
|
||||
/// \param[in] data The start address of the external memory.
|
||||
/// \param[in] length The length of data.
|
||||
///
|
||||
PaddleBuf(void* data, size_t length)
|
||||
: data_(data), length_(length), memory_owned_{false} {}
|
||||
///
|
||||
/// \brief Copy only available when memory is managed externally.
|
||||
///
|
||||
/// \param[in] other another `PaddleBuf`
|
||||
///
|
||||
explicit PaddleBuf(const PaddleBuf& other);
|
||||
///
|
||||
/// \brief Resize the memory.
|
||||
///
|
||||
/// \param[in] length The length of data.
|
||||
///
|
||||
void Resize(size_t length);
|
||||
///
|
||||
/// \brief Reset to external memory, with address and length set.
|
||||
///
|
||||
/// \param[in] data The start address of the external memory.
|
||||
/// \param[in] length The length of data.
|
||||
///
|
||||
void Reset(void* data, size_t length);
|
||||
///
|
||||
/// \brief Tell whether the buffer is empty.
|
||||
///
|
||||
bool empty() const { return length_ == 0; }
|
||||
///
|
||||
/// \brief Get the data's memory address.
|
||||
///
|
||||
void* data() const { return data_; }
|
||||
///
|
||||
/// \brief Get the memory length.
|
||||
///
|
||||
size_t length() const { return length_; }
|
||||
|
||||
~PaddleBuf() { Free(); }
|
||||
PaddleBuf& operator=(const PaddleBuf&);
|
||||
PaddleBuf& operator=(PaddleBuf&&) noexcept;
|
||||
PaddleBuf() = default;
|
||||
PaddleBuf(PaddleBuf&& other) noexcept;
|
||||
|
||||
private:
|
||||
void Free();
|
||||
void* data_{nullptr}; ///< pointer to the data memory.
|
||||
size_t length_{0}; ///< number of memory bytes.
|
||||
bool memory_owned_{true};
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Basic input and output data structure for PaddlePredictor.
|
||||
///
|
||||
struct PD_INFER_DECL PaddleTensor {
|
||||
PaddleTensor() = default;
|
||||
std::string name; ///< variable name.
|
||||
std::vector<int> shape;
|
||||
PaddleBuf data; ///< blob of data.
|
||||
PaddleDType dtype;
|
||||
std::vector<std::vector<size_t>> lod; ///< Tensor+LoD equals DenseTensor
|
||||
};
|
||||
|
||||
/// \brief Represents an n-dimensional array of values.
|
||||
/// The ZeroCopyTensor is used to store the input or output of the network.
|
||||
/// Zero copy means that the tensor supports direct copy of host or device data
|
||||
/// to device,
|
||||
/// eliminating additional CPU copy. ZeroCopyTensor is only used in the
|
||||
/// AnalysisPredictor.
|
||||
/// It is obtained through PaddlePredictor::GetInputTensor()
|
||||
/// and PaddlePredictor::GetOutputTensor() interface.
|
||||
|
||||
class PD_INFER_DECL ZeroCopyTensor : public paddle_infer::Tensor {
|
||||
public:
|
||||
/// \brief Copy the host memory to tensor data.
|
||||
/// It's usually used to set the input tensor data.
|
||||
/// \param data The pointer of the data, from which the tensor will copy.
|
||||
template <typename T>
|
||||
void copy_from_cpu(const T* data) {
|
||||
return CopyFromCpu(data);
|
||||
}
|
||||
|
||||
/// \brief Experimental interface.
|
||||
/// It's usually used to set the input tensor data with Strings data type.
|
||||
/// \param data The pointer of the data, from which the tensor will copy.
|
||||
void copy_strings_from_cpu(const paddle_infer::Strings* data) {
|
||||
return CopyStringsFromCpu(data);
|
||||
}
|
||||
|
||||
/// \brief Copy the tensor data to the host memory.
|
||||
/// It's usually used to get the output tensor data.
|
||||
/// \param[out] data The tensor will copy the data to the address.
|
||||
template <typename T>
|
||||
void copy_to_cpu(T* data) {
|
||||
return CopyToCpu(data);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class AnalysisPredictor;
|
||||
friend class ONNXRuntimePredictor;
|
||||
explicit ZeroCopyTensor(void* scope, const void* device_contexts)
|
||||
: paddle_infer::Tensor{scope, device_contexts} {}
|
||||
};
|
||||
|
||||
/// \brief A Predictor for executing inference on a model.
|
||||
/// Base class for AnalysisPredictor and NativePaddlePredictor.
|
||||
class PD_INFER_DECL PaddlePredictor {
|
||||
public:
|
||||
struct Config;
|
||||
PaddlePredictor() = default;
|
||||
PaddlePredictor(const PaddlePredictor&) = delete;
|
||||
PaddlePredictor& operator=(const PaddlePredictor&) = delete;
|
||||
|
||||
/// \brief This interface takes input and runs the network.
|
||||
/// There are redundant copies of data between hosts in this operation,
|
||||
/// so it is more recommended to use the zecopyrun interface
|
||||
/// \param[in] inputs An list of PaddleTensor as the input to the network.
|
||||
/// \param[out] output_data Pointer to the tensor list, which holds the output
|
||||
/// paddletensor
|
||||
/// \param[in] batch_size This setting has been discarded and can be ignored.
|
||||
/// \return Whether the run is successful
|
||||
virtual bool Run(const std::vector<PaddleTensor>& inputs,
|
||||
std::vector<PaddleTensor>* output_data,
|
||||
int batch_size = -1) = 0;
|
||||
|
||||
/// \brief This interface takes input and runs the network (Recommended).
|
||||
/// \param[in] inputs An list of Tensor as the input to the network.
|
||||
/// \param[out] output_data Pointer to the tensor list, which holds the output
|
||||
/// Tensor
|
||||
/// \return Whether the run is successful
|
||||
virtual bool Run(const std::vector<paddle::Tensor>& inputs,
|
||||
std::vector<paddle::Tensor>* outputs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Used to get the name of the network input.
|
||||
/// Be inherited by AnalysisPredictor, Only used in ZeroCopy scenarios.
|
||||
/// \return Input tensor names.
|
||||
virtual std::vector<std::string> GetInputNames() { return {}; }
|
||||
|
||||
/// \brief Get the input shape of the model.
|
||||
/// \return A map contains all the input names and shape defined in the model.
|
||||
virtual std::map<std::string, std::vector<int64_t>> GetInputTensorShape() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \brief Get the input type of the model.
|
||||
/// \return A map contains all the input names and type defined in the model.
|
||||
virtual std::map<std::string, paddle_infer::DataType> GetInputTypes() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \brief Used to get the name of the network output.
|
||||
/// Be inherited by AnalysisPredictor, Only used in ZeroCopy scenarios.
|
||||
/// \return Output tensor names.
|
||||
virtual std::vector<std::string> GetOutputNames() { return {}; }
|
||||
|
||||
/// \brief Get the output shape of the model.
|
||||
/// \return A map contains all the output names and shape defined in the
|
||||
/// model.
|
||||
virtual std::map<std::string, std::vector<int64_t>> GetOutputTensorShape() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \brief Get the output type of the model.
|
||||
/// \return A map contains all the output names and type defined in the model.
|
||||
virtual std::map<std::string, paddle_infer::DataType> GetOutputTypes() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \brief Get the input ZeroCopyTensor by name.
|
||||
/// Be inherited by AnalysisPredictor, Only used in ZeroCopy scenarios.
|
||||
/// The name is obtained from the GetInputNames() interface.
|
||||
/// \param name The input tensor name.
|
||||
/// \return Return the corresponding input ZeroCopyTensor.
|
||||
virtual std::unique_ptr<ZeroCopyTensor> GetInputTensor(
|
||||
const std::string& name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Get the output ZeroCopyTensor by name.
|
||||
/// Be inherited by AnalysisPredictor, Only used in ZeroCopy scenarios.
|
||||
/// The name is obtained from the GetOutputNames() interface.
|
||||
/// \param name The output tensor name.
|
||||
/// \return Return the corresponding output ZeroCopyTensor.
|
||||
virtual std::unique_ptr<ZeroCopyTensor> GetOutputTensor(
|
||||
const std::string& name) {
|
||||
return nullptr;
|
||||
}
|
||||
/// \brief Run the network with zero-copied inputs and outputs.
|
||||
/// Be inherited by AnalysisPredictor and only used in ZeroCopy scenarios.
|
||||
/// This will save the IO copy for transferring inputs and outputs to
|
||||
/// predictor workspace and get some performance improvement. To use it, one
|
||||
/// should call the AnalysisConfig.SwitchUseFeedFetchOp(false) and then use
|
||||
/// the `GetInputTensor` and `GetOutputTensor` to directly write or read the
|
||||
/// input/output tensors.
|
||||
/// \param switch_stream Whether the stream is switched.
|
||||
/// \return Whether the run is successful
|
||||
virtual bool ZeroCopyRun(bool switch_stream = false) { return false; }
|
||||
|
||||
///
|
||||
/// \brief Clear the intermediate tensors of the predictor
|
||||
///
|
||||
///
|
||||
virtual void ClearIntermediateTensor() {}
|
||||
|
||||
///
|
||||
/// \brief Release all tmp tensor to compress the size of the memory pool.
|
||||
/// The memory pool is considered to be composed of a list of chunks, if
|
||||
/// the chunk is not occupied, it can be released.
|
||||
///
|
||||
/// \return Number of bytes released. It may be smaller than the actual
|
||||
/// released memory, because part of the memory is not managed by the
|
||||
/// MemoryPool.
|
||||
///
|
||||
virtual uint64_t TryShrinkMemory() { return 0; }
|
||||
|
||||
///
|
||||
/// \brief Register a output hook function to operate the intermediate tensor
|
||||
/// of op output. when using this function, memory reuse should be turned off.
|
||||
/// The hook function signature is void(const std::string&, const
|
||||
/// std::string&, const paddle::Tensor&>). Here, the first parameter is op's
|
||||
/// type, the second param is output var name of the op, and the third
|
||||
/// parameter is output tensor with the var name.
|
||||
///
|
||||
virtual void RegisterOutputHook(const OutputTensorHookFunc& hookfunc) {}
|
||||
|
||||
/// \brief Same as RegisterOutputHook
|
||||
virtual void RegisterInputHook(const InputTensorHookFunc& hookfunc) {}
|
||||
|
||||
/// \brief Clone an existing predictor
|
||||
/// When using clone, the same network will be created,
|
||||
/// and the parameters between them are shared.
|
||||
/// \return unique_ptr which contains the pointer of predictor
|
||||
virtual std::unique_ptr<PaddlePredictor> Clone(void* stream = nullptr) = 0;
|
||||
|
||||
/// \brief Destroy the Predictor.
|
||||
virtual ~PaddlePredictor() = default;
|
||||
|
||||
virtual std::string GetSerializedProgram() const {
|
||||
assert(false); // Force raise error.
|
||||
return "NotImplemented";
|
||||
}
|
||||
|
||||
/// \brief Base class for NativeConfig and AnalysisConfig.
|
||||
struct Config {
|
||||
std::string model_dir; /*!< path to the model directory. */
|
||||
};
|
||||
|
||||
virtual void* GetExecStream() const { return nullptr; }
|
||||
|
||||
protected:
|
||||
virtual const void* GetDeviceContexts() const { return nullptr; }
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief configuration manager for `NativePredictor`.
|
||||
///
|
||||
/// `AnalysisConfig` manages configurations of `NativePredictor`.
|
||||
/// During inference procedure, there are many parameters(model/params path,
|
||||
/// place of inference, etc.)
|
||||
///
|
||||
struct PD_INFER_DECL NativeConfig : public PaddlePredictor::Config {
|
||||
NativeConfig();
|
||||
/// GPU related fields.
|
||||
bool use_xpu{false};
|
||||
bool use_gpu{false};
|
||||
int device{0};
|
||||
float fraction_of_gpu_memory{
|
||||
-1.f}; ///< Change to a float in (0,1] if needed.
|
||||
|
||||
std::string prog_file;
|
||||
std::string
|
||||
param_file; ///< Specify the exact path of program and parameter files.
|
||||
|
||||
bool specify_input_name{false}; ///< Specify the variable's name of each
|
||||
///< input if input tensors don't follow the
|
||||
///< `feeds` and `fetches` of the phase
|
||||
///< `save_inference_model`.
|
||||
|
||||
/// Set and get the number of cpu math library threads.
|
||||
void SetCpuMathLibraryNumThreads(int cpu_math_library_num_threads) {
|
||||
cpu_math_library_num_threads_ = cpu_math_library_num_threads;
|
||||
}
|
||||
int cpu_math_library_num_threads() const {
|
||||
return cpu_math_library_num_threads_;
|
||||
}
|
||||
|
||||
protected:
|
||||
int cpu_math_library_num_threads_{1}; ///< number of cpu math library (such
|
||||
///< as MKL, OpenBlas) threads for each
|
||||
///< instance.
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A factory to help create different predictors.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// NativeConfig config;
|
||||
/// ... // change the configs.
|
||||
/// auto native_predictor = CreatePaddlePredictor(config);
|
||||
/// \endcode
|
||||
///
|
||||
/// FOR EXTENSION DEVELOPER:
|
||||
/// Different predictors are designated by config type. Similar configs can be
|
||||
/// merged, but there shouldn't be a huge config containing different fields for
|
||||
/// more than one kind of predictors.
|
||||
////
|
||||
template <typename ConfigT>
|
||||
std::unique_ptr<PaddlePredictor> CreatePaddlePredictor(const ConfigT& config);
|
||||
|
||||
struct AnalysisConfig;
|
||||
struct NativeConfig;
|
||||
struct DemoConfig;
|
||||
|
||||
template <>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<AnalysisConfig>(const AnalysisConfig& config);
|
||||
|
||||
template <>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<NativeConfig>(const NativeConfig& config);
|
||||
|
||||
template <>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<DemoConfig>(const DemoConfig& config);
|
||||
|
||||
/// NOTE The following APIs are too trivial, we will discard it in the following
|
||||
/// versions.
|
||||
///
|
||||
enum class PaddleEngineKind {
|
||||
kNative = 0, ///< Use the native Fluid facility.
|
||||
kAutoMixedTensorRT, ///< Automatically mix Fluid with TensorRT.
|
||||
kAnalysis, ///< More optimization.
|
||||
kONNXRuntime, ///< Use ONNXRuntime
|
||||
};
|
||||
|
||||
template <typename ConfigT, PaddleEngineKind engine>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor> CreatePaddlePredictor(
|
||||
const ConfigT& config);
|
||||
|
||||
template <>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<NativeConfig, PaddleEngineKind::kNative>(
|
||||
const NativeConfig& config);
|
||||
|
||||
template <>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<AnalysisConfig, PaddleEngineKind::kAnalysis>(
|
||||
const AnalysisConfig& config);
|
||||
|
||||
template <>
|
||||
PD_INFER_DECL std::unique_ptr<PaddlePredictor>
|
||||
CreatePaddlePredictor<AnalysisConfig, PaddleEngineKind::kONNXRuntime>(
|
||||
const AnalysisConfig& config);
|
||||
|
||||
PD_INFER_DECL int PaddleDtypeSize(PaddleDType dtype);
|
||||
|
||||
PD_INFER_DECL std::string get_version();
|
||||
|
||||
PD_INFER_DECL void UpdateDllFlag(const char* name, const char* value);
|
||||
|
||||
PD_INFER_DECL std::shared_ptr<framework::Cipher> MakeCipher(
|
||||
const std::string& config_file);
|
||||
|
||||
} // namespace paddle
|
||||
|
||||
// forward declaration
|
||||
using cudaStream_t = struct CUstream_st*;
|
||||
using hipStream_t = struct ihipStream_t*;
|
||||
|
||||
namespace paddle_infer {
|
||||
class Predictor;
|
||||
class Tensor;
|
||||
using Config = paddle::AnalysisConfig;
|
||||
namespace experimental {
|
||||
struct XpuRuntimeConfig {
|
||||
// xpu_context(from baidu::xpu::api::create_context) for execution.
|
||||
// If context is nullptr, default context is used.
|
||||
void* context{nullptr};
|
||||
// Stream for execution.
|
||||
// Note: It has a higher priority than stream in "context"
|
||||
void* stream{nullptr};
|
||||
// Available l3 size (Byte)
|
||||
// For kunlun1, max l3_size is 16773120 Byte
|
||||
// For kunlun2, max l3_size is 67104768 Byte
|
||||
// Note: If it is difference from l3_size in "context", new l3 buffer is
|
||||
// malloced.
|
||||
size_t l3_size{16773120};
|
||||
// If l3_ptr is not nullptr, it is used as l3 buffer.
|
||||
// If l3_ptr is nullptr, new l3 buffer will be created.
|
||||
void* l3_ptr{nullptr};
|
||||
// Available l3 size for autotune.
|
||||
// If l3_autotune_size is 0, autotune is closed.
|
||||
// Note: The remaining l3 size (l3_size - l3_autotune_size) is for
|
||||
// kernels (both paddle/xdnn kernels)
|
||||
size_t l3_autotune_size{0};
|
||||
};
|
||||
|
||||
// Unstable interface, may be modified or deleted in the future.
|
||||
class PD_INFER_DECL InternalUtils {
|
||||
public:
|
||||
// Note: Can only be used under thread_local semantics.
|
||||
static bool RunWithExternalStream(paddle_infer::Predictor* pred,
|
||||
cudaStream_t stream);
|
||||
static bool RunWithExternalStream(paddle_infer::Predictor* pred,
|
||||
hipStream_t stream);
|
||||
static bool RunWithRuntimeConfig(paddle_infer::Predictor* pred, void* config);
|
||||
|
||||
static void UpdateConfigInterleaved(paddle_infer::Config* c,
|
||||
bool with_interleaved);
|
||||
|
||||
static void SetTransformerPosid(
|
||||
paddle_infer::Config* c, const std::string& tensorrt_transformer_posid);
|
||||
|
||||
static void SetTransformerMaskid(
|
||||
paddle_infer::Config* c, const std::string& tensorrt_transformer_maskid);
|
||||
|
||||
static void DisableTensorRtHalfOps(
|
||||
paddle_infer::Config* c, const std::unordered_set<std::string>& ops);
|
||||
|
||||
static void SyncStream(paddle_infer::Predictor* pred);
|
||||
static void SyncStream(cudaStream_t stream);
|
||||
static void SyncStream(hipStream_t stream);
|
||||
template <typename T>
|
||||
static void CopyFromCpuWithIoStream(paddle_infer::Tensor* t,
|
||||
const T* data,
|
||||
cudaStream_t stream);
|
||||
template <typename T>
|
||||
static void CopyToCpuWithIoStream(paddle_infer::Tensor* t,
|
||||
T* data,
|
||||
cudaStream_t stream);
|
||||
};
|
||||
} // namespace experimental
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,291 @@
|
||||
// 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.
|
||||
|
||||
#include "paddle/fluid/inference/api/paddle_infer_contrib.h"
|
||||
|
||||
#include "paddle/fluid/framework/scope.h"
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
#include "paddle/phi/common/float16.h"
|
||||
#include "paddle/phi/core/memory/memcpy.h"
|
||||
#include "paddle/phi/core/platform/device_context.h"
|
||||
|
||||
namespace paddle_infer::contrib {
|
||||
|
||||
using paddle::PaddleDType;
|
||||
|
||||
void* TensorUtils::CudaMallocPinnedMemory(size_t size) {
|
||||
#if defined(PADDLE_WITH_CUDA)
|
||||
void* ptr = nullptr;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaMallocHost(&ptr, size));
|
||||
return ptr;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TensorUtils::CudaFreePinnedMemory(void* ptr) {
|
||||
#if defined(PADDLE_WITH_CUDA)
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaFreeHost(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
void TensorUtils::CopyTensorImpl(Tensor* p_dst,
|
||||
const Tensor& src,
|
||||
void* exec_stream,
|
||||
CallbackFunc cb,
|
||||
void* cb_params) {
|
||||
Tensor& dst = *p_dst;
|
||||
dst.Reshape(src.shape());
|
||||
PADDLE_ENFORCE(
|
||||
src.place() == PlaceType::kCPU || src.place() == PlaceType::kGPU,
|
||||
common::errors::InvalidArgument(
|
||||
"CopyTensor only support PlaceType kCPU/kGPU now."));
|
||||
PADDLE_ENFORCE(
|
||||
dst.place() == PlaceType::kCPU || dst.place() == PlaceType::kGPU,
|
||||
common::errors::InvalidArgument(
|
||||
"CopyTensor only support PlaceType kCPU/kGPU now."));
|
||||
// copy to cpu, gpu => cpu or cpu => cpu
|
||||
if (dst.place() == PlaceType::kCPU) {
|
||||
switch (src.type()) {
|
||||
case PaddleDType::INT32:
|
||||
src.CopyToCpuImpl(dst.mutable_data<int32_t>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::INT64:
|
||||
src.CopyToCpuImpl(dst.mutable_data<int64_t>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::FLOAT64:
|
||||
src.CopyToCpuImpl(dst.mutable_data<double>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::FLOAT32:
|
||||
src.CopyToCpuImpl(dst.mutable_data<float>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::UINT8:
|
||||
src.CopyToCpuImpl(dst.mutable_data<uint8_t>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::INT8:
|
||||
src.CopyToCpuImpl(dst.mutable_data<int8_t>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::BOOL:
|
||||
src.CopyToCpuImpl(dst.mutable_data<bool>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::FLOAT16:
|
||||
src.CopyToCpuImpl(
|
||||
dst.mutable_data<phi::dtype::float16>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
case PaddleDType::BFLOAT16:
|
||||
src.CopyToCpuImpl(
|
||||
dst.mutable_data<phi::dtype::bfloat16>(PlaceType::kCPU),
|
||||
exec_stream,
|
||||
cb,
|
||||
cb_params);
|
||||
break;
|
||||
default:
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Only INT32, INT64, UINT8, INT8, BOOL, FLOAT16, BFLOAT16, FLOAT32 "
|
||||
"and "
|
||||
"FLOAT64 is supported in Tensor. Others not implements"));
|
||||
}
|
||||
// gpu => gpu or cpu => gpu
|
||||
} else {
|
||||
#if defined(PADDLE_WITH_CUDA)
|
||||
void* dst_data = nullptr;
|
||||
void* src_data = nullptr;
|
||||
size_t data_len = 0;
|
||||
int data_size = 0;
|
||||
PlaceType src_place;
|
||||
switch (src.type()) {
|
||||
case PaddleDType::INT32:
|
||||
dst_data =
|
||||
static_cast<void*>(dst.mutable_data<int32_t>(PlaceType::kGPU));
|
||||
src_data =
|
||||
static_cast<void*>(src.data<int32_t>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(int32_t);
|
||||
break;
|
||||
case PaddleDType::INT64:
|
||||
dst_data =
|
||||
static_cast<void*>(dst.mutable_data<int64_t>(PlaceType::kGPU));
|
||||
src_data =
|
||||
static_cast<void*>(src.data<int64_t>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(int64_t);
|
||||
break;
|
||||
case PaddleDType::FLOAT64:
|
||||
dst_data =
|
||||
static_cast<void*>(dst.mutable_data<double>(PlaceType::kGPU));
|
||||
src_data = static_cast<void*>(src.data<double>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(double);
|
||||
break;
|
||||
case PaddleDType::FLOAT32:
|
||||
dst_data = static_cast<void*>(dst.mutable_data<float>(PlaceType::kGPU));
|
||||
src_data = static_cast<void*>(src.data<float>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(float);
|
||||
break;
|
||||
case PaddleDType::UINT8:
|
||||
dst_data =
|
||||
static_cast<void*>(dst.mutable_data<uint8_t>(PlaceType::kGPU));
|
||||
src_data =
|
||||
static_cast<void*>(src.data<uint8_t>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(uint8_t);
|
||||
break;
|
||||
case PaddleDType::INT8:
|
||||
dst_data =
|
||||
static_cast<void*>(dst.mutable_data<int8_t>(PlaceType::kGPU));
|
||||
src_data = static_cast<void*>(src.data<int8_t>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(int8_t);
|
||||
break;
|
||||
case PaddleDType::BOOL:
|
||||
dst_data = static_cast<void*>(dst.mutable_data<bool>(PlaceType::kGPU));
|
||||
src_data = static_cast<void*>(src.data<bool>(&src_place, &data_size));
|
||||
data_len = data_size * sizeof(bool);
|
||||
break;
|
||||
case PaddleDType::FLOAT16:
|
||||
dst_data = static_cast<void*>(
|
||||
dst.mutable_data<phi::dtype::float16>(PlaceType::kGPU));
|
||||
src_data = static_cast<void*>(
|
||||
src.data<phi::dtype::float16>(&src_place, &data_size));
|
||||
data_len = data_size * 2;
|
||||
break;
|
||||
case PaddleDType::BFLOAT16:
|
||||
dst_data = static_cast<void*>(
|
||||
dst.mutable_data<phi::dtype::bfloat16>(PlaceType::kGPU));
|
||||
src_data = static_cast<void*>(
|
||||
src.data<phi::dtype::bfloat16>(&src_place, &data_size));
|
||||
data_len = data_size * 2;
|
||||
break;
|
||||
default:
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Only INT32, INT64, UINT8, INT8, BOOL, FLOAT16, BFLOAT16, FLOAT32 "
|
||||
"and "
|
||||
"FLOAT64 is supported in Tensor. Others not implements"));
|
||||
}
|
||||
|
||||
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
|
||||
phi::GPUPlace gpu_place(dst.device_);
|
||||
auto* dev_ctx = static_cast<const phi::GPUContext*>(pool.Get(gpu_place));
|
||||
|
||||
if (src.place() == PlaceType::kCPU) {
|
||||
paddle::memory::Copy(gpu_place,
|
||||
static_cast<void*>(dst_data),
|
||||
phi::CPUPlace(),
|
||||
src_data,
|
||||
data_len,
|
||||
dev_ctx->stream());
|
||||
} else {
|
||||
paddle::memory::Copy(gpu_place,
|
||||
static_cast<void*>(dst_data),
|
||||
phi::GPUPlace(),
|
||||
src_data,
|
||||
data_len,
|
||||
dev_ctx->stream());
|
||||
}
|
||||
|
||||
if (nullptr != exec_stream) {
|
||||
*(static_cast<cudaStream_t*>(exec_stream)) = dev_ctx->stream();
|
||||
} else if (cb) {
|
||||
cudaLaunchHostFunc(dev_ctx->stream(), cb, cb_params);
|
||||
} else {
|
||||
cudaStreamSynchronize(dev_ctx->stream());
|
||||
}
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Can not copy tensor to GPU CUDA place because paddle is not compiled "
|
||||
"with CUDA."));
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void TensorUtils::CopyTensor(Tensor* p_dst, const Tensor& src) {
|
||||
CopyTensorImpl(p_dst, src, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void TensorUtils::CopyTensorAsync(Tensor* p_dst,
|
||||
const Tensor& src,
|
||||
void* exec_stream) {
|
||||
CopyTensorImpl(p_dst, src, exec_stream, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void TensorUtils::CopyTensorAsync(Tensor* p_dst,
|
||||
const Tensor& src,
|
||||
CallbackFunc cb,
|
||||
void* cb_params) {
|
||||
CopyTensorImpl(p_dst, src, nullptr, cb, cb_params);
|
||||
}
|
||||
|
||||
struct Status::Impl {
|
||||
int ec{0};
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
Status::Status() : impl_(std::make_shared<Impl>()) {}
|
||||
Status::Status(const Status& status) : impl_(std::make_shared<Impl>()) {
|
||||
*impl_ = *status.impl_;
|
||||
}
|
||||
|
||||
Status& Status::operator=(const Status& status) noexcept {
|
||||
if (this == &status) {
|
||||
return *this;
|
||||
}
|
||||
*impl_ = *status.impl_;
|
||||
return *this;
|
||||
}
|
||||
Status::Status(std::exception_ptr e) : impl_(std::make_shared<Impl>()) {
|
||||
constexpr int kDefaultError{-1};
|
||||
impl_->ec = kDefaultError;
|
||||
try {
|
||||
std::rethrow_exception(e);
|
||||
} catch (paddle::platform::EnforceNotMet& e) {
|
||||
// Add one to the error code to make the number zero a non-error
|
||||
// status code.
|
||||
impl_->ec = e.code() + 1;
|
||||
impl_->msg = e.what();
|
||||
} catch (const std::exception& e) {
|
||||
impl_->msg = e.what();
|
||||
}
|
||||
}
|
||||
Status Status::OK() { return Status(); }
|
||||
bool Status::ok() const noexcept { return impl_->ec == 0; }
|
||||
Status::Code Status::code() const noexcept { return impl_->ec; }
|
||||
const std::string& Status::error_message() const noexcept { return impl_->msg; }
|
||||
bool Status::operator==(const Status& x) const noexcept {
|
||||
return code() == x.code() && error_message() == x.error_message();
|
||||
}
|
||||
bool Status::operator!=(const Status& x) const noexcept {
|
||||
return !(*this == x);
|
||||
}
|
||||
|
||||
} // namespace paddle_infer::contrib
|
||||
@@ -0,0 +1,132 @@
|
||||
// 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 "paddle/common/macros.h"
|
||||
#include "paddle_inference_api.h" // NOLINT
|
||||
|
||||
namespace paddle_infer {
|
||||
namespace contrib {
|
||||
|
||||
class TensorUtils {
|
||||
public:
|
||||
static void* CudaMallocPinnedMemory(size_t size);
|
||||
static void CudaFreePinnedMemory(void* mem);
|
||||
|
||||
static void CopyTensor(Tensor* p_dst, const Tensor& src);
|
||||
static void CopyTensorAsync(Tensor* p_dst,
|
||||
const Tensor& src,
|
||||
void* exec_stream);
|
||||
static void CopyTensorAsync(Tensor* p_dst,
|
||||
const Tensor& src,
|
||||
CallbackFunc cb,
|
||||
void* cb_params);
|
||||
|
||||
private:
|
||||
static void CopyTensorImpl(Tensor* p_dst,
|
||||
const Tensor& src,
|
||||
void* exec_stream,
|
||||
CallbackFunc cb,
|
||||
void* cb_params);
|
||||
};
|
||||
|
||||
/// \brief A status class, used to intercept exceptions and convert
|
||||
/// them into a status number.
|
||||
class PADDLE_API Status {
|
||||
public:
|
||||
using Code = int;
|
||||
struct Impl;
|
||||
|
||||
Status();
|
||||
explicit Status(std::exception_ptr e);
|
||||
|
||||
Status(const Status&);
|
||||
Status& operator=(const Status&) noexcept;
|
||||
Status& operator=(Status&&) = default;
|
||||
Status(Status&&) = default;
|
||||
|
||||
///
|
||||
/// \brief Construct a status which indicate ok.
|
||||
///
|
||||
/// \return A status which indicate ok.
|
||||
///
|
||||
static Status OK();
|
||||
|
||||
///
|
||||
/// \brief Determine whether the status is ok.
|
||||
///
|
||||
/// \return Whether the status is ok.
|
||||
///
|
||||
bool ok() const noexcept;
|
||||
|
||||
///
|
||||
/// \brief Return the error code.
|
||||
/// The meaning corresponds to the following.
|
||||
///
|
||||
/// CODE IMPLICATION
|
||||
/// -1 UNKNOWN
|
||||
/// 0 NORMAL
|
||||
/// 1 LEGACY
|
||||
/// 2 INVALID_ARGUMENT
|
||||
/// 3 NOT_FOUND
|
||||
/// 4 OUT_OF_RANGE
|
||||
/// 5 ALREADY_EXISTS
|
||||
/// 6 RESOURCE_EXHAUSTED
|
||||
/// 7 PRECONDITION_NOT_MET
|
||||
/// 8 PERMISSION_DENIED
|
||||
/// 9 EXECUTION_TIMEOUT
|
||||
/// 10 UNIMPLEMENTED
|
||||
/// 11 UNAVAILABLE
|
||||
/// 12 FATAL
|
||||
/// 13 EXTERNAL
|
||||
///
|
||||
/// \return The error code.
|
||||
///
|
||||
Code code() const noexcept;
|
||||
|
||||
///
|
||||
/// \brief Return the error message.
|
||||
///
|
||||
/// \return The error message.
|
||||
///
|
||||
const std::string& error_message() const noexcept;
|
||||
|
||||
bool operator==(const Status& x) const noexcept;
|
||||
bool operator!=(const Status& x) const noexcept;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A wrapper used to provide exception safety.
|
||||
///
|
||||
/// \param func Wrapped function.
|
||||
/// \param args Parameters of the wrapped function.
|
||||
/// \return State result of calling function.
|
||||
///
|
||||
template <typename Func, typename... Args>
|
||||
Status get_status(Func func, Args&&... args) noexcept(
|
||||
noexcept(Status(std::declval<Status>()))) {
|
||||
try {
|
||||
func(std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
return Status(std::current_exception());
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
} // namespace contrib
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifndef PD_INFER_DECL
|
||||
#ifdef PADDLE_DLL_INFERENCE
|
||||
#define PD_INFER_DECL __declspec(dllexport)
|
||||
#else
|
||||
#define PD_INFER_DECL __declspec(dllimport)
|
||||
#endif // PADDLE_DLL_INFERENCE
|
||||
#endif // PD_INFER_DECL
|
||||
#else
|
||||
#ifndef PD_INFER_DECL
|
||||
#define PD_INFER_DECL __attribute__((visibility("default")))
|
||||
#endif // PD_INFER_DECL
|
||||
#endif // _WIN32
|
||||
@@ -0,0 +1,278 @@
|
||||
/* Copyright (c) 2018 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. */
|
||||
|
||||
/*
|
||||
* This file contains the definition of a simple Inference API for Paddle.
|
||||
*
|
||||
* ATTENTION: It requires some C++11 features, for lower version C++ or C, we
|
||||
* might release another API.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle_analysis_config.h" // NOLINT
|
||||
#include "paddle_api.h" // NOLINT
|
||||
|
||||
///
|
||||
/// \file paddle_inference_api.h
|
||||
///
|
||||
/// \brief Paddle Inference API
|
||||
///
|
||||
/// \author paddle-infer@baidu.com
|
||||
/// \date 2020-09-01
|
||||
/// \since 2.0.0-beta
|
||||
///
|
||||
|
||||
namespace paddle_infer {
|
||||
|
||||
using PrecisionType = paddle::AnalysisConfig::Precision;
|
||||
using Config = paddle::AnalysisConfig;
|
||||
using XpuConfig = paddle::XpuConfig;
|
||||
|
||||
///
|
||||
/// \class Predictor
|
||||
///
|
||||
/// \brief Predictor is the interface for model prediction.
|
||||
///
|
||||
/// The predictor has the following typical uses:
|
||||
///
|
||||
/// Get predictor
|
||||
/// \code{cpp}
|
||||
/// auto predictor = CreatePredictor(config);
|
||||
/// \endcode
|
||||
///
|
||||
/// Get input or output names
|
||||
/// \code{cpp}
|
||||
/// auto input_names = predictor->GetInputNames();
|
||||
/// auto output_names = predictor->GetOutputNames();
|
||||
/// \endcode
|
||||
///
|
||||
/// Get input or output handle
|
||||
/// \code{cpp}
|
||||
/// auto input_t = predictor->GetInputHandle(input_names[0]);
|
||||
/// auto output_t = predictor->GetOutputHandle(output_names[0]);
|
||||
/// \endcode
|
||||
///
|
||||
/// Run predictor
|
||||
/// \code{cpp}
|
||||
/// predictor->Run();
|
||||
/// \endcode
|
||||
///
|
||||
class PD_INFER_DECL Predictor {
|
||||
public:
|
||||
Predictor() = delete;
|
||||
~Predictor() {}
|
||||
// Use for clone
|
||||
explicit Predictor(std::unique_ptr<paddle::PaddlePredictor>&& pred)
|
||||
: predictor_(std::move(pred)) {}
|
||||
|
||||
///
|
||||
/// \brief Construct a new Predictor object
|
||||
///
|
||||
/// \param[in] Config config
|
||||
///
|
||||
explicit Predictor(const Config& config);
|
||||
|
||||
///
|
||||
/// \brief Get all input names and their corresponding shapes
|
||||
///
|
||||
/// \return the map of input names and shape
|
||||
///
|
||||
std::map<std::string, std::vector<int64_t>> GetInputTensorShape();
|
||||
|
||||
///
|
||||
/// \brief Get all input names and their corresponding type
|
||||
///
|
||||
/// \return the map of input names and type
|
||||
///
|
||||
std::map<std::string, DataType> GetInputTypes();
|
||||
|
||||
///
|
||||
/// \brief Get the input names
|
||||
///
|
||||
/// \return input names
|
||||
///
|
||||
std::vector<std::string> GetInputNames();
|
||||
|
||||
///
|
||||
/// \brief Get the Input Tensor object
|
||||
///
|
||||
/// \param[in] name input name
|
||||
/// \return input tensor
|
||||
///
|
||||
std::unique_ptr<Tensor> GetInputHandle(const std::string& name);
|
||||
|
||||
///
|
||||
/// \brief Run the prediction engine
|
||||
///
|
||||
/// \return Whether the function executed successfully
|
||||
///
|
||||
bool Run();
|
||||
|
||||
///
|
||||
/// \brief Run the prediction engine (Recommended)
|
||||
///
|
||||
/// \param[in] inputs An list of Tensor as the input to the network.
|
||||
/// \param[out] outputs Pointer to the tensor list, which holds the output
|
||||
/// Tensor
|
||||
///
|
||||
/// \return Whether the run is successful
|
||||
bool Run(const std::vector<paddle::Tensor>& inputs,
|
||||
std::vector<paddle::Tensor>* outputs);
|
||||
|
||||
///
|
||||
/// \brief Get the output names
|
||||
///
|
||||
/// \return output names
|
||||
///
|
||||
std::vector<std::string> GetOutputNames();
|
||||
|
||||
///
|
||||
/// \brief Get the Output Tensor object
|
||||
///
|
||||
/// \param[in] name output name
|
||||
/// \return output tensor
|
||||
///
|
||||
std::unique_ptr<Tensor> GetOutputHandle(const std::string& name);
|
||||
|
||||
///
|
||||
/// \brief Get all output names and their corresponding shapes
|
||||
///
|
||||
/// \return the map of output names and shape
|
||||
///
|
||||
std::map<std::string, std::vector<int64_t>> GetOutputTensorShape();
|
||||
|
||||
///
|
||||
/// \brief Get all output names and their corresponding type
|
||||
///
|
||||
/// \return the map of output names and type
|
||||
///
|
||||
std::map<std::string, DataType> GetOutputTypes();
|
||||
|
||||
///
|
||||
/// \brief Clone to get the new predictor. thread safe.
|
||||
///
|
||||
/// \return get a new predictor
|
||||
///
|
||||
std::unique_ptr<Predictor> Clone(void* stream = nullptr);
|
||||
|
||||
/// \brief Clear the intermediate tensors of the predictor
|
||||
void ClearIntermediateTensor();
|
||||
|
||||
///
|
||||
/// \brief Release all tmp tensor to compress the size of the memory pool.
|
||||
/// The memory pool is considered to be composed of a list of chunks, if
|
||||
/// the chunk is not occupied, it can be released.
|
||||
///
|
||||
/// \return Number of bytes released. It may be smaller than the actual
|
||||
/// released memory, because part of the memory is not managed by the
|
||||
/// MemoryPool.
|
||||
///
|
||||
uint64_t TryShrinkMemory();
|
||||
|
||||
///
|
||||
/// \brief Register a output hook function to operate the intermediate tensor
|
||||
/// of op output. when using this function, memory reuse should be turned off.
|
||||
/// The hook function signature is void(const std::string&, const
|
||||
/// std::string&, const Tensor&>). Here, the first parameter is op's
|
||||
/// type, the second param is output var name of the op, and the third
|
||||
/// parameter is output tensor with the var name.
|
||||
///
|
||||
void RegisterOutputHook(const OutputTensorHookFunc& hookfunc);
|
||||
|
||||
/// The same as RegisterOutputHook.
|
||||
void RegisterInputHook(const InputTensorHookFunc& hookfunc);
|
||||
|
||||
///
|
||||
/// \brief Get the execution stream on devices with a concept of stream,
|
||||
/// otherwise returns nullptr.
|
||||
///
|
||||
/// \return The execution stream or nullptr (CPU).
|
||||
///
|
||||
void* GetExecStream() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<paddle::PaddlePredictor> predictor_;
|
||||
friend class paddle_infer::experimental::InternalUtils;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A factory to help create predictors.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// Config config;
|
||||
/// ... // change the configs.
|
||||
/// auto predictor = CreatePredictor(config);
|
||||
/// \endcode
|
||||
///
|
||||
PD_INFER_DECL std::shared_ptr<Predictor> CreatePredictor(
|
||||
const Config& config); // NOLINT
|
||||
|
||||
PD_INFER_DECL int GetNumBytesOfDataType(DataType dtype);
|
||||
|
||||
PD_INFER_DECL std::string GetVersion();
|
||||
PD_INFER_DECL std::tuple<int, int, int> GetTrtCompileVersion();
|
||||
PD_INFER_DECL std::tuple<int, int, int> GetTrtRuntimeVersion();
|
||||
PD_INFER_DECL void UpdateDllFlag(const char* name, const char* value);
|
||||
|
||||
PD_INFER_DECL void ConvertToMixedPrecision(
|
||||
const std::string& model_file,
|
||||
const std::string& params_file,
|
||||
const std::string& mixed_model_file,
|
||||
const std::string& mixed_params_file,
|
||||
PrecisionType mixed_precision,
|
||||
PlaceType backend,
|
||||
bool keep_io_types = true,
|
||||
std::unordered_set<std::string> black_list = {},
|
||||
std::unordered_set<std::string> white_list = {});
|
||||
|
||||
namespace services {
|
||||
///
|
||||
/// \class PredictorPool
|
||||
///
|
||||
/// \brief PredictorPool is a simple encapsulation of Predictor, suitable for
|
||||
/// use in multi-threaded situations. According to the thread id, the
|
||||
/// corresponding Predictor is taken out from PredictorPool to complete the
|
||||
/// prediction.
|
||||
///
|
||||
class PD_INFER_DECL PredictorPool {
|
||||
public:
|
||||
PredictorPool() = delete;
|
||||
PredictorPool(const PredictorPool&) = delete;
|
||||
PredictorPool& operator=(const PredictorPool&) = delete;
|
||||
|
||||
/// \brief Construct the predictor pool with \param size predictor instances.
|
||||
explicit PredictorPool(const Config& config, size_t size = 1);
|
||||
|
||||
/// \brief Get \param id-th predictor.
|
||||
Predictor* Retrieve(size_t idx);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Predictor> main_pred_;
|
||||
std::vector<std::unique_ptr<Predictor>> preds_;
|
||||
};
|
||||
} // namespace services
|
||||
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,729 @@
|
||||
// Copyright (c) 2018 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 "paddle/fluid/inference/api/paddle_pass_builder.h"
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
#include <cudnn.h>
|
||||
#endif
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
#include <miopen/miopen.h>
|
||||
#endif
|
||||
#ifdef PADDLE_WITH_TENSORRT
|
||||
#include "paddle/fluid/inference/tensorrt/helper.h"
|
||||
#endif
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include "paddle/fluid/inference/api/paddle_api.h"
|
||||
namespace paddle {
|
||||
|
||||
void PaddlePassBuilder::AppendPass(const std::string &pass_type) {
|
||||
passes_.push_back(pass_type);
|
||||
}
|
||||
|
||||
void PaddlePassBuilder::TurnOnDebug() {
|
||||
std::vector<std::string> passes;
|
||||
auto it = std::begin(passes_);
|
||||
while (it != std::end(passes_)) {
|
||||
if (*it != "graph_viz_pass") {
|
||||
it = passes_.insert(it + 1, "graph_viz_pass");
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string PaddlePassBuilder::DebugString() {
|
||||
std::stringstream ss;
|
||||
ss << "Passes to apply:\n";
|
||||
for (auto &pass : passes_) {
|
||||
ss << " - " << pass << '\n';
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void PaddlePassBuilder::DeletePass(const std::string &pass_type) {
|
||||
deleted_passes_.insert(pass_type);
|
||||
auto it = std::begin(passes_);
|
||||
while (it != std::end(passes_)) {
|
||||
if (*it == pass_type) {
|
||||
it = passes_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t PaddlePassBuilder::GetPassIndex(const std::string &pass_type) {
|
||||
auto iter = std::find(std::begin(passes_), std::end(passes_), pass_type);
|
||||
if (iter == std::end(passes_)) return -1;
|
||||
return std::distance(std::begin(passes_), iter);
|
||||
}
|
||||
|
||||
void PaddlePassBuilder::InsertPass(size_t idx, const std::string &pass_type) {
|
||||
passes_.insert(std::begin(passes_) + idx, pass_type); // NOLINT
|
||||
}
|
||||
|
||||
void PaddlePassBuilder::DeletePass(size_t idx) {
|
||||
passes_.erase(std::begin(passes_) + idx); // NOLINT
|
||||
}
|
||||
|
||||
void PaddlePassBuilder::AppendAnalysisPass(const std::string &pass) {
|
||||
analysis_passes_.push_back(pass);
|
||||
}
|
||||
|
||||
void PaddlePassBuilder::ClearPasses() { passes_.clear(); }
|
||||
#ifdef PADDLE_WITH_OPENVINO
|
||||
const std::vector<std::string> kOVSubgraphPasses({"openvino_subgraph_pass"});
|
||||
#endif
|
||||
const std::vector<std::string> kTRTSubgraphPasses({
|
||||
"set_subgraph_edge_pass", //
|
||||
"trt_remove_amp_strategy_op_pass", //
|
||||
"trt_support_nhwc_pass", //
|
||||
"adaptive_pool2d_convert_global_pass", //
|
||||
"trt_map_ops_to_matrix_multiply_pass", //
|
||||
"shuffle_channel_detect_pass", //
|
||||
"quant_conv2d_dequant_fuse_pass", //
|
||||
"delete_quant_dequant_op_pass", //
|
||||
"delete_quant_dequant_filter_op_pass", //
|
||||
"trt_delete_weight_dequant_linear_op_pass", //
|
||||
"delete_quant_dequant_linear_op_pass", //
|
||||
"identity_op_clean_pass", //
|
||||
"add_support_int8_pass", //
|
||||
"simplify_with_basic_ops_pass", //
|
||||
"trt_prompt_tuning_embedding_eltwise_layernorm_fuse_pass", //
|
||||
"trt_embedding_eltwise_layernorm_fuse_pass", //
|
||||
"preln_embedding_eltwise_layernorm_fuse_pass", //
|
||||
"trt_multihead_matmul_fuse_pass_v2", //
|
||||
"trt_multihead_matmul_fuse_pass_v3", //
|
||||
"multihead_matmul_roformer_fuse_pass", //
|
||||
#if defined _WIN32 // Windows does not support sparse_conv3d_implicit_gemm
|
||||
#else
|
||||
"sparse_conv_optim_pass", //
|
||||
#endif
|
||||
"constant_folding_pass", //
|
||||
#ifdef PADDLE_WITH_TENSORRT
|
||||
#if !IS_TRT_VERSION_GE(8610)
|
||||
"trt_flash_multihead_matmul_fuse_pass", //
|
||||
"trt_cross_multihead_matmul_fuse_pass", //
|
||||
#endif
|
||||
#endif
|
||||
"vit_attention_fuse_pass", //
|
||||
"trt_qk_multihead_matmul_fuse_pass", //
|
||||
"layernorm_shift_partition_fuse_pass", //
|
||||
"merge_layernorm_fuse_pass", //
|
||||
#if !defined _WIN32
|
||||
"split_layernorm_to_math_ops_pass", //
|
||||
#endif
|
||||
#if defined _WIN32 // Windows CI is TensorRT7.0. Remove this after upgrading.
|
||||
#else
|
||||
"trt_skip_layernorm_fuse_pass", //
|
||||
"preln_skip_layernorm_fuse_pass", //
|
||||
#endif
|
||||
"preln_residual_bias_fuse_pass", //
|
||||
"preln_layernorm_x_fuse_pass", //
|
||||
"reverse_roll_fuse_pass", //
|
||||
"conv_bn_fuse_pass", //
|
||||
"conv_elementwise_add_fuse_pass", //
|
||||
#if defined _WIN32 // Windows CI is TensorRT7.0. Remove this after upgrading.
|
||||
#else
|
||||
"trans_layernorm_fuse_pass", //
|
||||
#endif
|
||||
"remove_padding_recover_padding_pass", //
|
||||
"delete_remove_padding_recover_padding_pass", //
|
||||
// "yolo_box_fuse_pass", //
|
||||
"dense_fc_to_sparse_pass", //
|
||||
"dense_multihead_matmul_to_sparse_pass", //
|
||||
#if defined _WIN32 // Windows CI is TensorRT7.0. Remove this after upgrading.
|
||||
#else
|
||||
"elementwise_groupnorm_act_pass", //
|
||||
"preln_elementwise_groupnorm_act_pass", //
|
||||
"groupnorm_act_pass", //
|
||||
"elementwiseadd_transpose_pass", //
|
||||
#endif
|
||||
"tensorrt_subgraph_pass", //
|
||||
"conv_bn_fuse_pass", //
|
||||
// cudnn8.0 has memory leak problem in conv + eltwise + act, so we
|
||||
// disable the pass.
|
||||
#if !(CUDNN_VERSION >= 8000 && CUDNN_VERSION < 8100)
|
||||
"conv_elementwise_add_act_fuse_pass", //
|
||||
"conv_elementwise_add2_act_fuse_pass", //
|
||||
#endif
|
||||
"transpose_flatten_concat_fuse_pass", //
|
||||
"auto_mixed_precision_pass",
|
||||
});
|
||||
|
||||
// TODO(inference): Most of the existing pass fusion operators do not
|
||||
// support fp16/bf16 precision, temporarily use low precision pass to prevent
|
||||
// running errors. After fusion operator supports low precision, delete this.
|
||||
const std::vector<std::string> kGpuLowerPrecisionPasses{
|
||||
"map_op_to_another_pass",
|
||||
"identity_op_clean_pass",
|
||||
"simplify_with_basic_ops_pass",
|
||||
"silu_fuse_pass",
|
||||
"delete_quant_dequant_linear_op_pass",
|
||||
"delete_weight_dequant_linear_op_pass",
|
||||
"conv_bn_fuse_pass",
|
||||
"conv_eltwiseadd_bn_fuse_pass",
|
||||
"conv_elementwise_add_act_fuse_pass",
|
||||
"conv_elementwise_add2_act_fuse_pass",
|
||||
"conv_elementwise_add_fuse_pass",
|
||||
"transfer_layout_pass",
|
||||
"multihead_matmul_fuse_pass_v2",
|
||||
"fused_multi_transformer_encoder_pass",
|
||||
"fused_multi_transformer_decoder_pass",
|
||||
"fused_multi_transformer_encoder_fuse_qkv_pass",
|
||||
"fused_multi_transformer_decoder_fuse_qkv_pass",
|
||||
"multi_devices_fused_multi_transformer_encoder_pass",
|
||||
"multi_devices_fused_multi_transformer_encoder_fuse_qkv_pass",
|
||||
"multi_devices_fused_multi_transformer_decoder_fuse_qkv_pass",
|
||||
"fuse_multi_transformer_layer_pass",
|
||||
"gpu_cpu_map_matmul_v2_to_mul_pass",
|
||||
"gpu_cpu_map_matmul_v2_to_matmul_pass",
|
||||
"gpu_cpu_map_matmul_to_mul_pass",
|
||||
"fc_fuse_pass",
|
||||
// "fc_elementwise_layernorm_fuse_pass",
|
||||
"embedding_eltwise_layernorm_fuse_pass",
|
||||
"inplace_op_var_pass"};
|
||||
|
||||
const std::vector<std::string> kTrtLowerPrecisionPasses{
|
||||
"trt_remove_amp_strategy_op_pass",
|
||||
"trt_support_nhwc_pass",
|
||||
"trt_map_ops_to_matrix_multiply_pass",
|
||||
"simplify_with_basic_ops_pass",
|
||||
// "conv_bn_fuse_pass",
|
||||
// "conv_eltwiseadd_bn_fuse_pass",
|
||||
"trt_embedding_eltwise_layernorm_fuse_pass",
|
||||
"trt_skip_layernorm_fuse_pass",
|
||||
"tensorrt_subgraph_pass",
|
||||
};
|
||||
|
||||
const std::vector<std::string> kCINNCompilerPasses{
|
||||
"gpu_cpu_map_matmul_v2_to_mul_pass",
|
||||
"gpu_cpu_map_matmul_v2_to_matmul_pass",
|
||||
"gpu_cpu_map_matmul_to_mul_pass",
|
||||
};
|
||||
|
||||
const std::vector<std::string> CpuBasicPasses{
|
||||
"simplify_with_basic_ops_pass", //
|
||||
"layer_norm_fuse_pass",
|
||||
"attention_lstm_fuse_pass", //
|
||||
"seqconv_eltadd_relu_fuse_pass", //
|
||||
// "seqpool_concat_fuse_pass", //
|
||||
"seqpool_cvm_concat_fuse_pass", //
|
||||
// "embedding_fc_lstm_fuse_pass", //
|
||||
// TODO(wilber): fix correctness problem.
|
||||
// "fc_lstm_fuse_pass", //
|
||||
"mul_lstm_fuse_pass", //
|
||||
"fc_gru_fuse_pass", //
|
||||
"mul_gru_fuse_pass", //
|
||||
"seq_concat_fc_fuse_pass", //
|
||||
"gpu_cpu_squeeze2_matmul_fuse_pass", //
|
||||
"gpu_cpu_reshape2_matmul_fuse_pass", //
|
||||
"gpu_cpu_flatten2_matmul_fuse_pass", //
|
||||
"matmul_v2_scale_fuse_pass", //
|
||||
"gpu_cpu_map_matmul_v2_to_mul_pass", //
|
||||
"gpu_cpu_map_matmul_v2_to_matmul_pass", //
|
||||
"matmul_scale_fuse_pass", //
|
||||
"gpu_cpu_map_matmul_to_mul_pass", //
|
||||
"fc_fuse_pass", //
|
||||
"repeated_fc_relu_fuse_pass", //
|
||||
"squared_mat_sub_fuse_pass", //
|
||||
"conv_bn_fuse_pass", //
|
||||
"conv_eltwiseadd_bn_fuse_pass", //
|
||||
"conv_transpose_bn_fuse_pass", //
|
||||
"conv_transpose_eltwiseadd_bn_fuse_pass", //
|
||||
"is_test_pass", //
|
||||
"constant_folding_pass",
|
||||
};
|
||||
|
||||
GpuPassStrategy::GpuPassStrategy() : PassStrategy({}) {
|
||||
passes_.assign({
|
||||
"map_op_to_another_pass", //
|
||||
"is_test_pass", //
|
||||
"simplify_with_basic_ops_pass", //
|
||||
"delete_quant_dequant_linear_op_pass", //
|
||||
"delete_weight_dequant_linear_op_pass", //
|
||||
#if defined _WIN32 // Windows does not support sparse_conv3d_implicit_gemm
|
||||
#else
|
||||
"sparse_conv_optim_pass", //
|
||||
#endif
|
||||
"constant_folding_pass", //
|
||||
"silu_fuse_pass", //
|
||||
"conv_bn_fuse_pass", //
|
||||
"conv_eltwiseadd_bn_fuse_pass", //
|
||||
"embedding_eltwise_layernorm_fuse_pass", //
|
||||
"multihead_matmul_fuse_pass_v2", //
|
||||
"vit_attention_fuse_pass", //
|
||||
"fused_multi_transformer_encoder_pass", //
|
||||
"fused_multi_transformer_decoder_pass", //
|
||||
"fused_multi_transformer_encoder_fuse_qkv_pass", //
|
||||
"fused_multi_transformer_decoder_fuse_qkv_pass", //
|
||||
"multi_devices_fused_multi_transformer_encoder_pass", //
|
||||
"multi_devices_fused_multi_transformer_encoder_fuse_qkv_pass", //
|
||||
"multi_devices_fused_multi_transformer_decoder_fuse_qkv_pass", //
|
||||
"fuse_multi_transformer_layer_pass", //
|
||||
"gpu_cpu_squeeze2_matmul_fuse_pass", //
|
||||
"gpu_cpu_reshape2_matmul_fuse_pass", //
|
||||
"gpu_cpu_flatten2_matmul_fuse_pass", //
|
||||
"gpu_cpu_map_matmul_v2_to_mul_pass", //
|
||||
"gpu_cpu_map_matmul_v2_to_matmul_pass", //
|
||||
"matmul_scale_fuse_pass", //
|
||||
"multihead_matmul_fuse_pass_v3", //
|
||||
"gpu_cpu_map_matmul_to_mul_pass", //
|
||||
"fc_fuse_pass", //
|
||||
"fc_elementwise_layernorm_fuse_pass", //
|
||||
// cudnn8.0 has memory leak problem in conv + eltwise + act, so we
|
||||
// disable the pass.
|
||||
#if !(CUDNN_VERSION >= 8000 && CUDNN_VERSION < 8100)
|
||||
"conv_elementwise_add_act_fuse_pass", //
|
||||
"conv_elementwise_add2_act_fuse_pass", //
|
||||
#endif
|
||||
"conv_elementwise_add_fuse_pass", //
|
||||
"transpose_flatten_concat_fuse_pass", //
|
||||
"transfer_layout_pass", //
|
||||
"transfer_layout_elim_pass",
|
||||
"auto_mixed_precision_pass", //
|
||||
"identity_op_clean_pass", // should be after auto_mixed_precision_pass.
|
||||
"inplace_op_var_pass", // should be the last pass.
|
||||
});
|
||||
|
||||
use_gpu_ = true;
|
||||
}
|
||||
|
||||
void GpuPassStrategy::EnableCUDNN() {
|
||||
if (!use_cudnn_) {
|
||||
passes_.insert(passes_.begin(), "cudnn_placement_pass");
|
||||
}
|
||||
use_cudnn_ = true;
|
||||
}
|
||||
|
||||
void GpuPassStrategy::EnableMKLDNN() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EnableONEDNN);
|
||||
EnableONEDNN();
|
||||
}
|
||||
void GpuPassStrategy::EnableONEDNN() {
|
||||
LOG(ERROR) << "GPU not support MKLDNN yet";
|
||||
}
|
||||
|
||||
void GpuPassStrategy::EnableMkldnnBfloat16() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EnableOnednnBfloat16);
|
||||
EnableOnednnBfloat16();
|
||||
}
|
||||
void GpuPassStrategy::EnableOnednnBfloat16() {
|
||||
LOG(ERROR) << "GPU not support MKL-DNN bfloat16";
|
||||
}
|
||||
|
||||
void GpuPassStrategy::EnableMkldnnInt8() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EnableOnednnInt8);
|
||||
EnableOnednnInt8();
|
||||
}
|
||||
void GpuPassStrategy::EnableOnednnInt8() {
|
||||
LOG(ERROR) << "GPU not support MKL-DNN int8";
|
||||
}
|
||||
|
||||
void GpuPassStrategy::DisableMkldnnFcPasses() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(DisableOnednnFcPasses);
|
||||
DisableOnednnFcPasses();
|
||||
}
|
||||
void GpuPassStrategy::DisableOnednnFcPasses() {
|
||||
LOG(ERROR) << "GPU not support MKL-DNN fc";
|
||||
}
|
||||
|
||||
CpuPassStrategy::CpuPassStrategy() : PassStrategy({}) {
|
||||
// NOTE the large fusions should be located in the front, so that they will
|
||||
// not be damaged by smaller ones.
|
||||
passes_.assign(CpuBasicPasses.begin(), CpuBasicPasses.end());
|
||||
|
||||
use_gpu_ = false;
|
||||
}
|
||||
|
||||
void CpuPassStrategy::EnableCUDNN() { LOG(ERROR) << "CPU not support cuDNN"; }
|
||||
|
||||
void CpuPassStrategy::EnableMKLDNN() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EnableONEDNN);
|
||||
EnableONEDNN();
|
||||
}
|
||||
void CpuPassStrategy::EnableONEDNN() {
|
||||
// TODO(Superjomn) Consider the way to mix CPU with GPU.
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (!use_onednn_) {
|
||||
passes_.insert(passes_.begin(), "onednn_placement_pass");
|
||||
|
||||
for (auto &pass : std::vector<std::string>({
|
||||
"squeeze2_transpose2_onednn_fuse_pass",
|
||||
"depthwise_conv_onednn_pass", //
|
||||
"conv_bn_fuse_pass", // Execute BN passes again to
|
||||
"conv_eltwiseadd_bn_fuse_pass", // preserve correct pass order
|
||||
"conv_affine_channel_onednn_fuse_pass", //
|
||||
"conv_transpose_bn_fuse_pass", //
|
||||
"conv_transpose_eltwiseadd_bn_fuse_pass", //
|
||||
"conv_bias_onednn_fuse_pass", //
|
||||
"conv_transpose_bias_onednn_fuse_pass",
|
||||
// TODO(baoachun): Need to support 5-dimensional input.
|
||||
// "conv3d_bias_onednn_fuse_pass", //
|
||||
"conv_elementwise_add_onednn_fuse_pass",
|
||||
"conv_activation_onednn_fuse_pass", //
|
||||
"scale_matmul_fuse_pass", //
|
||||
"reshape_transpose_matmul_onednn_fuse_pass", //
|
||||
"matmul_transpose_reshape_onednn_fuse_pass", //
|
||||
"matmul_elementwise_add_onednn_fuse_pass", //
|
||||
"matmul_activation_onednn_fuse_pass", //
|
||||
// Disabled due to topology-dependent speed-up
|
||||
"fc_onednn_pass",
|
||||
"fc_act_onednn_fuse_pass",
|
||||
"self_attention_fuse_pass", //
|
||||
"batch_norm_act_fuse_pass", //
|
||||
"softplus_activation_onednn_fuse_pass", //
|
||||
"shuffle_channel_onednn_detect_pass", //
|
||||
"elementwise_act_onednn_fuse_pass", //
|
||||
"operator_scale_onednn_fuse_pass", //
|
||||
"operator_unsqueeze2_onednn_fuse_pass", //
|
||||
"operator_reshape2_onednn_fuse_pass", //
|
||||
})) {
|
||||
passes_.push_back(pass);
|
||||
}
|
||||
}
|
||||
use_onednn_ = true;
|
||||
#else
|
||||
use_onednn_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CpuPassStrategy::DisableMKLDNN() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(DisableONEDNN);
|
||||
DisableONEDNN();
|
||||
}
|
||||
void CpuPassStrategy::DisableONEDNN() {
|
||||
ClearPasses();
|
||||
passes_.assign(CpuBasicPasses.begin(), CpuBasicPasses.end());
|
||||
}
|
||||
|
||||
void CpuPassStrategy::EnableMkldnnBfloat16() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EnableOnednnBfloat16);
|
||||
EnableOnednnBfloat16();
|
||||
}
|
||||
void CpuPassStrategy::EnableOnednnBfloat16() {
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (!use_onednn_bfloat16_) {
|
||||
passes_.emplace_back("fc_onednn_pass");
|
||||
passes_.emplace_back("fc_act_onednn_fuse_pass");
|
||||
|
||||
passes_.emplace_back("cpu_bfloat16_placement_pass");
|
||||
passes_.emplace_back("cpu_bfloat16_pass");
|
||||
passes_.emplace_back("cpu_quantize_squash_pass");
|
||||
}
|
||||
use_onednn_bfloat16_ = true;
|
||||
#else
|
||||
use_onednn_bfloat16_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CpuPassStrategy::EnableMkldnnInt8() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EnableOnednnInt8);
|
||||
EnableOnednnInt8();
|
||||
}
|
||||
void CpuPassStrategy::EnableOnednnInt8() {
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (!use_onednn_int8_) {
|
||||
passes_.clear();
|
||||
passes_.emplace_back("simplify_with_basic_ops_pass");
|
||||
passes_.emplace_back("quant_dequant_onednn_pass");
|
||||
passes_.emplace_back("onednn_placement_pass");
|
||||
passes_.emplace_back("constant_folding_pass");
|
||||
passes_.emplace_back("squeeze2_transpose2_onednn_fuse_pass");
|
||||
passes_.emplace_back("layer_norm_fuse_pass");
|
||||
passes_.emplace_back("attention_lstm_fuse_pass");
|
||||
passes_.emplace_back("seqconv_eltadd_relu_fuse_pass");
|
||||
passes_.emplace_back("fc_lstm_fuse_pass");
|
||||
passes_.emplace_back("mul_lstm_fuse_pass");
|
||||
passes_.emplace_back("fc_gru_fuse_pass");
|
||||
passes_.emplace_back("mul_gru_fuse_pass");
|
||||
passes_.emplace_back("multi_gru_fuse_pass");
|
||||
passes_.emplace_back("multi_gru_seq_fuse_pass");
|
||||
passes_.emplace_back("seq_concat_fc_fuse_pass");
|
||||
passes_.emplace_back("gpu_cpu_squeeze2_matmul_fuse_pass");
|
||||
passes_.emplace_back("gpu_cpu_reshape2_matmul_fuse_pass");
|
||||
passes_.emplace_back("gpu_cpu_flatten2_matmul_fuse_pass");
|
||||
passes_.emplace_back("matmul_v2_scale_fuse_pass");
|
||||
passes_.emplace_back("squared_mat_sub_fuse_pass");
|
||||
passes_.emplace_back("is_test_pass");
|
||||
passes_.emplace_back("gpu_cpu_map_matmul_v2_to_mul_pass");
|
||||
passes_.emplace_back("gpu_cpu_map_matmul_v2_to_matmul_pass");
|
||||
passes_.emplace_back("matmul_scale_fuse_pass");
|
||||
passes_.emplace_back("gpu_cpu_map_matmul_to_mul_pass");
|
||||
passes_.emplace_back("repeated_fc_relu_fuse_pass");
|
||||
passes_.emplace_back("depthwise_conv_onednn_pass");
|
||||
passes_.emplace_back("conv_bn_fuse_pass");
|
||||
passes_.emplace_back("conv_eltwiseadd_bn_fuse_pass");
|
||||
passes_.emplace_back("conv_affine_channel_onednn_fuse_pass");
|
||||
passes_.emplace_back("conv_transpose_bn_fuse_pass");
|
||||
passes_.emplace_back("conv_transpose_eltwiseadd_bn_fuse_pass");
|
||||
passes_.emplace_back("conv_bias_onednn_fuse_pass");
|
||||
passes_.emplace_back("conv_transpose_bias_onednn_fuse_pass");
|
||||
passes_.emplace_back("conv_elementwise_add_onednn_fuse_pass");
|
||||
passes_.emplace_back("conv_activation_onednn_fuse_pass");
|
||||
passes_.emplace_back("fc_fuse_pass");
|
||||
passes_.emplace_back("repeated_fc_relu_fuse_pass");
|
||||
passes_.emplace_back("fc_onednn_pass");
|
||||
passes_.emplace_back("fc_act_onednn_fuse_pass");
|
||||
passes_.emplace_back("matmul_transpose_reshape_onednn_fuse_pass");
|
||||
passes_.emplace_back("batch_norm_act_fuse_pass");
|
||||
passes_.emplace_back("softplus_activation_onednn_fuse_pass");
|
||||
passes_.emplace_back("compute_propagate_scales_onednn_pass");
|
||||
passes_.emplace_back("scale_matmul_fuse_pass");
|
||||
passes_.emplace_back("reshape_transpose_matmul_onednn_fuse_pass");
|
||||
passes_.emplace_back("matmul_elementwise_add_onednn_fuse_pass");
|
||||
passes_.emplace_back("operator_scale_onednn_fuse_pass");
|
||||
passes_.emplace_back("operator_unsqueeze2_onednn_fuse_pass");
|
||||
passes_.emplace_back("operator_reshape2_onednn_fuse_pass");
|
||||
passes_.emplace_back("cpu_quantize_placement_pass");
|
||||
passes_.emplace_back("cpu_quantize_pass");
|
||||
passes_.emplace_back("cpu_quantize_squash_pass");
|
||||
passes_.emplace_back("quant_transpose2_dequant_onednn_fuse_pass");
|
||||
}
|
||||
use_onednn_int8_ = true;
|
||||
#else
|
||||
use_onednn_int8_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CpuPassStrategy::DisableMkldnnFcPasses() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(DisableOnednnFcPasses);
|
||||
DisableOnednnFcPasses();
|
||||
}
|
||||
void CpuPassStrategy::DisableOnednnFcPasses() {
|
||||
#ifdef PADDLE_WITH_DNNL
|
||||
if (!disable_onednn_fc_passes_) {
|
||||
EraseFcOnednnPasses();
|
||||
}
|
||||
disable_onednn_fc_passes_ = true;
|
||||
#else
|
||||
disable_onednn_fc_passes_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CpuPassStrategy::EraseFcMkldnnPasses() {
|
||||
LOG(WARNING) << ONEDNN_UPDATE_WARNING(EraseFcOnednnPasses);
|
||||
EraseFcOnednnPasses();
|
||||
}
|
||||
void CpuPassStrategy::EraseFcOnednnPasses() {
|
||||
std::vector<std::string> fc_passes_to_erase(
|
||||
{"fc_onednn_pass", "fc_act_onednn_fuse_pass"});
|
||||
for (const auto &pass : fc_passes_to_erase) {
|
||||
int idx = static_cast<int>(GetPassIndex(pass));
|
||||
if (idx != -1) {
|
||||
passes_.erase(std::begin(passes_) + idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XpuPassStrategy::XpuPassStrategy() : PassStrategy({}) {
|
||||
passes_.assign({
|
||||
"map_op_to_another_pass",
|
||||
// "quant_dequant_xpu_pass", open this pass when use old int8 model
|
||||
"delete_quant_dequant_linear_op_pass",
|
||||
"delete_weight_dequant_linear_op_pass",
|
||||
"delete_assign_op_pass",
|
||||
"delete_dropout_op_pass",
|
||||
"delete_concat_op_pass",
|
||||
"gather_squeeze_pass",
|
||||
"roformer_relative_pos_fuse_pass",
|
||||
"delete_repeated_ops_pass",
|
||||
"identity_op_clean_pass",
|
||||
"fused_continuous_same_ops_pass",
|
||||
"reshape_unstack_concat_fuse_pass",
|
||||
"delete_op_device_pass",
|
||||
"constant_folding_pass",
|
||||
"cast_embedding_trans_ids_to_int32_pass",
|
||||
"delete_elementwise_mul_op_pass",
|
||||
"generate_sequence_xpu_fuse_pass",
|
||||
"group_norm_silu_xpu_fuse_pass",
|
||||
"layer_norm_relu_xpu_fuse_pass",
|
||||
"embedding_with_eltwise_add_xpu_fuse_pass",
|
||||
"qk_qkv_attention_xpu_fuse_pass",
|
||||
"block_multihead_attention_xpu_pass",
|
||||
"multi_encoder_xpu_fuse_pass",
|
||||
"multi_encoder_xpu_adaptive_seqlen_fuse_pass",
|
||||
"multi_encoder_xpu_slice_fuse_pass",
|
||||
"weight_only_linear_xpu_pass",
|
||||
"fused_multi_transformer_cachekv_layout_trans_pass",
|
||||
"fused_multi_transformer_int8_cachekv_layout_trans_pass",
|
||||
"cross_attention_xpu_fuse_pass",
|
||||
"decoder_attention_xpu_fuse_pass",
|
||||
"one_beam_size_fuse_pass",
|
||||
"fold_interp_outsize_fuse_pass",
|
||||
"fold_two_squeeze2_fuse_pass",
|
||||
// "conv1d_xpu_fuse_pass",
|
||||
"duplicated_transpose_fuse_pass",
|
||||
"conv2d_bias_fuse_pass",
|
||||
"redundant_unsqueeze_squeeze_elimination_pass",
|
||||
"reduce_ops_fuse_pass",
|
||||
"delete_cast_op_pass",
|
||||
"xpu_delete_cast_op_pass",
|
||||
"conv2d_trans_filter_dilations_nxn_to_1x1_pass",
|
||||
"stack_fuse_pass",
|
||||
"fused_multi_transformer_xpu_pass",
|
||||
"fused_multi_transformer_int8_xpu_quant_pass",
|
||||
"relu6_fuse_pass",
|
||||
"sigmoid_elementmul_fuse_pass",
|
||||
"layer_norm_fuse_pass",
|
||||
"matmul_weight_trans_pass",
|
||||
"map_matmulv2_to_matmul_xpu_pass",
|
||||
"reshape2_matmul_xpu_fuse_pass",
|
||||
"squeeze2_matmul_xpu_fuse_pass",
|
||||
"redundant_squeeze_unsqueeze_elimination_pass",
|
||||
"fc_xpu_fuse_pass",
|
||||
"conv2d_xpu_fuse_pass",
|
||||
"conv2d_transpose_xpu_fuse_pass",
|
||||
"squeeze_excitation_fuse_pass",
|
||||
"add_activation_xpu_fuse_pass",
|
||||
"add_layernorm_xpu_fuse_pass",
|
||||
"layer_norm_act_xpu_fuse_pass",
|
||||
"fast_layernorm_xpu_fuse_pass",
|
||||
"bn_act_xpu_fuse_pass",
|
||||
"yolo_box_xpu_fuse_pass",
|
||||
"fast_where_xpu_fuse_pass",
|
||||
"elementwise_mul_add_fuse_pass",
|
||||
"sine_pos_fuse_pass",
|
||||
"pad2d_xpu_fuse_pass",
|
||||
// "auto_mixed_precision_pass",
|
||||
"cast_mixed_precision_op_fuse_pass",
|
||||
"xpu_quantize_op_pass",
|
||||
"xpu_quantize_squash_pass",
|
||||
"link_xpu_op_max_pass",
|
||||
"spatial_transformer_resblock_xpu_fuse_pass",
|
||||
"delete_isolated_node_pass",
|
||||
"inplace_op_var_pass",
|
||||
});
|
||||
use_xpu_ = true;
|
||||
}
|
||||
|
||||
IpuPassStrategy::IpuPassStrategy() : PassStrategy({}) {
|
||||
passes_.assign({"inference_process_pass"});
|
||||
}
|
||||
const std::vector<std::string> kPirCustomDevicePasses{
|
||||
// Functional pass
|
||||
"add_shadow_output_after_dead_parameter_pass",
|
||||
"delete_quant_dequant_linear_op_pass",
|
||||
"delete_weight_dequant_linear_op_pass",
|
||||
"map_op_to_another_pass",
|
||||
"identity_op_clean_pass",
|
||||
"matmul_scale_fuse_pass",
|
||||
};
|
||||
|
||||
const std::vector<std::string> kPirGpuPasses{
|
||||
// Functional pass
|
||||
"add_shadow_output_after_dead_parameter_pass",
|
||||
"delete_quant_dequant_linear_op_pass",
|
||||
"delete_weight_dequant_linear_op_pass",
|
||||
"map_op_to_another_pass",
|
||||
"identity_op_clean_pass",
|
||||
// Operator fusion pass
|
||||
"silu_fuse_pass",
|
||||
"conv2d_bn_fuse_pass",
|
||||
"conv2d_add_act_fuse_pass",
|
||||
"conv2d_add_fuse_pass",
|
||||
"embedding_eltwise_layernorm_fuse_pass",
|
||||
"fused_rotary_position_embedding_pass",
|
||||
"fused_flash_attn_pass",
|
||||
"multihead_matmul_fuse_pass",
|
||||
"fused_weight_only_linear_pass",
|
||||
"matmul_add_act_fuse_pass",
|
||||
"fc_elementwise_layernorm_fuse_pass",
|
||||
"add_norm_fuse_pass",
|
||||
"group_norm_silu_fuse_pass",
|
||||
"matmul_scale_fuse_pass",
|
||||
"matmul_transpose_fuse_pass",
|
||||
"transpose_flatten_concat_fuse_pass",
|
||||
"remove_redundant_transpose_pass",
|
||||
"horizontal_fuse_pass",
|
||||
};
|
||||
|
||||
const std::vector<std::string> kPirXpuPasses{
|
||||
// Functional pass
|
||||
"add_shadow_output_after_dead_parameter_pass",
|
||||
"delete_quant_dequant_linear_op_pass",
|
||||
"delete_weight_dequant_linear_op_pass",
|
||||
"map_op_to_another_pass",
|
||||
"identity_op_clean_pass",
|
||||
// Operator fusion pass
|
||||
"add_activation_xpu_fuse_pass",
|
||||
"add_layernorm_xpu_fuse_pass",
|
||||
"rms_norm_xpu_fuse_pass",
|
||||
"elementwise_mul_add_xpu_fuse_pass",
|
||||
"conv2d_xpu_fuse_pass",
|
||||
"conv2d_add_xpu_fuse_pass",
|
||||
"group_norm_silu_fuse_pass",
|
||||
"fc_xpu_fuse_pass"};
|
||||
|
||||
const std::vector<std::string> kPirOnednnPasses {
|
||||
"add_shadow_output_after_dead_parameter_pass",
|
||||
"delete_quant_dequant_linear_op_pass", //
|
||||
"delete_weight_dequant_linear_op_pass", //
|
||||
"depthwise_conv_onednn_pass", //
|
||||
"squeeze_transpose_onednn_fuse_pass", //
|
||||
"conv2d_bn_onednn_fuse_pass", //
|
||||
"conv2d_bias_bn_onednn_fuse_pass", //
|
||||
"conv2d_bias_fuse_pass", //
|
||||
"conv2d_transpose_bn_fuse_pass", //
|
||||
"conv2d_transpose_bias_bn_fuse_pass", //
|
||||
"conv2d_transpose_bias_fuse_pass", //
|
||||
"conv3d_bias_fuse_pass", //
|
||||
"conv_elementwise_add_onednn_fuse_pass", //
|
||||
"conv_activation_onednn_fuse_pass", //
|
||||
"conv_concat_activation_onednn_fuse_pass", //
|
||||
"matmul_scale_fuse_pass", //
|
||||
"scale_matmul_fuse_pass", //
|
||||
"reshape_transpose_matmul_fuse_pass", //
|
||||
"matmul_transpose_reshape_fuse_pass", //
|
||||
"matmul_add_act_fuse_pass", //
|
||||
"matmul_reshape_add_fuse_pass", //
|
||||
"fc_onednn_enable_pass", //
|
||||
"matmul_elementwise_add_fuse_pass", //
|
||||
"matmul_activation_fuse_pass", //
|
||||
"matmul_add_act_fuse_pass", //
|
||||
"fc_onednn_enable_pass", //
|
||||
"fc_activation_fuse_pass", //
|
||||
#if defined(PADDLE_WITH_AVX512F) && defined(PADDLE_WITH_MKLML) && \
|
||||
defined(PADDLE_WITH_DNNL)
|
||||
"self_attention_fuse_pass", //
|
||||
#endif
|
||||
"batch_norm_act_fuse_pass", //
|
||||
"softplus_activation_fuse_pass", //
|
||||
"shuffle_channel_detect_pass", //
|
||||
"elementwise_act_onednn_fuse_pass", //
|
||||
"operator_scale_onednn_fuse_pass", //
|
||||
"operator_unsqueeze_onednn_fuse_pass", //
|
||||
"operator_reshape_onednn_fuse_pass", //
|
||||
"onednn_placement_pass", //
|
||||
};
|
||||
|
||||
const std::vector<std::string> kPirOnednnBf16Passes{
|
||||
"add_shadow_output_after_dead_parameter_pass",
|
||||
"cpu_bfloat16_placement_pass",
|
||||
"cpu_bfloat16_pass",
|
||||
"cpu_bfloat16_type_placement_pass",
|
||||
"cpu_special_ops_bf16_pass",
|
||||
"cpu_bf16_quantize_squash_pass",
|
||||
};
|
||||
|
||||
const std::vector<std::string> kPirCpuPasses{
|
||||
"add_shadow_output_after_dead_parameter_pass",
|
||||
"delete_quant_dequant_linear_op_pass",
|
||||
"delete_weight_dequant_linear_op_pass"};
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,398 @@
|
||||
// Copyright (c) 2018 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 <sstream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle_infer_declare.h" // NOLINT
|
||||
|
||||
///
|
||||
/// \file paddle_pass_builder.h
|
||||
///
|
||||
/// \brief Class Paddle Pass Builder and its subclasses(pass strategies).
|
||||
/// \section sec_intro Introduction
|
||||
/// This class aims to build passes for paddle and define passes' strategies.
|
||||
///
|
||||
/// \author paddle-infer@baidu.com
|
||||
/// \date 2020-3-23
|
||||
/// \since 1.7
|
||||
|
||||
/// \namespace paddle
|
||||
namespace paddle {
|
||||
|
||||
/// \class PaddlePassBuilder
|
||||
/// \brief This class build passes based on vector<string> input. It is part of
|
||||
/// inference API. Users can build passes, insert new passes, delete passes
|
||||
/// using this class and its functions.
|
||||
///
|
||||
/// Example Usage:
|
||||
/// Build a new pass.
|
||||
/// \code{cpp}
|
||||
/// const vector<string> passes(1, "conv_relu_onednn_fuse_pass");
|
||||
/// PaddlePassBuilder builder(passes);
|
||||
/// \endcode
|
||||
class PD_INFER_DECL PaddlePassBuilder {
|
||||
public:
|
||||
/// \brief Constructor of the class. It stores the input passes.
|
||||
/// \param[in] passes passes' types.
|
||||
explicit PaddlePassBuilder(const std::vector<std::string> &passes)
|
||||
: passes_(passes) {}
|
||||
|
||||
/// \brief Stores the input passes.
|
||||
/// \param[in] passes passes' types.
|
||||
void SetPasses(std::initializer_list<std::string> passes) {
|
||||
passes_ = passes;
|
||||
}
|
||||
|
||||
/// \brief Append a pass to the end of the passes.
|
||||
/// \param[in] pass_type the type of the new pass.
|
||||
void AppendPass(const std::string &pass_type);
|
||||
|
||||
/// \brief Insert a pass to a specific position.
|
||||
/// \param[in] idx the position to insert.
|
||||
/// \param[in] pass_type the type of insert pass.
|
||||
void InsertPass(size_t idx, const std::string &pass_type);
|
||||
|
||||
/// \brief Delete the pass at certain position 'idx'.
|
||||
/// \param[in] idx the position to delete.
|
||||
void DeletePass(size_t idx);
|
||||
|
||||
/// \brief Get the certain position of a pass.
|
||||
/// \param[in] pass_type the type of insert pass.
|
||||
size_t GetPassIndex(const std::string &pass_type);
|
||||
|
||||
/// \brief Delete all passes that has a certain type 'pass_type'.
|
||||
/// \param[in] pass_type the certain pass type to be deleted.
|
||||
void DeletePass(const std::string &pass_type);
|
||||
|
||||
/// \brief Delete all the passes.
|
||||
void ClearPasses();
|
||||
|
||||
/// \brief Append an analysis pass.
|
||||
/// \param[in] pass the type of the new analysis pass.
|
||||
void AppendAnalysisPass(const std::string &pass);
|
||||
|
||||
/// \brief Visualize the computation graph after each pass by generating a DOT
|
||||
/// language file, one can draw them with the Graphviz toolkit.
|
||||
void TurnOnDebug();
|
||||
/// \brief Human-readable information of the passes.
|
||||
std::string DebugString();
|
||||
|
||||
/// \brief Get information of passes.
|
||||
/// \return Return list of the passes.
|
||||
const std::vector<std::string> &AllPasses() const { return passes_; }
|
||||
|
||||
/// \brief Get information of analysis passes.
|
||||
/// \return Return list of analysis passes.
|
||||
std::vector<std::string> AnalysisPasses() const {
|
||||
auto passes = analysis_passes_;
|
||||
// To make sure the ir_graph_to_program should be the last pass so any
|
||||
// modification of IR will persist to the program.
|
||||
passes.push_back("ir_graph_to_program_pass");
|
||||
return passes;
|
||||
}
|
||||
|
||||
const std::unordered_set<std::string> &GetAllDeletedPasses() const {
|
||||
return deleted_passes_;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \cond Protected
|
||||
std::vector<std::string> analysis_passes_{{
|
||||
"ir_graph_build_pass",
|
||||
"ir_analysis_pass",
|
||||
"ir_params_sync_among_devices_pass",
|
||||
"adjust_cudnn_workspace_size_pass",
|
||||
"inference_op_replace_pass",
|
||||
"save_optimized_model_pass",
|
||||
}};
|
||||
std::vector<std::string> passes_;
|
||||
std::unordered_set<std::string> deleted_passes_;
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/// \class PassStrategy
|
||||
/// \brief This class defines the pass strategies like whether to use gpu/cuDNN
|
||||
/// kernel/MKLDNN.
|
||||
class PD_INFER_DECL PassStrategy : public PaddlePassBuilder {
|
||||
public:
|
||||
/// \brief Constructor of PassStrategy class. It works the same as
|
||||
/// PaddlePassBuilder class. \param[in] passes passes' types.
|
||||
explicit PassStrategy(const std::vector<std::string> &passes)
|
||||
: PaddlePassBuilder(passes) {}
|
||||
|
||||
/// \brief Enable the use of cuDNN kernel.
|
||||
virtual void EnableCUDNN() {}
|
||||
|
||||
/// \brief Enable the use of OneDNN.
|
||||
/// The OneDNN control exists in both CPU and GPU mode, because there can
|
||||
/// still be some CPU kernels running in GPU mode.
|
||||
virtual void EnableMKLDNN() {} // deprecated
|
||||
|
||||
/// \brief Disable the use of OneDNN.
|
||||
virtual void DisableMKLDNN() {} // deprecated
|
||||
|
||||
/// \brief Enable OneDNN bfloat16.
|
||||
virtual void EnableMkldnnBfloat16() {} // deprecated
|
||||
|
||||
/// \brief Enable OneDNN int8.
|
||||
virtual void EnableMkldnnInt8() {} // deprecated
|
||||
|
||||
/// \brief Disable OneDNN fc passes.
|
||||
virtual void DisableMkldnnFcPasses() {} // deprecated
|
||||
|
||||
/// \brief Enable the use of OneDNN.
|
||||
/// The OneDNN control exists in both CPU and GPU mode, because there can
|
||||
/// still be some CPU kernels running in GPU mode.
|
||||
virtual void EnableONEDNN() {}
|
||||
|
||||
/// \brief Disable the use of OneDNN.
|
||||
virtual void DisableONEDNN() {}
|
||||
|
||||
/// \brief Enable OneDNN bfloat16.
|
||||
virtual void EnableOnednnBfloat16() {}
|
||||
|
||||
/// \brief Enable OneDNN int8.
|
||||
virtual void EnableOnednnInt8() {}
|
||||
|
||||
/// \brief Disable OneDNN fc passes.
|
||||
virtual void DisableOnednnFcPasses() {}
|
||||
|
||||
/// \brief Check if we are using gpu.
|
||||
/// \return A bool variable implying whether we are in gpu mode.
|
||||
bool use_gpu() const { return use_gpu_; }
|
||||
|
||||
/// \brief Check if we are using xpu.
|
||||
/// \return A bool variable implying whether we are in xpu mode.
|
||||
bool use_xpu() const { return use_xpu_; }
|
||||
|
||||
/// \brief Check if we are using ipu.
|
||||
/// \return A bool variable implying whether we are in ipu mode.
|
||||
bool use_ipu() const { return use_ipu_; }
|
||||
|
||||
/// \brief Check if we are using CustomDevice.
|
||||
/// \return A bool variable implying whether we are in CustomDevice mode.
|
||||
bool use_custom_device() const { return use_custom_device_; }
|
||||
|
||||
/// \brief Default destructor.
|
||||
virtual ~PassStrategy() = default;
|
||||
|
||||
protected:
|
||||
/// \cond Protected
|
||||
bool use_xpu_{false};
|
||||
bool use_gpu_{false};
|
||||
bool use_ipu_{false};
|
||||
bool use_onednn_{false};
|
||||
bool use_custom_device_{false};
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/// \class CpuPassStrategy
|
||||
/// \brief The CPU passes controller, it is used in AnalysisPredictor with CPU
|
||||
/// mode.
|
||||
class PD_INFER_DECL CpuPassStrategy : public PassStrategy {
|
||||
public:
|
||||
/// \brief Default constructor of CpuPassStrategy.
|
||||
CpuPassStrategy();
|
||||
|
||||
/// \brief Construct by copying another CpuPassStrategy object.
|
||||
/// \param[in] other The CpuPassStrategy object we want to copy.
|
||||
explicit CpuPassStrategy(const CpuPassStrategy &other)
|
||||
: PassStrategy(other.AllPasses()) {
|
||||
use_gpu_ = other.use_gpu_;
|
||||
use_onednn_ = other.use_onednn_;
|
||||
use_onednn_bfloat16_ = other.use_onednn_bfloat16_;
|
||||
use_onednn_int8_ = other.use_onednn_int8_;
|
||||
disable_onednn_fc_passes_ = other.disable_onednn_fc_passes_;
|
||||
deleted_passes_ = other.deleted_passes_;
|
||||
}
|
||||
/// \brief Default destructor.
|
||||
virtual ~CpuPassStrategy() = default;
|
||||
|
||||
/// \brief Enable the use of cuDNN kernel.
|
||||
void EnableCUDNN() override;
|
||||
|
||||
/// \brief Enable the use of OneDNN.
|
||||
void EnableMKLDNN() override; // deprecated
|
||||
|
||||
/// \brief Disable the use of OneDNN.
|
||||
void DisableMKLDNN() override; // deprecated
|
||||
|
||||
/// \brief Enable OneDNN bfloat16.
|
||||
void EnableMkldnnBfloat16() override; // deprecated
|
||||
|
||||
/// \brief Enable OneDNN int8.
|
||||
void EnableMkldnnInt8() override; // deprecated
|
||||
|
||||
/// \brief Disable OneDNN fc passes.
|
||||
void DisableMkldnnFcPasses() override; // deprecated
|
||||
|
||||
/// \brief Enable the use of OneDNN.
|
||||
void EnableONEDNN() override;
|
||||
|
||||
/// \brief Disable the use of OneDNN.
|
||||
void DisableONEDNN() override;
|
||||
|
||||
/// \brief Enable OneDNN bfloat16.
|
||||
void EnableOnednnBfloat16() override;
|
||||
|
||||
/// \brief Enable OneDNN int8.
|
||||
void EnableOnednnInt8() override;
|
||||
|
||||
/// \brief Disable OneDNN fc passes.
|
||||
void DisableOnednnFcPasses() override;
|
||||
|
||||
protected:
|
||||
/// \brief Erase OneDNN fc passes.
|
||||
void EraseFcMkldnnPasses(); // deprecated
|
||||
|
||||
/// \brief Erase OneDNN fc passes.
|
||||
void EraseFcOnednnPasses();
|
||||
|
||||
/// \cond Protected
|
||||
bool use_onednn_bfloat16_{false};
|
||||
bool use_onednn_int8_{false};
|
||||
bool disable_onednn_fc_passes_{false};
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/// \class GpuPassStrategy
|
||||
/// \brief The GPU passes controller, it is used in AnalysisPredictor with GPU
|
||||
/// mode.
|
||||
class PD_INFER_DECL GpuPassStrategy : public PassStrategy {
|
||||
public:
|
||||
/// \brief Default constructor of GpuPassStrategy.
|
||||
GpuPassStrategy();
|
||||
|
||||
/// \brief Construct by copying another GpuPassStrategy object.
|
||||
/// \param[in] other The GpuPassStrategy object we want to copy.
|
||||
explicit GpuPassStrategy(const GpuPassStrategy &other)
|
||||
: PassStrategy(other.AllPasses()) {
|
||||
use_gpu_ = true;
|
||||
use_cudnn_ = other.use_cudnn_;
|
||||
deleted_passes_ = other.deleted_passes_;
|
||||
}
|
||||
|
||||
/// \brief Enable the use of cuDNN kernel.
|
||||
void EnableCUDNN() override;
|
||||
|
||||
/// \brief Not supported in GPU mode yet.
|
||||
void EnableMKLDNN() override; // deprecated
|
||||
|
||||
/// \brief Not supported in GPU mode yet.
|
||||
void EnableMkldnnBfloat16() override; // deprecated
|
||||
|
||||
/// \brief Not supported in GPU mode yet.
|
||||
void EnableMkldnnInt8() override; // deprecated
|
||||
|
||||
/// \brief Disable OneDNN fc passes.
|
||||
void DisableMkldnnFcPasses() override; // deprecated
|
||||
|
||||
/// \brief Not supported in GPU mode yet.
|
||||
void EnableONEDNN() override;
|
||||
|
||||
/// \brief Not supported in GPU mode yet.
|
||||
void EnableOnednnBfloat16() override;
|
||||
|
||||
/// \brief Not supported in GPU mode yet.
|
||||
void EnableOnednnInt8() override;
|
||||
|
||||
/// \brief Disable OneDNN fc passes.
|
||||
void DisableOnednnFcPasses() override;
|
||||
|
||||
/// \brief Default destructor.
|
||||
virtual ~GpuPassStrategy() = default;
|
||||
|
||||
protected:
|
||||
/// \cond Protected
|
||||
bool use_cudnn_{false};
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
/// \class XpuPassStrategy
|
||||
/// \brief The XPU passes controller, it is used in AnalysisPredictor with XPU
|
||||
/// mode.
|
||||
class PD_INFER_DECL XpuPassStrategy final : public PassStrategy {
|
||||
public:
|
||||
XpuPassStrategy();
|
||||
explicit XpuPassStrategy(const XpuPassStrategy &other)
|
||||
: PassStrategy(other.AllPasses()) {
|
||||
use_xpu_ = true;
|
||||
deleted_passes_ = other.deleted_passes_;
|
||||
}
|
||||
};
|
||||
|
||||
/// \class CustomDevicePassStrategy
|
||||
/// \brief The CustomDevice passes controller, it is used in AnalysisPredictor
|
||||
/// with CustomDevice
|
||||
/// mode.
|
||||
class PD_INFER_DECL CustomDevicePassStrategy final : public PassStrategy {
|
||||
public:
|
||||
CustomDevicePassStrategy() : PassStrategy({}) { use_custom_device_ = true; }
|
||||
|
||||
/// \brief Construct by copying another CustomDevicePassStrategy object.
|
||||
/// \param[in] other The CustomDevicePassStrategy object we want to copy.
|
||||
explicit CustomDevicePassStrategy(const CustomDevicePassStrategy &other)
|
||||
: PassStrategy(other.AllPasses()) {
|
||||
use_custom_device_ = true;
|
||||
deleted_passes_ = other.deleted_passes_;
|
||||
}
|
||||
};
|
||||
|
||||
/// \class IpuPassStrategy
|
||||
/// \brief The IPU passes controller, it is used in AnalysisPredictor with IPU
|
||||
/// mode.
|
||||
class PD_INFER_DECL IpuPassStrategy final : public PassStrategy {
|
||||
public:
|
||||
/// \brief Default constructor of IpuPassStrategy.
|
||||
IpuPassStrategy();
|
||||
|
||||
/// \brief Construct by copying another IpuPassStrategy object.
|
||||
/// \param[in] other The IpuPassStrategy object we want to copy.
|
||||
explicit IpuPassStrategy(const IpuPassStrategy &other)
|
||||
: PassStrategy(other.AllPasses()) {
|
||||
use_ipu_ = true;
|
||||
deleted_passes_ = other.deleted_passes_;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef PADDLE_WITH_OPENVINO
|
||||
/// \brief List of OpenVINO subgraph passes.
|
||||
PD_INFER_DECL extern const std::vector<std::string> kOVSubgraphPasses;
|
||||
#endif
|
||||
|
||||
/// \brief List of tensorRT subgraph passes.
|
||||
PD_INFER_DECL extern const std::vector<std::string> kTRTSubgraphPasses;
|
||||
|
||||
/// \brief List of cinn compiler passes.
|
||||
PD_INFER_DECL extern const std::vector<std::string> kCINNCompilerPasses;
|
||||
|
||||
/// \brief TODO(inference): Most of the existing pass fusion operators do not
|
||||
/// support fp16/bf16 precision, temporarily use low precision pass to prevent
|
||||
/// running errors. After fusion operator supports low precision, delete this.
|
||||
PD_INFER_DECL extern const std::vector<std::string> kGpuLowerPrecisionPasses;
|
||||
PD_INFER_DECL extern const std::vector<std::string> kTrtLowerPrecisionPasses;
|
||||
|
||||
PD_INFER_DECL extern const std::vector<std::string> kPirCustomDevicePasses;
|
||||
PD_INFER_DECL extern const std::vector<std::string> kPirGpuPasses;
|
||||
PD_INFER_DECL extern const std::vector<std::string> kPirCpuPasses;
|
||||
PD_INFER_DECL extern const std::vector<std::string> kPirXpuPasses;
|
||||
PD_INFER_DECL extern const std::vector<std::string> kPirOnednnPasses;
|
||||
PD_INFER_DECL extern const std::vector<std::string> kPirOnednnBf16Passes;
|
||||
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,237 @@
|
||||
// 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 <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle_infer_declare.h" // NOLINT
|
||||
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
#include "onnxruntime_c_api.h" // NOLINT
|
||||
#include "onnxruntime_cxx_api.h" // NOLINT
|
||||
#endif
|
||||
|
||||
namespace paddle {
|
||||
class Tensor;
|
||||
}
|
||||
|
||||
namespace paddle_infer {
|
||||
|
||||
/// \brief Experimental.
|
||||
/// Strings for text data.
|
||||
using Strings = std::vector<std::string>;
|
||||
|
||||
using OutputTensorHookFunc = std::function<void(
|
||||
const std::string&, const std::string&, const paddle::Tensor&)>;
|
||||
using InputTensorHookFunc = OutputTensorHookFunc;
|
||||
|
||||
typedef void (*CallbackFunc)(void*);
|
||||
|
||||
#if defined(PADDLE_WITH_TESTING) && defined(PADDLE_WITH_INFERENCE_API_TEST)
|
||||
class InferApiTesterUtils;
|
||||
#endif
|
||||
|
||||
namespace contrib {
|
||||
class TensorUtils;
|
||||
}
|
||||
|
||||
namespace experimental {
|
||||
class InternalUtils;
|
||||
};
|
||||
|
||||
/// \brief Paddle data type.
|
||||
enum DataType {
|
||||
FLOAT32,
|
||||
INT64,
|
||||
INT32,
|
||||
UINT8,
|
||||
INT8,
|
||||
FLOAT16,
|
||||
BOOL,
|
||||
FLOAT64,
|
||||
BFLOAT16,
|
||||
FLOAT8E4M3,
|
||||
// TODO(Inference): support more data types if needed.
|
||||
};
|
||||
|
||||
enum class PlaceType { kUNK = -1, kCPU, kGPU, kXPU, kIPU, kCUSTOM };
|
||||
|
||||
enum class DataLayout { kUNK = -1, kAny, kNHWC, kNCHW };
|
||||
|
||||
/// \brief Represents an n-dimensional array of values.
|
||||
/// The Tensor is used to store the input or output of the network.
|
||||
/// Zero copy means that the tensor supports direct copy of host or device data
|
||||
/// to device,
|
||||
/// eliminating additional CPU copy. Tensor is only used in the
|
||||
/// AnalysisPredictor.
|
||||
/// It is obtained through PaddlePredictor::GetInputTensor()
|
||||
/// and PaddlePredictor::GetOutputTensor() interface.
|
||||
class PD_INFER_DECL Tensor {
|
||||
public:
|
||||
/// \brief Reset the shape of the tensor.
|
||||
/// Generally it's only used for the input tensor.
|
||||
/// Reshape must be called before calling mutable_data() or copy_from_cpu()
|
||||
/// \param shape The shape to set.
|
||||
void Reshape(const std::vector<int>& shape);
|
||||
|
||||
/// \brief Experimental interface.
|
||||
/// Reset the shape of the Strings tensor.
|
||||
/// Generally it's only used for the input tensor.
|
||||
/// Reshape must be called before calling
|
||||
/// ZeroCopyStringTensorCreate() or PaddleInferTensorCreate()
|
||||
/// \param shape The shape to set.
|
||||
void ReshapeStrings(const std::size_t& shape);
|
||||
|
||||
/// \brief Get the memory pointer in CPU or GPU with specific data type.
|
||||
/// Please Reshape the tensor first before call this.
|
||||
/// It's usually used to get input data pointer.
|
||||
/// \param place The place of the tensor.
|
||||
template <typename T>
|
||||
T* mutable_data(PlaceType place);
|
||||
|
||||
/// \brief Get the memory pointer directly.
|
||||
/// It's usually used to get the output data pointer.
|
||||
/// \param[out] place To get the device type of the tensor.
|
||||
/// \param[out] size To get the data size of the tensor.
|
||||
/// \return The tensor data buffer pointer.
|
||||
template <typename T>
|
||||
T* data(PlaceType* place, int* size) const;
|
||||
|
||||
/// \brief Copy the host memory to tensor data.
|
||||
/// It's usually used to set the input tensor data.
|
||||
/// \param data The pointer of the data, from which the tensor will copy.
|
||||
template <typename T>
|
||||
void CopyFromCpu(const T* data);
|
||||
|
||||
/// \brief Share the data with tensor data.
|
||||
/// It's usually used to set the tensor data.
|
||||
/// \param data The pointer of the data, from which the tensor will share.
|
||||
/// \param shape The shape of data.
|
||||
/// \param place The place of data.
|
||||
/// \param layout The layout of data. Only NCHW is supported now.
|
||||
template <typename T>
|
||||
void ShareExternalData(const T* data,
|
||||
const std::vector<int>& shape,
|
||||
PlaceType place,
|
||||
DataLayout layout = DataLayout::kNCHW);
|
||||
|
||||
/// \brief Experimental interface.
|
||||
/// It's usually used to set the input tensor data with Strings data type.
|
||||
/// \param data The pointer of the data, from which the tensor will copy.
|
||||
void CopyStringsFromCpu(const paddle_infer::Strings* data);
|
||||
|
||||
/// \brief Copy the tensor data to the host memory.
|
||||
/// It's usually used to get the output tensor data.
|
||||
/// \param[out] data The tensor will copy the data to the address.
|
||||
template <typename T>
|
||||
void CopyToCpu(T* data) const;
|
||||
|
||||
/// \brief Copy the tensor data to the host memory asynchronously.
|
||||
/// \param[out] data The tensor will copy the data to the address.
|
||||
/// \param[out] exec_stream The tensor will execute copy in this stream(Only
|
||||
/// GPU CUDA stream supported now).
|
||||
template <typename T>
|
||||
void CopyToCpuAsync(T* data, void* exec_stream) const;
|
||||
|
||||
/// \brief Copy the tensor data to the host memory asynchronously.
|
||||
/// \param[out] data The tensor will copy the data to the address.
|
||||
/// \param[out] cb Callback function cb(cb_params) will be executed on the
|
||||
/// host after all currently enqueued items in the stream have completed .
|
||||
template <typename T>
|
||||
void CopyToCpuAsync(T* data, CallbackFunc cb, void* cb_params) const;
|
||||
|
||||
/// \brief Return the shape of the Tensor.
|
||||
std::vector<int> shape() const;
|
||||
|
||||
/// \brief Set lod info of the tensor.
|
||||
/// More about LOD can be seen here:
|
||||
/// https://www.paddlepaddle.org.cn/documentation/docs/zh/beginners_guide/basic_concept/lod_tensor.html#lodtensor
|
||||
/// \param x the lod info.
|
||||
void SetLoD(const std::vector<std::vector<size_t>>& x);
|
||||
/// \brief Return the lod info of the tensor.
|
||||
std::vector<std::vector<size_t>> lod() const;
|
||||
/// \brief Return the name of the tensor.
|
||||
const std::string& name() const;
|
||||
|
||||
/// \brief Return the data type of the tensor.
|
||||
/// It's usually used to get the output tensor data type.
|
||||
/// \return The data type of the tensor.
|
||||
DataType type() const;
|
||||
|
||||
/// \brief Return the place type of the tensor.
|
||||
/// \return The place type of the tensor.
|
||||
PlaceType place() const;
|
||||
|
||||
protected:
|
||||
explicit Tensor(void* scope, const void* device_contexts);
|
||||
|
||||
template <typename T>
|
||||
void* FindTensor() const;
|
||||
|
||||
void SetPlace(PlaceType place,
|
||||
int device = -1,
|
||||
const std::string device_type = "");
|
||||
|
||||
void SetName(const std::string& name);
|
||||
|
||||
template <typename T>
|
||||
void CopyToCpuImpl(T* data,
|
||||
void* stream = nullptr,
|
||||
CallbackFunc cb = nullptr,
|
||||
void* cb_params = nullptr) const;
|
||||
|
||||
std::string name_;
|
||||
// The corresponding tensor pointer inside Paddle workspace is cached for
|
||||
// performance.
|
||||
mutable void* tensor_{nullptr};
|
||||
DataType dtype_;
|
||||
bool input_or_output_;
|
||||
void* scope_{nullptr};
|
||||
const void* device_contexts_{nullptr};
|
||||
PlaceType place_;
|
||||
int device_;
|
||||
std::string device_type_;
|
||||
|
||||
#ifdef PADDLE_WITH_ONNXRUNTIME
|
||||
bool is_ort_tensor_{false};
|
||||
std::vector<int64_t> shape_;
|
||||
std::weak_ptr<Ort::IoBinding> binding_;
|
||||
int idx_{-1};
|
||||
|
||||
void SetOrtMark(bool is_ort_tensor);
|
||||
|
||||
void SetOrtBinding(const std::shared_ptr<Ort::IoBinding> binding);
|
||||
|
||||
template <typename T>
|
||||
T* ORTGetMutableData();
|
||||
|
||||
template <typename T>
|
||||
void ORTCopyFromCpu(const T* data);
|
||||
|
||||
template <typename T>
|
||||
void ORTCopyToCpu(T* data) const;
|
||||
#endif
|
||||
|
||||
friend class paddle_infer::contrib::TensorUtils;
|
||||
friend class paddle_infer::experimental::InternalUtils;
|
||||
#if defined(PADDLE_WITH_TESTING) && defined(PADDLE_WITH_INFERENCE_API_TEST)
|
||||
friend class paddle_infer::InferApiTesterUtils;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace paddle_infer
|
||||
@@ -0,0 +1,477 @@
|
||||
// Copyright (c) 2022 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 "paddle/fluid/inference/api/resource_manager.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "paddle/common/errors.h"
|
||||
#include "paddle/phi/backends/gpu/forwards.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_decls.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_resources.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/allocator.h"
|
||||
#include "paddle/phi/core/generator.h"
|
||||
#include "paddle/phi/core/memory/allocation/allocator_facade.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_types.h"
|
||||
#include "unsupported/Eigen/CXX11/Tensor"
|
||||
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
#include "paddle/phi/backends/dynload/cublas.h"
|
||||
#include "paddle/phi/backends/dynload/cudnn.h"
|
||||
#include "paddle/phi/backends/dynload/cusolver.h"
|
||||
#include "paddle/phi/backends/dynload/cusparse.h"
|
||||
#endif // PADDLE_WITH_CUDA
|
||||
|
||||
namespace paddle {
|
||||
namespace internal {
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
class EigenGpuStreamDevice : public Eigen::StreamInterface {
|
||||
public:
|
||||
EigenGpuStreamDevice()
|
||||
: stream_(nullptr),
|
||||
allocator_(nullptr),
|
||||
device_prop_(nullptr),
|
||||
semaphore_(nullptr),
|
||||
allocations_() {
|
||||
Eigen::initializeDeviceProp();
|
||||
}
|
||||
~EigenGpuStreamDevice() override = default;
|
||||
|
||||
void Reinitialize(gpuStream_t cuda_stream,
|
||||
phi::Allocator* allocator,
|
||||
GPUPlace place) {
|
||||
stream_ = cuda_stream;
|
||||
allocator_ = allocator;
|
||||
device_prop_ = &Eigen::m_deviceProperties[place.device];
|
||||
}
|
||||
|
||||
const gpuStream_t& stream() const override { return stream_; }
|
||||
|
||||
const gpuDeviceProp& deviceProperties() const override {
|
||||
return *device_prop_;
|
||||
}
|
||||
|
||||
void* allocate(size_t num_bytes) const override {
|
||||
if (UNLIKELY(num_bytes == 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto buf = allocator_->Allocate(num_bytes);
|
||||
VLOG(4) << "Eigen allocated at " << buf->ptr() << " requested "
|
||||
<< num_bytes;
|
||||
void* retv = buf->ptr();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
allocations_.emplace(retv, std::move(buf));
|
||||
}
|
||||
return retv;
|
||||
}
|
||||
|
||||
void deallocate(void* buffer) const override {
|
||||
if (LIKELY(buffer)) {
|
||||
std::lock_guard<std::mutex> lock(mtx_);
|
||||
allocations_.erase(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void* scratchpad() const override {
|
||||
if (scratch_ == nullptr) {
|
||||
scratch_ = allocate(Eigen::kGpuScratchSize + sizeof(unsigned int));
|
||||
}
|
||||
return scratch_;
|
||||
}
|
||||
|
||||
unsigned int* semaphore() const override {
|
||||
if (semaphore_ == nullptr) {
|
||||
char* scratch = static_cast<char*>(scratchpad()) + Eigen::kGpuScratchSize;
|
||||
semaphore_ = reinterpret_cast<unsigned int*>(scratch);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
hipMemsetAsync(semaphore_, 0, sizeof(unsigned int), stream_));
|
||||
#else
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
cudaMemsetAsync(semaphore_, 0, sizeof(unsigned int), stream_));
|
||||
#endif
|
||||
}
|
||||
return semaphore_;
|
||||
}
|
||||
|
||||
private:
|
||||
gpuStream_t stream_; // not owned;
|
||||
phi::Allocator* allocator_; // not owned;
|
||||
const gpuDeviceProp* device_prop_; // not owned;
|
||||
mutable void* scratch_;
|
||||
mutable unsigned int* semaphore_;
|
||||
mutable std::mutex mtx_; // to protect allocations_
|
||||
mutable std::unordered_map<void*, phi::Allocator::AllocationPtr> allocations_;
|
||||
};
|
||||
#endif
|
||||
} // namespace internal
|
||||
|
||||
Eigen::DefaultDevice* CPUContextResource::GetCPUEigenDevice() const {
|
||||
return cpu_eigen_device_.get();
|
||||
}
|
||||
|
||||
void CPUContextResource::InitCPUResource() {
|
||||
cpu_eigen_device_ = std::make_unique<Eigen::DefaultDevice>();
|
||||
}
|
||||
|
||||
CPUContextResource::CPUContextResource() : cpu_eigen_device_(nullptr) {
|
||||
InitCPUResource();
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
GPUContextResource::GPUContextResource(const phi::Place& place, void* stream)
|
||||
: place_(place),
|
||||
compute_capability_(0),
|
||||
runtime_version_(0),
|
||||
driver_version_(0),
|
||||
multi_process_(0),
|
||||
max_threads_per_mp_(0),
|
||||
max_threads_per_block_(0),
|
||||
stream_(nullptr),
|
||||
gpu_eigen_device_(nullptr),
|
||||
eigen_stream_(nullptr) {
|
||||
InitGPUResource(stream);
|
||||
}
|
||||
|
||||
GPUContextResource::~GPUContextResource() { DestroyGPUResource(); } // NOLINT
|
||||
|
||||
void GPUContextResource::InitGPUResource(void* stream) {
|
||||
phi::backends::gpu::GPUDeviceGuard guard(place_.device);
|
||||
if (stream == nullptr) {
|
||||
owned_stream_ = true;
|
||||
phi::InitStream(&stream_);
|
||||
} else {
|
||||
owned_stream_ = false;
|
||||
stream_ = reinterpret_cast<gpuStream_t>(stream);
|
||||
}
|
||||
|
||||
InitGpuProperties();
|
||||
InitGpuEigenDevice();
|
||||
}
|
||||
|
||||
void GPUContextResource::DestroyGPUResource() {
|
||||
if (owned_stream_) {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipStreamDestroy(stream_));
|
||||
#else
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaStreamDestroy(stream_));
|
||||
#endif
|
||||
stream_ = nullptr;
|
||||
}
|
||||
|
||||
DestroyDnnHandle();
|
||||
DestroyBlasHandle();
|
||||
DestroyBlasLtHandle();
|
||||
DestroySolverHandle();
|
||||
DestroySparseHandle();
|
||||
}
|
||||
|
||||
void GPUContextResource::InitGpuProperties() {
|
||||
phi::InitGpuProperties(place_,
|
||||
&compute_capability_,
|
||||
&runtime_version_,
|
||||
&driver_version_,
|
||||
&multi_process_,
|
||||
&max_threads_per_mp_,
|
||||
&max_threads_per_block_,
|
||||
&max_grid_dim_size_);
|
||||
}
|
||||
|
||||
void GPUContextResource::InitGpuEigenDevice() {
|
||||
auto* allocator = paddle::memory::allocation::AllocatorFacade::Instance()
|
||||
.GetAllocator(place_)
|
||||
.get();
|
||||
eigen_stream_ = std::make_unique<internal::EigenGpuStreamDevice>();
|
||||
eigen_stream_->Reinitialize(stream_, allocator, place_);
|
||||
gpu_eigen_device_ = std::make_unique<Eigen::GpuDevice>(eigen_stream_.get());
|
||||
}
|
||||
|
||||
void GPUContextResource::InitDnnHandle() {
|
||||
phi::InitDnnHandle(&dnn_handle_, stream_, place_);
|
||||
}
|
||||
|
||||
void GPUContextResource::DestroyDnnHandle() {
|
||||
phi::DestroyDnnHandle(dnn_handle_);
|
||||
}
|
||||
|
||||
void GPUContextResource::DestroyBlasHandle() {
|
||||
phi::DestroyBlasHandle(blas_handle_);
|
||||
phi::DestroyBlasHandle(blas_tensor_core_handle_);
|
||||
phi::DestroyBlasHandle(blas_tf32_tensor_core_handle_);
|
||||
}
|
||||
|
||||
void GPUContextResource::InitBlasLtHandle() {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
phi::InitBlasLtHandle(reinterpret_cast<void**>(&blaslt_handle_));
|
||||
#else // PADDLE_WITH_CUDA
|
||||
phi::InitBlasLtHandle(&blaslt_handle_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GPUContextResource::DestroyBlasLtHandle() {
|
||||
phi::DestroyBlasLtHandle(blaslt_handle_);
|
||||
}
|
||||
|
||||
void GPUContextResource::InitSolverHandle() {
|
||||
phi::InitSolverHandle(&solver_handle_, stream_);
|
||||
}
|
||||
|
||||
void GPUContextResource::DestroySolverHandle() {
|
||||
phi::DestroySolverHandle(solver_handle_);
|
||||
}
|
||||
|
||||
void GPUContextResource::InitSparseHandle() {
|
||||
phi::InitSparseHandle(&sparse_handle_, stream_);
|
||||
}
|
||||
|
||||
void GPUContextResource::DestroySparseHandle() {
|
||||
phi::DestroySparseHandle(sparse_handle_);
|
||||
}
|
||||
|
||||
phi::Place GPUContextResource::Place() const { return place_; }
|
||||
|
||||
gpuStream_t GPUContextResource::GetStream() const { return stream_; }
|
||||
|
||||
dnnHandle_t GPUContextResource::GetDnnHandle() const { return dnn_handle_; }
|
||||
|
||||
std::function<phi::dnnHandle_t()> GPUContextResource::GetDnnHandleCreator() {
|
||||
return [&]() -> phi::dnnHandle_t {
|
||||
InitDnnHandle();
|
||||
return dnn_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
blasHandle_t GPUContextResource::GetBlasHandle() const { return blas_handle_; }
|
||||
|
||||
std::function<phi::blasHandle_t()> GPUContextResource::GetBlasHandleCreator() {
|
||||
return [&]() -> phi::blasHandle_t {
|
||||
phi::InitBlasHandle(&blas_handle_, stream_);
|
||||
return blas_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
blasHandle_t GPUContextResource::GetBlasTensorCoreHandle() const {
|
||||
return blas_tensor_core_handle_;
|
||||
}
|
||||
|
||||
std::function<phi::blasHandle_t()>
|
||||
GPUContextResource::GetBlasTensorCoreHandleCreator() {
|
||||
return [&]() -> phi::blasHandle_t {
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
#if CUDA_VERSION >= 9000
|
||||
phi::InitBlasHandle(&blas_tensor_core_handle_, stream_);
|
||||
PADDLE_RETRY_CUDA_SUCCESS(phi::dynload::cublasSetMathMode(
|
||||
blas_tensor_core_handle_, CUBLAS_TENSOR_OP_MATH));
|
||||
#endif
|
||||
#endif
|
||||
return blas_tensor_core_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
blasHandle_t GPUContextResource::GetBlasTF32Handle() const {
|
||||
return blas_tf32_tensor_core_handle_;
|
||||
}
|
||||
|
||||
std::function<phi::blasHandle_t()>
|
||||
GPUContextResource::GetBlasTF32TensorCoreHandleCreator() {
|
||||
return [&]() -> phi::blasHandle_t {
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
#if CUDA_VERSION >= 11000
|
||||
phi::InitBlasHandle(&blas_tf32_tensor_core_handle_, stream_);
|
||||
PADDLE_RETRY_CUDA_SUCCESS(phi::dynload::cublasSetMathMode(
|
||||
blas_tf32_tensor_core_handle_, CUBLAS_TF32_TENSOR_OP_MATH));
|
||||
#endif
|
||||
#endif
|
||||
return blas_tf32_tensor_core_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
blasLtHandle_t GPUContextResource::GetBlasLtHandle() const {
|
||||
return blaslt_handle_;
|
||||
}
|
||||
|
||||
std::function<phi::blasLtHandle_t()>
|
||||
GPUContextResource::GetBlasLtHandleCreator() {
|
||||
return [&]() {
|
||||
InitBlasLtHandle();
|
||||
return blaslt_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
phi::solverHandle_t GPUContextResource::GetSolverDnHandle() const {
|
||||
return solver_handle_;
|
||||
}
|
||||
|
||||
std::function<phi::solverHandle_t()>
|
||||
GPUContextResource::GetSolverDnHandleCreator() {
|
||||
return [&]() {
|
||||
InitSolverHandle();
|
||||
return solver_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
phi::sparseHandle_t GPUContextResource::GetSparseHandle() const {
|
||||
return sparse_handle_;
|
||||
}
|
||||
|
||||
std::function<phi::sparseHandle_t()>
|
||||
GPUContextResource::GetSparseHandleCreator() {
|
||||
return [&]() {
|
||||
InitSparseHandle();
|
||||
return sparse_handle_;
|
||||
};
|
||||
}
|
||||
|
||||
Eigen::GpuDevice* GPUContextResource::GetGpuEigenDevice() const {
|
||||
return gpu_eigen_device_.get();
|
||||
}
|
||||
|
||||
std::function<Eigen::GpuDevice*()>
|
||||
GPUContextResource::GetGpuEigenDeviceCreator() {
|
||||
return [&]() {
|
||||
InitGpuEigenDevice();
|
||||
return gpu_eigen_device_.get();
|
||||
};
|
||||
}
|
||||
|
||||
int GPUContextResource::GetGpuComputeCapability() const {
|
||||
return compute_capability_;
|
||||
}
|
||||
|
||||
int GPUContextResource::GetGpuRuntimeVersion() const {
|
||||
return runtime_version_;
|
||||
}
|
||||
|
||||
int GPUContextResource::GetGpuDriverVersion() const { return driver_version_; }
|
||||
|
||||
int GPUContextResource::GetGPUMultiProcessors() const { return multi_process_; }
|
||||
|
||||
int GPUContextResource::GetGpuMaxThreadsPerMp() const {
|
||||
return max_threads_per_mp_;
|
||||
}
|
||||
|
||||
int GPUContextResource::GetGpuMaxThreadsPerBlock() const {
|
||||
return max_threads_per_block_;
|
||||
}
|
||||
|
||||
std::array<unsigned int, 3> GPUContextResource::GetGpuMaxGridDimSize() const {
|
||||
return max_grid_dim_size_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ResourceManager& ResourceManager::Instance() {
|
||||
static ResourceManager* resource_manager = new ResourceManager;
|
||||
return *resource_manager;
|
||||
}
|
||||
|
||||
void ResourceManager::InitCPUResource() {
|
||||
std::lock_guard<std::mutex> lock_guard(cpu_mutex_);
|
||||
if (cpu_resource_ == nullptr) {
|
||||
cpu_resource_ = std::make_unique<CPUContextResource>();
|
||||
}
|
||||
}
|
||||
|
||||
CPUContextResource* ResourceManager::GetCPUResource() const {
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
cpu_resource_.get(),
|
||||
common::errors::PreconditionNotMet("cpu_resource should be not null!"));
|
||||
return cpu_resource_.get();
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
void* ResourceManager::InitGPUResource(const phi::Place& place, void* stream) {
|
||||
std::lock_guard<std::mutex> lock_guard(gpu_mutex_);
|
||||
if (gpu_resources_.count(stream)) {
|
||||
Increase(stream);
|
||||
return stream;
|
||||
} else {
|
||||
std::unique_ptr<GPUContextResource> resource{
|
||||
new GPUContextResource(place, stream)};
|
||||
gpuStream_t s = resource->GetStream();
|
||||
ref_count_[s] = 1;
|
||||
gpu_resources_.emplace(s, std::move(resource));
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::DestroyGPUResource(void* stream) {
|
||||
PADDLE_ENFORCE_EQ(gpu_resources_.count(stream),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"The stream[%p] not found in gpu_resources.", stream));
|
||||
Decrease(stream);
|
||||
}
|
||||
|
||||
void ResourceManager::Decrease(void* stream) {
|
||||
if (ref_count_.count(stream) == 0) return;
|
||||
--ref_count_[stream];
|
||||
|
||||
if (ref_count_[stream] == 0) {
|
||||
ref_count_.erase(stream);
|
||||
if (gpu_resources_.count(stream) > 0) gpu_resources_.erase(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceManager::Increase(void* stream) { ++ref_count_[stream]; }
|
||||
|
||||
GPUContextResource* ResourceManager::GetGPUResource(void* stream) const {
|
||||
PADDLE_ENFORCE_EQ(gpu_resources_.count(stream),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"The stream[%p] not found in gpu_resources.", stream));
|
||||
return gpu_resources_.at(stream).get();
|
||||
}
|
||||
|
||||
void ResourceManager::GpuResourceSwitchStream(void* old_stream,
|
||||
void* new_stream) {
|
||||
// NOTE: add lock to support stream rebind in multi-thread
|
||||
std::lock_guard<std::mutex> lock_guard(gpu_mutex_);
|
||||
if (old_stream == new_stream) return;
|
||||
PADDLE_ENFORCE_EQ(
|
||||
gpu_resources_.count(old_stream),
|
||||
true,
|
||||
common::errors::InvalidArgument(
|
||||
"The stream[%p] not found in gpu_resources.", old_stream));
|
||||
|
||||
// NOTE: stream may be used by multiple predictor, skip resource
|
||||
// operation if resource of new_stream is already exists
|
||||
bool new_stream_existed = gpu_resources_.count(new_stream) > 0;
|
||||
if (!new_stream_existed) {
|
||||
auto place = gpu_resources_.at(old_stream)->Place();
|
||||
std::unique_ptr<GPUContextResource> resource{
|
||||
new GPUContextResource(place, new_stream)};
|
||||
gpu_resources_.emplace(new_stream, std::move(resource));
|
||||
}
|
||||
|
||||
Decrease(old_stream);
|
||||
Increase(new_stream);
|
||||
}
|
||||
|
||||
int ResourceManager::RefCount(void* stream) const {
|
||||
if (ref_count_.count(stream) == 0) return 0;
|
||||
return ref_count_.at(stream);
|
||||
}
|
||||
#endif
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2022 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 <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
#include "paddle/phi/api/include/tensor.h"
|
||||
#include "paddle/phi/backends/cpu/forwards.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/device_context.h"
|
||||
#include "paddle/utils/test_macros.h"
|
||||
#include "unsupported/Eigen/CXX11/Tensor"
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
#include "paddle/phi/backends/gpu/forwards.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_decls.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_resources.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_types.h"
|
||||
#endif
|
||||
|
||||
namespace paddle {
|
||||
namespace internal {
|
||||
class EigenGpuStreamDevice;
|
||||
} // namespace internal
|
||||
|
||||
class CPUContextResource {
|
||||
public:
|
||||
CPUContextResource();
|
||||
Eigen::DefaultDevice* GetCPUEigenDevice() const;
|
||||
|
||||
private:
|
||||
void InitCPUResource();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Eigen::DefaultDevice> cpu_eigen_device_;
|
||||
};
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
class GPUContextResource {
|
||||
public:
|
||||
explicit GPUContextResource(const phi::Place& place, void* stream);
|
||||
TEST_API ~GPUContextResource();
|
||||
phi::Place Place() const;
|
||||
|
||||
std::function<phi::dnnHandle_t()> GetDnnHandleCreator();
|
||||
std::function<phi::blasHandle_t()> GetBlasHandleCreator();
|
||||
std::function<phi::blasHandle_t()> GetBlasTensorCoreHandleCreator();
|
||||
std::function<phi::blasHandle_t()> GetBlasTF32TensorCoreHandleCreator();
|
||||
std::function<phi::blasLtHandle_t()> GetBlasLtHandleCreator();
|
||||
std::function<phi::solverHandle_t()> GetSolverDnHandleCreator();
|
||||
std::function<phi::sparseHandle_t()> GetSparseHandleCreator();
|
||||
std::function<Eigen::GpuDevice*()> GetGpuEigenDeviceCreator();
|
||||
|
||||
gpuStream_t GetStream() const;
|
||||
dnnHandle_t GetDnnHandle() const;
|
||||
blasHandle_t GetBlasHandle() const;
|
||||
blasHandle_t GetBlasTensorCoreHandle() const;
|
||||
blasHandle_t GetBlasTF32Handle() const;
|
||||
blasLtHandle_t GetBlasLtHandle() const;
|
||||
phi::solverHandle_t GetSolverDnHandle() const;
|
||||
phi::sparseHandle_t GetSparseHandle() const;
|
||||
Eigen::GpuDevice* GetGpuEigenDevice() const;
|
||||
int GetGpuComputeCapability() const;
|
||||
int GetGpuRuntimeVersion() const;
|
||||
int GetGpuDriverVersion() const;
|
||||
int GetGPUMultiProcessors() const;
|
||||
int GetGpuMaxThreadsPerMp() const;
|
||||
int GetGpuMaxThreadsPerBlock() const;
|
||||
std::array<unsigned int, 3> GetGpuMaxGridDimSize() const;
|
||||
|
||||
private:
|
||||
void InitGPUResource(void* stream);
|
||||
void DestroyGPUResource();
|
||||
void InitGpuProperties();
|
||||
void InitGpuEigenDevice();
|
||||
void InitDnnHandle();
|
||||
void DestroyDnnHandle();
|
||||
void DestroyBlasHandle();
|
||||
void InitBlasLtHandle();
|
||||
void DestroyBlasLtHandle();
|
||||
void InitSolverHandle();
|
||||
void DestroySolverHandle();
|
||||
void InitSparseHandle();
|
||||
void DestroySparseHandle();
|
||||
|
||||
private:
|
||||
phi::Place place_;
|
||||
|
||||
int compute_capability_;
|
||||
int runtime_version_;
|
||||
int driver_version_;
|
||||
int multi_process_;
|
||||
int max_threads_per_mp_;
|
||||
int max_threads_per_block_;
|
||||
std::array<unsigned int, 3> max_grid_dim_size_;
|
||||
|
||||
bool owned_stream_{true};
|
||||
gpuStream_t stream_;
|
||||
std::unique_ptr<Eigen::GpuDevice> gpu_eigen_device_;
|
||||
std::unique_ptr<internal::EigenGpuStreamDevice> eigen_stream_;
|
||||
|
||||
blasHandle_t blas_handle_{nullptr};
|
||||
blasHandle_t blas_tensor_core_handle_{nullptr};
|
||||
blasHandle_t blas_tf32_tensor_core_handle_{nullptr};
|
||||
blasLtHandle_t blaslt_handle_{nullptr};
|
||||
dnnHandle_t dnn_handle_{nullptr};
|
||||
phi::solverHandle_t solver_handle_{nullptr};
|
||||
phi::sparseHandle_t sparse_handle_{nullptr};
|
||||
// DnnWorkspaceHandle
|
||||
};
|
||||
#endif
|
||||
|
||||
class ResourceManager {
|
||||
public:
|
||||
ResourceManager() = default;
|
||||
TEST_API static ResourceManager& Instance();
|
||||
|
||||
// CPU Resource
|
||||
public:
|
||||
void InitCPUResource();
|
||||
CPUContextResource* GetCPUResource() const;
|
||||
|
||||
private:
|
||||
std::mutex cpu_mutex_;
|
||||
std::unique_ptr<CPUContextResource> cpu_resource_{nullptr};
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
// GPU Resource
|
||||
public:
|
||||
void* InitGPUResource(const phi::Place& place, void* stream);
|
||||
void DestroyGPUResource(void* stream);
|
||||
TEST_API GPUContextResource* GetGPUResource(void* stream) const;
|
||||
TEST_API int RefCount(void* stream) const;
|
||||
void GpuResourceSwitchStream(void* old_stream, void* new_stream);
|
||||
|
||||
private:
|
||||
void Decrease(void* stream);
|
||||
void Increase(void* stream);
|
||||
|
||||
private:
|
||||
std::mutex gpu_mutex_;
|
||||
// a stream corresponding to a series of resource.
|
||||
std::map<void* /*stream*/, std::atomic<int>> ref_count_;
|
||||
std::map<void* /*stream*/, std::unique_ptr<GPUContextResource>>
|
||||
gpu_resources_;
|
||||
#endif
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN(ResourceManager);
|
||||
};
|
||||
|
||||
} // namespace paddle
|
||||
Reference in New Issue
Block a user