composite_backward_api.h 9.4 KB
Newer Older
J
Jiabin Yang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright (c) 2022 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
16
#include "paddle/fluid/prim/api/all.h"
17 18 19
#include "paddle/phi/common/int_array.h"
#include "paddle/phi/core/ddim.h"

J
Jiabin Yang 已提交
20 21
namespace paddle {
namespace prim {
22 23 24 25 26
using Tensor = paddle::experimental::Tensor;
using IntArray =
    paddle::experimental::IntArrayBase<paddle::experimental::Tensor>;
//  This function should have as same signature as phi, which defined in
//  paddle/phi/api/backward/backward_api.h
J
Jiabin Yang 已提交
27 28
template <typename T>
void tanh_grad(const Tensor& out, const Tensor& grad_out, Tensor* grad_x) {
29
  if (!grad_x) return;
J
Jiabin Yang 已提交
30 31 32
  auto tmp = pow<T>(out, 2.0);
  tmp = scale<T>(tmp, -1.0, 1.0, true);
  auto grad_x_tmp = multiply<T>(grad_out, tmp);
33
  set_output<T>(grad_x_tmp, grad_x);
J
Jiabin Yang 已提交
34
}
35

36 37 38 39 40 41 42 43 44
template <typename T>
void subtract_grad(const Tensor& x,
                   const Tensor& y,
                   const Tensor& out_grad,
                   int axis,
                   Tensor* dx,
                   Tensor* dy) {
  if (dy) {
    auto scale_out_grad = scale<T>(out_grad, -1.0, 0.0, true);
45
    if (x.dims() != y.dims()) {
46
      // Maybe need reduce here
47 48 49 50 51 52 53
      phi::DDim reduce_dim = get_reduce_dims(y.dims(), x.dims());
      if (!reduce_dim.size()) {
        by_pass<T>(scale_out_grad, dy);
      } else {
        auto dy_reduce_res = sum<T>(
            scale_out_grad, phi::vectorize(reduce_dim), y.dtype(), false);
        auto dy_tmp = reshape<T>(dy_reduce_res, phi::vectorize(y.dims()));
54
        set_output<T>(dy_tmp, dy);
55
      }
56 57 58 59 60
    } else {
      by_pass<T>(scale_out_grad, dy);
    }
  }
  if (dx) {
61
    if (y.dims() != x.dims()) {
62
      // Maybe need reduce here
63 64 65 66 67 68 69
      auto reduce_dim = get_reduce_dims(x.dims(), y.dims());
      if (!reduce_dim.size()) {
        by_pass<T>(out_grad, dx);
      } else {
        auto dx_reduce_res =
            sum<T>(out_grad, phi::vectorize(reduce_dim), x.dtype(), false);
        auto dx_tmp = reshape<T>(dx_reduce_res, phi::vectorize(x.dims()));
70
        set_output<T>(dx_tmp, dx);
71
      }
72 73 74 75 76 77 78 79 80 81 82 83 84 85
    } else {
      by_pass<T>(out_grad, dx);
    }
  }
}

template <typename T>
void add_grad(const Tensor& x,
              const Tensor& y,
              const Tensor& out_grad,
              int axis,
              Tensor* dx,
              Tensor* dy) {
  if (dy) {
86
    if (x.dims() != y.dims()) {
87
      // Maybe need reduce here
88 89 90 91 92 93 94
      phi::DDim reduce_dim = get_reduce_dims(y.dims(), x.dims());
      if (!reduce_dim.size()) {
        by_pass<T>(out_grad, dy);
      } else {
        auto dy_reduce_res =
            sum<T>(out_grad, phi::vectorize(reduce_dim), y.dtype(), false);
        auto dy_tmp = reshape<T>(dy_reduce_res, phi::vectorize(y.dims()));
95
        set_output<T>(dy_tmp, dy);
96 97
      }

98 99 100 101 102
    } else {
      by_pass<T>(out_grad, dy);
    }
  }
  if (dx) {
103
    if (y.dims() != x.dims()) {
104
      // Maybe need reduce here
105 106 107 108 109 110 111
      auto reduce_dim = get_reduce_dims(x.dims(), y.dims());
      if (!reduce_dim.size()) {
        by_pass<T>(out_grad, dx);
      } else {
        auto dx_reduce_res =
            sum<T>(out_grad, phi::vectorize(reduce_dim), x.dtype(), false);
        auto dx_tmp = reshape<T>(dx_reduce_res, phi::vectorize(x.dims()));
112
        set_output<T>(dx_tmp, dx);
113
      }
114 115 116 117 118 119
    } else {
      by_pass<T>(out_grad, dx);
    }
  }
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
template <typename T>
void sum_grad(const Tensor& x,
              const Tensor& out_grad,
              const IntArray& axis,
              bool keepdim,
              bool reduce_all,
              Tensor* x_grad) {
  if (!x_grad) {
    return;
  }
  std::vector<int> x_dim = phi::vectorize<int>(x.dims());
  int64_t axis_size = axis.size();
  int64_t x_dim_size = x_dim.size();
  reduce_all = false;
  if (reduce_all || axis_size == 0 || axis_size == x_dim_size) {
    reduce_all = true;
  } else {
    reduce_all = false;
  }
  auto x_grad_tmp = Tensor();
140 141 142 143 144 145 146 147 148 149 150
  if (x_dim_size == 1) {
    x_grad_tmp = expand<T>(out_grad, IntArray(x_dim));
  } else {
    if (!keepdim) {
      auto axis_ = std::vector<int64_t>();
      if (reduce_all) {
        for (int64_t i = 1; i < x_dim_size; i++) {
          axis_.push_back(i);
        }
      } else {
        axis_ = axis.GetData();
151
      }
152 153
      auto out_grad_ = unsqueeze<T>(out_grad, axis_);
      x_grad_tmp = expand<T>(out_grad_, IntArray(x_dim));
154
    } else {
155
      x_grad_tmp = expand<T>(out_grad, IntArray(x_dim));
156 157 158
    }
  }

159
  set_output<T>(x_grad_tmp, x_grad);
160 161
}

162 163 164 165 166 167 168 169 170 171 172 173 174 175
template <typename T>
void divide_grad(const Tensor& x,
                 const Tensor& y,
                 const Tensor& out,
                 const Tensor& out_grad,
                 int axis,
                 Tensor* dx,
                 Tensor* dy) {
  if (dy) {
    // dy = -(x/y^2) * dout
    auto tmp0 = pow<T>(y, 2.0);
    auto tmp1 = divide<T>(x, tmp0);
    auto tmp2 = scale<T>(tmp1, -1.0, 0.0, true);
    auto dy_res = multiply<T>(tmp2, out_grad);
176
    if (x.dims() != y.dims()) {
177
      // Maybe need reduce here
178 179
      phi::DDim reduce_dim = get_reduce_dims(y.dims(), x.dims());
      if (!reduce_dim.size()) {
180
        set_output<T>(dy_res, dy);
181 182 183 184
      } else {
        auto dy_reduce_res =
            sum<T>(dy_res, phi::vectorize(reduce_dim), y.dtype(), false);
        auto dy_tmp = reshape<T>(dy_reduce_res, phi::vectorize(y.dims()));
185
        set_output<T>(dy_tmp, dy);
186
      }
187
    } else {
188
      set_output<T>(dy_res, dy);
189 190 191 192
    }
  }  // indicate we will compute dy
  if (dx) {
    // dx = (1/y) * dout
193
    auto one_tensor = full<T>(phi::vectorize(y.dims()), 1.0, y.dtype());
194 195
    auto tmp0 = divide<T>(one_tensor, y);
    auto dx_res = multiply<T>(tmp0, out_grad);
196
    if (y.dims() != x.dims()) {
197
      // Maybe need reduce here
198 199
      auto reduce_dim = get_reduce_dims(x.dims(), y.dims());
      if (!reduce_dim.size()) {
200
        set_output<T>(dx_res, dx);
201 202 203 204
      } else {
        auto dx_reduce_res =
            sum<T>(dx_res, phi::vectorize(reduce_dim), x.dtype(), false);
        auto dx_tmp = reshape<T>(dx_reduce_res, phi::vectorize(x.dims()));
205
        set_output<T>(dx_tmp, dx);
206 207
      }

208
    } else {
209
      set_output<T>(dx_res, dx);
210 211 212
    }
  }  // indicate we will compute dx
}
213 214 215 216 217 218 219

template <typename T>
void sqrt_grad(const Tensor& out, const Tensor& out_grad, Tensor* x_grad) {
  if (x_grad) {
    auto div_x = full<T>(phi::vectorize(out.dims()), 0.5);
    auto tmp = divide<T>(div_x, out);
    auto x_grad_tmp = multiply<T>(out_grad, tmp);
220
    set_output<T>(x_grad_tmp, x_grad);
221 222
  }
}
223 224 225 226 227 228 229 230 231 232

template <typename T>
void multiply_grad(const Tensor& x,
                   const Tensor& y,
                   const Tensor& out_grad,
                   int axis,
                   Tensor* x_grad,
                   Tensor* y_grad) {
  if (x_grad) {
    auto x_grad_unreduce = multiply<T>(out_grad, y);
233 234
    if (x_grad_unreduce.dims() != x.dims()) {
      auto axes = get_reduce_dims_from_out(x_grad_unreduce.dims(), x.dims());
235
      if (!axes.size()) {
236
        set_output<T>(x_grad_unreduce, x_grad);
237 238 239 240 241 242 243 244
      } else {
        auto x_grad_reduced = sum<T>(x_grad_unreduce,
                                     phi::vectorize(axes),
                                     x_grad_unreduce.dtype(),
                                     false);
        if (x_grad_reduced.dims().size() != x.dims().size()) {
          x_grad_reduced = reshape<T>(x_grad_reduced, x.shape());
        }
245
        set_output<T>(x_grad_reduced, x_grad);
246 247
      }
    } else {
248
      set_output<T>(x_grad_unreduce, x_grad);
249 250 251 252
    }
  }
  if (y_grad) {
    auto y_grad_unreduce = multiply<T>(out_grad, x);
253 254
    if (y_grad_unreduce.dims() != y.dims()) {
      auto axes = get_reduce_dims_from_out(y_grad_unreduce.dims(), y.dims());
255
      if (!axes.size()) {
256
        set_output<T>(y_grad_unreduce, y_grad);
257 258 259 260 261 262 263 264
      } else {
        auto y_grad_reduced = sum<T>(y_grad_unreduce,
                                     phi::vectorize(axes),
                                     y_grad_unreduce.dtype(),
                                     false);
        if (y_grad_reduced.dims().size() != y.dims().size()) {
          y_grad_reduced = reshape<T>(y_grad_reduced, y.shape());
        }
265
        set_output<T>(y_grad_reduced, y_grad);
266 267
      }
    } else {
268
      set_output<T>(y_grad_unreduce, y_grad);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    }
  }
}

template <typename T>
void expand_grad(const Tensor& x,
                 const Tensor& out_grad,
                 const IntArray& shape,
                 Tensor* x_grad) {
  if (x_grad) {
    auto out_dims = phi::make_ddim(shape.GetData());
    if (out_dims != x.dims()) {
      auto axes = get_reduce_dims(x.dims(), out_dims);
      if (!axes.size()) {
        by_pass<T>(out_grad, x_grad);
      } else {
        auto reduced = sum<T>(out_grad, phi::vectorize(axes), x.dtype(), false);
        if (reduced.dims().size() != x.dims().size()) {
          reduced = reshape<T>(reduced, x.shape());
        }
289
        set_output<T>(reduced, x_grad);
290 291 292 293 294 295 296 297 298 299
      }
    } else {
      by_pass<T>(out_grad, x_grad);
    }
  }
}

template <typename T>
void exp_grad(const Tensor& out, const Tensor& out_grad, Tensor* x_grad) {
  if (x_grad) {
300
    set_output<T>(multiply<T>(out_grad, out), x_grad);
301 302 303
  }
}

J
Jiabin Yang 已提交
304 305
}  // namespace prim
}  // namespace paddle