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

#include "paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.h"
#include "paddle/fluid/imperative/layout_autotune.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/tensor_utils.h"
namespace egr {
inline paddle::experimental::Tensor EagerTraceTransposeOp(
23
    const phi::DataLayout layout, const paddle::experimental::Tensor& in) {
24
  VLOG(4) << "AutoTune Transpose from " << in.layout() << " to " << layout
25
          << ", tensor's dim size is " << in.shape().size();
26 27 28 29
  if (in.shape().size() != 4) {
    return in;
  }
  std::vector<int> axis;
30
  if (layout == phi::DataLayout::NHWC) {
31
    axis = {0, 2, 3, 1};
32
  } else if (layout == phi::DataLayout::NCHW) {
33 34 35 36
    axis = {0, 3, 1, 2};
  } else {
    axis = {0, 1, 2, 3};
  }
J
Jiabin Yang 已提交
37
  auto out_tensor = transpose_ad_func(in, axis);
38
  VLOG(4) << "AutoTune Transpose from " << in.layout() << " to " << layout;
39 40 41
  return out_tensor;
}

42
inline phi::DataLayout DesiredLayout() {
43 44 45
  return paddle::imperative::LayoutAutoTune::Instance().GetDesiredLayout();
}

46
inline phi::DataLayout DefaultLayout() {
47 48 49 50
  return paddle::imperative::LayoutAutoTune::Instance().GetDefaultLayout();
}

inline void UpdateLayout(paddle::experimental::Tensor* out_tensor,
51
                         const phi::DataLayout layout) {
52 53 54 55 56 57 58 59 60 61
  if (out_tensor->layout() != layout) {
    VLOG(4) << "Update out_tensor's layout from " << out_tensor->layout()
            << " to " << layout;
    phi::DenseTensorUtils::GetMutableMeta(
        static_cast<phi::DenseTensor*>(out_tensor->impl().get()))
        ->layout = layout;
  }
}

inline void DealWithShapeOp(paddle::experimental::Tensor* out_tensor,
62
                            const phi::DataLayout layout,
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
                            int dim_size) {
  auto des_layout = DesiredLayout();
  auto def_layout = DefaultLayout();
  int32_t* value =
      static_cast<phi::DenseTensor*>(out_tensor->impl().get())->data<int32_t>();
  bool change_dim =
      (des_layout != def_layout && layout == des_layout && dim_size == 4);
  VLOG(6) << "'Shape OP', layout autotune: True"
          << " desired_layout: " << des_layout
          << " default_layout: " << def_layout
          << " tensor layout: " << out_tensor->layout()
          << " tensor's shape size is : " << dim_size;
  // It's means input tensor has been autotune and tensor's layout is
  // desired_layout
  std::vector<int32_t> dims;
  dims.resize(dim_size);
  for (int i = 0; i < dim_size; i++) {
    dims[i] = value[i];
  }
82
  auto des_str = phi::DataLayoutToString(des_layout);
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  if (change_dim && des_str == "NCHW") {
    // NCHW -> NHWC
    VLOG(6) << "layout autotune get Shape from NCHW -> NHWC " << value[0] << " "
            << value[1] << " " << value[2] << " " << value[3] << " to "
            << dims[0] << " " << dims[2] << " " << dims[3] << " " << dims[1];
    value[0] = dims[0];
    value[1] = dims[2];
    value[2] = dims[3];
    value[3] = dims[1];
  } else if (change_dim && des_str == "NHWC") {
    // NHWC -> NCHW
    VLOG(6) << "layout autotune get Shape from NHWC -> NCHW " << value[0] << " "
            << value[1] << " " << value[2] << " " << value[3] << " to "
            << dims[0] << " " << dims[3] << " " << dims[1] << " " << dims[2];
    value[0] = dims[0];
    value[1] = dims[3];
    value[2] = dims[1];
    value[3] = dims[2];
  }
}

104 105
// agnostic op
class EagerLayoutTransformer {
106
  using Layout = phi::DataLayout;
107

108
 public:
109
  EagerLayoutTransformer() : op_name_(""), final_layout_(Layout::UNDEFINED) {}
110 111 112 113 114

  EagerLayoutTransformer(const EagerLayoutTransformer&) = delete;

  EagerLayoutTransformer& operator=(const EagerLayoutTransformer&) = delete;

115 116 117 118 119
  explicit EagerLayoutTransformer(
      const std::string& op_name,
      const paddle::small_vector<std::vector<paddle::experimental::Tensor>,
                                 kSlotSmallVectorSize>& tensors_vector,
      const Layout final_layout = Layout::UNDEFINED)
120 121
      : op_name_(op_name), final_layout_(final_layout), dim_size_(1) {
    VLOG(4) << "Agnostic op : " << op_name_ << "'s layout is " << final_layout_;
122 123
  }

124 125
  virtual ~EagerLayoutTransformer() {}

126 127
  virtual paddle::experimental::Tensor TransInTensor(
      const std::string& in_name, const paddle::experimental::Tensor& in) {
128 129 130 131 132 133
    // update in shape size
    dim_size_ = in.shape().size();
    bool need_trans =
        !(final_layout_ == Layout::UNDEFINED || final_layout_ == in.layout());
    // This is for Agnostic op when layout is differnet
    if (need_trans) {
134 135 136 137 138 139
      auto out_tensor = EagerTraceTransposeOp(final_layout_, in);
      phi::DenseTensorUtils::GetMutableMeta(
          static_cast<phi::DenseTensor*>(out_tensor.impl().get()))
          ->layout = final_layout_;
      return out_tensor;
    }
140
    return in;
141 142
  }

143
  virtual paddle::optional<paddle::experimental::Tensor> TransInTensor(
144
      const std::string& in_name,
145 146
      const paddle::optional<paddle::experimental::Tensor>& in) {
    return in ? TransInTensor(in_name, *in) : in;
147 148
  }

149
  virtual std::vector<paddle::experimental::Tensor> TransInTensors(
150 151 152 153 154
      const std::string& in_name,
      const std::vector<paddle::experimental::Tensor>& in) {
    return in;
  }

155 156 157 158
  virtual paddle::optional<std::vector<paddle::experimental::Tensor>>
  TransInTensors(
      const std::string& in_name,
      const paddle::optional<std::vector<paddle::experimental::Tensor>>& in) {
159
    return (in ? TransInTensors(in_name, *in) : in);
160 161 162 163
  }

  virtual void SetOutTensorLayout(
      std::vector<paddle::experimental::Tensor>* out_tensor) {
164 165
    bool update_layout = !(final_layout_ == Layout::UNDEFINED);
    if (update_layout) {
166 167 168
      for (size_t i = 0; i < out_tensor->size(); i++) {
        phi::DenseTensorUtils::GetMutableMeta(
            static_cast<phi::DenseTensor*>((*out_tensor)[i].impl().get()))
169
            ->layout = DesiredLayout();
170 171
      }
    }
172 173 174 175 176
  }

  virtual void SetOutTensorLayout(
      paddle::optional<paddle::experimental::Tensor>* out_tensor) {
    VLOG(4) << "AutoTune out tensor is optional";
177 178
  }

179 180
  virtual void SetOutTensorLayout(
      paddle::optional<std::vector<paddle::experimental::Tensor>>* out_tensor) {
181
    VLOG(4) << "AutoTune out tensor is optional";
182 183 184
  }

  virtual void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
185 186 187 188 189 190
    if (op_name_ == "shape") {
      return DealWithShapeOp(out_tensor, final_layout_, dim_size_);
    }
    bool need_update = !(final_layout_ == Layout::UNDEFINED);
    if (need_update) {
      UpdateLayout(out_tensor, final_layout_);
191 192 193
    }
  }

194 195
 protected:
  std::string op_name_;
196
  const Layout final_layout_;
197
  int dim_size_;
198 199 200 201 202 203
};

class EagerHeavilyLayoutSensitiveOpTransformer : public EagerLayoutTransformer {
 public:
  explicit EagerHeavilyLayoutSensitiveOpTransformer(const std::string& op_name,
                                                    std::string* layout)
204 205
      : op_name_(op_name), desired_layout_(DesiredLayout()) {
    VLOG(4) << "Heavily op: " << op_name;
206
    *layout = phi::DataLayoutToString(DesiredLayout());
207 208 209 210 211 212 213 214 215 216 217 218
  }

  paddle::experimental::Tensor TransInTensor(
      const std::string& in_name, const paddle::experimental::Tensor& in) {
    if (heavily_input_.count(in_name) != 0 && in.layout() != desired_layout_) {
      auto out_tensor = EagerTraceTransposeOp(desired_layout_, in);
      return out_tensor;
    }
    return in;
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
219
    UpdateLayout(out_tensor, desired_layout_);
220 221 222 223 224 225 226 227 228 229 230 231 232
  }

  void SetOutTensorLayout(
      std::vector<paddle::experimental::Tensor*>* out_tensor) {
    for (size_t i = 0; i < out_tensor->size(); i++) {
      SetOutTensorLayout((*out_tensor)[i]);
    }
  }

  void SetOutTensorLayout(
      std::vector<paddle::experimental::Tensor>* out_tensor) {
    for (size_t i = 0; i < out_tensor->size(); i++) {
      if ((*out_tensor)[i].layout() != desired_layout_) {
233 234
        VLOG(4) << "Update out_tensor's layout from "
                << (*out_tensor)[i].layout() << " to " << desired_layout_;
235 236 237 238 239 240 241 242 243
        phi::DenseTensorUtils::GetMutableMeta(
            static_cast<phi::DenseTensor*>((*out_tensor)[i].impl().get()))
            ->layout = desired_layout_;
      }
    }
  }

 protected:
  std::string op_name_;
244
  const phi::DataLayout desired_layout_;
245 246 247 248 249 250
  std::unordered_set<std::string> heavily_input_{"x", "y", "input"};
};

class EagerLightlyLayoutSensitiveOpTransformer : public EagerLayoutTransformer {
 public:
  EagerLightlyLayoutSensitiveOpTransformer() {}
251 252 253 254
  explicit EagerLightlyLayoutSensitiveOpTransformer(
      const std::string& op_name) {
    VLOG(4) << "Lightly op : " << op_name;
    auto desired_layout = DesiredLayout();
255
    final_layout_ = phi::DataLayoutToString(desired_layout);
256 257 258 259 260
  }

  // transpose from desired to default
  paddle::experimental::Tensor TransInTensor(
      const std::string& in_name, const paddle::experimental::Tensor& in) {
261
    std::string input_layout = phi::DataLayoutToString(in.layout());
262
    auto default_layout = DefaultLayout();
263
    if (final_layout_ == input_layout && in.shape().size() == 4) {
264
      auto out_tensor = EagerTraceTransposeOp(phi::DataLayout::UNDEFINED, in);
265 266 267 268 269 270 271 272
      phi::DenseTensorUtils::GetMutableMeta(
          static_cast<phi::DenseTensor*>(out_tensor.impl().get()))
          ->layout = default_layout;
      return out_tensor;
    }
    return in;
  }

273
  virtual std::vector<paddle::experimental::Tensor> TransInTensors(
274 275 276
      const std::string& in_name,
      const std::vector<paddle::experimental::Tensor>& in) {
    std::vector<paddle::experimental::Tensor> result;
277 278
    auto desired_layout = DesiredLayout();
    auto default_layout = DefaultLayout();
279 280 281
    for (size_t i = 0; i < in.size(); i++) {
      auto in_tensor = in[i];
      if (in_tensor.layout() == desired_layout) {
282 283
        auto out_tensor =
            EagerTraceTransposeOp(phi::DataLayout::UNDEFINED, in_tensor);
284 285 286 287 288 289 290 291 292 293 294 295
        phi::DenseTensorUtils::GetMutableMeta(
            static_cast<phi::DenseTensor*>(out_tensor.impl().get()))
            ->layout = default_layout;
        result.emplace_back(out_tensor);
      } else {
        result.emplace_back(in_tensor);
      }
    }
    return result;
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
296
    UpdateLayout(out_tensor, DefaultLayout());
297 298 299 300 301 302 303 304 305 306 307
  }

  void SetOutTensorLayout(
      std::vector<paddle::experimental::Tensor*>* out_tensor) {
    for (size_t i = 0; i < out_tensor->size(); i++) {
      SetOutTensorLayout((*out_tensor)[i]);
    }
  }

  void SetOutTensorLayout(
      std::vector<paddle::experimental::Tensor>* out_tensor) {
308
    auto default_layout = DefaultLayout();
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    for (size_t i = 0; i < out_tensor->size(); i++) {
      phi::DenseTensorUtils::GetMutableMeta(
          static_cast<phi::DenseTensor*>((*out_tensor)[i].impl().get()))
          ->layout = default_layout;
    }
  }

 protected:
  std::string final_layout_;
  std::unordered_set<std::string> heavily_input_{"x", "y", "input"};
};

class EagerTransposeOpTransformer
    : public EagerLightlyLayoutSensitiveOpTransformer {
 public:
  EagerTransposeOpTransformer() {}
325 326
  explicit EagerTransposeOpTransformer(const std::string& op_name) {
    VLOG(4) << "AutoTuneTransformer op: " << op_name;
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
  }

  void SetAttr(std::vector<int>* axis, bool is_nhwc) {
    std::vector<int> perm_nchw = {0, 2, 3, 1};
    std::vector<int> perm_nhwc = {0, 3, 1, 2};
    auto perm = is_nhwc ? perm_nhwc : perm_nchw;
    (*axis)[0] = perm[(*axis)[0]];
    (*axis)[1] = perm[(*axis)[1]];
    (*axis)[2] = perm[(*axis)[2]];
    (*axis)[3] = perm[(*axis)[3]];
  }

  paddle::experimental::Tensor TransInTensor(
      const std::string& in_name, const paddle::experimental::Tensor& in) {
    return in;
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
345
    UpdateLayout(out_tensor, DefaultLayout());
346 347 348 349 350 351 352
  }
};

class EagerArgmaxOpTransformer
    : public EagerLightlyLayoutSensitiveOpTransformer {
 public:
  EagerArgmaxOpTransformer() {}
353 354
  explicit EagerArgmaxOpTransformer(const std::string& op_name) {
    VLOG(4) << "AutoTuneTransformer op: " << op_name;
355 356 357 358 359 360 361 362 363 364 365
  }

  void SetAttr(paddle::experimental::Scalar* axis, bool is_nhwc) {
    std::vector<int> perm_nhwc = {0, 3, 1, 2};
    std::vector<int> perm_nchw = {0, 2, 3, 1};
    auto perm = is_nhwc ? perm_nhwc : perm_nchw;
    int axes = axis->to<int>();
    (*axis) = static_cast<paddle::experimental::Scalar>(perm[axes]);
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
366
    UpdateLayout(out_tensor, DesiredLayout());
367 368 369 370 371 372 373
  }
};

class EagerFlattenOpTransformer
    : public EagerLightlyLayoutSensitiveOpTransformer {
 public:
  EagerFlattenOpTransformer() {}
374 375
  explicit EagerFlattenOpTransformer(const std::string& op_name) {
    VLOG(4) << "AutoTuneTransformer op: " << op_name;
376 377 378 379 380 381 382 383 384
  }

  // transpose from NHWC to NCHW
  paddle::experimental::Tensor TransInTensor(
      const std::string& in_name, const paddle::experimental::Tensor& in) {
    return in;
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
385
    UpdateLayout(out_tensor, DefaultLayout());
386 387 388 389 390 391 392
  }
};

class EagerConcatOpTransformer
    : public EagerLightlyLayoutSensitiveOpTransformer {
 public:
  EagerConcatOpTransformer() {}
393 394
  explicit EagerConcatOpTransformer(const std::string& op_name) {
    VLOG(4) << "AutoTuneTransformer op : " << op_name;
395 396
  }

397
  void SetAttr(paddle::experimental::Scalar* axis, phi::DataLayout layout) {
398 399 400
    std::vector<int> perm_nhwc = {0, 3, 1, 2};
    std::vector<int> perm_nchw = {0, 2, 3, 1};
    int axes = axis->to<int>();
401
    axes = axes < 0 ? axes + 4 : axes;
402
    auto perm = (phi::DataLayout::NHWC == layout) ? perm_nhwc : perm_nchw;
403 404 405
    (*axis) = static_cast<paddle::experimental::Scalar>(perm[axes]);
  }

406
  virtual std::vector<paddle::experimental::Tensor> TransInTensors(
407 408 409 410 411 412
      const std::string& in_name,
      const std::vector<paddle::experimental::Tensor>& in) {
    return in;
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
413
    UpdateLayout(out_tensor, DesiredLayout());
414 415 416
  }
};
}  // namespace egr