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

#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/inference/api/paddle_inference_api.h"
N
nhzlx 已提交
18
#include "paddle/fluid/memory/memcpy.h"
19 20
#include "paddle/fluid/platform/enforce.h"

21
namespace paddle_infer {
22

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

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

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

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

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

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

95
DataType Tensor::type() const {
96 97
  EAGER_GET_TENSOR;
  auto type = tensor->type();
98 99 100 101 102 103 104 105
  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;
106
  }
107
  return DataType::FLOAT32;
108 109
}

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

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

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

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

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

214 215 216 217 218 219 220 221 222 223
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;
224

225 226 227 228 229
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);
230

231 232 233 234 235 236
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."));
}
237

238
void *Tensor::FindTensor() const {
W
Wilber 已提交
239 240
  PADDLE_ENFORCE_EQ(
      name_.empty(), false,
241
      paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
242 243
          "Need to SetName first, so that the corresponding tensor can "
          "be retrieved."));
244
  auto *scope = static_cast<paddle::framework::Scope *>(scope_);
245
  auto *var = scope->FindVar(name_);
W
Wilber 已提交
246
  PADDLE_ENFORCE_NOT_NULL(
247
      var, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
248
               "No tensor called [%s] in the runtime scope", name_));
249
  auto *tensor = var->GetMutable<paddle::framework::LoDTensor>();
250 251 252
  return tensor;
}

253
std::vector<int> Tensor::shape() const {
254
  EAGER_GET_TENSOR;
W
Wilber 已提交
255
  PADDLE_ENFORCE_NOT_NULL(
256
      tensor_, paddle::platform::errors::PreconditionNotMet(
W
Wilber 已提交
257
                   "Not found tensor called %s in the scope", name_));
258
  return paddle::framework::vectorize<int>(tensor->dims());
259 260
}

261
void Tensor::SetLoD(const std::vector<std::vector<size_t>> &x) {
262
  EAGER_GET_TENSOR;
263
  paddle::framework::LoD lod;
264 265 266 267 268 269
  for (auto &level : x) {
    lod.emplace_back(level);
  }
  tensor->set_lod(lod);
}

270
std::vector<std::vector<size_t>> Tensor::lod() const {
271
  EAGER_GET_TENSOR;
272 273 274 275 276 277 278
  std::vector<std::vector<size_t>> res;
  for (auto &level : tensor->lod()) {
    res.emplace_back(level);
  }
  return res;
}

279 280 281 282 283 284 285 286 287 288
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