paddle_api.h 10.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 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

16 17 18
/*! \file paddle_api.h
 */

Y
Yan Chunwei 已提交
19 20 21 22 23 24
/*! \mainpage Paddle Inference APIs
 * \section intro_sec Introduction
 * The Paddle inference library aims to offer an high performance inference SDK
 * for Paddle users.
 */

25
#include <cassert>
26
#include <map>
27 28 29 30
#include <memory>
#include <string>
#include <vector>

31 32
/*! \namespace paddle
 */
33 34
namespace paddle {

35 36
/** paddle data type.
 */
37 38 39
enum PaddleDType {
  FLOAT32,
  INT64,
40
  INT32,
41
  UINT8,
42 43 44
  // TODO(Superjomn) support more data types if needed.
};

45
/**
Y
Yan Chunwei 已提交
46
 * \brief Memory manager for `PaddleTensor`.
47
 *
Y
Yan Chunwei 已提交
48 49 50
 * 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.
51
 *
Y
Yan Chunwei 已提交
52 53 54 55
 * 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
56
 *memory.
Y
Yan Chunwei 已提交
57
 * ATTENTION, for user allocated memory, deallocation should be done by users
58 59 60
 *externally after the program finished. The PaddleBuf won't do any allocation
 *or deallocation.
 *
Y
Yan Chunwei 已提交
61 62 63
 * 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
64
 *  if the allocated memory is larger than `length`, nothing will done.
Y
Yan Chunwei 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
 *
 * 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
89 90 91
 */
class PaddleBuf {
 public:
92 93
  /** PaddleBuf allocate memory internally, and manage it.
   */
94 95
  explicit PaddleBuf(size_t length)
      : data_(new char[length]), length_(length), memory_owned_(true) {}
96 97
  /** Set external memory, the PaddleBuf won't manage it.
   */
98 99
  PaddleBuf(void* data, size_t length)
      : data_(data), length_(length), memory_owned_{false} {}
100 101
  /** Copy only available when memory is managed externally.
   */
102 103
  explicit PaddleBuf(const PaddleBuf&);

104 105
  /** Resize the memory.
   */
106
  void Resize(size_t length);
107 108
  /** Reset to external memory, with address and length set.
   */
109
  void Reset(void* data, size_t length);
110 111
  /** Tell whether the buffer is empty.
   */
112
  bool empty() const { return length_ == 0; }
Y
Yan Chunwei 已提交
113
  /** Get the data's memory address.
114
   */
115
  void* data() const { return data_; }
116 117
  /** Get the memory length.
   */
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
  size_t length() const { return length_; }

  ~PaddleBuf() { Free(); }
  PaddleBuf& operator=(const PaddleBuf&);
  PaddleBuf& operator=(PaddleBuf&&);
  PaddleBuf() = default;
  PaddleBuf(PaddleBuf&& other);

 private:
  void Free();
  void* data_{nullptr};  // pointer to the data memory.
  size_t length_{0};     // number of memory bytes.
  bool memory_owned_{true};
};

133 134
/** Basic input and output data structure for PaddlePredictor.
 */
135 136 137 138 139 140 141 142 143 144
struct 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 LoDTensor
};

enum class PaddlePlace { kUNK = -1, kCPU, kGPU };
Y
Yan Chunwei 已提交
145 146

/** Tensor without copy, currently only supports `AnalysisPredictor`.
147
 */
148 149 150 151
class ZeroCopyTensor {
 public:
  void Reshape(const std::vector<int>& shape);

152 153
  /** Get the memory in CPU or GPU with specific data type, should Reshape first
   * to tell the data size.
154 155
   * One can directly call this data to feed the data.
   * This is for writing the input tensor.
156
   */
157 158
  template <typename T>
  T* mutable_data(PaddlePlace place);
T
tensor-tang 已提交
159 160
  /** Get the memory directly, will return the place and element size by
   * pointer.
161 162
   * This is for reading the output tensor.
   */
163 164 165
  template <typename T>
  T* data(PaddlePlace* place, int* size) const;

N
nhzlx 已提交
166 167 168 169 170 171 172
  template <typename T>
  void copy_from_cpu(const T* data);

  template <typename T>
  void copy_to_cpu(T* data);

  std::vector<int> shape() const;
173 174 175 176

  void SetLoD(const std::vector<std::vector<size_t>>& x);
  std::vector<std::vector<size_t>> lod() const;
  const std::string& name() const { return name_; }
N
nhzlx 已提交
177 178 179 180
  void SetPlace(PaddlePlace place, int device = -1) {
    place_ = place;
    device_ = device;
  }
181

N
nhzlx 已提交
182
  PaddleDType type() const;
183

184 185 186 187 188 189 190 191 192 193
 protected:
  explicit ZeroCopyTensor(void* scope) : scope_{scope} {}
  void SetName(const std::string& name) { name_ = name; }
  void* FindTensor() const;

 private:
  std::string name_;
  bool input_or_output_;
  friend class AnalysisPredictor;
  void* scope_{nullptr};
194 195 196
  // The corresponding tensor pointer inside Paddle workspace is cached for
  // performance.
  mutable void* tensor_{nullptr};
N
nhzlx 已提交
197
  PaddlePlace place_;
198
  PaddleDType dtype_;
N
nhzlx 已提交
199
  int device_;
200 201
};

202
/** A simple Inference API for Paddle.
203 204 205 206 207 208 209 210
 */
class PaddlePredictor {
 public:
  struct Config;
  PaddlePredictor() = default;
  PaddlePredictor(const PaddlePredictor&) = delete;
  PaddlePredictor& operator=(const PaddlePredictor&) = delete;

211 212 213 214 215 216
  /** Predict an record.
   * The caller should be responsible for allocating and releasing the memory of
   * `inputs`. `inputs` should be available until Run returns. Caller should be
   * responsible for the output tensor's buffer, either allocated or passed from
   * outside.
   */
217 218 219 220
  virtual bool Run(const std::vector<PaddleTensor>& inputs,
                   std::vector<PaddleTensor>* output_data,
                   int batch_size = -1) = 0;

N
nhzlx 已提交
221 222 223 224
  /** \brief Get input names of the model
   */
  virtual std::vector<std::string> GetInputNames() { return {}; }

225 226 227 228 229 230
  /** \brief Get input shapes of the model
   */
  virtual std::map<std::string, std::vector<int64_t>> GetInputTensorShape() {
    return {};
  }

N
nhzlx 已提交
231 232 233 234
  /** \brief Get output names of the model
   */
  virtual std::vector<std::string> GetOutputNames() { return {}; }

235 236 237 238 239 240 241
  /** \brief Get a mutable tensor directly.
   *
   * NOTE Only works in AnalysisPredictor.
   *
   * One can also use this to modify any temporary variable related tensors in
   * the predictor.
   *
242
   */
243 244 245 246
  virtual std::unique_ptr<ZeroCopyTensor> GetInputTensor(
      const std::string& name) {
    return nullptr;
  }
247 248 249 250 251 252 253
  /**
   * \brief Get an immutable tensor without copy.
   *
   * NOTE Only works in AnalysisPredictor.
   * One can use this API to get any temporary tensors in the predictor and
   * read it.
   */
254 255 256 257
  virtual std::unique_ptr<ZeroCopyTensor> GetOutputTensor(
      const std::string& name) {
    return nullptr;
  }
258 259 260 261 262 263 264 265 266 267 268
  /**
   * \brief Run the predictor with zero-copied inputs and outputs.
   *
   * NOTE Only works in AnalysisPredictor.
   *
   * This will save the IO copy for transfering inputs and outputs to predictor
   * workspace and get some performance improvement.
   * To use it, one should call the `AnalysisConfig.SwitchUseFeedFetchOp(true)`
   * and then use the `GetInputTensor` and `GetOutputTensor` to directly write
   * or read the input/output tensors.
   */
269 270
  virtual bool ZeroCopyRun() { return false; }

271 272 273
  /** Clone a predictor that share the model weights, the Cloned predictor
   * should be thread-safe.
   */
274 275
  virtual std::unique_ptr<PaddlePredictor> Clone() = 0;

276 277
  /** Destroy the Predictor.
   */
278 279
  virtual ~PaddlePredictor() = default;

Y
Yan Chunwei 已提交
280 281 282
  /** \brief Get the serialized model program that executes in inference phase.
   * Its data type is ProgramDesc, which is a protobuf message.
   */
283
  virtual std::string GetSerializedProgram() const {
Y
Yan Chunwei 已提交
284 285
    assert(false);  // Force raise error.
    return "NotImplemented";
286
  }
Y
Yan Chunwei 已提交
287

288 289
  /** The common configs for all the predictors.
   */
290
  struct Config {
291
    std::string model_dir; /*!< path to the model directory. */
292 293 294 295 296 297 298
  };
};

struct NativeConfig : public PaddlePredictor::Config {
  // GPU related fields.
  bool use_gpu{false};
  int device{0};
299 300
  float fraction_of_gpu_memory{
      -1.f}; /*!< Change to a float in (0,1] if needed. */
301 302 303 304 305

  // Specify the exact path of program and parameter files.
  std::string prog_file;
  std::string param_file;

306 307 308 309
  /** Specify the variable's name of each input if input tensors don't follow
   * the
   * `feeds` and `fetches` of the phase `save_inference_model`.
   */
310
  bool specify_input_name{false};
L
luotao1 已提交
311

312 313
  /** Set and get the number of cpu math library threads.
   */
L
luotao1 已提交
314 315 316 317 318
  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_;
L
luotao1 已提交
319 320 321
  }

 protected:
L
luotao1 已提交
322 323 324
  // number of cpu math library (such as MKL, OpenBlas) threads for each
  // instance.
  int cpu_math_library_num_threads_{1};
325 326
};

327 328 329 330 331 332 333
/*! \fn std::unique_ptr<PaddlePredictor> CreatePaddlePredictor(const ConfigT&
 * config);
 *
 * \brief A factory to help create different predictors.
 *
 * Usage:
 *
Y
Yan Chunwei 已提交
334
 * \code{.cpp}
335 336 337
 * NativeConfig config;
 * ... // change the configs.
 * auto native_predictor = CreatePaddlePredictor(config);
Y
Yan Chunwei 已提交
338
 * \endcode
339 340 341 342 343 344
 *
 * 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.
 */
345 346 347
template <typename ConfigT>
std::unique_ptr<PaddlePredictor> CreatePaddlePredictor(const ConfigT& config);

348 349 350
/** NOTE The following APIs are too trivial, we will discard it in the following
 * versions.
 */
351
enum class PaddleEngineKind {
352 353 354 355
  kNative = 0,        /*!< Use the native Fluid facility. */
  kAutoMixedTensorRT, /*!< Automatically mix Fluid with TensorRT. */
  kAnalysis,          /*!< More optimization. */
  kAnakin             /*!< Use Anakin for inference, not mature yet. */
356 357 358 359 360 361 362
};

template <typename ConfigT, PaddleEngineKind engine>
std::unique_ptr<PaddlePredictor> CreatePaddlePredictor(const ConfigT& config);

int PaddleDtypeSize(PaddleDType dtype);

Y
Yan Chunwei 已提交
363 364
std::string get_version();

365
}  // namespace paddle