eager_layout_transformer.h 14.6 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 23 24
// 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(
    const paddle::experimental::DataLayout layout,
    const paddle::experimental::Tensor& in) {
25
  VLOG(4) << "AutoTune Transpose from " << in.layout() << " to " << layout
26
          << ", tensor's dim size is " << in.shape().size();
27 28 29 30 31 32 33 34 35 36 37
  if (in.shape().size() != 4) {
    return in;
  }
  std::vector<int> axis;
  if (layout == paddle::experimental::DataLayout::NHWC) {
    axis = {0, 2, 3, 1};
  } else if (layout == paddle::experimental::DataLayout::NCHW) {
    axis = {0, 3, 1, 2};
  } else {
    axis = {0, 1, 2, 3};
  }
38
  auto out_tensor = transpose_ad_func(in, axis);
39
  VLOG(4) << "AutoTune Transpose from " << in.layout() << " to " << layout;
40 41 42
  return out_tensor;
}

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
inline paddle::experimental::DataLayout DesiredLayout() {
  return paddle::imperative::LayoutAutoTune::Instance().GetDesiredLayout();
}

inline paddle::experimental::DataLayout DefaultLayout() {
  return paddle::imperative::LayoutAutoTune::Instance().GetDefaultLayout();
}

inline void UpdateLayout(paddle::experimental::Tensor* out_tensor,
                         const paddle::experimental::DataLayout layout) {
  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,
                            const paddle::experimental::DataLayout layout,
                            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];
  }
  auto des_str = paddle::framework::DataLayoutToString(des_layout);
  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];
  }
}

105 106
// agnostic op
class EagerLayoutTransformer {
107 108
  using Layout = paddle::experimental::DataLayout;

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

  EagerLayoutTransformer(const EagerLayoutTransformer&) = delete;

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

116 117 118 119 120
  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)
121 122
      : op_name_(op_name), final_layout_(final_layout), dim_size_(1) {
    VLOG(4) << "Agnostic op : " << op_name_ << "'s layout is " << final_layout_;
123 124
  }

125 126
  virtual ~EagerLayoutTransformer() {}

127 128
  virtual paddle::experimental::Tensor TransInTensor(
      const std::string& in_name, const paddle::experimental::Tensor& in) {
129 130 131 132 133 134
    // 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) {
135 136 137 138 139 140
      auto out_tensor = EagerTraceTransposeOp(final_layout_, in);
      phi::DenseTensorUtils::GetMutableMeta(
          static_cast<phi::DenseTensor*>(out_tensor.impl().get()))
          ->layout = final_layout_;
      return out_tensor;
    }
141
    return in;
142 143
  }

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

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

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

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

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

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

  virtual void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
186 187 188 189 190 191
    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_);
192 193 194
    }
  }

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

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

  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) {
220
    UpdateLayout(out_tensor, desired_layout_);
221 222 223 224 225 226 227 228 229 230 231 232 233
  }

  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_) {
234 235
        VLOG(4) << "Update out_tensor's layout from "
                << (*out_tensor)[i].layout() << " to " << desired_layout_;
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
        phi::DenseTensorUtils::GetMutableMeta(
            static_cast<phi::DenseTensor*>((*out_tensor)[i].impl().get()))
            ->layout = desired_layout_;
      }
    }
  }

 protected:
  std::string op_name_;
  const paddle::experimental::DataLayout desired_layout_;
  std::unordered_set<std::string> heavily_input_{"x", "y", "input"};
};

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

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

276
  virtual std::vector<paddle::experimental::Tensor> TransInTensors(
277 278 279
      const std::string& in_name,
      const std::vector<paddle::experimental::Tensor>& in) {
    std::vector<paddle::experimental::Tensor> result;
280 281
    auto desired_layout = DesiredLayout();
    auto default_layout = DefaultLayout();
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    for (size_t i = 0; i < in.size(); i++) {
      auto in_tensor = in[i];
      if (in_tensor.layout() == desired_layout) {
        auto out_tensor = EagerTraceTransposeOp(
            paddle::experimental::DataLayout::UNDEFINED, in_tensor);
        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) {
299
    UpdateLayout(out_tensor, DefaultLayout());
300 301 302 303 304 305 306 307 308 309 310
  }

  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) {
311
    auto default_layout = DefaultLayout();
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    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() {}
328 329
  explicit EagerTransposeOpTransformer(const std::string& op_name) {
    VLOG(4) << "AutoTuneTransformer op: " << op_name;
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
  }

  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) {
348
    UpdateLayout(out_tensor, DefaultLayout());
349 350 351 352 353 354 355
  }
};

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

  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) {
369
    UpdateLayout(out_tensor, DesiredLayout());
370 371 372 373 374 375 376
  }
};

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

  // 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) {
388
    UpdateLayout(out_tensor, DefaultLayout());
389 390 391 392 393 394 395
  }
};

class EagerConcatOpTransformer
    : public EagerLightlyLayoutSensitiveOpTransformer {
 public:
  EagerConcatOpTransformer() {}
396 397
  explicit EagerConcatOpTransformer(const std::string& op_name) {
    VLOG(4) << "AutoTuneTransformer op : " << op_name;
398 399 400 401 402 403 404
  }

  void SetAttr(paddle::experimental::Scalar* axis,
               paddle::framework::DataLayout layout) {
    std::vector<int> perm_nhwc = {0, 3, 1, 2};
    std::vector<int> perm_nchw = {0, 2, 3, 1};
    int axes = axis->to<int>();
405
    axes = axes < 0 ? axes + 4 : axes;
406 407 408 409 410
    auto perm =
        (paddle::framework::DataLayout::NHWC == layout) ? perm_nhwc : perm_nchw;
    (*axis) = static_cast<paddle::experimental::Scalar>(perm[axes]);
  }

411
  virtual std::vector<paddle::experimental::Tensor> TransInTensors(
412 413 414 415 416 417
      const std::string& in_name,
      const std::vector<paddle::experimental::Tensor>& in) {
    return in;
  }

  void SetOutTensorLayout(paddle::experimental::Tensor* out_tensor) {
418
    UpdateLayout(out_tensor, DesiredLayout());
419 420 421
  }
};
}  // namespace egr