fluid_cpu_engine.h 15.7 KB
Newer Older
W
wangguibao 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright (c) 2019 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.

W
wangguibao 已提交
15 16 17
#pragma once

#include <pthread.h>
W
wangguibao 已提交
18 19
#include <fstream>
#include <map>
W
wangguibao 已提交
20 21
#include <string>
#include <vector>
G
guru4elephant 已提交
22 23 24
#include "core/configure/include/configure_parser.h"
#include "core/configure/inferencer_configure.pb.h"
#include "core/predictor/framework/infer.h"
B
barrierye 已提交
25
#include "paddle_inference_api.h"  // NOLINT
26
//#include "predictor/framework/infer.h"
W
wangguibao 已提交
27 28 29 30 31

namespace baidu {
namespace paddle_serving {
namespace fluid_cpu {

32 33
using configure::SigmoidConf;

W
wangguibao 已提交
34
class AutoLock {
W
wangguibao 已提交
35 36 37 38
 public:
  explicit AutoLock(pthread_mutex_t& mutex) : _mut(mutex) {
    pthread_mutex_lock(&mutex);
  }
W
wangguibao 已提交
39

W
wangguibao 已提交
40
  ~AutoLock() { pthread_mutex_unlock(&_mut); }
W
wangguibao 已提交
41

W
wangguibao 已提交
42 43
 private:
  pthread_mutex_t& _mut;
W
wangguibao 已提交
44 45 46
};

class GlobalPaddleCreateMutex {
W
wangguibao 已提交
47 48
 public:
  pthread_mutex_t& mutex() { return _mut; }
W
wangguibao 已提交
49

W
wangguibao 已提交
50 51 52 53
  static pthread_mutex_t& instance() {
    static GlobalPaddleCreateMutex gmutex;
    return gmutex.mutex();
  }
W
wangguibao 已提交
54

W
wangguibao 已提交
55 56
 private:
  GlobalPaddleCreateMutex() { pthread_mutex_init(&_mut, NULL); }
W
wangguibao 已提交
57

W
wangguibao 已提交
58
  pthread_mutex_t _mut;
W
wangguibao 已提交
59 60 61
};

class GlobalSigmoidCreateMutex {
W
wangguibao 已提交
62 63 64
 public:
  pthread_mutex_t& mutex() { return _mut; }
  static pthread_mutex_t& instance() {
W
wangguibao 已提交
65
    static GlobalSigmoidCreateMutex gmutex;
W
wangguibao 已提交
66 67
    return gmutex.mutex();
  }
W
wangguibao 已提交
68

W
wangguibao 已提交
69 70 71 72
 private:
  GlobalSigmoidCreateMutex() { pthread_mutex_init(&_mut, NULL); }

  pthread_mutex_t _mut;
W
wangguibao 已提交
73 74 75 76
};

// data interface
class FluidFamilyCore {
W
wangguibao 已提交
77 78 79 80
 public:
  virtual ~FluidFamilyCore() {}
  virtual bool Run(const void* in_data, void* out_data) {
    if (!_core->Run(*(std::vector<paddle::PaddleTensor>*)in_data,
W
wangguibao 已提交
81
                    (std::vector<paddle::PaddleTensor>*)out_data)) {
W
wangguibao 已提交
82 83
      LOG(ERROR) << "Failed call Run with paddle predictor";
      return false;
W
wangguibao 已提交
84 85
    }

W
wangguibao 已提交
86 87 88
    return true;
  }

89
  virtual int create(const predictor::InferEngineCreationParams& params) = 0;
W
wangguibao 已提交
90 91 92 93 94 95 96 97 98 99 100 101

  virtual int clone(void* origin_core) {
    if (origin_core == NULL) {
      LOG(ERROR) << "origin paddle Predictor is null.";
      return -1;
    }
    paddle::PaddlePredictor* p_predictor =
        (paddle::PaddlePredictor*)origin_core;
    _core = p_predictor->Clone();
    if (_core.get() == NULL) {
      LOG(ERROR) << "fail to clone paddle predictor: " << origin_core;
      return -1;
W
wangguibao 已提交
102
    }
W
wangguibao 已提交
103 104
    return 0;
  }
W
wangguibao 已提交
105

W
wangguibao 已提交
106
  virtual void* get() { return _core.get(); }
W
wangguibao 已提交
107

W
wangguibao 已提交
108 109
 protected:
  std::unique_ptr<paddle::PaddlePredictor> _core;
W
wangguibao 已提交
110 111 112 113
};

// infer interface
class FluidCpuAnalysisCore : public FluidFamilyCore {
W
wangguibao 已提交
114
 public:
115 116
  int create(const predictor::InferEngineCreationParams& params) {
    std::string data_path = params.get_path();
W
wangguibao 已提交
117 118 119 120
    if (access(data_path.c_str(), F_OK) == -1) {
      LOG(ERROR) << "create paddle predictor failed, path not exits: "
                 << data_path;
      return -1;
W
wangguibao 已提交
121
    }
W
wangguibao 已提交
122

W
wangguibao 已提交
123 124 125 126 127
    paddle::AnalysisConfig analysis_config;
    analysis_config.SetParamsFile(data_path + "/__params__");
    analysis_config.SetProgFile(data_path + "/__model__");
    analysis_config.DisableGpu();
    analysis_config.SetCpuMathLibraryNumThreads(1);
128 129

    if (params.enable_memory_optimization()) {
W
wangguibao 已提交
130
      analysis_config.EnableMemoryOptim();
131 132
    }

W
wangguibao 已提交
133
    analysis_config.SwitchSpecifyInputNames(true);
W
wangguibao 已提交
134
    AutoLock lock(GlobalPaddleCreateMutex::instance());
W
wangguibao 已提交
135 136
    _core =
        paddle::CreatePaddlePredictor<paddle::AnalysisConfig>(analysis_config);
W
wangguibao 已提交
137 138 139 140 141
    if (NULL == _core.get()) {
      LOG(ERROR) << "create paddle predictor failed, path: " << data_path;
      return -1;
    }

142
    VLOG(2) << "create paddle predictor sucess, path: " << data_path;
W
wangguibao 已提交
143 144
    return 0;
  }
W
wangguibao 已提交
145 146 147
};

class FluidCpuNativeCore : public FluidFamilyCore {
W
wangguibao 已提交
148
 public:
149 150
  int create(const predictor::InferEngineCreationParams& params) {
    std::string data_path = params.get_path();
W
wangguibao 已提交
151 152 153 154
    if (access(data_path.c_str(), F_OK) == -1) {
      LOG(ERROR) << "create paddle predictor failed, path not exits: "
                 << data_path;
      return -1;
W
wangguibao 已提交
155
    }
W
wangguibao 已提交
156 157 158 159 160 161

    paddle::NativeConfig native_config;
    native_config.param_file = data_path + "/__params__";
    native_config.prog_file = data_path + "/__model__";
    native_config.use_gpu = false;
    native_config.device = 0;
W
Wang Guibao 已提交
162 163
    native_config.fraction_of_gpu_memory = 0;

W
wangguibao 已提交
164 165 166 167 168 169 170 171 172
    AutoLock lock(GlobalPaddleCreateMutex::instance());
    _core = paddle::CreatePaddlePredictor<paddle::NativeConfig,
                                          paddle::PaddleEngineKind::kNative>(
        native_config);
    if (NULL == _core.get()) {
      LOG(ERROR) << "create paddle predictor failed, path: " << data_path;
      return -1;
    }

173
    VLOG(2) << "create paddle predictor sucess, path: " << data_path;
W
wangguibao 已提交
174 175
    return 0;
  }
W
wangguibao 已提交
176 177 178
};

class FluidCpuAnalysisDirCore : public FluidFamilyCore {
W
wangguibao 已提交
179
 public:
180 181
  int create(const predictor::InferEngineCreationParams& params) {
    std::string data_path = params.get_path();
W
wangguibao 已提交
182 183 184 185
    if (access(data_path.c_str(), F_OK) == -1) {
      LOG(ERROR) << "create paddle predictor failed, path not exits: "
                 << data_path;
      return -1;
W
wangguibao 已提交
186 187
    }

W
wangguibao 已提交
188 189 190 191 192
    paddle::AnalysisConfig analysis_config;
    analysis_config.SetModel(data_path);
    analysis_config.DisableGpu();
    analysis_config.SwitchSpecifyInputNames(true);
    analysis_config.SetCpuMathLibraryNumThreads(1);
193 194

    if (params.enable_memory_optimization()) {
W
wangguibao 已提交
195
      analysis_config.EnableMemoryOptim();
196 197
    }

M
MRXLT 已提交
198 199 200 201 202 203
    if (params.enable_ir_optimization()) {
      analysis_config.SwitchIrOptim(true);
    } else {
      analysis_config.SwitchIrOptim(false);
    }

W
wangguibao 已提交
204
    AutoLock lock(GlobalPaddleCreateMutex::instance());
W
wangguibao 已提交
205 206
    _core =
        paddle::CreatePaddlePredictor<paddle::AnalysisConfig>(analysis_config);
W
wangguibao 已提交
207 208 209 210 211
    if (NULL == _core.get()) {
      LOG(ERROR) << "create paddle predictor failed, path: " << data_path;
      return -1;
    }

212
    VLOG(2) << "create paddle predictor sucess, path: " << data_path;
W
wangguibao 已提交
213 214
    return 0;
  }
W
wangguibao 已提交
215 216 217
};

class FluidCpuNativeDirCore : public FluidFamilyCore {
W
wangguibao 已提交
218
 public:
219 220
  int create(const predictor::InferEngineCreationParams& params) {
    std::string data_path = params.get_path();
W
wangguibao 已提交
221 222 223 224 225 226 227 228 229 230
    if (access(data_path.c_str(), F_OK) == -1) {
      LOG(ERROR) << "create paddle predictor failed, path not exits: "
                 << data_path;
      return -1;
    }

    paddle::NativeConfig native_config;
    native_config.model_dir = data_path;
    native_config.use_gpu = false;
    native_config.device = 0;
W
Wang Guibao 已提交
231
    native_config.fraction_of_gpu_memory = 0;
W
wangguibao 已提交
232 233 234 235 236 237 238
    AutoLock lock(GlobalPaddleCreateMutex::instance());
    _core = paddle::CreatePaddlePredictor<paddle::NativeConfig,
                                          paddle::PaddleEngineKind::kNative>(
        native_config);
    if (NULL == _core.get()) {
      LOG(ERROR) << "create paddle predictor failed, path: " << data_path;
      return -1;
W
wangguibao 已提交
239 240
    }

241
    VLOG(2) << "create paddle predictor sucess, path: " << data_path;
W
wangguibao 已提交
242 243
    return 0;
  }
W
wangguibao 已提交
244 245 246
};

class Parameter {
W
wangguibao 已提交
247 248 249
 public:
  Parameter() : _row(0), _col(0), _params(NULL) {}
  ~Parameter() {
250
    VLOG(2) << "before destroy Parameter, file_name[" << _file_name << "]";
W
wangguibao 已提交
251 252 253 254 255 256 257 258 259 260 261 262
    destroy();
  }

  int init(int row, int col, const char* file_name) {
    destroy();
    _file_name = file_name;
    _row = row;
    _col = col;
    _params = reinterpret_cast<float*>(malloc(_row * _col * sizeof(float)));
    if (_params == NULL) {
      LOG(ERROR) << "Load " << _file_name << " malloc error.";
      return -1;
W
wangguibao 已提交
263
    }
264
    VLOG(2) << "Load parameter file[" << _file_name << "] success.";
W
wangguibao 已提交
265 266 267 268 269 270 271 272 273
    return 0;
  }

  void destroy() {
    _row = 0;
    _col = 0;
    if (_params != NULL) {
      free(_params);
      _params = NULL;
W
wangguibao 已提交
274
    }
W
wangguibao 已提交
275
  }
W
wangguibao 已提交
276

W
wangguibao 已提交
277 278 279 280
  int load() {
    if (_params == NULL || _row <= 0 || _col <= 0) {
      LOG(ERROR) << "load parameter error [not inited].";
      return -1;
W
wangguibao 已提交
281 282
    }

W
wangguibao 已提交
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    FILE* fs = fopen(_file_name.c_str(), "rb");
    if (fs == NULL) {
      LOG(ERROR) << "load " << _file_name << " fopen error.";
      return -1;
    }
    static const uint32_t MODEL_FILE_HEAD_LEN = 16;
    char head[MODEL_FILE_HEAD_LEN] = {0};
    if (fread(head, 1, MODEL_FILE_HEAD_LEN, fs) != MODEL_FILE_HEAD_LEN) {
      destroy();
      LOG(ERROR) << "Load " << _file_name << " read head error.";
      if (fs != NULL) {
        fclose(fs);
        fs = NULL;
      }
      return -1;
W
wangguibao 已提交
298 299
    }

W
wangguibao 已提交
300 301 302 303 304 305
    uint32_t matrix_size = _row * _col;
    if (matrix_size == fread(_params, sizeof(float), matrix_size, fs)) {
      if (fs != NULL) {
        fclose(fs);
        fs = NULL;
      }
306
      VLOG(2) << "load " << _file_name << " read ok.";
W
wangguibao 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
      return 0;
    } else {
      LOG(ERROR) << "load " << _file_name << " read error.";
      destroy();
      if (fs != NULL) {
        fclose(fs);
        fs = NULL;
      }
      return -1;
    }
    return 0;
  }

 public:
  std::string _file_name;
  int _row;
  int _col;
  float* _params;
W
wangguibao 已提交
325 326 327
};

class SigmoidModel {
W
wangguibao 已提交
328 329 330 331 332 333 334 335 336 337
 public:
  ~SigmoidModel() {}
  int load(const char* sigmoid_w_file,
           const char* sigmoid_b_file,
           float exp_max,
           float exp_min) {
    AutoLock lock(GlobalSigmoidCreateMutex::instance());
    if (0 != _sigmoid_w.init(2, 1, sigmoid_w_file) || 0 != _sigmoid_w.load()) {
      LOG(ERROR) << "load params sigmoid_w failed.";
      return -1;
W
wangguibao 已提交
338
    }
339 340
    VLOG(2) << "load sigmoid_w [" << _sigmoid_w._params[0] << "] ["
            << _sigmoid_w._params[1] << "].";
W
wangguibao 已提交
341 342 343
    if (0 != _sigmoid_b.init(2, 1, sigmoid_b_file) || 0 != _sigmoid_b.load()) {
      LOG(ERROR) << "load params sigmoid_b failed.";
      return -1;
W
wangguibao 已提交
344
    }
345
    VLOG(2) << "load sigmoid_b [" << _sigmoid_b._params[0] << "] ["
B
barrierye 已提交
346
            << _sigmoid_b._params[1] << "].";
W
wangguibao 已提交
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
    _exp_max_input = exp_max;
    _exp_min_input = exp_min;
    return 0;
  }

  int softmax(float x, double& o) {  // NOLINT
    float _y0 = x * _sigmoid_w._params[0] + _sigmoid_b._params[0];
    float _y1 = x * _sigmoid_w._params[1] + _sigmoid_b._params[1];
    _y0 = (_y0 > _exp_max_input)
              ? _exp_max_input
              : ((_y0 < _exp_min_input) ? _exp_min_input : _y0);
    _y1 = (_y1 > _exp_max_input)
              ? _exp_max_input
              : ((_y1 < _exp_min_input) ? _exp_min_input : _y1);
    o = 1.0f / (1.0f + exp(_y0 - _y1));
    return 0;
  }

 public:
  Parameter _sigmoid_w;
  Parameter _sigmoid_b;
  float _exp_max_input;
  float _exp_min_input;
W
wangguibao 已提交
370 371 372
};

class SigmoidFluidModel {
W
wangguibao 已提交
373 374 375 376 377 378 379 380 381 382
 public:
  int softmax(float x, double& o) {  // NOLINT
    return _sigmoid_core->softmax(x, o);
  }  // NOLINT

  std::unique_ptr<SigmoidFluidModel> Clone() {
    std::unique_ptr<SigmoidFluidModel> clone_model;
    clone_model.reset(new SigmoidFluidModel());
    clone_model->_sigmoid_core = _sigmoid_core;
    clone_model->_fluid_core = _fluid_core->Clone();
B
barrierye 已提交
383
    return std::move(clone_model);  // NOLINT
W
wangguibao 已提交
384 385 386 387 388
  }

 public:
  std::unique_ptr<paddle::PaddlePredictor> _fluid_core;
  std::shared_ptr<SigmoidModel> _sigmoid_core;
W
wangguibao 已提交
389 390 391
};

class FluidCpuWithSigmoidCore : public FluidFamilyCore {
W
wangguibao 已提交
392 393 394 395
 public:
  virtual ~FluidCpuWithSigmoidCore() {}

 public:
396 397
  int create(const predictor::InferEngineCreationParams& params) {
    std::string model_path = params.get_path();
W
wangguibao 已提交
398 399 400 401 402 403 404
    size_t pos = model_path.find_last_of("/\\");
    std::string conf_path = model_path.substr(0, pos);
    std::string conf_file = model_path.substr(pos);
    configure::SigmoidConf conf;
    if (configure::read_proto_conf(conf_path, conf_file, &conf) != 0) {
      LOG(ERROR) << "failed load model path: " << model_path;
      return -1;
W
wangguibao 已提交
405 406
    }

W
wangguibao 已提交
407
    _core.reset(new SigmoidFluidModel);
W
wangguibao 已提交
408

W
wangguibao 已提交
409
    std::string fluid_model_data_path = conf.dnn_model_path();
410 411 412
    predictor::InferEngineCreationParams new_params(params);
    new_params.set_path(fluid_model_data_path);
    int ret = load_fluid_model(new_params);
W
wangguibao 已提交
413 414 415
    if (ret < 0) {
      LOG(ERROR) << "fail to load fluid model.";
      return -1;
W
wangguibao 已提交
416
    }
W
wangguibao 已提交
417 418 419 420 421
    const char* sigmoid_w_file = conf.sigmoid_w_file().c_str();
    const char* sigmoid_b_file = conf.sigmoid_b_file().c_str();
    float exp_max = conf.exp_max_input();
    float exp_min = conf.exp_min_input();
    _core->_sigmoid_core.reset(new SigmoidModel);
422 423
    VLOG(2) << "create sigmoid core[" << _core->_sigmoid_core.get()
            << "], use count[" << _core->_sigmoid_core.use_count() << "].";
W
wangguibao 已提交
424 425 426 427 428
    ret = _core->_sigmoid_core->load(
        sigmoid_w_file, sigmoid_b_file, exp_max, exp_min);
    if (ret < 0) {
      LOG(ERROR) << "fail to load sigmoid model.";
      return -1;
W
wangguibao 已提交
429
    }
W
wangguibao 已提交
430 431 432 433 434 435 436 437 438
    return 0;
  }

  virtual bool Run(const void* in_data, void* out_data) {
    if (!_core->_fluid_core->Run(
            *(std::vector<paddle::PaddleTensor>*)in_data,
            (std::vector<paddle::PaddleTensor>*)out_data)) {
      LOG(ERROR) << "Failed call Run with paddle predictor";
      return false;
W
wangguibao 已提交
439 440
    }

W
wangguibao 已提交
441 442
    return true;
  }
W
wangguibao 已提交
443

W
wangguibao 已提交
444 445 446 447
  virtual int clone(SigmoidFluidModel* origin_core) {
    if (origin_core == NULL) {
      LOG(ERROR) << "origin paddle Predictor is null.";
      return -1;
W
wangguibao 已提交
448
    }
W
wangguibao 已提交
449 450 451 452 453
    _core = origin_core->Clone();
    if (_core.get() == NULL) {
      LOG(ERROR) << "fail to clone paddle predictor: " << origin_core;
      return -1;
    }
454 455
    VLOG(2) << "clone sigmoid core[" << _core->_sigmoid_core.get()
            << "] use count[" << _core->_sigmoid_core.use_count() << "].";
W
wangguibao 已提交
456 457 458 459 460
    return 0;
  }

  virtual SigmoidFluidModel* get() { return _core.get(); }

461 462
  virtual int load_fluid_model(
      const predictor::InferEngineCreationParams& params) = 0;
W
wangguibao 已提交
463

W
wangguibao 已提交
464 465 466 467 468
  int softmax(float x, double& o) {  // NOLINT
    return _core->_sigmoid_core->softmax(x, o);
  }

 protected:
B
barrierye 已提交
469
  std::unique_ptr<SigmoidFluidModel> _core;  // NOLINT
W
wangguibao 已提交
470 471 472
};

class FluidCpuNativeDirWithSigmoidCore : public FluidCpuWithSigmoidCore {
W
wangguibao 已提交
473
 public:
474 475
  int load_fluid_model(const predictor::InferEngineCreationParams& params) {
    std::string data_path = params.get_path();
W
wangguibao 已提交
476 477 478 479 480 481 482 483 484 485
    if (access(data_path.c_str(), F_OK) == -1) {
      LOG(ERROR) << "create paddle predictor failed, path not exits: "
                 << data_path;
      return -1;
    }

    paddle::NativeConfig native_config;
    native_config.model_dir = data_path;
    native_config.use_gpu = false;
    native_config.device = 0;
W
Wang Guibao 已提交
486
    native_config.fraction_of_gpu_memory = 0;
W
wangguibao 已提交
487 488 489 490 491 492 493 494
    AutoLock lock(GlobalPaddleCreateMutex::instance());
    _core->_fluid_core =
        paddle::CreatePaddlePredictor<paddle::NativeConfig,
                                      paddle::PaddleEngineKind::kNative>(
            native_config);
    if (NULL == _core.get()) {
      LOG(ERROR) << "create paddle predictor failed, path: " << data_path;
      return -1;
W
wangguibao 已提交
495 496
    }

497
    VLOG(2) << "create paddle predictor sucess, path: " << data_path;
W
wangguibao 已提交
498 499
    return 0;
  }
W
wangguibao 已提交
500 501 502
};

class FluidCpuAnalysisDirWithSigmoidCore : public FluidCpuWithSigmoidCore {
W
wangguibao 已提交
503
 public:
504 505
  int load_fluid_model(const predictor::InferEngineCreationParams& params) {
    std::string data_path = params.get_path();
W
wangguibao 已提交
506 507 508 509
    if (access(data_path.c_str(), F_OK) == -1) {
      LOG(ERROR) << "create paddle predictor failed, path not exits: "
                 << data_path;
      return -1;
W
wangguibao 已提交
510
    }
W
wangguibao 已提交
511

W
wangguibao 已提交
512 513 514 515 516
    paddle::AnalysisConfig analysis_config;
    analysis_config.SetModel(data_path);
    analysis_config.DisableGpu();
    analysis_config.SwitchSpecifyInputNames(true);
    analysis_config.SetCpuMathLibraryNumThreads(1);
517 518

    if (params.enable_memory_optimization()) {
W
wangguibao 已提交
519
      analysis_config.EnableMemoryOptim();
520 521
    }

W
wangguibao 已提交
522 523
    AutoLock lock(GlobalPaddleCreateMutex::instance());
    _core->_fluid_core =
W
wangguibao 已提交
524
        paddle::CreatePaddlePredictor<paddle::AnalysisConfig>(analysis_config);
W
wangguibao 已提交
525 526 527 528 529
    if (NULL == _core.get()) {
      LOG(ERROR) << "create paddle predictor failed, path: " << data_path;
      return -1;
    }

530
    VLOG(2) << "create paddle predictor sucess, path: " << data_path;
W
wangguibao 已提交
531 532
    return 0;
  }
W
wangguibao 已提交
533 534
};

W
wangguibao 已提交
535 536 537
}  // namespace fluid_cpu
}  // namespace paddle_serving
}  // namespace baidu