eager_utils.h 11.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/* 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

13 14 15 16 17
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif

18
#include <Python.h>
19

20
#include "paddle/fluid/eager/hooks.h"
21
#include "paddle/fluid/framework/lod_tensor.h"
22
#include "paddle/fluid/framework/lod_tensor_array.h"
23
#include "paddle/fluid/framework/tensor.h"
24
#include "paddle/fluid/jit/function.h"
25
#include "paddle/fluid/platform/place.h"
26 27
#include "paddle/phi/common/backend.h"
#include "paddle/phi/common/data_type.h"
28
#include "paddle/phi/common/int_array.h"
29
#include "paddle/phi/common/scalar.h"
30
#include "paddle/phi/core/dense_tensor.h"
31
#include "paddle/phi/core/selected_rows.h"
32 33 34
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
namespace paddle {
35
class CustomOpKernelContext;
0
0x45f 已提交
36 37 38
namespace framework {
class Scope;
}
39 40
namespace pybind {

41
namespace py = ::pybind11;
42 43 44 45
#define RETURN_PY_NONE \
  Py_INCREF(Py_None);  \
  return Py_None;

46
int TensorDtype2NumpyDtype(phi::DataType dtype);
47

W
wanghuancoder 已提交
48 49
bool IsEagerTensor(PyObject* obj);

50 51 52 53 54 55
bool PyObject_CheckLongOrConvertToLong(PyObject** obj);
bool PyObject_CheckFloatOrConvertToFloat(PyObject** obj);
bool PyObject_CheckStr(PyObject* obj);
bool CastPyArg2AttrBoolean(PyObject* obj, ssize_t arg_pos);
int CastPyArg2AttrInt(PyObject* obj, ssize_t arg_pos);
int64_t CastPyArg2AttrLong(PyObject* obj, ssize_t arg_pos);
W
wanghuancoder 已提交
56
size_t CastPyArg2AttrSize_t(PyObject* obj, ssize_t arg_pos);
57 58
float CastPyArg2AttrFloat(PyObject* obj, ssize_t arg_pos);
std::string CastPyArg2AttrString(PyObject* obj, ssize_t arg_pos);
59 60
paddle::CustomOpKernelContext CastPyArg2CustomOpKernelContext(PyObject* obj,
                                                              ssize_t arg_pos);
61
paddle::experimental::Tensor CastPyArg2Tensor(PyObject* obj, ssize_t arg_pos);
J
Jiabin Yang 已提交
62 63
std::shared_ptr<imperative::VarBase> CastPyArg2VarBase(PyObject* obj,
                                                       ssize_t arg_pos);
64 65
std::vector<paddle::experimental::Tensor> CastPyArg2VectorOfTensor(
    PyObject* obj, ssize_t arg_pos);
66
platform::Place CastPyArg2Place(PyObject* obj, ssize_t arg_pos);
67
phi::DenseTensor CastPyArg2FrameworkTensor(PyObject* obj, ssize_t arg_pos);
68 69
std::vector<phi::DenseTensor> CastPyArg2VectorOfTensorBase(PyObject* obj,
                                                           ssize_t arg_pos);
70
std::vector<int> CastPyArg2VectorOfInt(PyObject* obj, size_t arg_pos);
W
wanghuancoder 已提交
71 72 73
std::vector<size_t> CastPyArg2VectorOfSize_t(PyObject* obj, size_t arg_pos);
std::vector<std::vector<size_t>> CastPyArg2VectorOfVectorOfSize_t(
    PyObject* obj, size_t arg_pos);
J
Jiabin Yang 已提交
74 75
framework::proto::VarType::Type CastPyArg2ProtoType(PyObject* obj,
                                                    ssize_t arg_pos);
76 77 78
std::unordered_map<std::wstring, int> CastPyArg2Vocab(PyObject* obj,
                                                      ssize_t arg_pos);
std::vector<std::string> CastPyArg2Strings(PyObject* obj, ssize_t arg_pos);
79 80
std::shared_ptr<jit::Function> CastPyArg2JitFunction(PyObject* obj,
                                                     ssize_t arg_pos);
81

82
PyObject* ToPyObject(int value);
83
PyObject* ToPyObject(uint32_t value);
84 85
PyObject* ToPyObject(bool value);
PyObject* ToPyObject(int64_t value);
W
wanghuancoder 已提交
86
PyObject* ToPyObject(size_t value);
87 88 89 90
PyObject* ToPyObject(float value);
PyObject* ToPyObject(double value);
PyObject* ToPyObject(const char* value);
PyObject* ToPyObject(const std::string& value);
W
wanghuancoder 已提交
91 92
PyObject* ToPyObject(const paddle::experimental::Tensor& value,
                     bool return_py_none_if_not_initialize = false);
93
PyObject* ToPyObject(const paddle::experimental::Tensor& value,
94
                     PyObject* args,
95 96
                     const std::map<ssize_t, ssize_t>& inplace_var_idx_map);
PyObject* ToPyObject(PyObject* args, ssize_t arg_idx);
97 98 99
PyObject* ToPyObject(const std::vector<bool>& value);
PyObject* ToPyObject(const std::vector<int>& value);
PyObject* ToPyObject(const std::vector<int64_t>& value);
W
wanghuancoder 已提交
100
PyObject* ToPyObject(const std::vector<size_t>& value);
101 102
PyObject* ToPyObject(const std::vector<float>& value);
PyObject* ToPyObject(const std::vector<double>& value);
W
wanghuancoder 已提交
103
PyObject* ToPyObject(const std::vector<std::vector<size_t>>& value);
104 105
PyObject* ToPyObject(const std::vector<paddle::experimental::Tensor>& value,
                     bool return_py_none_if_not_initialize = false);
106
PyObject* ToPyObject(const platform::Place& value);
107
PyObject* ToPyObject(const phi::DenseTensor* value);
108
PyObject* ToPyObject(const phi::SelectedRows* value);
J
Jiabin Yang 已提交
109
PyObject* ToPyObject(const paddle::framework::proto::VarType::Type& dtype);
110
PyObject* ToPyObject(const paddle::framework::proto::VarType& type);
W
wanghuancoder 已提交
111
PyObject* ToPyObject(const void* value);
112 113
PyObject* ToPyObject(
    const std::unordered_map<std::string, std::vector<std::string>>& value);
114
PyObject* ToPyObject(const std::unordered_map<std::wstring, int>& value);
115

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
class PyTensorHook : public egr::TensorHook {
 public:
  explicit PyTensorHook(PyObject* func) : py_func_(func) {
    Py_INCREF(py_func_);
  }

  ~PyTensorHook() {
    py::gil_scoped_acquire gil;
    Py_DECREF(py_func_);
  }

  paddle::experimental::Tensor operator()(
      const paddle::experimental::Tensor& var) override;

 private:
  PyObject* py_func_;
};

class PyVoidHook : public egr::VoidHook {
 public:
  explicit PyVoidHook(PyObject* func) : py_func_(func) { Py_INCREF(py_func_); }

  ~PyVoidHook() {
    py::gil_scoped_acquire gil;
    Py_DECREF(py_func_);
  }

  void operator()() override;

 private:
  PyObject* py_func_;
};

149
template <typename Tuple, size_t N>
150
struct TupleTensorResult {
151
  static void Run(const Tuple& out, PyObject* result) {
152
    TupleTensorResult<Tuple, N - 1>::Run(out, result);
153 154
    PyTuple_SET_ITEM(result, N - 1, ToPyObject(std::get<N - 1>(out)));
  }
155

156 157 158
  static void Run(const Tuple& out,
                  PyObject* result,
                  PyObject* args,
159 160 161 162
                  const std::map<ssize_t, ssize_t>& inplace_var_idx_map) {
    TupleTensorResult<Tuple, N - 1>::Run(
        out, result, args, inplace_var_idx_map);
    if (!inplace_var_idx_map.empty() && inplace_var_idx_map.count(N - 1)) {
163
      PyTuple_SET_ITEM(
164
          result, N - 1, ToPyObject(args, inplace_var_idx_map.at(N - 1)));
165 166 167 168
    } else {
      PyTuple_SET_ITEM(result, N - 1, ToPyObject(std::get<N - 1>(out)));
    }
  }
169 170 171
};

template <typename Tuple>
172
struct TupleTensorResult<Tuple, 1> {
173 174 175
  static void Run(const Tuple& out, PyObject* result) {
    PyTuple_SET_ITEM(result, 0, ToPyObject(std::get<0>(out)));
  }
176

177 178 179
  static void Run(const Tuple& out,
                  PyObject* result,
                  PyObject* args,
180 181 182
                  const std::map<ssize_t, ssize_t>& inplace_var_idx_map) {
    if (!inplace_var_idx_map.empty() && inplace_var_idx_map.count(0)) {
      PyTuple_SET_ITEM(result, 0, ToPyObject(args, inplace_var_idx_map.at(0)));
183 184 185 186
    } else {
      PyTuple_SET_ITEM(result, 0, ToPyObject(std::get<0>(out)));
    }
  }
187 188 189 190 191 192 193
};

template <typename... Args>
PyObject* ToPyObject(const std::tuple<Args...>& out) {
  auto len = sizeof...(Args);
  PyObject* result = PyTuple_New(len);

194
  TupleTensorResult<decltype(out), sizeof...(Args)>::Run(out, result);
195 196 197 198

  return result;
}

199
template <typename... Args>
200 201
PyObject* ToPyObject(const std::tuple<Args...>& out,
                     PyObject* args,
202
                     const std::map<ssize_t, ssize_t>& inplace_var_idx_map) {
203 204 205 206
  // For inplace op, directly return the input PyObject of the inplace tensor.
  // [Parameter]
  // out: Outputs tuple after executing op.
  // args: Input PyObject.
207 208 209 210 211
  // inplace_var_idx_map: Index of Tensors in inplace_map, e.g. {{value_idx,
  // arg_idx}}.
  // - value_idx: Index of inplace tensor in outputs tuple. Used to find the
  // output inplace tensor.
  // - arg_idx: Index of inplace PyObject in input args. Used to find the input
212 213 214 215
  // inplace PyObject.
  auto len = sizeof...(Args);
  PyObject* result = PyTuple_New(len);

216
  TupleTensorResult<decltype(out), sizeof...(Args)>::Run(
217
      out, result, args, inplace_var_idx_map);
218 219 220 221

  return result;
}

222 223 224 225
paddle::experimental::Scalar CastPyArg2Scalar(PyObject* obj,
                                              const std::string& op_type,
                                              ssize_t arg_pos);

226 227 228 229
paddle::experimental::Scalar CastNumpy2Scalar(PyObject* obj,
                                              const std::string& op_type,
                                              ssize_t arg_pos);

230 231 232 233
std::vector<phi::Scalar> CastPyArg2ScalarArray(PyObject* obj,
                                               const std::string& op_type,
                                               ssize_t arg_pos);

234 235 236
paddle::experimental::IntArray CastPyArg2IntArray(PyObject* obj,
                                                  const std::string& op_type,
                                                  ssize_t arg_pos);
237

238 239
paddle::Place CastPyArg2Place(PyObject* obj,
                              const std::string& op_type,
240
                              ssize_t arg_pos);
241

242 243
paddle::DataType CastPyArg2DataType(PyObject* obj,
                                    const std::string& op_type,
244
                                    ssize_t arg_pos);
245

246
paddle::optional<paddle::experimental::Tensor> GetOptionalTensorFromArgs(
247 248 249 250 251
    const std::string& op_type,
    const std::string& arg_name,
    PyObject* args,
    ssize_t arg_idx,
    bool dispensable = false);
252

253 254
paddle::experimental::Tensor& GetTensorFromArgs(const std::string& op_type,
                                                const std::string& arg_name,
255 256
                                                PyObject* args,
                                                ssize_t arg_idx,
257
                                                bool dispensable = false);
258

259 260 261 262 263 264 265
paddle::optional<std::vector<paddle::experimental::Tensor>>
GetOptionalTensorListFromArgs(const std::string& op_type,
                              const std::string& arg_name,
                              PyObject* args,
                              ssize_t arg_idx,
                              bool dispensable = false);

266
std::vector<paddle::experimental::Tensor> GetTensorListFromArgs(
267 268 269 270 271
    const std::string& op_type,
    const std::string& arg_name,
    PyObject* args,
    ssize_t arg_idx,
    bool dispensable = false);
272

273 274 275 276 277
paddle::experimental::Tensor* GetTensorPtrFromArgs(const std::string& op_type,
                                                   const std::string& arg_name,
                                                   PyObject* args,
                                                   ssize_t arg_idx,
                                                   bool dispensable = false);
278

279
std::vector<paddle::experimental::Tensor*> GetTensorPtrListFromArgs(
280 281 282 283 284
    const std::string& op_type,
    const std::string& arg_name,
    PyObject* args,
    ssize_t arg_idx,
    bool dispensable = false);
285

W
wanghuancoder 已提交
286 287 288 289 290 291 292 293
std::vector<paddle::experimental::Tensor*> GetTensorPtrListFromPyObject(
    PyObject* obj);

std::vector<paddle::experimental::Tensor> GetTensorListFromPyObject(
    PyObject* obj);

paddle::experimental::Tensor& GetTensorFromPyObject(PyObject* obj);

J
Jiabin Yang 已提交
294
// end of Slice related methods
295

0
0x45f 已提交
296
std::vector<paddle::framework::Scope*> GetScopePtrListFromArgs(
297 298 299 300 301
    const std::string& op_type,
    const std::string& arg_name,
    PyObject* args,
    ssize_t arg_idx,
    bool dispensable);
J
Jiabin Yang 已提交
302

303 304 305 306 307 308 309 310 311 312 313 314
class eager_gil_scoped_release {
 public:
  eager_gil_scoped_release() { tstate = PyEval_SaveThread(); }
  ~eager_gil_scoped_release() {
    if (!tstate) return;
    PyEval_RestoreThread(tstate);
  }

 private:
  PyThreadState* tstate{nullptr};
};

315 316
}  // namespace pybind
}  // namespace paddle