Program Listing for File computation.cc

Return to documentation for file (/WorkSpace/CINN/cinn/frontend/computation.cc)

// Copyright (c) 2021 CINN 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.

#include "cinn/frontend/computation.h"

#include "cinn/frontend/program_pass.h"
#include "cinn/hlir/framework/graph.h"
#include "cinn/hlir/framework/graph_compiler.h"
#include "cinn/hlir/framework/pass.h"
#include "cinn/hlir/framework/scope.h"

namespace cinn {
namespace frontend {

struct ComputationContext {
  Target target;
  void *stream;
  std::shared_ptr<hlir::framework::Graph> graph;
  std::shared_ptr<hlir::framework::Scope> scope;
  std::shared_ptr<hlir::framework::Program> program;
  std::shared_ptr<hlir::framework::GraphCompiler> graph_compiler;

  CinnComputation::CompileOptions compile_options;

  std::vector<hlir::framework::Tensor> inputs;
  std::vector<hlir::framework::Tensor> outputs;
  std::unordered_map<std::string, Variable> varmap;
  std::unordered_map<std::string, std::string> varmap_paddle2program;
};

std::shared_ptr<ComputationContext> CompileProgram(const Target &target,
                                                   Program &program,
                                                   const std::vector<Variable> &outputs,
                                                   std::shared_ptr<hlir::framework::Scope> scope,
                                                   const CinnComputation::CompileOptions &options,
                                                   void *stream) {
  std::shared_ptr<ComputationContext> ctx(new ComputationContext());
  ctx->stream          = stream;
  ctx->target          = target;
  ctx->compile_options = options;
  if (ctx->compile_options.use_decomposer) {
    ProgramPass::Apply(&program, target, {"Decomposer"});
  }
  ctx->graph.reset(new hlir::framework::Graph(program, target));

  if (ctx->compile_options.use_default_passes) {
    hlir::framework::ApplyPass(ctx->graph.get(), "InferShape");

#ifndef CINN_WITH_CUDA
    if (target.arch == Target::Arch::X86) {
      hlir::framework::ApplyPass(ctx->graph.get(), "AlterLayout");
    }
#endif
    hlir::framework::ApplyPass(ctx->graph.get(), "ConstPropagate");
    hlir::framework::ApplyPass(ctx->graph.get(), "OpFusion");
  }
  for (auto &pass_name : ctx->compile_options.passes) {
    hlir::framework::ApplyPass(ctx->graph.get(), pass_name);
  }

  ctx->scope = hlir::framework::BuildScope(target, ctx->graph, scope);
  ctx->graph_compiler.reset(new hlir::framework::GraphCompiler(target, ctx->scope, ctx->graph));

  std::unordered_set<std::string> fetch_var_ids;
  for (auto &out : outputs) {
    fetch_var_ids.insert(out->id);
  }

  ctx->program = ctx->graph_compiler->Build(options, std::move(fetch_var_ids)).runtime_program;
  if (ctx->compile_options.do_prerun) {
    ctx->program->PreRun();
  }

  for (auto &in_v : program.GetInputs()) {
    hlir::framework::Tensor t = ctx->scope->GetTensor(in_v->id);
    ctx->inputs.push_back(t);
  }
  for (auto &out_v : outputs) {
    hlir::framework::Tensor t = ctx->scope->GetTensor(out_v->id);
    ctx->outputs.push_back(t);
  }
  return ctx;
}

std::vector<std::string> CinnComputation::GetAllTensorNames() {
  std::vector<std::string> res;
  for (auto &v : context_->scope->var_names()) {
    res.push_back(std::string(v));
  }
  return res;
}

std::shared_ptr<CinnComputation> CinnComputation::CompilePaddleModel(
    const Target &target,
    const std::string &model_path,
    const std::vector<std::string> &input_names,
    const std::vector<hlir::framework::shape_t> &input_shapes,
    bool params_combined,
    const CompileOptions &options,
    void *stream) {
  CHECK(input_names.size() == input_shapes.size());
  auto scope                  = std::make_shared<hlir::framework::Scope>();
  auto loadedProgram          = LoadPaddleProgram(model_path, scope.get(), params_combined, target);
  auto &program               = std::get<0>(loadedProgram);
  auto &varmap                = std::get<1>(loadedProgram);
  auto &varmap_paddle2program = std::get<2>(loadedProgram);
  auto &fetch_names           = std::get<3>(loadedProgram);

  std::vector<Variable> input_vars;
  std::vector<Variable> output_vars;
  for (int i = 0; i < input_names.size(); i++) {
    auto &name = input_names[i];
    auto &var  = varmap.at(name);
    var->shape = input_shapes[i];
    input_vars.push_back(var);
  }
  program->SetInputs({input_vars});
  program->Validate();
  VLOG(3) << "program:\n" << *program;

  for (auto &name : fetch_names) {
    output_vars.push_back(varmap.at(name));
  }

  std::shared_ptr<ComputationContext> ctx = CompileProgram(target, *program, output_vars, scope, options, stream);
  for (auto &v : varmap) {
    ctx->varmap[v.first] = v.second;
  }
  for (auto &v : varmap_paddle2program) {
    ctx->varmap_paddle2program[v.first] = v.second;
  }

  auto computation      = std::make_shared<CinnComputation>();
  computation->context_ = std::move(ctx);

  return computation;
}

std::shared_ptr<CinnComputation> CinnComputation::BuildAndCompile(const Target &target,
                                                                  BaseBuilder &builder,
                                                                  const CompileOptions &options,
                                                                  const std::vector<Variable> &outputs,
                                                                  void *stream) {
  auto program = builder.Build();
  return Compile(target, program, options, outputs, stream);
}

std::shared_ptr<CinnComputation> CinnComputation::Compile(const Target &target,
                                                          Program &program,
                                                          const CompileOptions &options,
                                                          const std::vector<Variable> &outputs,
                                                          void *stream) {
  std::vector<Variable> output_vars = outputs;
  if (output_vars.empty()) {
    output_vars.push_back(program[program.size() - 1].GetOutput(0));
  }

  std::shared_ptr<ComputationContext> ctx = CompileProgram(target, program, output_vars, nullptr, options, stream);

  auto computation      = std::make_shared<CinnComputation>();
  computation->context_ = std::move(ctx);

  return computation;
}

void CinnComputation::SetTensorData(const std::string &tname, void *data, size_t size) {
  hlir::framework::Tensor t = GetTensor(tname);
  SetTensorData(t, data, size);
}

void CinnComputation::SetTensorData(hlir::framework::Tensor &t, void *data, size_t size) {
  void *tdata = reinterpret_cast<void *>(t->mutable_data<float>(context_->target));
  CHECK_EQ(size, t->shape().numel() * sizeof(float));
  if (context_->target.arch == Target::Arch::NVGPU) {
#ifdef CINN_WITH_CUDA
    CUDA_CALL(cudaMemcpy(tdata, data, size, cudaMemcpyHostToDevice));
#else
    CINN_NOT_IMPLEMENTED
#endif
  } else if (context_->target.arch == Target::Arch::X86) {
    memcpy(tdata, data, size);
  } else {
    CINN_NOT_IMPLEMENTED
  }
}
void CinnComputation::GetTensorData(hlir::framework::Tensor &t, void *data, size_t size) {
  void *tdata = reinterpret_cast<void *>(t->mutable_data<float>(context_->target));
  CHECK_EQ(size, t->shape().numel() * sizeof(float));
  if (context_->target.arch == Target::Arch::NVGPU) {
#ifdef CINN_WITH_CUDA
    CUDA_CALL(cudaMemcpy(data, tdata, size, cudaMemcpyDeviceToHost));
#else
    CINN_NOT_IMPLEMENTED
#endif
  } else if (context_->target.arch == Target::Arch::X86) {
    memcpy(data, tdata, size);
  } else {
    CINN_NOT_IMPLEMENTED
  }
}

void CinnComputation::GetTensorData(const std::string &tname, void *data, size_t size) {
  hlir::framework::Tensor t = GetTensor(tname);
  GetTensorData(t, data, size);
}

std::vector<hlir::framework::Tensor> CinnComputation::GetInputTensors() { return context_->inputs; }

std::vector<hlir::framework::Tensor> CinnComputation::GetOutputTensors() { return context_->outputs; }

hlir::framework::Tensor CinnComputation::GetTensor(const std::string &tname) {
  if (context_->scope->FindVar(tname)) {
    return context_->scope->GetTensor(tname);
  }
  auto it = context_->varmap_paddle2program.find(tname);
  if (it == context_->varmap_paddle2program.end()) {
    LOG(FATAL) << "No variable called [" << tname
               << "] found in computation\nThe existing vars: " << utils::Join(context_->scope->var_names(), ", ");
  }
  return context_->scope->GetTensor(it->second);
}

void CinnComputation::Execute(const std::map<std::string, cinn_pod_value_t> *name2podargs) {
  context_->program->Execute(name2podargs, context_->stream);
}

}  // namespace frontend
}  // namespace cinn