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

#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"

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

namespace egr {

25 26
class TensorWrapper;

27 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
/**
 * 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 {
59 60 61
    // Dispensable Tensors feeds in nullptr autograd_meta
    if (!element) return;

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    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;
    }
80
    element->WeakSetStopGradient(stop_gradient_);
81 82 83 84 85 86 87 88 89 90
  }

  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
91
   * egr::EagerVariable's
92 93 94
   * constructor (it's abstract class there)
   *
   * **/
95
  static AutogradMeta* autograd_meta(paddle::experimental::Tensor* target);
96

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

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

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

  // 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.
119 120
  static AutogradMeta* nullable_autograd_meta(
      const paddle::experimental::Tensor& target);
121
  static std::vector<AutogradMeta*> nullable_autograd_meta(
122 123 124
      const std::vector<paddle::experimental::Tensor>& targets);
  static AutogradMeta* unsafe_autograd_meta(
      const paddle::experimental::Tensor& target);
125
  static std::vector<AutogradMeta*> unsafe_autograd_meta(
126
      const std::vector<paddle::experimental::Tensor>& targets);
127

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
  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)...);
  }

145
  // TensorWrapper Utils
146 147 148 149
  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,
150 151
      const std::shared_ptr<GradNodeBase>& grad_node);

152
  // Intermidate needed remove this once we don't need legacy
153
  // Inner Method
154
  static std::shared_ptr<egr::EagerVariable> TrySyncToVar(
155 156
      const paddle::experimental::Tensor& tensor);
  // Basic Input
157
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
158 159
      const paddle::experimental::Tensor& tensor);
  // Basic Output
160
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
161 162
      paddle::experimental::Tensor* tensor);
  // Multi Output
163
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
164 165
      const std::vector<paddle::experimental::Tensor*>& tensors);
  // Multi Input
166
  static std::vector<std::shared_ptr<egr::EagerVariable>> TrySyncToVars(
167 168
      const std::vector<paddle::experimental::Tensor>& tensors);
  // Construct empty output
169 170
  static std::vector<std::shared_ptr<EagerVariable>> CreateVars(
      const size_t num);
171 172
  // Construct Tensor From var
  static std::vector<paddle::experimental::Tensor> GetOutputs(
173
      const std::vector<std::shared_ptr<EagerVariable>>& outs);
174
  static paddle::experimental::Tensor GetOutput(
175
      const std::shared_ptr<EagerVariable>& out);
176 177 178
  static void GetOutput(const std::shared_ptr<EagerVariable>& out,
                        paddle::experimental::Tensor* out_var);
  static void GetOutputs(
179
      const std::vector<std::shared_ptr<EagerVariable>>& outs,
180 181 182 183 184 185 186 187 188 189 190 191 192 193
      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);

194 195 196 197
  // end Intermidate needed

  static void CheckAndRetainGrad(const paddle::experimental::Tensor& tensor);
  static void CheckAndRetainGrad(
198
      const std::vector<paddle::experimental::Tensor>& tensors);
199 200
  static std::shared_ptr<egr::GradNodeBase> GetGradAccumulationNode(
      const paddle::experimental::Tensor& tensor);
201 202 203
};

}  // namespace egr