zero_copy_tensor.cc 13.4 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
    }
    default:
69 70 71 72
      PADDLE_THROW(paddle::platform::errors::Unavailable(
          "Only CPU / CUDA / XPU places is supported. The place `%d` is not "
          "supported.",
          static_cast<int>(place)));
73 74 75 76 77 78
      break;
  }
  return nullptr;
}

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

83 84 85 86 87 88
  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;
89
  } else {
90
    *place = PlaceType::kUNK;
91 92 93 94 95 96
  }

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

97
DataType Tensor::type() const {
98 99
  EAGER_GET_TENSOR;
  auto type = tensor->type();
100 101 102 103 104 105 106 107
  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;
108 109
  } else if (type == paddle::framework::proto::VarType::INT8) {
    return DataType::INT8;
110
  }
111
  return DataType::FLOAT32;
112 113
}

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

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

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

template <typename T>
178
void Tensor::CopyToCpu(T *data) {
N
nhzlx 已提交
179 180 181 182 183
  EAGER_GET_TENSOR;
  auto ele_num = tensor->numel();
  auto *t_data = tensor->data<T>();
  auto t_place = tensor->place();

184 185 186 187 188 189
  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);

190
  if (paddle::platform::is_cpu_place(t_place)) {
191 192 193 194 195 196 197 198 199
#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 已提交
200
    std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
201
#endif
202
  } else if (place_ == PlaceType::kGPU) {
203
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
204 205 206 207 208 209 210 211
    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());
212 213 214
#ifdef PADDLE_WITH_HIP
    hipStreamSynchronize(dev_ctx->stream());
#else
215
    cudaStreamSynchronize(dev_ctx->stream());
216
#endif
N
nhzlx 已提交
217
#else
218 219 220
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with CUDA place because paddle is not compiled "
        "with CUDA."));
N
nhzlx 已提交
221
#endif
222
  } else if (place_ == PlaceType::kXPU) {
223
#ifdef PADDLE_WITH_XPU
224 225 226 227
    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));
228
#else
229 230 231
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with XPU place because paddle is not compiled "
        "with XPU."));
W
Wilber 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
#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."));
248 249 250
#endif
  } else {
    PADDLE_THROW(paddle::platform::errors::InvalidArgument(
W
Wilber 已提交
251
        "The analysis predictor supports CPU, GPU, NPU and XPU now."));
N
nhzlx 已提交
252 253
  }
}
254 255 256 257 258 259 260 261 262 263 264
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);
265

266 267 268 269 270 271 272 273 274 275
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;
276

277 278 279 280 281
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);
282

283 284 285 286 287 288
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."));
}
289

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

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

313
void Tensor::SetLoD(const std::vector<std::vector<size_t>> &x) {
314
  EAGER_GET_TENSOR;
315
  paddle::framework::LoD lod;
316 317 318 319 320 321
  for (auto &level : x) {
    lod.emplace_back(level);
  }
  tensor->set_lod(lod);
}

322
std::vector<std::vector<size_t>> Tensor::lod() const {
323
  EAGER_GET_TENSOR;
324 325 326 327 328 329 330
  std::vector<std::vector<size_t>> res;
  for (auto &level : tensor->lod()) {
    res.emplace_back(level);
  }
  return res;
}

331 332 333 334 335 336 337 338 339 340
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