layer.cc 11.5 KB
Newer Older
J
Jiabin Yang 已提交
1
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15
//
// 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.

#include "paddle/fluid/imperative/layer.h"
16
#include <algorithm>
J
Jiabin Yang 已提交
17
#include <queue>
18
#include <utility>
19
#include "paddle/fluid/framework/framework.pb.h"
20
#include "paddle/fluid/framework/op_registry.h"
J
Jiabin Yang 已提交
21 22 23
#include "paddle/fluid/framework/variable_helper.h"
#include "paddle/fluid/imperative/prepared_operator.h"
#include "paddle/fluid/operators/math/math_function.h"
M
minqiyang 已提交
24
#include "paddle/fluid/platform/device_context.h"
J
Jiabin Yang 已提交
25
#include "paddle/fluid/platform/enforce.h"
C
chengduo 已提交
26
#include "paddle/fluid/platform/profiler.h"
27 28 29 30

namespace paddle {
namespace imperative {

J
Jiabin Yang 已提交
31
using framework::Variable;
Z
Zeng Jinle 已提交
32 33 34 35 36 37 38 39
void ThreadSafeNameSet::Insert(const std::string& name) {
  std::lock_guard<std::mutex> guard(mtx_);
  set_.insert(name);
}

void ThreadSafeNameSet::Remove(const std::string& name) {
  std::lock_guard<std::mutex> guard(mtx_);
  auto iter = set_.find(name);
J
Jiabin Yang 已提交
40
  PADDLE_ENFORCE_EQ(iter != set_.end(), true, "%s does not exist", name);
Z
Zeng Jinle 已提交
41 42 43 44 45 46 47 48 49 50 51 52
  set_.erase(iter);
}

std::vector<std::string> ThreadSafeNameSet::Names() const {
  std::lock_guard<std::mutex> guard(mtx_);
  return std::vector<std::string>(set_.begin(), set_.end());
}

ThreadSafeNameSet VarBase::name_set_;

std::vector<std::string> VarBase::AliveVarNames() { return name_set_.Names(); }

J
Jiabin Yang 已提交
53 54 55 56
static framework::VariableNameMap CreateVarNameMap(
    const framework::OpInfo& op_info, const std::string& op_type,
    const NameVarBaseMap& varbase_map, bool is_input) {
  if (op_info.proto_ == nullptr) {
H
hong 已提交
57 58 59 60 61 62 63 64 65 66 67 68
    framework::VariableNameMap result;

    for (auto& it : varbase_map) {
      auto& var_vector = it.second;
      std::vector<std::string> args;
      args.reserve(var_vector.size());
      for (auto& var_base : var_vector) {
        args.emplace_back(var_base->Name());
      }
      result[it.first] = std::move(args);
    }
    return result;
M
minqiyang 已提交
69 70
  }

J
Jiabin Yang 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
  framework::VariableNameMap result;

  for (auto& var :
       is_input ? op_info.Proto().inputs() : op_info.Proto().outputs()) {
    auto it = varbase_map.find(var.name());
    if (it == varbase_map.end()) {
      PADDLE_ENFORCE_EQ(
          var.dispensable(), true,
          "Var: %s not dispensable and there are no such var in inputs",
          var.name());
      result[var.name()] = {};
    } else {
      auto& var_vector = it->second;
      std::vector<std::string> args;
      args.reserve(var_vector.size());
      for (auto& var_base : var_vector) {
        args.emplace_back(var_base->Name());
      }
      result[var.name()] = std::move(args);
    }
M
minqiyang 已提交
91
  }
J
Jiabin Yang 已提交
92 93
  return result;
}
M
minqiyang 已提交
94

J
Jiabin Yang 已提交
95 96 97 98 99 100 101 102 103
static framework::RuntimeContext PrepareRuntimeContext(
    const NameVarBaseMap& ins, const NameVarBaseMap& outs) {
  framework::VariableValueMap inputs, outputs;
  for (auto& in_pair : ins) {
    auto& in_ctx = inputs[in_pair.first];
    in_ctx.reserve(in_pair.second.size());
    for (auto& in_var : in_pair.second) {
      in_ctx.emplace_back(in_var->MutableVar());
    }
M
minqiyang 已提交
104 105
  }

J
Jiabin Yang 已提交
106 107 108 109 110
  for (auto& out_pair : outs) {
    auto& out_ctx = outputs[out_pair.first];
    out_ctx.reserve(out_pair.second.size());
    for (auto& out_var : out_pair.second) {
      out_ctx.emplace_back(out_var->MutableVar());
111
    }
J
Jiabin Yang 已提交
112 113 114 115
  }
  return framework::RuntimeContext(std::move(inputs), std::move(outputs));
}

116
template <typename VarType>
J
Jiabin Yang 已提交
117 118
static std::string DebugString(
    const std::string& name,
119
    const std::vector<std::shared_ptr<VarType>>& vars) {
J
Jiabin Yang 已提交
120 121
  std::stringstream ss;
  ss << name << "{";
M
minqiyang 已提交
122

J
Jiabin Yang 已提交
123 124
  for (size_t i = 0; i < vars.size(); ++i) {
    if (i > 0) ss << ", ";
M
minqiyang 已提交
125

J
Jiabin Yang 已提交
126 127 128 129 130
    if (vars[i] == nullptr) {
      ss << "NULL";
      continue;
    }
    ss << vars[i]->Name() << "[";
131
    const framework::Variable& var = vars[i]->Var();
J
Jiabin Yang 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144
    if (!var.IsInitialized()) {
      ss << "NOT_INITED_VAR";
    } else if (var.IsType<framework::LoDTensor>()) {
      auto& tensor = var.Get<framework::LoDTensor>();
      ss << "LoDTensor<";
      if (tensor.IsInitialized()) {
        ss << framework::DataTypeToString(tensor.type()) << ", ";
        ss << tensor.place() << ", ";
        ss << "(" << tensor.dims() << ")";
      } else {
        ss << "NOT_INITED";
      }
      ss << ">";
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
    } else if (var.IsType<framework::SelectedRows>()) {
      ss << "SelectedRows<";
      auto& selected_rows = var.Get<framework::SelectedRows>();
      auto& tensor = selected_rows.value();
      auto& rows = selected_rows.rows();
      if (tensor.IsInitialized()) {
        ss << framework::DataTypeToString(tensor.type()) << ", ";
        ss << tensor.place() << ", ";
        ss << "height(" << selected_rows.height() << "), rows(";
        std::for_each(rows.cbegin(), rows.cend(),
                      [&ss](const int64_t r) { ss << r << " "; });
        ss << "), dims(" << tensor.dims() << ")";
      } else {
        ss << "NOT_INITED";
      }
      ss << ">";
J
Jiabin Yang 已提交
161 162 163 164
    } else {
      ss << "UNRESOLVED_TYPE";
    }
    ss << "]";
165
  }
166

J
Jiabin Yang 已提交
167 168
  ss << "}";
  return ss.str();
169 170
}

171 172 173 174
template <typename VarType>
static std::string LayerDebugStringImpl(const std::string& op_type,
                                        const NameVarMap<VarType>& ins,
                                        const NameVarMap<VarType>& outs) {
J
Jiabin Yang 已提交
175 176 177 178 179 180 181 182 183 184
  std::stringstream ss;
  ss << "Op(" << op_type << "): ";

  ss << "Inputs: ";

  size_t i = 0;
  for (auto& pair : ins) {
    if (i > 0) ss << ", ";
    ss << DebugString(pair.first, pair.second);
    ++i;
185 186
  }

J
Jiabin Yang 已提交
187 188 189 190 191 192 193 194 195
  ss << ",   Outputs: ";
  i = 0;
  for (auto& pair : outs) {
    if (i > 0) ss << ", ";
    ss << DebugString(pair.first, pair.second);
    ++i;
  }
  return ss.str();
}
196

197 198 199 200 201 202 203 204 205 206
std::string LayerDebugString(const std::string& op_type,
                             const NameVarMap<VarBase>& ins,
                             const NameVarMap<VarBase>& outs) {
  return LayerDebugStringImpl<VarBase>(op_type, ins, outs);
}

std::string LayerDebugString(const std::string& op_type,
                             const NameVarMap<VariableWrapper>& ins,
                             const NameVarMap<VariableWrapper>& outs) {
  return LayerDebugStringImpl<VariableWrapper>(op_type, ins, outs);
J
Jiabin Yang 已提交
207
}
208

J
Jiabin Yang 已提交
209 210
void VarBase::ClearGradient() {
  if (grad_var_) {
211 212 213
    if (grad_var_->Var().IsType<framework::SelectedRows>()) {
      auto* grad_t =
          grad_var_->MutableVar()->GetMutable<framework::SelectedRows>();
214 215 216 217 218
      if (grad_t->mutable_value()->IsInitialized()) {
        grad_t->mutable_rows()->clear();
        grad_t->mutable_value()->clear();
      }
    } else {
219 220
      auto* grad_t =
          grad_var_->MutableVar()->GetMutable<framework::LoDTensor>();
221 222 223 224 225
      if (grad_t->IsInitialized()) {
        auto* dev_ctx =
            platform::DeviceContextPool::Instance().Get(grad_t->place());
        operators::math::set_constant(*dev_ctx, grad_t, 0.0);
      }
226 227
    }
  }
J
Jiabin Yang 已提交
228
}
229

J
Jiabin Yang 已提交
230
std::shared_ptr<VarBase> VarBase::NewVarBase(const platform::Place& dst_place,
M
minqiyang 已提交
231
                                             const bool blocking) const {
232
  PADDLE_ENFORCE_EQ(
233 234
      Var().IsInitialized() && (Var().IsType<framework::LoDTensor>() ||
                                Var().IsType<framework::SelectedRows>()),
235 236 237
      true, platform::errors::InvalidArgument(
                "Variable is not initialized or Variable's type is not "
                "LoDTensor or SelectedRows when getting numpy tensor"));
238 239
  if (Var().IsType<framework::LoDTensor>()) {
    auto& src_tensor = Var().Get<framework::LoDTensor>();
240 241 242

    // TODO(Jiabin): change this after move unique_name generator to CXX
    auto new_var = std::make_shared<VarBase>(
243
        true, Name() + std::to_string(copied_counter_++));
244

245 246
    auto* dst_tensor =
        new_var->MutableVar()->GetMutable<framework::LoDTensor>();
247
    dst_tensor->set_lod(src_tensor.lod());
248 249 250
    new_var->SetPersistable(Persistable());
    new_var->SetDataType(DataType());
    new_var->SetType(Type());
251 252 253 254 255 256 257
    framework::TensorCopy(src_tensor, dst_place, dst_tensor);
    if (blocking) {
      platform::DeviceContextPool::Instance().Get(dst_place)->Wait();
      auto src_place = src_tensor.place();
      if (!(src_place == dst_place)) {
        platform::DeviceContextPool::Instance().Get(src_place)->Wait();
      }
258
    }
P
Paddle CI 已提交
259

260 261 262 263 264
    if (platform::is_gpu_place(dst_place)) {
      VLOG(3) << "copy tensor " << Name() << " from gpu";
    }
    return new_var;
  } else {
265
    auto& src_selected_rows = Var().Get<framework::SelectedRows>();
266 267 268 269
    auto new_var = std::make_shared<VarBase>(
        false, "Itmp" + std::to_string(copied_counter_++));
    new_var->SetType(framework::proto::VarType::SELECTED_ROWS);
    auto* dst_selected_rows =
270
        new_var->MutableVar()->GetMutable<framework::SelectedRows>();
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

    framework::TensorCopy(src_selected_rows.value(), dst_place,
                          dst_selected_rows->mutable_value());
    if (blocking) {
      platform::DeviceContextPool::Instance().Get(dst_place)->Wait();
      auto src_place = src_selected_rows.place();
      if (!(src_place == dst_place)) {
        platform::DeviceContextPool::Instance().Get(src_place)->Wait();
      }
    }
    dst_selected_rows->set_height(src_selected_rows.height());
    dst_selected_rows->set_rows(src_selected_rows.rows());
    if (platform::is_gpu_place(dst_place)) {
      VLOG(3) << "copy selected rows " << Name() << " from gpu";
    }
    return new_var;
  }
M
minqiyang 已提交
288 289
}

290
void OpBase::SetType(const std::string& type) {
H
hong 已提交
291
  op_ = framework::OpRegistry::CreateOp(type, {}, {}, {}, false);
J
Jiabin Yang 已提交
292
}
293

294 295 296 297 298
void OpBase::ClearBackwardTrace() {
  grad_pending_ops_.clear();
  allow_empty_vars_.clear();
  ins_.clear();
  outs_.clear();
H
hong 已提交
299 300
}

301 302 303 304 305 306 307
template <typename VarType>
static void OpBaseRunImpl(const framework::OperatorBase& op,
                          const NameVarMap<VarType>& ins,
                          const NameVarMap<VarType>& outs,
                          const framework::AttributeMap& attrs,
                          const platform::Place& place) {
  auto* op_kernel = dynamic_cast<const framework::OperatorWithKernel*>(&op);
J
Jiabin Yang 已提交
308
  PADDLE_ENFORCE_NOT_NULL(op_kernel, "only support op with kernel");
309
  auto& info = op.Info();
J
Jiabin Yang 已提交
310
  if (info.infer_var_type_) {
311
    RuntimeInferVarTypeContext<VarType> infer_var_type_ctx(ins, &outs, attrs);
J
Jiabin Yang 已提交
312
    info.infer_var_type_(&infer_var_type_ctx);
X
Xin Pan 已提交
313
  }
314

J
Jiabin Yang 已提交
315 316 317 318
  // Initialize output var type
  for (auto& var_pair : outs) {
    for (auto& var : var_pair.second) {
      InitializeVariable(var->MutableVar(), var->Type());
319 320
    }
  }
X
Xin Pan 已提交
321

322 323 324
  // VLOG(3) << "Running Op " << op.Type();
  VLOG(5) << LayerDebugString(op.Type(), ins, outs);
  auto prepared_op = PreparedOp::Prepare(ins, outs, *op_kernel, place, attrs);
325

326
  prepared_op.Run(ins, outs, attrs);
327

328
  VLOG(4) << LayerDebugString(op.Type(), ins, outs);
329 330
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344
void OpBase::Run(const framework::OperatorBase& op,
                 const NameVarMap<VarBase>& ins,
                 const NameVarMap<VarBase>& outs,
                 const framework::AttributeMap& attrs,
                 const platform::Place& place) {
  OpBaseRunImpl<VarBase>(op, ins, outs, attrs, place);
}

void OpBase::Run(const framework::OperatorBase& op,
                 const NameVarMap<VariableWrapper>& ins,
                 const NameVarMap<VariableWrapper>& outs,
                 const framework::AttributeMap& attrs,
                 const platform::Place& place) {
  OpBaseRunImpl<VariableWrapper>(op, ins, outs, attrs, place);
345 346 347 348
}

}  // namespace imperative
}  // namespace paddle