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

#include "paddle/fluid/eager/utils.h"
16
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
17
#include "paddle/fluid/eager/api/utils/global_utils.h"
18
#include "paddle/fluid/eager/api/utils/hook_utils.h"
19
#include "paddle/fluid/eager/tensor_wrapper.h"
20

21 22
#include "paddle/phi/api/all.h"
#include "paddle/phi/common/layout.h"
23
#include "paddle/phi/core/compat/convert_utils.h"
24
#include "paddle/phi/core/tensor_meta.h"
25 26

#include "paddle/fluid/framework/data_layout.h"
27
#include "paddle/fluid/framework/phi_utils.h"
28
#include "paddle/fluid/framework/variable.h"
29

30
PADDLE_DEFINE_EXPORTED_bool(retain_grad_for_all_tensor, false,
31 32
                            "retain grad for all tensor");

33
namespace egr {
34 35 36 37
/**
 * Implementation of Eager Utils.
**/

38
AutogradMeta* EagerUtils::autograd_meta(paddle::experimental::Tensor* target) {
39 40 41 42 43 44 45 46 47
  auto* p_autograd_meta = target->get_autograd_meta();
  if (!p_autograd_meta) {
    auto p_autograd_meta_ptr = std::make_shared<AutogradMeta>();
    p_autograd_meta = p_autograd_meta_ptr.get();
    target->set_autograd_meta(p_autograd_meta_ptr);
  }
  return static_cast<AutogradMeta*>(p_autograd_meta);
}

48 49
AutogradMeta* EagerUtils::unsafe_autograd_meta(
    const paddle::experimental::Tensor& target) {
50 51 52 53 54 55 56 57
  auto* p_autograd_meta = target.get_autograd_meta();
  PADDLE_ENFORCE(p_autograd_meta,
                 paddle::platform::errors::Fatal(
                     "Null autograd_meta gotten from unsafe_autograd_meta()"));
  return static_cast<AutogradMeta*>(p_autograd_meta);
}

std::vector<AutogradMeta*> EagerUtils::unsafe_autograd_meta(
58
    const std::vector<paddle::experimental::Tensor>& targets) {
59
  std::vector<AutogradMeta*> metas;
60
  metas.reserve(targets.size());
61
  for (const paddle::experimental::Tensor& t : targets) {
62
    metas.emplace_back(unsafe_autograd_meta(t));
63 64 65 66
  }
  return metas;
}

67
AutogradMeta* EagerUtils::nullable_autograd_meta(
68
    const paddle::experimental::Tensor& target) {
69 70 71 72 73 74
  auto* p_autograd_meta = target.get_autograd_meta();
  if (!p_autograd_meta) return nullptr;

  return static_cast<AutogradMeta*>(p_autograd_meta);
}

H
hong 已提交
75
AutogradMeta* EagerUtils::nullable_autograd_meta(
76
    const paddle::optional<paddle::experimental::Tensor>& target) {
H
hong 已提交
77 78 79 80 81 82
  if (target.get_ptr() != nullptr) {
    return EagerUtils::nullable_autograd_meta(*(target.get_ptr()));
  }
  return nullptr;
}

83
std::vector<AutogradMeta*> EagerUtils::nullable_autograd_meta(
84
    const std::vector<paddle::experimental::Tensor>& targets) {
85 86
  std::vector<AutogradMeta*> metas;
  metas.reserve(targets.size());
87
  for (const paddle::experimental::Tensor& t : targets) {
88 89 90 91 92
    metas.emplace_back(nullable_autograd_meta(t));
  }
  return metas;
}

W
wanghuancoder 已提交
93 94 95 96 97 98 99 100 101 102
std::vector<AutogradMeta*> EagerUtils::nullable_autograd_meta(
    const std::vector<paddle::experimental::Tensor*>& targets) {
  std::vector<AutogradMeta*> metas;
  metas.reserve(targets.size());
  for (const paddle::experimental::Tensor* t : targets) {
    metas.emplace_back(nullable_autograd_meta(*t));
  }
  return metas;
}

103
std::vector<AutogradMeta*> EagerUtils::autograd_meta(
104
    std::vector<paddle::experimental::Tensor>* targets) {
105 106 107
  std::vector<AutogradMeta*> ret;
  ret.reserve(targets->size());

108
  // for autograd_meta we can tolerent it has nullptr.
109 110 111
  for (size_t i = 0; i < targets->size(); i++) {
    auto* p_autograd_meta = autograd_meta(&((*targets)[i]));
    ret.emplace_back(p_autograd_meta);
112 113 114 115
  }
  return ret;
}

W
wanghuancoder 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128
std::vector<AutogradMeta*> EagerUtils::autograd_meta(
    std::vector<paddle::experimental::Tensor*>* targets) {
  std::vector<AutogradMeta*> ret;
  ret.reserve(targets->size());

  // for autograd_meta we can tolerent it has nullptr.
  for (size_t i = 0; i < targets->size(); i++) {
    auto* p_autograd_meta = autograd_meta((*targets)[i]);
    ret.emplace_back(p_autograd_meta);
  }
  return ret;
}

129
std::pair<size_t, size_t> EagerUtils::OutRankInfo(
130
    const paddle::experimental::Tensor& target) {
131 132 133 134
  return unsafe_autograd_meta(target)->OutRankInfo();
}

std::shared_ptr<GradNodeBase> EagerUtils::grad_node(
135
    const paddle::experimental::Tensor& target) {
136 137 138 139 140 141
  auto* meta = nullable_autograd_meta(target);
  if (meta) {
    return meta->GetMutableGradNode();
  } else {
    return nullptr;
  }
142 143
}

144 145 146 147 148 149 150 151 152 153
paddle::experimental::Tensor* EagerUtils::mutable_grad(
    const paddle::experimental::Tensor& target) {
  auto* meta = nullable_autograd_meta(target);
  if (meta) {
    return meta->MutableGrad();
  } else {
    return nullptr;
  }
}

154 155 156
void EagerUtils::SetHistory(std::vector<AutogradMeta*>* autograd_metas,
                            const std::shared_ptr<GradNodeBase>& grad_node) {
  for (const auto& autograd_meta : *autograd_metas) {
J
Jiabin Yang 已提交
157 158 159
    if (autograd_meta->GradNode()) {
      VLOG(7) << "Should not set grad node twice, original node is:"
              << autograd_meta->GradNode()->name()
160
              << " current is: " << grad_node->name();
161
    }
162 163 164 165 166 167
    autograd_meta->SetGradNode(grad_node);
  }
}

void EagerUtils::SetHistory(AutogradMeta* autograd_meta,
                            const std::shared_ptr<GradNodeBase>& grad_node) {
J
Jiabin Yang 已提交
168 169 170 171
  if (autograd_meta->GradNode()) {
    VLOG(7) << "Should not set grad node twice, original node is:"
            << autograd_meta->GradNode()->name()
            << "current is: " << grad_node->name();
172
  }
173 174 175 176 177 178 179 180 181 182 183 184 185 186
  autograd_meta->SetGradNode(grad_node);
}

void EagerUtils::SetOutRankWithSlot(std::vector<AutogradMeta*>* targets,
                                    size_t slot_id) {
  // Set OutRankInfo from 0 to size of targets
  for (size_t i = 0; i < targets->size(); i++) {
    (*targets)[i]->SetSingleOutRankWithSlot(slot_id, i);
  }
}
void EagerUtils::SetOutRankWithSlot(AutogradMeta* target, size_t slot_id) {
  target->SetSingleOutRankWithSlot(slot_id, 0);
}

187
std::shared_ptr<egr::EagerVariable> EagerUtils::TrySyncToVar(
188
    const paddle::experimental::Tensor& tensor) {
189
  return std::make_shared<egr::EagerVariable>(tensor);
190 191
}

192
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
193
    const paddle::experimental::Tensor& tensor) {
194 195 196
  return {TrySyncToVar(tensor)};
}

197
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
198 199 200 201 202 203 204
    paddle::experimental::Tensor* tensor) {
  PADDLE_ENFORCE_NOT_NULL(
      tensor,
      paddle::platform::errors::Fatal(
          "Should Not Pass Empty tensor pointer in, since only output can "
          "reach this, please check output value and make sure it's not null"));
  return {TrySyncToVar(*tensor)};
205 206
}

207
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
208
    const std::vector<paddle::experimental::Tensor*>& tensors) {
209
  std::vector<std::shared_ptr<EagerVariable>> res;
210 211 212
  size_t num = tensors.size();
  res.reserve(num);
  for (size_t i = 0; i < num; i++) {
213 214 215 216 217 218 219 220
    auto* tensor = tensors[i];
    PADDLE_ENFORCE_NOT_NULL(
        tensor, paddle::platform::errors::Fatal(
                    "Tensor is null and cannot be copied. "
                    "We are tring to TrySyncToVars tensor from its "
                    "shared_ptr, this error may indicate some outputs "
                    "are nullptr"));
    res.emplace_back(TrySyncToVar(*tensor));
221 222 223 224
  }
  return res;
}

225
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
226
    const std::vector<paddle::experimental::Tensor>& tensors) {
227
  std::vector<std::shared_ptr<EagerVariable>> res;
228 229 230
  size_t num = tensors.size();
  res.reserve(num);
  for (size_t i = 0; i < num; i++) {
231
    res.emplace_back(TrySyncToVar(tensors[i]));
232 233 234 235
  }
  return res;
}

236
std::vector<std::shared_ptr<EagerVariable>> EagerUtils::CreateVars(
237
    const size_t num) {
238
  std::vector<std::shared_ptr<EagerVariable>> res;
239 240 241
  res.reserve(num);
  for (size_t i = 0; i < num; i++) {
    res.emplace_back(
242
        new EagerVariable(egr::Controller::Instance().GenerateUniqueName()));
243 244 245 246
  }
  return res;
}

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
void EagerUtils::HandleViewBetweenInputAndOutput(
    const std::shared_ptr<EagerVariable>& input_var,
    const std::shared_ptr<EagerVariable>& view_output_var) {
  PADDLE_ENFORCE_EQ(
      input_var->Var().IsInitialized(), true,
      paddle::platform::errors::InvalidArgument(
          "Tensor %s has not been initialized!", input_var->name()));

  if (phi::DenseTensor::classof(input_var->GetTensorBase().get())) {
    auto input_dense_tensor =
        std::dynamic_pointer_cast<phi::DenseTensor>(input_var->GetTensorBase());
    PADDLE_ENFORCE_EQ(
        input_dense_tensor->IsInitialized(), true,
        paddle::platform::errors::InvalidArgument(
            "DenseTensor %s has not been initialized!", input_var->name()));

    auto* view_output_tensor =
        view_output_var->MutableVar()->GetMutable<phi::DenseTensor>();
    view_output_tensor->ShareBufferWith(*input_dense_tensor);
    view_output_tensor->ShareInplaceVersionCounterWith(*input_dense_tensor);

    VLOG(3) << "Perform View between Output Var(" << view_output_var->name()
            << ") and Input Var(" << input_var->name()
            << "), share allocation and inplace version.";
  }
}

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
void EagerUtils::HandleViewBetweenInputAndOutput(
    const paddle::experimental::Tensor& input_tensor,
    paddle::experimental::Tensor* view_output_tensor) {
  PADDLE_ENFORCE_EQ(
      input_tensor.initialized(), true,
      paddle::platform::errors::InvalidArgument(
          "Tensor %s has not been initialized!", input_tensor.name()));

  if (input_tensor.is_dense_tensor()) {
    auto input_dense_tensor =
        std::dynamic_pointer_cast<phi::DenseTensor>(input_tensor.impl());
    if (view_output_tensor->impl() == nullptr) {
      view_output_tensor->set_impl(std::make_shared<phi::DenseTensor>());
    }
    auto view_output_dense_tensor =
        std::dynamic_pointer_cast<phi::DenseTensor>(view_output_tensor->impl());
    view_output_dense_tensor->ShareBufferWith(*input_dense_tensor);
    view_output_dense_tensor->ShareInplaceVersionCounterWith(
        *input_dense_tensor);

    VLOG(3) << "Perform View between Output Tensor("
            << view_output_tensor->name() << ") and Input Tensor("
            << input_tensor.name()
            << "), share allocation and inplace version.";
  }
}

301
std::vector<paddle::experimental::Tensor> EagerUtils::GetOutputs(
302
    const std::vector<std::shared_ptr<EagerVariable>>& outs) {
303
  std::vector<paddle::experimental::Tensor> res;
304 305 306 307 308 309 310 311 312
  res.reserve(outs.size());
  for (const auto& out : outs) {
    PADDLE_ENFORCE_NOT_NULL(
        out.get(), paddle::platform::errors::Fatal(
                       "Eager Tensor %s is null and cannot be copied. "
                       "We are tring to Get Output tensor from its "
                       "shared_ptr, this error may indicate some outputs "
                       "are nullptr",
                       out->name()));
313
    res.emplace_back(out->GetTensorBase(), out->name());
314 315 316 317
  }
  return res;
}

318
paddle::experimental::Tensor EagerUtils::GetOutput(
319
    const std::shared_ptr<EagerVariable>& out) {
320 321 322 323 324 325
  PADDLE_ENFORCE_NOT_NULL(
      out.get(), paddle::platform::errors::Fatal(
                     "Eager Tensor %s is null and cannot be copied. We "
                     "are tring to Get Output tensor from its shared_ptr, "
                     "this error may indicate output is nullptr",
                     out->name()));
326 327 328
  return paddle::experimental::Tensor(out->GetTensorBase(), out->name());
}

329 330
void EagerUtils::GetOutput(const std::shared_ptr<EagerVariable>& out,
                           paddle::experimental::Tensor* out_var) {
331
  PADDLE_ENFORCE_NOT_NULL(
332 333 334 335 336 337
      out_var, paddle::platform::errors::Fatal(
                   "Tensor is null and cannot be copied. "
                   "We are tring to OverwriteOutput from its "
                   "shared_ptr, this error may indicate some outputs "
                   "are nullptr"));
  out_var->set_impl(out->GetTensorBase());
338
  out_var->set_name(out->name());
339 340
}

341
void EagerUtils::GetOutputs(
342
    const std::vector<std::shared_ptr<EagerVariable>>& outs,
343
    std::vector<paddle::experimental::Tensor>* result) {
344
  for (size_t i = 0; i < outs.size(); i++) {
345
    result->emplace_back(outs[i]->GetTensorBase());
346
  }
347 348
}

349 350 351
void EagerUtils::GetOutputs(
    const std::vector<std::shared_ptr<EagerVariable>>& outs,
    const std::vector<paddle::experimental::Tensor*>& out_var) {
352 353
  for (size_t i = 0; i < outs.size(); i++) {
    PADDLE_ENFORCE_NOT_NULL(
354
        out_var[i], paddle::platform::errors::Fatal(
355 356 357 358
                        "Tensor is null and cannot be copied. "
                        "We are tring to OverwriteOutput from its "
                        "shared_ptr, this error may indicate some outputs "
                        "are nullptr"));
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
    out_var[i]->set_impl(outs[i]->GetTensorBase());
  }
}

void EagerUtils::GetOutputs(const std::shared_ptr<EagerVariable>& out,
                            std::vector<paddle::experimental::Tensor>* result) {
  result->emplace_back(out->GetTensorBase());
}

void EagerUtils::GetOutputs(
    const std::shared_ptr<EagerVariable>& out,
    const std::vector<paddle::experimental::Tensor*>& out_var) {
  PADDLE_ENFORCE_NOT_NULL(
      out_var[0], paddle::platform::errors::Fatal(
                      "Tensor is null and cannot be copied. "
                      "We are tring to OverwriteOutput from its "
                      "shared_ptr, this error may indicate some outputs "
                      "are nullptr"));
  out_var[0]->set_impl(out->GetTensorBase());
}

void EagerUtils::Output2Result(
    const std::vector<paddle::experimental::Tensor*>& out_var,
    std::vector<paddle::experimental::Tensor>* result) {
  result->reserve(out_var.size());
  for (size_t i = 0; i < out_var.size(); i++) {
    result->emplace_back(*out_var[i]);
386 387 388 389
  }
}

paddle::experimental::Tensor EagerUtils::RecoverTensorWrapper(
390 391
    TensorWrapper* tw) {
  return tw->recover();
392 393
}

394
std::vector<paddle::experimental::Tensor> EagerUtils::RecoverTensorWrapper(
395
    std::vector<TensorWrapper>* tw) {
396
  std::vector<paddle::experimental::Tensor> ret;
397
  for (auto& t : *tw) {
398
    ret.emplace_back(t.recover());
399 400 401 402
  }
  return ret;
}

403 404
void EagerUtils::CheckAndRetainGrad(
    const paddle::experimental::Tensor& tensor) {
405 406
  VLOG(6) << "Check RetainGradForTensor: " << tensor.name();
  if (FLAGS_retain_grad_for_all_tensor) {
407
    VLOG(6) << "RetainGradForTensor: " << tensor.name();
408 409 410 411 412
    egr::egr_utils_api::RetainGradForTensor(tensor);
  }
}

void EagerUtils::CheckAndRetainGrad(
413
    const std::vector<paddle::experimental::Tensor>& tensors) {
414 415
  if (FLAGS_retain_grad_for_all_tensor) {
    for (auto& tensor : tensors) {
416
      VLOG(6) << "RetainGradForTensor: " << tensor.name();
417 418 419 420 421
      egr::egr_utils_api::RetainGradForTensor(tensor);
    }
  }
}

W
wanghuancoder 已提交
422 423 424 425 426 427 428 429 430 431
void EagerUtils::CheckAndRetainGrad(
    const std::vector<paddle::experimental::Tensor*>& tensors) {
  if (FLAGS_retain_grad_for_all_tensor) {
    for (auto& tensor : tensors) {
      VLOG(6) << "RetainGradForTensor: " << tensor->name();
      egr::egr_utils_api::RetainGradForTensor(*tensor);
    }
  }
}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
std::shared_ptr<egr::GradNodeBase> EagerUtils::GetGradAccumulationNode(
    const paddle::experimental::Tensor& tensor) {
  auto* autograd_ptr = nullable_autograd_meta(tensor);
  if (!autograd_ptr) {
    return nullptr;
  }
  auto node_ptr = autograd_ptr->GetMutableGradNode();
  if (node_ptr && node_ptr.get()) {
    if (!autograd_ptr->StopGradient()) {
      auto accumulation_ptr =
          std::dynamic_pointer_cast<GradNodeAccumulation>(node_ptr);
      if (accumulation_ptr) {
        return accumulation_ptr;
      } else {
        // Current GradNode is not a egr::GradNodeAccumulation
        PADDLE_THROW(paddle::platform::errors::Fatal(
            "GetGradAccumulationNode should only be called on leaf tensor, but "
            "target tensor: %s has GradNode which is not a "
            "GradNodeAccumulation, and this should not happend unless target "
            "tensor is modified by some ops and calling set history for it.",
            tensor.name()));
      }
    } else {
      // Current Tensor does not have grad since it's stop_gradient is true;
      return nullptr;
    }
  } else {
    if (!autograd_ptr->StopGradient()) {
      VLOG(6) << "Add GradNodeAccumulation for tensor: " << tensor.name();
461 462
      autograd_ptr->SetGradNode(
          std::make_shared<egr::GradNodeAccumulation>(autograd_ptr));
463 464 465 466 467 468 469
      return autograd_ptr->GetMutableGradNode();
    } else {
      return nullptr;
    }
  }
}

W
wanghuancoder 已提交
470 471 472
void EagerUtils::FillZeroForEmptyOptionalGradInput(
    std::vector<paddle::experimental::Tensor>* in_grads,
    const std::vector<GradSlotMeta>& grad_in_metas) {
473
  for (size_t i = 0; i < in_grads->size(); i++) {
W
wanghuancoder 已提交
474 475 476 477 478 479
    paddle::experimental::Tensor& grad = (*in_grads)[i];
    if (!grad.initialized() && grad_in_metas[i].HasTensorMeta()) {
      auto tensor_with_zero = paddle::experimental::full(
          phi::vectorize(grad_in_metas[i].GetTensorMeta().dims), 0.0,
          grad_in_metas[i].GetTensorMeta().dtype, grad_in_metas[i].GetPlace());
      grad.set_impl(tensor_with_zero.impl());
480 481 482 483
    }
  }
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
void EagerUtils::FillZeroForEmptyGradInput(
    paddle::experimental::Tensor* in_grad, const GradSlotMeta& grad_in_meta) {
  if (!in_grad->initialized()) {
    PADDLE_ENFORCE(
        grad_in_meta.HasTensorMeta(),
        paddle::platform::errors::Fatal(
            "Unable to fill empty grad inputs due to empty GradSlotMeta"));
    const auto& tensor_meta = grad_in_meta.GetTensorMeta();
    auto tensor_with_zero =
        paddle::experimental::full(phi::vectorize(tensor_meta.dims), 0.0,
                                   tensor_meta.dtype, grad_in_meta.GetPlace());
    in_grad->set_impl(tensor_with_zero.impl());
  }
}

void EagerUtils::FillZeroForEmptyOptionalGradInput(
    paddle::experimental::Tensor* in_grad, const GradSlotMeta& grad_in_meta) {
  if (!in_grad->initialized() && grad_in_meta.HasTensorMeta()) {
    const auto& tensor_meta = grad_in_meta.GetTensorMeta();
    auto tensor_with_zero =
        paddle::experimental::full(phi::vectorize(tensor_meta.dims), 0.0,
                                   tensor_meta.dtype, grad_in_meta.GetPlace());
    in_grad->set_impl(tensor_with_zero.impl());
  }
}

void EagerUtils::FillZeroForEmptyGradInput(
    std::vector<paddle::experimental::Tensor>* in_grads,
    const std::vector<GradSlotMeta>& grad_in_metas) {
  for (size_t i = 0; i < in_grads->size(); i++) {
    FillZeroForEmptyGradInput(&in_grads->at(i), grad_in_metas[i]);
  }
}

518
}  // namespace egr