zero_copy_tensor.cc 11.9 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"
N
nhzlx 已提交
19
#include "paddle/fluid/memory/memcpy.h"
20 21
#include "paddle/fluid/platform/enforce.h"

22
namespace paddle_infer {
23

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

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

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

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

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

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

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

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

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

135 136 137
    paddle::memory::Copy(gpu_place, static_cast<void *>(t_data),
                         paddle::platform::CPUPlace(), data, ele_size,
                         dev_ctx->stream());
N
nhzlx 已提交
138
#else
139 140 141
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with CUDA place because paddle is not compiled "
        "with CUDA."));
N
nhzlx 已提交
142
#endif
143
  } else if (place_ == PlaceType::kXPU) {
144
#ifdef PADDLE_WITH_XPU
145
    paddle::platform::XPUPlace xpu_place(device_);
146
    auto *t_data = tensor->mutable_data<T>(xpu_place);
147 148
    paddle::memory::Copy(xpu_place, static_cast<void *>(t_data),
                         paddle::platform::CPUPlace(), data, ele_size);
149
#else
150 151 152
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with XPU place because paddle is not compiled "
        "with XPU."));
153 154 155 156
#endif
  } else {
    PADDLE_THROW(paddle::platform::errors::InvalidArgument(
        "The analysis predictor supports CPU, GPU and XPU now."));
N
nhzlx 已提交
157 158 159 160
  }
}

template <typename T>
161
void Tensor::CopyToCpu(T *data) {
N
nhzlx 已提交
162 163 164 165 166
  EAGER_GET_TENSOR;
  auto ele_num = tensor->numel();
  auto *t_data = tensor->data<T>();
  auto t_place = tensor->place();

167 168 169 170 171 172
  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);

173
  if (paddle::platform::is_cpu_place(t_place)) {
174 175 176 177 178 179 180 181 182
#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 已提交
183
    std::memcpy(static_cast<void *>(data), t_data, ele_num * sizeof(T));
184
#endif
185
  } else if (place_ == PlaceType::kGPU) {
186
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
187 188 189 190 191 192 193 194
    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());
195 196 197
#ifdef PADDLE_WITH_HIP
    hipStreamSynchronize(dev_ctx->stream());
#else
198
    cudaStreamSynchronize(dev_ctx->stream());
199
#endif
N
nhzlx 已提交
200
#else
201 202 203
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with CUDA place because paddle is not compiled "
        "with CUDA."));
N
nhzlx 已提交
204
#endif
205
  } else if (place_ == PlaceType::kXPU) {
206
#ifdef PADDLE_WITH_XPU
207 208 209 210
    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));
211
#else
212 213 214
    PADDLE_THROW(paddle::platform::errors::Unavailable(
        "Can not create tensor with XPU place because paddle is not compiled "
        "with XPU."));
215 216 217 218
#endif
  } else {
    PADDLE_THROW(paddle::platform::errors::InvalidArgument(
        "The analysis predictor supports CPU, GPU and XPU now."));
N
nhzlx 已提交
219 220
  }
}
221 222 223 224 225 226 227 228 229 230 231
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);
232

233 234 235 236 237 238 239 240 241 242
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;
243

244 245 246 247 248
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);
249

250 251 252 253 254 255
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."));
}
256

257
void *Tensor::FindTensor() const {
W
Wilber 已提交
258 259
  PADDLE_ENFORCE_EQ(
      name_.empty(), false,
260
      paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
261 262
          "Need to SetName first, so that the corresponding tensor can "
          "be retrieved."));
263
  auto *scope = static_cast<paddle::framework::Scope *>(scope_);
264
  auto *var = scope->FindVar(name_);
W
Wilber 已提交
265
  PADDLE_ENFORCE_NOT_NULL(
266
      var, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
267
               "No tensor called [%s] in the runtime scope", name_));
268
  auto *tensor = var->GetMutable<paddle::framework::LoDTensor>();
269 270 271
  return tensor;
}

272
std::vector<int> Tensor::shape() const {
273
  EAGER_GET_TENSOR;
W
Wilber 已提交
274
  PADDLE_ENFORCE_NOT_NULL(
275
      tensor_, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
276
                   "Not found tensor called %s in the scope", name_));
277
  return paddle::framework::vectorize<int>(tensor->dims());
278 279
}

280
void Tensor::SetLoD(const std::vector<std::vector<size_t>> &x) {
281
  EAGER_GET_TENSOR;
282
  paddle::framework::LoD lod;
283 284 285 286 287 288
  for (auto &level : x) {
    lod.emplace_back(level);
  }
  tensor->set_lod(lod);
}

289
std::vector<std::vector<size_t>> Tensor::lod() const {
290
  EAGER_GET_TENSOR;
291 292 293 294 295 296 297
  std::vector<std::vector<size_t>> res;
  for (auto &level : tensor->lod()) {
    res.emplace_back(level);
  }
  return res;
}

298 299 300 301 302 303 304 305 306 307
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