benchmark.cc 9.7 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"

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

namespace paddle {
namespace lite_api {

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

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

C
cc 已提交
103 104 105 106 107 108 109 110
int64_t ShapeProduction(const std::vector<int64_t>& shape) {
  int64_t num = 1;
  for (auto i : shape) {
    num *= i;
  }
  return num;
}

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

  auto predictor = lite_api::CreatePaddlePredictor(config);

J
juncaipeng 已提交
123
  // set input
124 125 126
  auto input_tensor = predictor->GetInput(0);
  input_tensor->Resize(input_shape);
  auto input_data = input_tensor->mutable_data<float>();
C
cc 已提交
127
  int64_t input_num = ShapeProduction(input_shape);
128
  if (FLAGS_input_img_path.empty()) {
Y
Yan Chunwei 已提交
129 130 131
    for (int i = 0; i < input_num; ++i) {
      input_data[i] = 1.f;
    }
132 133 134 135 136 137 138 139 140 141
  } 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 已提交
142 143
  }

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

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

  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;
  }
Y
Yan Chunwei 已提交
191 192 193 194 195 196
}
#endif

}  // namespace lite_api
}  // namespace paddle

C
cc 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
void print_usage() {
  std::string help_info =
      "Usage: \n"
      "./benchmark_bin \n"
      "  --optimized_model_path (the path of the model that is optimized\n"
      "    by opt.) type: string \n"
      "  --model_dir (the path of the model that is not optimized by opt,\n"
      "    the model and param files is under model_dir.) type: string \n"
      "  --model_filename (the filename of model file. When the model is\n "
      "    combined formate, please set model_file. Otherwise, it is not\n"
      "    necessary to set it.) type: string \n"
      "  --param_filename (the filename of param file, set param_file when\n"
      "    the model is combined formate. Otherwise, it is not necessary\n"
      "    to set it.) type: string \n"
      "  --input_shape (set input shapes according to the model, separated by\n"
      "    colon and comma, such as 1,3,244,244) type: string\n"
      "    default: 1,3,224,224 \n"
      "  --input_img_path (the path of input image, if not set\n"
      "    input_img_path, the input will be 1.0.) type: string \n "
      "  --power_mode (arm power mode: 0 for big cluster, 1 for little\n"
      "    cluster, 2 for all cores, 3 for no bind) type: int32 default: 3\n"
      "  --repeats (repeats times) type: int32 default: 1 \n"
      "  --result_filename (save the inference time to the file.) type: \n"
      "    string default: result.txt \n"
      "  --threads (threads num) type: int32 default: 1 \n"
      "  --warmup (warmup times) type: int32 default: 0 \n"
      "Note that: \n"
      "  If load the optimized model, set optimized_model_path, or set\n"
      "    model_dir, model_filename and param_filename according to the\n"
      "    model. \n";
  LOG(INFO) << help_info;
}

Y
Yan Chunwei 已提交
230
int main(int argc, char** argv) {
C
cc 已提交
231
  // Check inputs
Y
Yan Chunwei 已提交
232
  gflags::ParseCommandLineFlags(&argc, &argv, true);
C
cc 已提交
233 234 235 236 237
  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 已提交
238 239 240
    exit(0);
  }

C
cc 已提交
241
  // Get input shape
Y
Yan Chunwei 已提交
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  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;
  };
257
  std::vector<int64_t> input_shape = get_shape(FLAGS_input_shape);
Y
Yan Chunwei 已提交
258

C
cc 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
  // 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 已提交
277
  }
Y
Yan Chunwei 已提交
278 279

#ifdef LITE_WITH_LIGHT_WEIGHT_FRAMEWORK
C
cc 已提交
280 281
  // Run test
  paddle::lite_api::Run(input_shape, run_model_path, model_name);
Y
Yan Chunwei 已提交
282 283 284
#endif
  return 0;
}