utils.cc 16.0 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;
}

93
std::vector<AutogradMeta*> EagerUtils::autograd_meta(
94
    std::vector<paddle::experimental::Tensor>* targets) {
95 96 97
  std::vector<AutogradMeta*> ret;
  ret.reserve(targets->size());

98
  // for autograd_meta we can tolerent it has nullptr.
99 100 101
  for (size_t i = 0; i < targets->size(); i++) {
    auto* p_autograd_meta = autograd_meta(&((*targets)[i]));
    ret.emplace_back(p_autograd_meta);
102 103 104 105 106
  }
  return ret;
}

std::pair<size_t, size_t> EagerUtils::OutRankInfo(
107
    const paddle::experimental::Tensor& target) {
108 109 110 111
  return unsafe_autograd_meta(target)->OutRankInfo();
}

std::shared_ptr<GradNodeBase> EagerUtils::grad_node(
112
    const paddle::experimental::Tensor& target) {
113 114 115 116 117 118
  auto* meta = nullable_autograd_meta(target);
  if (meta) {
    return meta->GetMutableGradNode();
  } else {
    return nullptr;
  }
119 120
}

121 122 123 124 125 126 127 128 129 130
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;
  }
}

131 132 133
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 已提交
134 135 136 137
    if (autograd_meta->GradNode()) {
      VLOG(7) << "Should not set grad node twice, original node is:"
              << autograd_meta->GradNode()->name()
              << "current is: " << grad_node->name();
138
    }
139 140 141 142 143 144
    autograd_meta->SetGradNode(grad_node);
  }
}

void EagerUtils::SetHistory(AutogradMeta* autograd_meta,
                            const std::shared_ptr<GradNodeBase>& grad_node) {
J
Jiabin Yang 已提交
145 146 147 148
  if (autograd_meta->GradNode()) {
    VLOG(7) << "Should not set grad node twice, original node is:"
            << autograd_meta->GradNode()->name()
            << "current is: " << grad_node->name();
149
  }
150 151 152 153 154 155 156 157 158 159 160 161 162 163
  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);
}

164
std::shared_ptr<egr::EagerVariable> EagerUtils::TrySyncToVar(
165
    const paddle::experimental::Tensor& tensor) {
166
  return std::make_shared<egr::EagerVariable>(tensor);
167 168
}

169
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
170
    const paddle::experimental::Tensor& tensor) {
171 172 173
  return {TrySyncToVar(tensor)};
}

174
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
175 176 177 178 179 180 181
    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)};
182 183
}

184
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
185
    const std::vector<paddle::experimental::Tensor*>& tensors) {
186
  std::vector<std::shared_ptr<EagerVariable>> res;
187 188 189
  size_t num = tensors.size();
  res.reserve(num);
  for (size_t i = 0; i < num; i++) {
190 191 192 193 194 195 196 197
    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));
198 199 200 201
  }
  return res;
}

202
std::vector<std::shared_ptr<egr::EagerVariable>> EagerUtils::TrySyncToVars(
203
    const std::vector<paddle::experimental::Tensor>& tensors) {
204
  std::vector<std::shared_ptr<EagerVariable>> res;
205 206 207
  size_t num = tensors.size();
  res.reserve(num);
  for (size_t i = 0; i < num; i++) {
208
    res.emplace_back(TrySyncToVar(tensors[i]));
209 210 211 212
  }
  return res;
}

213
std::vector<std::shared_ptr<EagerVariable>> EagerUtils::CreateVars(
214
    const size_t num) {
215
  std::vector<std::shared_ptr<EagerVariable>> res;
216 217 218
  res.reserve(num);
  for (size_t i = 0; i < num; i++) {
    res.emplace_back(
219
        new EagerVariable(egr::Controller::Instance().GenerateUniqueName()));
220 221 222 223
  }
  return res;
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
void EagerUtils::ModifyInplaceInput(
    const std::shared_ptr<EagerVariable>& inplace_variable,
    paddle::experimental::Tensor* inplace_tensor) {
  // Only modify the meta information of the inplace tensor, because
  // EagerVariable cannot modify Tensor's meta information after inplace
  // op (such as ``reshape``) is executed.
  PADDLE_ENFORCE_NOT_NULL(inplace_tensor,
                          paddle::platform::errors::Fatal(
                              "Inplace Tensor is null and cannot be modified. "
                              "We are tring to Modify Inplace Input from its "
                              "shared_ptr, this error may indicate the inplace "
                              " input is nullptr"));
  if (phi::DenseTensor::classof(inplace_variable->GetTensorBase().get())) {
    phi::DenseTensor* variable_dense_tensor =
        static_cast<phi::DenseTensor*>(inplace_variable->GetTensorBase().get());
    phi::DenseTensor* tensor_dense_tensor =
        static_cast<phi::DenseTensor*>(inplace_tensor->impl().get());
    tensor_dense_tensor->set_meta(variable_dense_tensor->meta());
  }
}

245
std::vector<paddle::experimental::Tensor> EagerUtils::GetOutputs(
246
    const std::vector<std::shared_ptr<EagerVariable>>& outs) {
247
  std::vector<paddle::experimental::Tensor> res;
248 249 250 251 252 253 254 255 256
  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()));
257
    res.emplace_back(out->GetTensorBase(), out->name());
258 259 260 261
  }
  return res;
}

262
paddle::experimental::Tensor EagerUtils::GetOutput(
263
    const std::shared_ptr<EagerVariable>& out) {
264 265 266 267 268 269
  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()));
270 271 272
  return paddle::experimental::Tensor(out->GetTensorBase(), out->name());
}

273 274
void EagerUtils::GetOutput(const std::shared_ptr<EagerVariable>& out,
                           paddle::experimental::Tensor* out_var) {
275
  PADDLE_ENFORCE_NOT_NULL(
276 277 278 279 280 281
      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());
282
  out_var->set_name(out->name());
283 284
}

285
void EagerUtils::GetOutputs(
286
    const std::vector<std::shared_ptr<EagerVariable>>& outs,
287
    std::vector<paddle::experimental::Tensor>* result) {
288
  for (size_t i = 0; i < outs.size(); i++) {
289
    result->emplace_back(outs[i]->GetTensorBase());
290
  }
291 292
}

293 294 295
void EagerUtils::GetOutputs(
    const std::vector<std::shared_ptr<EagerVariable>>& outs,
    const std::vector<paddle::experimental::Tensor*>& out_var) {
296 297
  for (size_t i = 0; i < outs.size(); i++) {
    PADDLE_ENFORCE_NOT_NULL(
298
        out_var[i], paddle::platform::errors::Fatal(
299 300 301 302
                        "Tensor is null and cannot be copied. "
                        "We are tring to OverwriteOutput from its "
                        "shared_ptr, this error may indicate some outputs "
                        "are nullptr"));
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
    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]);
330 331 332 333
  }
}

paddle::experimental::Tensor EagerUtils::RecoverTensorWrapper(
334 335 336 337
    TensorWrapper* tw, const std::shared_ptr<GradNodeBase>& grad_node) {
  return tw->recover(grad_node);
}

H
hong 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
paddle::optional<const paddle::experimental::Tensor&>
EagerUtils::RecoverOptionalTensorWrapper(
    TensorWrapper* tw, const std::shared_ptr<GradNodeBase>& grad_node) {
  PADDLE_ENFORCE_NOT_NULL(
      tw, phi::errors::InvalidArgument("TensorWrapper in "
                                       "RecoverOptionalTensorWrapper function "
                                       "should not be null"));
  auto tmp = tw->recover(grad_node);

  paddle::optional<const paddle::experimental::Tensor&> res{paddle::none};
  if (tmp.initialized()) {
    res = tmp;
  }
  return res;
}

354
std::vector<paddle::experimental::Tensor> EagerUtils::RecoverTensorWrapper(
355 356
    std::vector<TensorWrapper>* tw,
    const std::shared_ptr<GradNodeBase>& grad_node) {
357
  std::vector<paddle::experimental::Tensor> ret;
358 359 360 361 362 363
  for (auto& t : *tw) {
    ret.emplace_back(t.recover(grad_node));
  }
  return ret;
}

364 365
void EagerUtils::CheckAndRetainGrad(
    const paddle::experimental::Tensor& tensor) {
366 367
  VLOG(6) << "Check RetainGradForTensor: " << tensor.name();
  if (FLAGS_retain_grad_for_all_tensor) {
368
    VLOG(6) << "RetainGradForTensor: " << tensor.name();
369 370 371 372 373
    egr::egr_utils_api::RetainGradForTensor(tensor);
  }
}

void EagerUtils::CheckAndRetainGrad(
374
    const std::vector<paddle::experimental::Tensor>& tensors) {
375 376
  if (FLAGS_retain_grad_for_all_tensor) {
    for (auto& tensor : tensors) {
377
      VLOG(6) << "RetainGradForTensor: " << tensor.name();
378 379 380 381 382
      egr::egr_utils_api::RetainGradForTensor(tensor);
    }
  }
}

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
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();
412 413
      autograd_ptr->SetGradNode(
          std::make_shared<egr::GradNodeAccumulation>(autograd_ptr));
414 415 416 417 418 419 420
      return autograd_ptr->GetMutableGradNode();
    } else {
      return nullptr;
    }
  }
}

421 422 423 424
void EagerUtils::FillZeroForEmptyGradInputs(
    std::vector<std::vector<paddle::experimental::Tensor>>* in_grads,
    const std::vector<std::vector<GradSlotMeta>>& grad_in_metas) {
  for (size_t i = 0; i < in_grads->size(); i++) {
425
    for (size_t j = 0; j < (*in_grads)[i].size(); j++) {
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
      paddle::experimental::Tensor& grad = (*in_grads)[i][j];
      if (!grad.is_initialized()) {
        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();
        phi::Place place = grad_in_meta.GetPlace();

        auto tensor_with_zero = paddle::experimental::full(
            phi::vectorize(tensor_meta.dims), 0.0, tensor_meta.dtype, place);
        grad.set_impl(tensor_with_zero.impl());
      }
    }
  }
}

445
}  // namespace egr