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

#pragma once

17
#include "paddle/fluid/eager/api/utils/tensor_utils.h"
18 19 20 21
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"

22
#include "paddle/phi/api/all.h"
23 24 25

namespace egr {

26 27
class TensorWrapper;

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
/**
 * EagerUtils is utils used to do some static conversion or autograd
 * members access, this class is desinged to be a full static functional
 * utils class
 * **/

template <typename ElementType>
class IterHelper {
  virtual void visit(ElementType element) = 0;

  void visit(std::vector<ElementType>* elements) {
    for (auto element : *elements) visit(element);
  }

  template <typename... Args>
  void apply() {}

 public:
  template <typename T, typename... Args>
  void apply(T&& arg, Args&&... args) {
    visit(std::forward<T>(arg));
    return apply(std::forward<Args>(args)...);
  }
  virtual ~IterHelper() = default;
};

class ComputeRequireGradIter : public IterHelper<AutogradMeta*> {
 public:
  bool RequireGrad() { return require_grad_; }

 private:
  void visit(AutogradMeta* element) override {
60 61 62
    // Dispensable Tensors feeds in nullptr autograd_meta
    if (!element) return;

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    bool stop_gradient = element->StopGradient();
    if (!stop_gradient) require_grad_ = true;
  }

  bool require_grad_ = false;
};

class PassStopGradientIter : public IterHelper<AutogradMeta*> {
 public:
  void SetStopGradient(bool stop_gradient) { stop_gradient_ = stop_gradient; }

 private:
  void visit(AutogradMeta* element) override {
    if (!element) {
      // TODO(jiabin): Add Tensor name here when we supported.
      VLOG(2) << "Tensor is NULL";
      return;
    }
81
    element->WeakSetStopGradient(stop_gradient_);
82 83 84 85 86 87 88 89 90 91
  }

  bool stop_gradient_ = true;
};

class EagerUtils {
 public:
  /**
   * We have to use autograd_meta and multi_autograd_meta to initialize
   * autograd_meta for tensor, since we can't init it in
92
   * egr::EagerVariable's
93 94 95
   * constructor (it's abstract class there)
   *
   * **/
96
  static AutogradMeta* autograd_meta(paddle::experimental::Tensor* target);
97

98
  static std::vector<AutogradMeta*> autograd_meta(
99
      std::vector<paddle::experimental::Tensor>* targets);
100

101 102
  static std::pair<size_t, size_t> OutRankInfo(
      const paddle::experimental::Tensor& target);
103 104

  static std::shared_ptr<GradNodeBase> grad_node(
105
      const paddle::experimental::Tensor& target);
106 107
  static paddle::experimental::Tensor* mutable_grad(
      const paddle::experimental::Tensor& target);
108 109 110 111 112 113 114 115 116 117 118 119 120 121

  // Set history is used to set backward info during forward process, it will
  // set forward var's autograd meta's grad node as current backward node.
  static void SetHistory(std::vector<AutogradMeta*>* autograd_metas,
                         const std::shared_ptr<GradNodeBase>& grad_node);
  static void SetHistory(AutogradMeta* autograd_meta,
                         const std::shared_ptr<GradNodeBase>& grad_node);

  // This is used for Set vector of tensors' rank
  static void SetOutRankWithSlot(std::vector<AutogradMeta*>* targets,
                                 size_t slot_id);
  static void SetOutRankWithSlot(AutogradMeta* target, size_t slot_id);

  // This method will return an AutogradMeta pointer unsafely.
122 123
  static AutogradMeta* nullable_autograd_meta(
      const paddle::experimental::Tensor& target);
H
hong 已提交
124 125
  static AutogradMeta* nullable_autograd_meta(
      paddle::optional<const paddle::experimental::Tensor&> target);
126
  static std::vector<AutogradMeta*> nullable_autograd_meta(
127 128 129
      const std::vector<paddle::experimental::Tensor>& targets);
  static AutogradMeta* unsafe_autograd_meta(
      const paddle::experimental::Tensor& target);
130
  static std::vector<AutogradMeta*> unsafe_autograd_meta(
131
      const std::vector<paddle::experimental::Tensor>& targets);
132

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
  template <typename T, typename... Args>
  static bool ComputeRequireGrad(T trace_backward, Args&&... args) {
    if (!trace_backward) return false;

    auto iter = ComputeRequireGradIter();
    iter.apply(std::forward<Args>(args)...);

    return iter.RequireGrad();
  }

  template <typename T, typename... Args>
  static void PassStopGradient(T stop_gradient, Args&&... args) {
    auto iter = PassStopGradientIter();
    iter.SetStopGradient(stop_gradient);
    iter.apply(std::forward<Args>(args)...);
  }

150 151 152 153 154 155 156 157 158 159 160 161 162
  static void CheckInplace(const paddle::experimental::Tensor& target,
                           const AutogradMeta* autograd_meta,
                           bool require_any_grad) {
    if (require_any_grad && autograd_meta) {
      PADDLE_ENFORCE_EQ(!autograd_meta->StopGradient() &&
                            egr::egr_utils_api::IsLeafTensor(target),
                        false, paddle::platform::errors::InvalidArgument(
                                   "Leaf Var (%s) that doesn't stop gradient "
                                   "can't use inplace strategy.",
                                   target.name()));
    }
  }

163
  // TensorWrapper Utils
164 165 166 167
  static paddle::experimental::Tensor RecoverTensorWrapper(
      TensorWrapper* tw, const std::shared_ptr<GradNodeBase>& grad_node);
  static std::vector<paddle::experimental::Tensor> RecoverTensorWrapper(
      std::vector<TensorWrapper>* tw,
168
      const std::shared_ptr<GradNodeBase>& grad_node);
H
hong 已提交
169 170 171
  static paddle::optional<const paddle::experimental::Tensor&>
  RecoverOptionalTensorWrapper(TensorWrapper* tw,
                               const std::shared_ptr<GradNodeBase>& grad_node);
172

173
  // Intermidate needed remove this once we don't need legacy
174
  // Inner Method
175
  static std::shared_ptr<egr::EagerVariable> TrySyncToVar(
176 177
      const paddle::experimental::Tensor& tensor);
  // Basic Input
178
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
179 180
      const paddle::experimental::Tensor& tensor);
  // Basic Output
181
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
182 183
      paddle::experimental::Tensor* tensor);
  // Multi Output
184
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
185 186
      const std::vector<paddle::experimental::Tensor*>& tensors);
  // Multi Input
187
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
188 189
      const std::vector<paddle::experimental::Tensor>& tensors);
  // Construct empty output
190 191
  static std::vector<std::shared_ptr<EagerVariable>> CreateVars(
      const size_t num);
192
  // Construct Tensor From var
193 194 195
  static void ModifyInplaceInput(
      const std::shared_ptr<EagerVariable>& inplace_variable,
      paddle::experimental::Tensor* inplace_tensor);
196
  static std::vector<paddle::experimental::Tensor> GetOutputs(
197
      const std::vector<std::shared_ptr<EagerVariable>>& outs);
198
  static paddle::experimental::Tensor GetOutput(
199
      const std::shared_ptr<EagerVariable>& out);
200 201 202
  static void GetOutput(const std::shared_ptr<EagerVariable>& out,
                        paddle::experimental::Tensor* out_var);
  static void GetOutputs(
203
      const std::vector<std::shared_ptr<EagerVariable>>& outs,
204 205 206 207 208 209 210 211 212 213 214 215 216 217
      std::vector<paddle::experimental::Tensor>* result);
  static void GetOutputs(
      const std::vector<std::shared_ptr<EagerVariable>>& outs,
      const std::vector<paddle::experimental::Tensor*>& out_var);
  static void GetOutputs(const std::shared_ptr<EagerVariable>& out,
                         std::vector<paddle::experimental::Tensor>* result);
  static void GetOutputs(
      const std::shared_ptr<EagerVariable>& out,
      const std::vector<paddle::experimental::Tensor*>& out_var);

  static void Output2Result(
      const std::vector<paddle::experimental::Tensor*>& out_var,
      std::vector<paddle::experimental::Tensor>* result);

218 219 220 221
  // end Intermidate needed

  static void CheckAndRetainGrad(const paddle::experimental::Tensor& tensor);
  static void CheckAndRetainGrad(
222
      const std::vector<paddle::experimental::Tensor>& tensors);
223 224
  static std::shared_ptr<egr::GradNodeBase> GetGradAccumulationNode(
      const paddle::experimental::Tensor& tensor);
225 226 227 228 229 230 231

  /**
    * Fill Zero
    * **/
  static void FillZeroForEmptyGradInputs(
      std::vector<std::vector<paddle::experimental::Tensor>>* out_grads,
      const std::vector<std::vector<GradSlotMeta>>& grad_out_metas);
232 233 234
};

}  // namespace egr