tracer.h 4.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 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
// Copyright (c) 2018 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 <map>
#include <string>
#include <vector>

#include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/imperative/engine.h"
#include "paddle/fluid/imperative/layer.h"

namespace paddle {
namespace imperative {

void CreateGradOp(const framework::OpDesc& op_desc,
                  const std::unordered_set<std::string>& no_grad_set,
                  const std::vector<framework::BlockDesc*>& grad_sub_block,
                  framework::OpDesc** grad_op_desc,
                  std::unordered_map<std::string, std::string>* grad_to_var) {
  std::vector<std::unique_ptr<framework::OpDesc>> grad_op_descs =
      framework::OpInfoMap::Instance()
          .Get(op_desc.Type())
          .GradOpMaker()(op_desc, no_grad_set, grad_to_var, grad_sub_block);
  PADDLE_ENFORCE(grad_op_descs.size() == 1, "Only support 1 grad op now.");
  // TODO(panyx0718): Leak?
  *grad_op_desc = grad_op_descs[0].release();
}

class Tracer {
 public:
M
minqiyang 已提交
46 47
  explicit Tracer(framework::BlockDesc* root_block)
      : root_scope_(new framework::Scope()) {}
48

M
minqiyang 已提交
49
  virtual ~Tracer() {}
50 51

  void Trace(OpBase* op, const std::vector<VarBase*>& inputs,
M
minqiyang 已提交
52 53
             const std::vector<VarBase*>& outputs, framework::BlockDesc* block,
             const bool stop_gradient) {
54
    framework::OpDesc* op_desc = op->op_desc_;
M
minqiyang 已提交
55
    VLOG(3) << "tracer tracing " << op_desc->Type();
56 57 58 59 60 61 62 63
    op_desc->InferShape(*block);
    op_desc->InferVarType(block);
    std::unique_ptr<framework::OperatorBase> op_base =
        framework::OpRegistry::CreateOp(*op_desc);

    *op->input_vars_ = inputs;
    for (VarBase* input : inputs) {
      const std::string vname = input->var_desc_->Name();
M
minqiyang 已提交
64
      framework::Variable* var = root_scope_->Var(vname);
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
      input->var_ = var;
      if (!var->IsInitialized()) {
        framework::VarDesc* var_desc = block->FindVar(vname);
        if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) {
          var->GetMutable<framework::LoDTensor>();
        } else {
          LOG(ERROR) << "tracer doesn't support yet";
        }
      }
      if (input->pre_op_) {
        op->pre_ops_->push_back(input->pre_op_);
        op->pre_ops_out_idx_->push_back(input->pre_op_out_idx_);
      } else {
        op->pre_ops_->push_back(nullptr);
      }
M
minqiyang 已提交
80 81
      VLOG(3) << "input vname " << vname << " "
              << var->Get<framework::LoDTensor>().dims().size();
82 83 84 85 86
    }

    *op->output_vars_ = outputs;
    for (size_t i = 0; i < outputs.size(); ++i) {
      const std::string vname = outputs[i]->var_desc_->Name();
M
minqiyang 已提交
87
      framework::Variable* var = root_scope_->Var(vname);
88 89 90 91 92 93 94 95
      if (!var->IsInitialized()) {
        framework::VarDesc* var_desc = block->FindVar(vname);
        if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) {
          var->GetMutable<framework::LoDTensor>();
        } else {
          LOG(ERROR) << "tracer doesn't support yet";
        }
      }
M
minqiyang 已提交
96 97

      outputs[i]->stop_gradient_ = stop_gradient;
98 99 100 101
      outputs[i]->var_ = var;
      outputs[i]->pre_op_ = op;
      outputs[i]->pre_op_out_idx_ = i;
    }
M
minqiyang 已提交
102

M
minqiyang 已提交
103
    VLOG(3) << "tracer running " << op_desc->Type();
M
minqiyang 已提交
104 105
    op_base->Run(*root_scope_, platform::CPUPlace());
    if (!stop_gradient) {
M
minqiyang 已提交
106 107 108 109 110
      framework::OpDesc* grad_op_desc;
      auto grad_to_var = new std::unordered_map<std::string, std::string>();
      CreateGradOp(*op_desc, {}, {block}, &grad_op_desc, grad_to_var);
      op->grad_op_desc_ = grad_op_desc;
      op->grad_to_var_ = grad_to_var;
M
minqiyang 已提交
111
      VLOG(3) << "tracer create grad op " << grad_op_desc->Type();
M
minqiyang 已提交
112
    }
113 114 115
    op->block_ = block;
  }

M
minqiyang 已提交
116
  framework::Scope* GetScope() { return root_scope_.get(); }
117 118

 private:
M
minqiyang 已提交
119
  std::unique_ptr<framework::Scope> root_scope_;
120 121 122 123
};

}  // namespace imperative
}  // namespace paddle