zero_copy_tensor.cc 13.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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.

15
#include "paddle/fluid/framework/data_layout_transform.h"
16 17 18
#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/inference/api/paddle_inference_api.h"
W
Wilber 已提交
19
#include "paddle/fluid/inference/api/paddle_tensor.h"
N
nhzlx 已提交
20
#include "paddle/fluid/memory/memcpy.h"
21 22
#include "paddle/fluid/platform/enforce.h"

23
namespace paddle_infer {
24

25
void Tensor::Reshape(const std::vector<int> &shape) {
W
Wilber 已提交
26 27
  PADDLE_ENFORCE_EQ(
      name_.empty(), false,
28
      paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
29 30 31
          "Need to SetName first, so that the corresponding tensor can "
          "be retrieved."));
  PADDLE_ENFORCE_EQ(input_or_output_, true,
32
                    paddle::platform::errors::PermissionDenied(
W
Wilber 已提交
33
                        "Can't reshape the output tensor, it is readonly"));
34
  auto *scope = static_cast<paddle::framework::Scope *>(scope_);
35
  auto *var = scope->FindVar(name_);
W
Wilber 已提交
36
  PADDLE_ENFORCE_NOT_NULL(
37
      var, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
38
               "No tensor called [%s] in the runtime scope", name_));
39 40
  auto *tensor = var->GetMutable<paddle::framework::LoDTensor>();
  tensor->Resize(paddle::framework::make_ddim(shape));
41 42
}

43 44 45 46
#define EAGER_GET_TENSOR    \
  if (!tensor_) {           \
    tensor_ = FindTensor(); \
  }                         \
47
  auto *tensor = static_cast<paddle::framework::LoDTensor *>(tensor_);
48

49
template <typename T>
50
T *Tensor::mutable_data(PlaceType place) {
51
  EAGER_GET_TENSOR;
52 53
  PADDLE_ENFORCE_GT(
      tensor->numel(), 0,
54 55
      paddle::platform::errors::PreconditionNotMet(
          "You should call Tensor::Reshape(const std::vector<int> "
W
Wilber 已提交
56 57
          "&shape)"
          "function before retrieving mutable_data from input tensor."));
58
  switch (static_cast<int>(place)) {
59 60
    case static_cast<int>(PlaceType::kCPU): {
      return tensor->mutable_data<T>(paddle::platform::CPUPlace());
61
    }
62 63 64 65 66
    case static_cast<int>(PlaceType::kGPU): {
      return tensor->mutable_data<T>(paddle::platform::CUDAPlace(device_));
    }
    case static_cast<int>(PlaceType::kXPU): {
      return tensor->mutable_data<T>(paddle::platform::XPUPlace(device_));
67
    }
68 69 70
    case static_cast<int>(PlaceType::kNPU): {
      return tensor->mutable_data<T>(paddle::platform::NPUPlace(device_));
    }
71
    default:
72
      PADDLE_THROW(paddle::platform::errors::Unavailable(
73 74
          "Only CPU / CUDA / XPU / NPU places is supported. The place `%d` is "
          "not supported.",
75
          static_cast<int>(place)));
76 77 78 79 80 81
      break;
  }
  return nullptr;
}

template <typename T>
82
T *Tensor::data(PlaceType *place, int *size) const {
83
  EAGER_GET_TENSOR;
84 85
  auto *res = tensor->data<T>();

86 87 88 89 90 91
  if (paddle::platform::is_cpu_place(tensor->place())) {
    *place = PlaceType::kCPU;
  } else if (paddle::platform::is_gpu_place(tensor->place())) {
    *place = PlaceType::kGPU;
  } else if (paddle::platform::is_xpu_place(tensor->place())) {
    *place = PlaceType::kXPU;
92 93
  } else if (paddle::platform::is_npu_place(tensor->place())) {
    *place = PlaceType::kNPU;
94
  } else {
95
    *place = PlaceType::kUNK;
96 97 98 99 100 101
  }

  *size = tensor->numel();
  return res;
}

102
DataType Tensor::type() const {
103 104
  EAGER_GET_TENSOR;
  auto type = tensor->type();
105 106 107 108 109 110 111 112
  if (type == paddle::framework::proto::VarType::FP32) {
    return DataType::FLOAT32;
  } 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;
113 114
  } else if (type == paddle::framework::proto::VarType::INT8) {
    return DataType::INT8;
115
  }
116
  return DataType::FLOAT32;
117 118
}

N
nhzlx 已提交
119
template <typename T>
120
void Tensor::CopyFromCpu(const T *data) {
N
nhzlx 已提交
121
  EAGER_GET_TENSOR;
W
Wilber 已提交
122
  PADDLE_ENFORCE_GE(tensor->numel(), 0,
123 124
                    paddle::platform::errors::PreconditionNotMet(
                        "You should call Tensor::Reshape(const "
W
Wilber 已提交
125 126
                        "std::vector<int> &shape)"
                        "function before copying data from cpu."));
N
nhzlx 已提交
127 128
  size_t ele_size = tensor->numel() * sizeof(T);

129 130
  if (place_ == PlaceType::kCPU) {
    auto *t_data = tensor->mutable_data<T>(paddle::platform::CPUPlace());
N
nhzlx 已提交
131
    std::memcpy(static_cast<void *>(t_data), data, ele_size);
132
  } else if (place_ == PlaceType::kGPU) {
133
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
134 135 136
    paddle::platform::DeviceContextPool &pool =
        paddle::platform::DeviceContextPool::Instance();
    paddle::platform::CUDAPlace gpu_place(device_);
N
nhzlx 已提交
137
    auto *t_data = tensor->mutable_data<T>(gpu_place);
138 139
    auto *dev_ctx = static_cast<const paddle::platform::CUDADeviceContext *>(
        pool.Get(gpu_place));
N
nhzlx 已提交
140

141 142 143
    paddle::memory::Copy(gpu_place, static_cast<void *>(t_data),
                         paddle::platform::CPUPlace(), data, ele_size,
                         dev_ctx->stream());
N
nhzlx 已提交
144
#else
145 146 147
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with CUDA place because paddle is not compiled "
        "with CUDA."));
N
nhzlx 已提交
148
#endif
149
  } else if (place_ == PlaceType::kXPU) {
150
#ifdef PADDLE_WITH_XPU
151
    paddle::platform::XPUPlace xpu_place(device_);
152
    auto *t_data = tensor->mutable_data<T>(xpu_place);
153 154
    paddle::memory::Copy(xpu_place, static_cast<void *>(t_data),
                         paddle::platform::CPUPlace(), data, ele_size);
155
#else
156 157 158
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with XPU place because paddle is not compiled "
        "with XPU."));
W
Wilber 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
#endif
  } else if (place_ == PlaceType::kNPU) {
#ifdef PADDLE_WITH_ASCEND_CL
    paddle::platform::DeviceContextPool &pool =
        paddle::platform::DeviceContextPool::Instance();
    paddle::platform::NPUPlace npu_place(device_);
    auto *t_data = tensor->mutable_data<T>(npu_place);
    auto *dev_ctx = static_cast<const paddle::platform::NPUDeviceContext *>(
        pool.Get(npu_place));
    paddle::memory::Copy(npu_place, static_cast<void *>(t_data),
                         paddle::platform::CPUPlace(), data, ele_size,
                         dev_ctx->stream());
#else
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with NPU place because paddle is not compiled "
        "with NPU."));
175 176 177
#endif
  } else {
    PADDLE_THROW(paddle::platform::errors::InvalidArgument(
W
Wilber 已提交
178
        "The analysis predictor supports CPU, GPU, NPU and XPU now."));
N
nhzlx 已提交
179 180 181 182
  }
}

template <typename T>
183
void Tensor::CopyToCpu(T *data) {
N
nhzlx 已提交
184 185 186 187 188
  EAGER_GET_TENSOR;
  auto ele_num = tensor->numel();
  auto *t_data = tensor->data<T>();
  auto t_place = tensor->place();

189 190 191 192 193 194
  paddle::framework::Tensor out;
  auto mem_allocation = std::make_shared<paddle::memory::Allocation>(
      static_cast<void *>(data), ele_num * sizeof(T),
      paddle::platform::CPUPlace());
  out.ResetHolder(mem_allocation);

195
  if (paddle::platform::is_cpu_place(t_place)) {
196 197 198 199 200 201 202 203 204
#ifdef PADDLE_WITH_MKLDNN
    if (tensor->layout() == paddle::framework::DataLayout::kMKLDNN)
      paddle::framework::innerTransDataLayoutFromMKLDNN(
          tensor->layout(), paddle::platform::MKLDNNDeviceContext::tls()
                                .get_cur_paddle_data_layout(),
          *tensor, &out, paddle::platform::CPUPlace(), true);
    else
      std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
#else
N
nhzlx 已提交
205
    std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
206
#endif
207
  } else if (place_ == PlaceType::kGPU) {
208
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
209 210 211 212 213 214 215 216
    paddle::platform::DeviceContextPool &pool =
        paddle::platform::DeviceContextPool::Instance();
    auto gpu_place = BOOST_GET_CONST(paddle::platform::CUDAPlace, t_place);
    auto *dev_ctx = static_cast<const paddle::platform::CUDADeviceContext *>(
        pool.Get(gpu_place));
    paddle::memory::Copy(paddle::platform::CPUPlace(),
                         static_cast<void *>(data), gpu_place, t_data,
                         ele_num * sizeof(T), dev_ctx->stream());
217 218 219
#ifdef PADDLE_WITH_HIP
    hipStreamSynchronize(dev_ctx->stream());
#else
220
    cudaStreamSynchronize(dev_ctx->stream());
221
#endif
N
nhzlx 已提交
222
#else
223 224 225
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with CUDA place because paddle is not compiled "
        "with CUDA."));
N
nhzlx 已提交
226
#endif
227
  } else if (place_ == PlaceType::kXPU) {
228
#ifdef PADDLE_WITH_XPU
229 230 231 232
    auto xpu_place = BOOST_GET_CONST(paddle::platform::XPUPlace, t_place);
    paddle::memory::Copy(paddle::platform::CPUPlace(),
                         static_cast<void *>(data), xpu_place, t_data,
                         ele_num * sizeof(T));
233
#else
234 235 236
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with XPU place because paddle is not compiled "
        "with XPU."));
W
Wilber 已提交
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
#endif
  } else if (place_ == PlaceType::kNPU) {
#ifdef PADDLE_WITH_ASCEND_CL
    paddle::platform::DeviceContextPool &pool =
        paddle::platform::DeviceContextPool::Instance();
    auto npu_place = BOOST_GET_CONST(paddle::platform::NPUPlace, t_place);
    auto *dev_ctx = static_cast<const paddle::platform::NPUDeviceContext *>(
        pool.Get(npu_place));
    paddle::memory::Copy(paddle::platform::CPUPlace(),
                         static_cast<void *>(data), npu_place, t_data,
                         ele_num * sizeof(T), dev_ctx->stream());
    aclrtSynchronizeStream(dev_ctx->stream());
#else
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with NPU place because paddle is not compiled "
        "with NPU."));
253 254 255
#endif
  } else {
    PADDLE_THROW(paddle::platform::errors::InvalidArgument(
W
Wilber 已提交
256
        "The analysis predictor supports CPU, GPU, NPU and XPU now."));
N
nhzlx 已提交
257 258
  }
}
259 260 261 262 263 264 265 266 267 268 269
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::CopyToCpu<float>(float *data);
template PD_INFER_DECL void Tensor::CopyToCpu<int64_t>(int64_t *data);
template PD_INFER_DECL void Tensor::CopyToCpu<int32_t>(int32_t *data);
template PD_INFER_DECL void Tensor::CopyToCpu<uint8_t>(uint8_t *data);
template PD_INFER_DECL void Tensor::CopyToCpu<int8_t>(int8_t *data);
270

271 272 273 274 275 276 277 278 279 280
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;
281

282 283 284 285 286
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);
287

288 289 290 291 292 293
Tensor::Tensor(void *scope) : scope_{scope} {
  PADDLE_ENFORCE_NOT_NULL(scope_,
                          paddle::platform::errors::PreconditionNotMet(
                              "The `scope` can not be nullptr. It should be "
                              "set to the pointer of scope."));
}
294

295
void *Tensor::FindTensor() const {
W
Wilber 已提交
296 297
  PADDLE_ENFORCE_EQ(
      name_.empty(), false,
298
      paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
299 300
          "Need to SetName first, so that the corresponding tensor can "
          "be retrieved."));
301
  auto *scope = static_cast<paddle::framework::Scope *>(scope_);
302
  auto *var = scope->FindVar(name_);
W
Wilber 已提交
303
  PADDLE_ENFORCE_NOT_NULL(
304
      var, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
305
               "No tensor called [%s] in the runtime scope", name_));
306
  auto *tensor = var->GetMutable<paddle::framework::LoDTensor>();
307 308 309
  return tensor;
}

310
std::vector<int> Tensor::shape() const {
311
  EAGER_GET_TENSOR;
W
Wilber 已提交
312
  PADDLE_ENFORCE_NOT_NULL(
313
      tensor_, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
314
                   "Not found tensor called %s in the scope", name_));
315
  return paddle::framework::vectorize<int>(tensor->dims());
316 317
}

318
void Tensor::SetLoD(const std::vector<std::vector<size_t>> &x) {
319
  EAGER_GET_TENSOR;
320
  paddle::framework::LoD lod;
321 322 323 324 325 326
  for (auto &level : x) {
    lod.emplace_back(level);
  }
  tensor->set_lod(lod);
}

327
std::vector<std::vector<size_t>> Tensor::lod() const {
328
  EAGER_GET_TENSOR;
329 330 331 332 333 334 335
  std::vector<std::vector<size_t>> res;
  for (auto &level : tensor->lod()) {
    res.emplace_back(level);
  }
  return res;
}

336 337 338 339 340 341 342 343 344 345
void Tensor::SetName(const std::string &name) { name_ = name; }

const std::string &Tensor::name() const { return name_; }

void Tensor::SetPlace(PlaceType place, int device) {
  place_ = place;
  device_ = device;
}

}  // namespace paddle_infer