io.cc 7.2 KB
Newer Older
1
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14

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. */

Y
Yi Wang 已提交
15
#include "paddle/fluid/inference/io.h"
16

17
#include <algorithm>
18
#include <fstream>
19
#include <vector>
20

Y
Yi Wang 已提交
21 22
#include "paddle/fluid/framework/block_desc.h"
#include "paddle/fluid/framework/feed_fetch_type.h"
23
#include "paddle/fluid/framework/op_registry.h"
X
version  
Xin Pan 已提交
24
#include "paddle/fluid/framework/version.h"
T
tensor-tang 已提交
25
#include "paddle/fluid/platform/cpu_helper.h"
26
#include "paddle/fluid/platform/enforce.h"
27
#include "paddle/fluid/pybind/pybind.h"
28

W
wanghaoshuang 已提交
29
DEFINE_string(devices, "", "The devices to be used which is joined by comma.");
30 31
DEFINE_int32(math_num_threads, 1,
             "Number of threads used to run math functions.");
32

33
namespace paddle {
34
namespace inference {
35

36 37
void Init(const std::vector<std::string> argv) {
  framework::InitGflags(argv);
T
tensor-tang 已提交
38
  platform::SetNumThreads(FLAGS_math_num_threads);
39 40 41 42 43 44 45
  // init devices
  std::vector<int> devices;
  std::string token;
  std::istringstream tokenStream(FLAGS_devices);
  while (std::getline(tokenStream, token, ',')) {
    devices.push_back(std::stoi(token));
  }
46
  framework::InitDevices(devices);
47
}
48

49
void ReadBinaryFile(const std::string& filename, std::string* contents) {
50
  std::ifstream fin(filename, std::ios::in | std::ios::binary);
51 52 53
  PADDLE_ENFORCE_EQ(
      fin.is_open(), true,
      platform::errors::Unavailable("Failed to open file %s.", filename));
54
  fin.seekg(0, std::ios::end);
55 56
  contents->clear();
  contents->resize(fin.tellg());
57
  fin.seekg(0, std::ios::beg);
58
  fin.read(&(contents->at(0)), contents->size());
59
  fin.close();
60 61
}

L
Liu Yiqun 已提交
62 63
bool IsPersistable(const framework::VarDesc* var) {
  if (var->Persistable() &&
64
      var->GetType() != framework::proto::VarType::FEED_MINIBATCH &&
65 66
      var->GetType() != framework::proto::VarType::FETCH_LIST &&
      var->GetType() != framework::proto::VarType::RAW) {
L
Liu Yiqun 已提交
67
    return true;
68 69 70 71
  }
  return false;
}

72
void LoadPersistables(framework::Executor* executor, framework::Scope* scope,
73
                      const framework::ProgramDesc& main_program,
74
                      const std::string& dirname,
T
Tao Luo 已提交
75
                      const std::string& param_filename,
T
Tao Luo 已提交
76
                      bool model_from_memory = false) {
K
kexinzhao 已提交
77
  const framework::BlockDesc& global_block = main_program.Block(0);
78

79 80
  framework::ProgramDesc* load_program = new framework::ProgramDesc();
  framework::BlockDesc* load_block = load_program->MutableBlock(0);
81 82
  std::vector<std::string> paramlist;

K
kexinzhao 已提交
83
  for (auto* var : global_block.AllVars()) {
L
Liu Yiqun 已提交
84
    if (IsPersistable(var)) {
85
      VLOG(4) << "persistable variable's name: " << var->Name();
86 87

      framework::VarDesc* new_var = load_block->Var(var->Name());
F
fengjiayi 已提交
88
      new_var->SetShape(var->GetShape());
89
      new_var->SetDataType(var->GetDataType());
90 91
      auto var_type = var->GetType();
      new_var->SetType(var_type);
92

93 94 95
      if ((var_type !=
           framework::proto::VarType::Type::VarType_Type_SELECTED_ROWS) &&
          (var_type != framework::proto::VarType::VOCAB)) {
96 97 98
        new_var->SetLoDLevel(var->GetLoDLevel());
      }

99 100
      new_var->SetPersistable(true);

101 102 103 104 105 106 107 108 109 110
      if (!param_filename.empty()) {
        paramlist.push_back(new_var->Name());
      } else {
        // append_op
        framework::OpDesc* op = load_block->AppendOp();
        op->SetType("load");
        op->SetOutput("Out", {new_var->Name()});
        op->SetAttr("file_path", {dirname + "/" + new_var->Name()});
        op->CheckAttrs();
      }
111 112
    }
  }
113 114 115 116 117 118 119 120 121

  if (!param_filename.empty()) {
    // sort paramlist to have consistent ordering
    std::sort(paramlist.begin(), paramlist.end());
    // append just the load_combine op
    framework::OpDesc* op = load_block->AppendOp();
    op->SetType("load_combine");
    op->SetOutput("Out", paramlist);
    op->SetAttr("file_path", {param_filename});
T
Tao Luo 已提交
122
    op->SetAttr("model_from_memory", {model_from_memory});
123 124 125
    op->CheckAttrs();
  }

126
  executor->Run(*load_program, scope, 0, true, true);
127

128
  delete load_program;
129
}
130

131 132
std::unique_ptr<framework::ProgramDesc> Load(framework::Executor* executor,
                                             framework::Scope* scope,
K
kexinzhao 已提交
133
                                             const std::string& dirname) {
134 135
  std::string model_filename = dirname + "/__model__";
  std::string program_desc_str;
M
minqiyang 已提交
136
  VLOG(3) << "loading model from " << model_filename;
137
  ReadBinaryFile(model_filename, &program_desc_str);
138 139 140

  std::unique_ptr<framework::ProgramDesc> main_program(
      new framework::ProgramDesc(program_desc_str));
141 142 143 144
  PADDLE_ENFORCE_EQ(
      framework::IsProgramVersionSupported(main_program->Version()), true,
      platform::errors::Unavailable("Model version %ld is not supported.",
                                    main_program->Version()));
145

T
tianshuo78520a 已提交
146
  // model_from_memory is false in separate parameters.
T
Tao Luo 已提交
147
  LoadPersistables(executor, scope, *main_program, dirname, "",
T
Tao Luo 已提交
148
                   false /* model_from_memory */);
149 150 151
  return main_program;
}

T
Tao Luo 已提交
152 153 154
std::unique_ptr<framework::ProgramDesc> Load(
    framework::Executor* executor, framework::Scope* scope,
    const std::string& prog_filename, const std::string& param_filename) {
155
  std::string program_desc_str;
T
Tao Luo 已提交
156
  ReadBinaryFile(prog_filename, &program_desc_str);
157

K
kexinzhao 已提交
158 159
  std::unique_ptr<framework::ProgramDesc> main_program(
      new framework::ProgramDesc(program_desc_str));
160 161 162 163
  PADDLE_ENFORCE_EQ(
      framework::IsProgramVersionSupported(main_program->Version()), true,
      platform::errors::Unavailable("Model version %ld is not supported.",
                                    main_program->Version()));
164

T
Tao Luo 已提交
165
  LoadPersistables(executor, scope, *main_program, "", param_filename,
T
Tao Luo 已提交
166
                   false /* model_from_memory */);
167 168 169
  return main_program;
}

T
Tao Luo 已提交
170
std::unique_ptr<framework::ProgramDesc> LoadFromMemory(
T
Tao Luo 已提交
171
    framework::Executor* executor, framework::Scope* scope,
T
Tao Luo 已提交
172 173 174
    const std::string& prog_buffer, const std::string& param_buffer) {
  std::unique_ptr<framework::ProgramDesc> main_program(
      new framework::ProgramDesc(prog_buffer));
175 176 177 178
  PADDLE_ENFORCE_EQ(
      framework::IsProgramVersionSupported(main_program->Version()), true,
      platform::errors::Unavailable("Model version %ld is not supported.",
                                    main_program->Version()));
T
Tao Luo 已提交
179 180 181 182

  LoadPersistables(executor, scope, *main_program, "", param_buffer,
                   true /* model_filename */);
  return main_program;
T
Tao Luo 已提交
183 184
}

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
void SaveVars(const framework::Scope& scope,
              const std::vector<std::string>& vars, const std::string& dirname,
              bool predicate) {
  framework::ProgramDesc prog;
  auto* block = prog.MutableBlock(0);
  auto* op = block->AppendOp();
  op->SetType("save_combine");
  op->SetInput("X", vars);
  op->SetAttr("file_path", dirname + "/param");
  op->CheckAttrs();

  platform::CPUPlace place;
  framework::Executor exe(place);
  exe.Run(prog, const_cast<framework::Scope*>(&scope), 0, true, true);
}

201
}  // namespace inference
202
}  // namespace paddle