utils.cc 17.9 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 31 32
PADDLE_DEFINE_EXPORTED_bool(retain_grad_for_all_tensor, true,
                            "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 76 77 78 79 80 81 82
AutogradMeta* EagerUtils::nullable_autograd_meta(
    paddle::optional<const paddle::experimental::Tensor&> target) {
  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
std::vector<paddle::experimental::Tensor> EagerUtils::GetOutputs(
275
    const std::vector<std::shared_ptr<EagerVariable>>& outs) {
276
  std::vector<paddle::experimental::Tensor> res;
277 278 279 280 281 282 283 284 285
  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()));
286
    res.emplace_back(out->GetTensorBase(), out->name());
287 288 289 290
  }
  return res;
}

291
paddle::experimental::Tensor EagerUtils::GetOutput(
292
    const std::shared_ptr<EagerVariable>& out) {
293 294 295 296 297 298
  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()));
299 300 301
  return paddle::experimental::Tensor(out->GetTensorBase(), out->name());
}

302 303
void EagerUtils::GetOutput(const std::shared_ptr<EagerVariable>& out,
                           paddle::experimental::Tensor* out_var) {
304
  PADDLE_ENFORCE_NOT_NULL(
305 306 307 308 309 310
      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());
311
  out_var->set_name(out->name());
312 313
}

314
void EagerUtils::GetOutputs(
315
    const std::vector<std::shared_ptr<EagerVariable>>& outs,
316
    std::vector<paddle::experimental::Tensor>* result) {
317
  for (size_t i = 0; i < outs.size(); i++) {
318
    result->emplace_back(outs[i]->GetTensorBase());
319
  }
320 321
}

322 323 324
void EagerUtils::GetOutputs(
    const std::vector<std::shared_ptr<EagerVariable>>& outs,
    const std::vector<paddle::experimental::Tensor*>& out_var) {
325 326
  for (size_t i = 0; i < outs.size(); i++) {
    PADDLE_ENFORCE_NOT_NULL(
327
        out_var[i], paddle::platform::errors::Fatal(
328 329 330 331
                        "Tensor is null and cannot be copied. "
                        "We are tring to OverwriteOutput from its "
                        "shared_ptr, this error may indicate some outputs "
                        "are nullptr"));
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    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]);
359 360 361 362
  }
}

paddle::experimental::Tensor EagerUtils::RecoverTensorWrapper(
363 364
    TensorWrapper* tw) {
  return tw->recover();
365 366
}

367
std::vector<paddle::experimental::Tensor> EagerUtils::RecoverTensorWrapper(
368
    std::vector<TensorWrapper>* tw) {
369
  std::vector<paddle::experimental::Tensor> ret;
370
  for (auto& t : *tw) {
371
    ret.emplace_back(t.recover());
372 373 374 375
  }
  return ret;
}

376 377
void EagerUtils::CheckAndRetainGrad(
    const paddle::experimental::Tensor& tensor) {
378 379
  VLOG(6) << "Check RetainGradForTensor: " << tensor.name();
  if (FLAGS_retain_grad_for_all_tensor) {
380
    VLOG(6) << "RetainGradForTensor: " << tensor.name();
381 382 383 384 385
    egr::egr_utils_api::RetainGradForTensor(tensor);
  }
}

void EagerUtils::CheckAndRetainGrad(
386
    const std::vector<paddle::experimental::Tensor>& tensors) {
387 388
  if (FLAGS_retain_grad_for_all_tensor) {
    for (auto& tensor : tensors) {
389
      VLOG(6) << "RetainGradForTensor: " << tensor.name();
390 391 392 393 394
      egr::egr_utils_api::RetainGradForTensor(tensor);
    }
  }
}

W
wanghuancoder 已提交
395 396 397 398 399 400 401 402 403 404
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);
    }
  }
}

405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
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();
434 435
      autograd_ptr->SetGradNode(
          std::make_shared<egr::GradNodeAccumulation>(autograd_ptr));
436 437 438 439 440 441 442
      return autograd_ptr->GetMutableGradNode();
    } else {
      return nullptr;
    }
  }
}

443
void EagerUtils::FillZeroForEmptyGradInputs(
444 445 446 447
    paddle::small_vector<std::vector<paddle::experimental::Tensor>,
                         kSlotSmallVectorSize>* in_grads,
    const paddle::small_vector<std::vector<GradSlotMeta>, kSlotSmallVectorSize>&
        grad_in_metas) {
448
  for (size_t i = 0; i < in_grads->size(); i++) {
449
    for (size_t j = 0; j < (*in_grads)[i].size(); j++) {
450
      paddle::experimental::Tensor& grad = (*in_grads)[i][j];
451
      if (!grad.initialized()) {
452 453 454 455 456 457 458
        const GradSlotMeta& grad_in_meta = grad_in_metas[i][j];
        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(
459 460
            phi::vectorize(tensor_meta.dims), 0.0, tensor_meta.dtype,
            grad_in_meta.GetPlace());
461 462 463 464 465 466
        grad.set_impl(tensor_with_zero.impl());
      }
    }
  }
}

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
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]);
  }
}

501
}  // namespace egr