io.cpp 13.5 KB
Newer Older
W
wangliu 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/* 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. */
朔-望's avatar
朔-望 已提交
14

L
liuruilong 已提交
15
#include "io.h"
朔-望's avatar
朔-望 已提交
16
#include <fstream>
L
liuruilong 已提交
17
#include <vector>
朔-望's avatar
朔-望 已提交
18

L
liuruilong 已提交
19
#include "common/enforce.h"
L
liuruilong 已提交
20
#include "common/log.h"
L
liuruilong 已提交
21
#include "framework/framework.pb-c.h"
L
liuruilong 已提交
22 23
#include "framework/lod_tensor.h"
#include "framework/operator.h"
L
liuruilong 已提交
24
#include "framework/program/program_desc.h"
L
liuruilong 已提交
25 26 27
#include "framework/program/var_desc.h"
#include "framework/scope.h"
#include "framework/tensor.h"
L
liuruilong 已提交
28

朔-望's avatar
朔-望 已提交
29
namespace paddle_mobile {
W
wangliu 已提交
30
using framework::Variable;
朔-望's avatar
朔-望 已提交
31

朔-望's avatar
朔-望 已提交
32
void ReadBinaryFile(const std::string &filename, std::string *contents) {
33
  std::ifstream fin(filename, std::ios::in | std::ios::binary);
L
liuruilong 已提交
34 35
  PADDLE_MOBILE_ENFORCE(fin.is_open(), "open file: %s failed",
                        filename.c_str());
36 37 38 39 40 41
  fin.seekg(0, std::ios::end);
  contents->clear();
  contents->resize(fin.tellg());
  fin.seekg(0, std::ios::beg);
  fin.read(&(contents->at(0)), contents->size());
  fin.close();
朔-望's avatar
朔-望 已提交
42 43
}

L
liuruilong 已提交
44
static size_t ReadBuffer(const char *file_name, uint8_t **out) {
L
liuruilong 已提交
45 46 47
  printf("%s \n", file_name);
  FILE *fp;
  fp = fopen(file_name, "rb");
W
wangliu 已提交
48
  PADDLE_MOBILE_ENFORCE(fp != NULL, " %s open failed !", file_name);
L
liuruilong 已提交
49 50 51 52 53 54 55 56 57 58 59

  fseek(fp, 0, SEEK_END);
  size_t size = ftell(fp);
  rewind(fp);

  DLOG << "model size: " << size;

  *out = (uint8_t *)malloc(size);

  size_t cur_len = 0;
  size_t nread;
L
liuruilong 已提交
60
  while ((nread = fread(*out + cur_len, 1, size - cur_len, fp)) != 0) {
L
liuruilong 已提交
61 62 63 64 65 66
    cur_len += nread;
  }
  fclose(fp);
  return cur_len;
}

朔-望's avatar
朔-望 已提交
67
template <typename Dtype, Precision P>
L
liuruilong 已提交
68 69
void Loader<Dtype, P>::LoadVar(framework::Variable *variable,
                               const framework::VarDesc &var_desc,
朔-望's avatar
朔-望 已提交
70
                               const std::string &file_path) {
L
liuruilong 已提交
71
  auto tensor = variable->GetMutable<framework::LoDTensor>();
72
  std::ifstream is(file_path);
L
liuruilong 已提交
73 74
  PADDLE_MOBILE_ENFORCE(is.is_open(), "open file: %s failed",
                        file_path.c_str());
L
liuruilong 已提交
75

朔-望's avatar
朔-望 已提交
76 77
  std::fpos<mbstate_t> pos;
  pos = is.tellg();  // save   current   position
78
  is.seekg(0, std::ios::end);
朔-望's avatar
朔-望 已提交
79
  is.seekg(pos);  // restore   saved   position
80 81 82 83 84 85 86 87 88 89 90 91

  // 1. version
  uint32_t version;
  is.read(reinterpret_cast<char *>(&version), sizeof(version));

  // 2 Lod information
  uint64_t lod_level;
  is.read(reinterpret_cast<char *>(&lod_level), sizeof(lod_level));
  auto &lod = *tensor->mutable_lod();
  lod.resize(lod_level);
  for (uint64_t i = 0; i < lod_level; ++i) {
    uint64_t size;
朔-望's avatar
朔-望 已提交
92
    is.read(reinterpret_cast<char *>(&size), sizeof(size));
93 94 95
    std::vector<size_t> tmp(size / sizeof(size_t));
    is.read(reinterpret_cast<char *>(tmp.data()),
            static_cast<std::streamsize>(size));
朔-望's avatar
朔-望 已提交
96 97
    for (auto j : tmp) {
      LOG(kLOG_DEBUG1) << "    lod - " << j;
朔-望's avatar
朔-望 已提交
98
    }
99 100 101 102 103 104 105 106 107 108 109 110 111
    lod[i] = tmp;
  }

  // 3. tensor version
  uint32_t tensor_version;
  is.read(reinterpret_cast<char *>(&tensor_version), sizeof(tensor_version));

  // 4. tensor desc
  int32_t size;
  is.read(reinterpret_cast<char *>(&size), sizeof(size));
  std::unique_ptr<char[]> buf(new char[size]);
  is.read(reinterpret_cast<char *>(buf.get()), size);

L
liuruilong 已提交
112 113
  const framework::TensorDesc &desc = var_desc.Tensor_desc();

L
liuruilong 已提交
114
  PaddleMobile__Framework__Proto__VarType__TensorDesc *tensor_desc = NULL;
L
liuruilong 已提交
115 116 117
  //  void *v;
  //  PaddleMobile__Framework__Proto__VarType__TensorDesc_Closure()(tensor_desc,
  //  buf.get());
L
liuruilong 已提交
118

L
liuruilong 已提交
119 120
  //  DLOG << "PaddleMobile__Framework__Proto__VarType__TensorDesc_Closure- " <<
  //  tensor_desc;
L
liuruilong 已提交
121

L
liuruilong 已提交
122 123 124 125 126 127
  //  framework::TensorDesc &tensor_desc = variable->
  //  PaddleMobile__Framework__Proto__ProgramDesc *c_program;
  //  uint8_t *proto_buf = NULL;
  //  size_t read_size = ReadBuffer(file_path.c_str(), &proto_buf);
  //  c_program = paddle_mobile__framework__proto__program_desc__unpack(NULL,
  //  read_size, buf);
L
liuruilong 已提交
128

L
liuruilong 已提交
129
  //  paddle_mobile__framework__proto__var_type__tensor_desc__init()
130 131

  int memory_size = 1;
L
liuruilong 已提交
132
  for (auto l : desc.Dims()) {
朔-望's avatar
朔-望 已提交
133
    memory_size *= l;
134 135
  }

L
liuruilong 已提交
136
  tensor->Resize(framework::make_ddim(desc.Dims()));
137

朔-望's avatar
朔-望 已提交
138
  void *memory = tensor;
139
  int type_size = 0;
L
liuruilong 已提交
140 141
  switch (desc.DataType()) {
    case framework::VARTYPE_TYPE_FP16:
朔-望's avatar
朔-望 已提交
142 143
      type_size = 2;
      break;
L
liuruilong 已提交
144
    case framework::VARTYPE_TYPE_FP32:
朔-望's avatar
朔-望 已提交
145 146 147
      type_size = 4;
      memory = tensor->mutable_data<float>();
      break;
L
liuruilong 已提交
148
    case framework::VARTYPE_TYPE_FP64:
朔-望's avatar
朔-望 已提交
149 150
      type_size = 8;
      break;
L
liuruilong 已提交
151
    case framework::VARTYPE_TYPE_INT32:
朔-望's avatar
朔-望 已提交
152 153
      type_size = 4;
      break;
L
liuruilong 已提交
154
    case framework::VARTYPE_TYPE_INT64:
朔-望's avatar
朔-望 已提交
155 156
      type_size = 8;
      break;
L
liuruilong 已提交
157
    case framework::VARTYPE_TYPE_BOOL:
朔-望's avatar
朔-望 已提交
158 159 160 161
      type_size = 1;
      break;
    default:
      break;
162 163 164 165
  }

  is.read(static_cast<char *>(memory), memory_size * type_size);
  is.close();
朔-望's avatar
朔-望 已提交
166
}
朔-望's avatar
朔-望 已提交
167 168

template <typename Dtype, Precision P>
朔-望's avatar
朔-望 已提交
169 170
const framework::Program<Dtype, P> Loader<Dtype, P>::Load(
    const std::string &dirname) {
171
  std::string model_filename = dirname + "/__model__";
L
liuruilong 已提交
172 173 174 175 176 177
  PaddleMobile__Framework__Proto__ProgramDesc *c_program;
  uint8_t *buf = NULL;
  size_t read_size = ReadBuffer(model_filename.c_str(), &buf);

  PADDLE_MOBILE_ENFORCE(buf != NULL, "read from __model__ is null");

L
liuruilong 已提交
178 179
  c_program = paddle_mobile__framework__proto__program_desc__unpack(
      NULL, read_size, buf);
L
liuruilong 已提交
180 181 182 183

  PADDLE_MOBILE_ENFORCE(c_program != NULL, "program is null");

  DLOG << "n_ops: " << (*c_program->blocks)->n_ops;
184 185

  std::shared_ptr<framework::ProgramDesc> originProgramDesc =
L
liuruilong 已提交
186
      std::make_shared<framework::ProgramDesc>(c_program);
187 188

  framework::Program<Dtype, P> program;
L
liuruilong 已提交
189
  program.model_path = dirname;
190 191 192 193 194
  program.originProgram = originProgramDesc;

  std::shared_ptr<framework::Scope> scope =
      std::make_shared<framework::Scope>();
  program.scope = scope;
E
eclipsess 已提交
195 196 197 198 199
  originProgramDesc->Block(0);

  for (const auto &block : originProgramDesc->Blocks()) {
    for (int i = 0; i < block->Vars().size(); ++i) {
      std::shared_ptr<framework::VarDesc> var_desc = block->Vars()[i];
L
liuruilong 已提交
200
      //      DLOG << "var name-- " << var_desc->Name();
E
eclipsess 已提交
201
      auto var = scope->Var(var_desc->Name());
L
liuruilong 已提交
202 203

      if (var_desc->Type() == framework::VARTYPE_TYPE_LOD_TENSOR) {
E
eclipsess 已提交
204
        if (var_desc->Persistable() &&
L
liuruilong 已提交
205 206
            var_desc->Type() != framework::VARTYPE_TYPE_FEED_MINIBATCH &&
            var_desc->Type() != framework::VARTYPE_TYPE_FETCH_LIST) {
L
liuruilong 已提交
207
          //          DLOG << "to load var ";
W
wangliu 已提交
208 209 210
          auto dim = var_desc->Tensor_desc().Dims();
          auto tensor = var->GetMutable<framework::LoDTensor>();
          tensor->Resize(framework::make_ddim(dim));
L
liuruilong 已提交
211 212
        } else {
          auto dim = var_desc->Tensor_desc().Dims();
W
wangliu 已提交
213
          PADDLE_MOBILE_ENFORCE(dim.size() > 0, "dim size is 0");
L
liuruilong 已提交
214 215 216
          dim[0] = 1;
          auto tensor = var->GetMutable<framework::LoDTensor>();
          tensor->Resize(framework::make_ddim(dim));
E
eclipsess 已提交
217 218 219 220 221 222
        }
      } else {
        // TODO(codeWorm): some.
      }
    }
  }
223

E
eclipsess 已提交
224
  //  originProgramDesc->Description("program: ");
朔-望's avatar
朔-望 已提交
225

L
liuruilong 已提交
226
  paddle_mobile__framework__proto__program_desc__free_unpacked(c_program, NULL);
227
  return program;
朔-望's avatar
朔-望 已提交
228
}
朔-望's avatar
朔-望 已提交
229

朔-望's avatar
朔-望 已提交
230
template class Loader<CPU, Precision::FP32>;
朔-望's avatar
朔-望 已提交
231

L
liuruilong 已提交
232 233 234 235 236 237 238 239 240 241
#pragma mark - executor

template <typename Dtype, Precision P>
Executor<Dtype, P>::Executor(const framework::Program<Dtype> p) : program_(p) {
  if (use_optimize_) {
    to_predict_program_ = program_.optimizeProgram;
  } else {
    to_predict_program_ = program_.originProgram;
  }

L
liuruilong 已提交
242 243 244 245 246 247 248
  const std::vector<std::shared_ptr<framework::BlockDesc>> blocks =
      to_predict_program_->Blocks();
  for (int i = 0; i < blocks.size(); ++i) {
    std::shared_ptr<framework::BlockDesc> block_desc = blocks[i];
    std::vector<std::shared_ptr<framework::OpDesc>> ops = block_desc->Ops();
    for (int j = 0; j < ops.size(); ++j) {
      std::shared_ptr<framework::OpDesc> op = ops[j];
W
wangliu 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
      auto op_base = framework::OpRegistry<Dtype>::CreateOp(
          op->Type(), op->GetInputs(), op->GetOutputs(), op->GetAttrMap(),
          program_.scope);
      op_base->InferShape();
      ops_of_block_[*block_desc.get()].push_back(op_base);
    }
  }
  InitMemory();
}

template <typename Dtype, Precision P>
Executor<Dtype, P>::Executor(const framework::Program<Dtype> p, int batch_size)
    : program_(p), batch_size_(batch_size) {
  if (use_optimize_) {
    to_predict_program_ = program_.optimizeProgram;
  } else {
    to_predict_program_ = program_.originProgram;
  }
  Variable *variable_ptr = program_.scope->Var("batch_size");
  variable_ptr[0].SetValue<int>(batch_size);
  const std::vector<std::shared_ptr<framework::BlockDesc>> blocks =
      to_predict_program_->Blocks();
  for (int i = 0; i < blocks.size(); ++i) {
    std::shared_ptr<framework::BlockDesc> block_desc = blocks[i];
    std::vector<std::shared_ptr<framework::OpDesc>> ops = block_desc->Ops();
    for (int j = 0; j < ops.size(); ++j) {
      std::shared_ptr<framework::OpDesc> op = ops[j];
      auto op_base = framework::OpRegistry<Dtype>::CreateOp(
          op->Type(), op->GetInputs(), op->GetOutputs(), op->GetAttrMap(),
          program_.scope);
      op_base->InferShape();

      ops_of_block_[*block_desc.get()].push_back(op_base);
L
liuruilong 已提交
282 283 284
    }
  }
  InitMemory();
L
liuruilong 已提交
285 286 287
}

template <typename Dtype, Precision P>
L
liuruilong 已提交
288 289
void Executor<Dtype, P>::LoadMemory(const framework::VarDesc var_desc,
                                    framework::LoDTensor *tensor,
L
liuruilong 已提交
290
                                    const std::string &file_path) {
L
liuruilong 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
  std::ifstream is(file_path);
  PADDLE_MOBILE_ENFORCE(is.is_open(), "open file: %s failed",
                        file_path.c_str());
  std::fpos<mbstate_t> pos;
  pos = is.tellg();  // save   current   position
  is.seekg(0, std::ios::end);
  is.seekg(pos);  // restore   saved   position

  // 1. version
  uint32_t version;
  is.read(reinterpret_cast<char *>(&version), sizeof(version));

  // 2 Lod information
  uint64_t lod_level;
  is.read(reinterpret_cast<char *>(&lod_level), sizeof(lod_level));
  auto &lod = *tensor->mutable_lod();
  lod.resize(lod_level);
  for (uint64_t i = 0; i < lod_level; ++i) {
    uint64_t size;
    is.read(reinterpret_cast<char *>(&size), sizeof(size));
    std::vector<size_t> tmp(size / sizeof(size_t));
    is.read(reinterpret_cast<char *>(tmp.data()),
            static_cast<std::streamsize>(size));
    for (auto j : tmp) {
      LOG(kLOG_DEBUG1) << "    lod - " << j;
    }
    lod[i] = tmp;
  }

  // 3. tensor version
  uint32_t tensor_version;
  is.read(reinterpret_cast<char *>(&tensor_version), sizeof(tensor_version));

  // 4. tensor desc
  int32_t size;
  is.read(reinterpret_cast<char *>(&size), sizeof(size));
  std::unique_ptr<char[]> buf(new char[size]);
  is.read(reinterpret_cast<char *>(buf.get()), size);

L
liuruilong 已提交
330 331
  const framework::TensorDesc &desc = var_desc.Tensor_desc();

L
liuruilong 已提交
332
  int memory_size = 1;
L
liuruilong 已提交
333
  for (auto l : desc.Dims()) {
L
liuruilong 已提交
334 335 336
    memory_size *= l;
  }

L
liuruilong 已提交
337
  tensor->Resize(framework::make_ddim(desc.Dims()));
L
liuruilong 已提交
338 339 340

  void *memory = tensor;
  int type_size = 0;
L
liuruilong 已提交
341 342
  switch (desc.DataType()) {
    case framework::VARTYPE_TYPE_FP16:
L
liuruilong 已提交
343 344
      type_size = 2;
      break;
L
liuruilong 已提交
345
    case framework::VARTYPE_TYPE_FP32:
L
liuruilong 已提交
346 347 348
      type_size = 4;
      memory = tensor->mutable_data<float>();
      break;
L
liuruilong 已提交
349
    case framework::VARTYPE_TYPE_FP64:
L
liuruilong 已提交
350 351
      type_size = 8;
      break;
L
liuruilong 已提交
352
    case framework::VARTYPE_TYPE_INT32:
L
liuruilong 已提交
353 354
      type_size = 4;
      break;
L
liuruilong 已提交
355
    case framework::VARTYPE_TYPE_INT64:
L
liuruilong 已提交
356 357
      type_size = 8;
      break;
L
liuruilong 已提交
358
    case framework::VARTYPE_TYPE_BOOL:
L
liuruilong 已提交
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
      type_size = 1;
      break;
    default:
      break;
  }

  is.read(static_cast<char *>(memory), memory_size * type_size);
  is.close();
};

template <typename Dtype, Precision P>
void Executor<Dtype, P>::InitMemory() {
  for (const auto &block : to_predict_program_->Blocks()) {
    for (const auto &var_desc : block->Vars()) {
      auto var = program_.scope->Var(var_desc->Name());
L
liuruilong 已提交
374 375
      if (var_desc->Persistable()) {
        auto tensor = var->template GetMutable<framework::LoDTensor>();
W
wangliu 已提交
376 377 378
        if (var_desc->Name() == "feed" || var_desc->Name() == "fetch") {
          continue;
        }
L
liuruilong 已提交
379 380
        LoadMemory(*var_desc, tensor,
                   program_.model_path + "/" + var_desc->Name());
L
liuruilong 已提交
381
      } else {
L
liuruilong 已提交
382
        if (var_desc->Type() == framework::VARTYPE_TYPE_LOD_TENSOR) {
W
wangliu 已提交
383 384
          auto tensor = var->template GetMutable<framework::LoDTensor>();

L
liuruilong 已提交
385 386 387
          tensor->template mutable_data<Ptype>();
        }
      }
L
liuruilong 已提交
388 389 390 391 392 393
    }
  }
}

template <typename Dtype, Precision P>
void Executor<Dtype, P>::predict(const framework::Tensor &t, int block_id) {
W
wangliu 已提交
394 395 396 397
  framework::Variable *g_feed_value = program_.scope->Var("feed");
  auto feed_tensor = g_feed_value->GetMutable<framework::LoDTensor>();
  feed_tensor->Resize(t.dims());
  feed_tensor->ShareDataWith(t);
L
liuruilong 已提交
398
  std::shared_ptr<framework::BlockDesc> to_predict_block =
L
liuruilong 已提交
399
      to_predict_program_->Block(block_id);
L
liuruilong 已提交
400 401
  for (int j = 0; j < ops_of_block_[*to_predict_block.get()].size(); ++j) {
    auto op = ops_of_block_[*to_predict_block.get()][j];
W
wangliu 已提交
402
      op->Run();
L
liuruilong 已提交
403 404 405 406
  }
}

template <typename Dtype, Precision P>
L
liuruilong 已提交
407 408
std::vector<typename Executor<Dtype, P>::Ptype> Executor<Dtype, P>::predict(
    const std::vector<Ptype> &input, const std::vector<int64_t> &dims) {
L
liuruilong 已提交
409 410 411 412 413
  DLOG << "start predict: ";

  framework::Tensor tensor;
  auto ddim = framework::make_ddim(dims);

L
liuruilong 已提交
414
  auto input_ptr = tensor.mutable_data<Ptype>(ddim);
L
liuruilong 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428
  for (int i = 0; i < input.size(); ++i) {
    input_ptr[i] = input[i];
  }

  predict(tensor, 0);

  framework::Variable *g_feed_value = program_.scope->Var("col");
  auto feed_tensor = g_feed_value->GetMutable<framework::Tensor>();

  return {};
}

template class Executor<CPU, Precision::FP32>;

朔-望's avatar
朔-望 已提交
429
}  // namespace paddle_mobile