benchmark.cc 10.2 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>
16
#if !defined(_WIN32)
J
juncaipeng 已提交
17
#include <sys/time.h>
18
#else
19
#define NOMINMAX  // msvc max/min macro conflict with std::min/max
20 21 22 23
#include <windows.h>
#include "lite/backends/x86/port.h"
#endif
#define GLOG_NO_ABBREVIATED_SEVERITIES  // msvc conflict logging with windows.h
J
juncaipeng 已提交
24 25
#include <time.h>
#include <algorithm>
Y
Yan Chunwei 已提交
26 27
#include <cstdio>
#include <fstream>
J
juncaipeng 已提交
28 29
#include <iomanip>
#include <numeric>
Y
Yan Chunwei 已提交
30 31 32
#include <string>
#include <vector>
#include "lite/api/paddle_api.h"
33
#include "lite/core/device_info.h"
Y
Yan Chunwei 已提交
34 35 36
#include "lite/utils/cp_logging.h"
#include "lite/utils/string.h"

C
cc 已提交
37 38 39
DEFINE_string(optimized_model_path,
              "",
              "the path of the model that is optimized by opt.");
40 41
DEFINE_string(model_dir,
              "",
42 43 44
              "the path of the model, the model and param files is under "
              "model_dir.");
DEFINE_string(model_filename,
45
              "",
46 47 48
              "the filename of model file. When the model is combined formate, "
              "please set model_file.");
DEFINE_string(param_filename,
49
              "",
50
              "the filename of param file, set param_file when the model is "
51
              "combined formate.");
Y
Yan Chunwei 已提交
52 53
DEFINE_string(input_shape,
              "1,3,224,224",
J
juncaipeng 已提交
54 55
              "set input shapes according to the model, "
              "separated by colon and comma, "
56
              "such as 1,3,244,244");
57 58 59 60
DEFINE_string(input_img_path,
              "",
              "the path of input image, if not set "
              "input_img_path, the input of model will be 1.0.");
J
juncaipeng 已提交
61 62 63 64 65 66 67 68 69 70 71 72
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",
73
              "save the inference time to the file.");
C
cc 已提交
74
DEFINE_bool(show_output, false, "Wether to show the output in shell.");
Y
Yan Chunwei 已提交
75 76 77 78

namespace paddle {
namespace lite_api {

J
juncaipeng 已提交
79 80 81 82 83 84
inline double GetCurrentUS() {
  struct timeval time;
  gettimeofday(&time, NULL);
  return 1e+6 * time.tv_sec + time.tv_usec;
}

85
void OutputOptModel(const std::string& save_optimized_model_dir) {
Y
Yan Chunwei 已提交
86
  lite_api::CxxConfig config;
87
  config.set_model_dir(FLAGS_model_dir);
88 89 90 91
  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);
  }
92 93
  std::vector<Place> vaild_places = {
      Place{TARGET(kARM), PRECISION(kFloat)},
94 95
      Place{TARGET(kARM), PRECISION(kInt32)},
      Place{TARGET(kARM), PRECISION(kInt64)},
96
  };
97
  config.set_valid_places(vaild_places);
Y
Yan Chunwei 已提交
98 99 100 101 102 103
  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 已提交
104
    LOG(INFO) << "Delete old optimized model " << save_optimized_model_dir;
Y
Yan Chunwei 已提交
105 106 107
  }
  predictor->SaveOptimizedModel(save_optimized_model_dir,
                                LiteModelType::kNaiveBuffer);
108
  LOG(INFO) << "Load model from " << FLAGS_model_dir;
Y
Yan Chunwei 已提交
109 110 111
  LOG(INFO) << "Save optimized model to " << save_optimized_model_dir;
}

C
cc 已提交
112 113 114 115 116 117 118 119
int64_t ShapeProduction(const std::vector<int64_t>& shape) {
  int64_t num = 1;
  for (auto i : shape) {
    num *= i;
  }
  return num;
}

Y
Yan Chunwei 已提交
120
#ifdef LITE_WITH_LIGHT_WEIGHT_FRAMEWORK
121
void Run(const std::vector<int64_t>& input_shape,
C
cc 已提交
122
         const std::string& model_path,
Y
Yan Chunwei 已提交
123
         const std::string model_name) {
J
juncaipeng 已提交
124
  // set config and create predictor
125
  lite_api::MobileConfig config;
J
juncaipeng 已提交
126 127
  config.set_threads(FLAGS_threads);
  config.set_power_mode(static_cast<PowerMode>(FLAGS_power_mode));
C
cc 已提交
128
  config.set_model_from_file(model_path);
Y
Yan Chunwei 已提交
129 130 131

  auto predictor = lite_api::CreatePaddlePredictor(config);

J
juncaipeng 已提交
132
  // set input
133 134 135
  auto input_tensor = predictor->GetInput(0);
  input_tensor->Resize(input_shape);
  auto input_data = input_tensor->mutable_data<float>();
C
cc 已提交
136
  int64_t input_num = ShapeProduction(input_shape);
137
  if (FLAGS_input_img_path.empty()) {
Y
Yan Chunwei 已提交
138 139 140
    for (int i = 0; i < input_num; ++i) {
      input_data[i] = 1.f;
    }
141 142 143 144 145 146 147 148 149 150
  } 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 已提交
151 152
  }

J
juncaipeng 已提交
153 154
  // warmup
  for (int i = 0; i < FLAGS_warmup; ++i) {
Y
Yan Chunwei 已提交
155 156 157
    predictor->Run();
  }

J
juncaipeng 已提交
158 159 160 161
  // run
  std::vector<float> perf_vct;
  for (int i = 0; i < FLAGS_repeats; ++i) {
    auto start = GetCurrentUS();
Y
Yan Chunwei 已提交
162
    predictor->Run();
J
juncaipeng 已提交
163 164
    auto end = GetCurrentUS();
    perf_vct.push_back((end - start) / 1000.0);
Y
Yan Chunwei 已提交
165
  }
166
  std::stable_sort(perf_vct.begin(), perf_vct.end());
J
juncaipeng 已提交
167 168 169 170 171 172 173 174 175
  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 已提交
176
  }
J
juncaipeng 已提交
177
  ofs.precision(5);
178
  ofs << std::setw(30) << std::fixed << std::left << model_name;
J
juncaipeng 已提交
179 180 181 182
  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 已提交
183
  ofs.close();
C
cc 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198

  if (FLAGS_show_output) {
    auto out_tensor = predictor->GetOutput(0);
    auto* out_data = out_tensor->data<float>();
    int64_t output_num = ShapeProduction(out_tensor->shape());
    float max_value = out_data[0];
    int max_index = 0;
    for (int i = 0; i < output_num; i++) {
      if (max_value < out_data[i]) {
        max_value = out_data[i];
        max_index = i;
      }
    }
    LOG(INFO) << "max_value:" << max_value;
    LOG(INFO) << "max_index:" << max_index;
199 200 201 202
    LOG(INFO) << "output data[0:10]:";
    for (int i = 0; i < 10; i++) {
      LOG(INFO) << out_data[i];
    }
C
cc 已提交
203
  }
Y
Yan Chunwei 已提交
204 205 206 207 208 209
}
#endif

}  // namespace lite_api
}  // namespace paddle

C
cc 已提交
210 211 212 213
void print_usage() {
  std::string help_info =
      "Usage: \n"
      "./benchmark_bin \n"
214 215 216 217
      "  --optimized_model_path (The path of the model that is optimized\n"
      "    by opt. If the model is optimized, please set the param.) \n"
      "    type: string \n"
      "  --model_dir (The path of the model that is not optimized by opt,\n"
C
cc 已提交
218
      "    the model and param files is under model_dir.) type: string \n"
219
      "  --model_filename (The filename of model file. When the model is\n "
C
cc 已提交
220 221
      "    combined formate, please set model_file. Otherwise, it is not\n"
      "    necessary to set it.) type: string \n"
222
      "  --param_filename (The filename of param file, set param_file when\n"
C
cc 已提交
223 224
      "    the model is combined formate. Otherwise, it is not necessary\n"
      "    to set it.) type: string \n"
225
      "  --input_shape (Set input shapes according to the model, separated by\n"
C
cc 已提交
226 227
      "    colon and comma, such as 1,3,244,244) type: string\n"
      "    default: 1,3,224,224 \n"
228
      "  --input_img_path (The path of input image, if not set\n"
C
cc 已提交
229
      "    input_img_path, the input will be 1.0.) type: string \n "
230
      "  --power_mode (Arm power mode: 0 for big cluster, 1 for little\n"
C
cc 已提交
231
      "    cluster, 2 for all cores, 3 for no bind) type: int32 default: 3\n"
232 233
      "  --repeats (Repeats times) type: int32 default: 1 \n"
      "  --result_filename (Save the inference time to the file.) type: \n"
C
cc 已提交
234
      "    string default: result.txt \n"
235 236
      "  --threads (Threads num) type: int32 default: 1 \n"
      "  --warmup (Warmup times) type: int32 default: 0 \n"
C
cc 已提交
237
      "Note that: \n"
238 239 240
      "  If load the optimized model, set optimized_model_path. Otherwise, \n"
      "    set model_dir, model_filename and param_filename according to \n"
      "    the model. \n";
C
cc 已提交
241 242 243
  LOG(INFO) << help_info;
}

Y
Yan Chunwei 已提交
244
int main(int argc, char** argv) {
C
cc 已提交
245
  // Check inputs
Y
Yan Chunwei 已提交
246
  gflags::ParseCommandLineFlags(&argc, &argv, true);
C
cc 已提交
247 248 249 250 251
  bool is_opt_model = (FLAGS_optimized_model_path != "");
  bool is_origin_model = (FLAGS_model_dir != "");
  if (!is_origin_model && !is_opt_model) {
    LOG(INFO) << "Input error, the model path should not be empty.\n";
    print_usage();
Y
Yan Chunwei 已提交
252 253 254
    exit(0);
  }

C
cc 已提交
255
  // Get input shape
Y
Yan Chunwei 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
  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;
  };
271
  std::vector<int64_t> input_shape = get_shape(FLAGS_input_shape);
Y
Yan Chunwei 已提交
272

C
cc 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
  // Get model_name and run_model_path
  std::string model_name;
  std::string run_model_path;
  if (is_origin_model) {
    if (FLAGS_model_dir.back() == '/') {
      FLAGS_model_dir.pop_back();
    }
    std::size_t found = FLAGS_model_dir.find_last_of("/");
    model_name = FLAGS_model_dir.substr(found + 1);
    std::string optimized_model_path = FLAGS_model_dir + "_opt2";
    paddle::lite_api::OutputOptModel(optimized_model_path);
    run_model_path = optimized_model_path + ".nb";
  } else {
    size_t found1 = FLAGS_optimized_model_path.find_last_of("/");
    size_t found2 = FLAGS_optimized_model_path.find_last_of(".");
    size_t len = found2 - found1 - 1;
    model_name = FLAGS_optimized_model_path.substr(found1 + 1, len);
    run_model_path = FLAGS_optimized_model_path;
J
juncaipeng 已提交
291
  }
Y
Yan Chunwei 已提交
292 293

#ifdef LITE_WITH_LIGHT_WEIGHT_FRAMEWORK
C
cc 已提交
294 295
  // Run test
  paddle::lite_api::Run(input_shape, run_model_path, model_name);
Y
Yan Chunwei 已提交
296 297 298
#endif
  return 0;
}