benchmark.cc 7.3 KB
Newer Older
Y
Yan Chunwei 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 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.

#include <gflags/gflags.h>
J
juncaipeng 已提交
16 17 18
#include <sys/time.h>
#include <time.h>
#include <algorithm>
Y
Yan Chunwei 已提交
19 20
#include <cstdio>
#include <fstream>
J
juncaipeng 已提交
21 22
#include <iomanip>
#include <numeric>
Y
Yan Chunwei 已提交
23 24 25
#include <string>
#include <vector>
#include "lite/api/paddle_api.h"
26
#include "lite/core/device_info.h"
Y
Yan Chunwei 已提交
27 28 29
#include "lite/utils/cp_logging.h"
#include "lite/utils/string.h"

30 31
DEFINE_string(model_dir,
              "",
32 33 34
              "the path of the model, the model and param files is under "
              "model_dir.");
DEFINE_string(model_filename,
35
              "",
36 37 38
              "the filename of model file. When the model is combined formate, "
              "please set model_file.");
DEFINE_string(param_filename,
39
              "",
40
              "the filename of param file, set param_file when the model is "
41
              "combined formate.");
Y
Yan Chunwei 已提交
42 43
DEFINE_string(input_shape,
              "1,3,224,224",
J
juncaipeng 已提交
44 45
              "set input shapes according to the model, "
              "separated by colon and comma, "
46 47
              "such as 1,3,244,244");
DEFINE_string(input_img_path, "", "the path of input image");
J
juncaipeng 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61
DEFINE_int32(warmup, 0, "warmup times");
DEFINE_int32(repeats, 1, "repeats times");
DEFINE_int32(power_mode,
             3,
             "arm power mode: "
             "0 for big cluster, "
             "1 for little cluster, "
             "2 for all cores, "
             "3 for no bind");
DEFINE_int32(threads, 1, "threads num");
DEFINE_string(result_filename,
              "result.txt",
              "save benchmark "
              "result to the file");
J
juncaipeng 已提交
62 63
DEFINE_bool(run_model_optimize,
            false,
J
juncaipeng 已提交
64 65 66 67 68 69
            "if set true, apply model_optimize_tool to "
            "model and use optimized model to test. ");
DEFINE_bool(is_quantized_model,
            false,
            "if set true, "
            "test the performance of the quantized model. ");
Y
Yan Chunwei 已提交
70 71 72 73

namespace paddle {
namespace lite_api {

J
juncaipeng 已提交
74 75 76 77 78 79
inline double GetCurrentUS() {
  struct timeval time;
  gettimeofday(&time, NULL);
  return 1e+6 * time.tv_sec + time.tv_usec;
}

80
void OutputOptModel(const std::string& save_optimized_model_dir) {
Y
Yan Chunwei 已提交
81
  lite_api::CxxConfig config;
82
  config.set_model_dir(FLAGS_model_dir);
83 84 85 86
  if (!FLAGS_model_filename.empty() && !FLAGS_param_filename.empty()) {
    config.set_model_file(FLAGS_model_dir + "/" + FLAGS_model_filename);
    config.set_param_file(FLAGS_model_dir + "/" + FLAGS_param_filename);
  }
87 88 89
  std::vector<Place> vaild_places = {
      Place{TARGET(kARM), PRECISION(kFloat)},
  };
90 91 92 93 94
  if (FLAGS_is_quantized_model) {
    vaild_places.insert(vaild_places.begin(),
                        Place{TARGET(kARM), PRECISION(kInt8)});
  }
  config.set_valid_places(vaild_places);
Y
Yan Chunwei 已提交
95 96 97 98 99 100
  auto predictor = lite_api::CreatePaddlePredictor(config);

  int ret = system(
      paddle::lite::string_format("rm -rf %s", save_optimized_model_dir.c_str())
          .c_str());
  if (ret == 0) {
J
juncaipeng 已提交
101
    LOG(INFO) << "Delete old optimized model " << save_optimized_model_dir;
Y
Yan Chunwei 已提交
102 103 104
  }
  predictor->SaveOptimizedModel(save_optimized_model_dir,
                                LiteModelType::kNaiveBuffer);
105
  LOG(INFO) << "Load model from " << FLAGS_model_dir;
Y
Yan Chunwei 已提交
106 107 108 109
  LOG(INFO) << "Save optimized model to " << save_optimized_model_dir;
}

#ifdef LITE_WITH_LIGHT_WEIGHT_FRAMEWORK
110
void Run(const std::vector<int64_t>& input_shape,
Y
Yan Chunwei 已提交
111 112
         const std::string& model_dir,
         const std::string model_name) {
J
juncaipeng 已提交
113
  // set config and create predictor
114
  lite_api::MobileConfig config;
J
juncaipeng 已提交
115 116
  config.set_threads(FLAGS_threads);
  config.set_power_mode(static_cast<PowerMode>(FLAGS_power_mode));
117
  config.set_model_from_file(model_dir + ".nb");
Y
Yan Chunwei 已提交
118 119 120

  auto predictor = lite_api::CreatePaddlePredictor(config);

J
juncaipeng 已提交
121
  // set input
122 123 124 125 126 127 128 129
  auto input_tensor = predictor->GetInput(0);
  input_tensor->Resize(input_shape);
  auto input_data = input_tensor->mutable_data<float>();
  int input_num = 1;
  for (size_t i = 0; i < input_shape.size(); ++i) {
    input_num *= input_shape[i];
  }
  if (FLAGS_input_img_path.empty()) {
Y
Yan Chunwei 已提交
130 131 132
    for (int i = 0; i < input_num; ++i) {
      input_data[i] = 1.f;
    }
133 134 135 136 137 138 139 140 141 142
  } else {
    std::fstream fs(FLAGS_input_img_path);
    if (!fs.is_open()) {
      LOG(FATAL) << "open input image " << FLAGS_input_img_path << " error.";
    }
    for (int i = 0; i < input_num; i++) {
      fs >> input_data[i];
    }
    // LOG(INFO) << "input data:" << input_data[0] << " " <<
    // input_data[input_num-1];
Y
Yan Chunwei 已提交
143 144
  }

J
juncaipeng 已提交
145 146
  // warmup
  for (int i = 0; i < FLAGS_warmup; ++i) {
Y
Yan Chunwei 已提交
147 148 149
    predictor->Run();
  }

J
juncaipeng 已提交
150 151 152 153
  // run
  std::vector<float> perf_vct;
  for (int i = 0; i < FLAGS_repeats; ++i) {
    auto start = GetCurrentUS();
Y
Yan Chunwei 已提交
154
    predictor->Run();
J
juncaipeng 已提交
155 156
    auto end = GetCurrentUS();
    perf_vct.push_back((end - start) / 1000.0);
Y
Yan Chunwei 已提交
157
  }
J
juncaipeng 已提交
158 159 160 161 162 163 164 165 166 167
  std::sort(perf_vct.begin(), perf_vct.end());
  float min_res = perf_vct.back();
  float max_res = perf_vct.front();
  float total_res = accumulate(perf_vct.begin(), perf_vct.end(), 0.0);
  float avg_res = total_res / FLAGS_repeats;

  // save result
  std::ofstream ofs(FLAGS_result_filename, std::ios::app);
  if (!ofs.is_open()) {
    LOG(FATAL) << "open result file failed";
Y
Yan Chunwei 已提交
168
  }
J
juncaipeng 已提交
169
  ofs.precision(5);
170
  ofs << std::setw(30) << std::fixed << std::left << model_name;
J
juncaipeng 已提交
171 172 173 174
  ofs << "min = " << std::setw(12) << min_res;
  ofs << "max = " << std::setw(12) << max_res;
  ofs << "average = " << std::setw(12) << avg_res;
  ofs << std::endl;
J
juncaipeng 已提交
175
  ofs.close();
Y
Yan Chunwei 已提交
176 177 178 179 180 181 182 183 184
}
#endif

}  // namespace lite_api
}  // namespace paddle

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  if (FLAGS_model_dir == "" || FLAGS_result_filename == "") {
J
juncaipeng 已提交
185
    LOG(INFO) << "please run ./benchmark_bin --help to obtain usage.";
Y
Yan Chunwei 已提交
186 187 188
    exit(0);
  }

189 190 191
  if (FLAGS_model_dir.back() == '/') {
    FLAGS_model_dir.pop_back();
  }
Y
Yan Chunwei 已提交
192 193
  std::size_t found = FLAGS_model_dir.find_last_of("/");
  std::string model_name = FLAGS_model_dir.substr(found + 1);
194
  std::string save_optimized_model_dir = FLAGS_model_dir + "_opt2";
Y
Yan Chunwei 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

  auto get_shape = [](const std::string& str_shape) -> std::vector<int64_t> {
    std::vector<int64_t> shape;
    std::string tmp_str = str_shape;
    while (!tmp_str.empty()) {
      int dim = atoi(tmp_str.data());
      shape.push_back(dim);
      size_t next_offset = tmp_str.find(",");
      if (next_offset == std::string::npos) {
        break;
      } else {
        tmp_str = tmp_str.substr(next_offset + 1);
      }
    }
    return shape;
  };

212
  std::vector<int64_t> input_shape = get_shape(FLAGS_input_shape);
Y
Yan Chunwei 已提交
213

J
juncaipeng 已提交
214
  // Output optimized model if needed
J
juncaipeng 已提交
215
  if (FLAGS_run_model_optimize) {
216
    paddle::lite_api::OutputOptModel(save_optimized_model_dir);
J
juncaipeng 已提交
217
  }
Y
Yan Chunwei 已提交
218 219 220

#ifdef LITE_WITH_LIGHT_WEIGHT_FRAMEWORK
  // Run inference using optimized model
J
juncaipeng 已提交
221 222
  std::string run_model_dir =
      FLAGS_run_model_optimize ? save_optimized_model_dir : FLAGS_model_dir;
223
  paddle::lite_api::Run(input_shape, run_model_dir, model_name);
Y
Yan Chunwei 已提交
224 225 226
#endif
  return 0;
}