example.cc 16.8 KB
Newer Older
L
Liangliang He 已提交
1
// Copyright 2018 The MACE Authors. All Rights Reserved.
Y
yejianwu 已提交
2
//
L
Liangliang He 已提交
3 4 5
// 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
Y
yejianwu 已提交
6
//
L
Liangliang He 已提交
7 8 9 10 11 12 13
//     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.
Y
yejianwu 已提交
14

15
#include <dirent.h>
L
liutuo 已提交
16
#include <errno.h>
B
Bin Li 已提交
17 18 19 20 21
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdint>
22
#include <cstdlib>
B
Bin Li 已提交
23
#include <cstring>
24 25 26
#include <fstream>
#include <iostream>
#include <numeric>
Y
yejianwu 已提交
27 28

#include "gflags/gflags.h"
L
Liangliang He 已提交
29 30
#include "mace/port/env.h"
#include "mace/port/file_system.h"
31
#include "mace/public/mace.h"
L
Liangliang He 已提交
32
#include "mace/utils/logging.h"
33
#include "mace/utils/memory.h"
L
Liangliang He 已提交
34
#include "mace/utils/string_util.h"
35
// if convert model to code.
36
#ifdef MODEL_GRAPH_FORMAT_CODE
37
#include "mace/codegen/engine/mace_engine_factory.h"
L
liuqi 已提交
38
#endif
Y
yejianwu 已提交
39

40 41 42 43 44 45 46 47 48 49
#ifdef MACE_ENABLE_OPENCL
namespace mace {
const unsigned char *LoadOpenCLBinary();
size_t OpenCLBinarySize();
const unsigned char *LoadOpenCLParameter();
size_t OpenCLParameterSize();
}  // namespace mace
#endif


L
liuqi 已提交
50 51
namespace mace {
namespace examples {
L
liuqi 已提交
52

L
liuqi 已提交
53 54
void ParseShape(const std::string &str, std::vector<int64_t> *shape) {
  std::string tmp = str;
Y
yejianwu 已提交
55 56 57 58
  while (!tmp.empty()) {
    int dim = atoi(tmp.data());
    shape->push_back(dim);
    size_t next_offset = tmp.find(",");
L
liuqi 已提交
59
    if (next_offset == std::string::npos) {
Y
yejianwu 已提交
60 61 62 63 64 65 66
      break;
    } else {
      tmp = tmp.substr(next_offset + 1);
    }
  }
}

L
liuqi 已提交
67 68 69 70 71 72 73 74
std::string FormatName(const std::string input) {
  std::string res = input;
  for (size_t i = 0; i < input.size(); ++i) {
    if (!isalnum(res[i])) res[i] = '_';
  }
  return res;
}

L
liuqi 已提交
75
DeviceType ParseDeviceType(const std::string &device_str) {
Y
yejianwu 已提交
76 77
  if (device_str.compare("CPU") == 0) {
    return DeviceType::CPU;
78 79
  } else if (device_str.compare("GPU") == 0) {
    return DeviceType::GPU;
Y
yejianwu 已提交
80 81
  } else if (device_str.compare("HEXAGON") == 0) {
    return DeviceType::HEXAGON;
B
Bin Li 已提交
82 83
  } else if (device_str.compare("HTA") == 0) {
    return DeviceType::HTA;
Y
yejianwu 已提交
84 85 86 87 88
  } else {
    return DeviceType::CPU;
  }
}

89 90 91 92 93
DataFormat ParseDataFormat(const std::string &data_format_str) {
  if (data_format_str == "NHWC") {
    return DataFormat::NHWC;
  } else if (data_format_str == "NCHW") {
    return DataFormat::NCHW;
94 95
  } else if (data_format_str == "OIHW") {
    return DataFormat::OIHW;
96
  } else {
97
    return DataFormat::NONE;
98 99
  }
}
Y
yejianwu 已提交
100

101
DEFINE_string(model_name,
102
              "",
L
liuqi 已提交
103
              "model name in model deployment file");
L
Liangliang He 已提交
104 105
DEFINE_string(input_node,
              "input_node0,input_node1",
L
liuqi 已提交
106
              "input nodes, separated by comma");
L
Liangliang He 已提交
107 108
DEFINE_string(input_shape,
              "1,224,224,3:1,1,1,10",
L
liuqi 已提交
109
              "input shapes, separated by colon and comma");
L
Liangliang He 已提交
110 111
DEFINE_string(output_node,
              "output_node0,output_node1",
L
liuqi 已提交
112
              "output nodes, separated by comma");
L
Liangliang He 已提交
113 114
DEFINE_string(output_shape,
              "1,224,224,2:1,1,1,10",
L
liuqi 已提交
115
              "output shapes, separated by colon and comma");
116 117 118 119 120 121
DEFINE_string(input_data_format,
              "NHWC",
              "input data formats, NONE|NHWC|NCHW");
DEFINE_string(output_data_format,
              "NHWC",
              "output data formats, NONE|NHWC|NCHW");
L
Liangliang He 已提交
122 123
DEFINE_string(input_file,
              "",
L
liuqi 已提交
124
              "input file name | input file prefix for multiple inputs.");
L
Liangliang He 已提交
125 126
DEFINE_string(output_file,
              "",
L
liuqi 已提交
127
              "output file name | output file prefix for multiple outputs");
128 129 130 131 132 133
DEFINE_string(input_dir,
              "",
              "input directory name");
DEFINE_string(output_dir,
              "",
              "output directory name");
L
liuqi 已提交
134 135 136
DEFINE_string(opencl_binary_file,
              "",
              "compiled opencl binary file path");
L
liuqi 已提交
137 138 139
DEFINE_string(opencl_parameter_file,
              "",
              "tuned OpenCL parameter file path");
L
Liangliang He 已提交
140 141
DEFINE_string(model_data_file,
              "",
L
liuqi 已提交
142
              "model data file name, used when model_data_format == file");
143 144 145
DEFINE_string(model_file,
              "",
              "model file name, used when load mace model in pb");
146
DEFINE_string(device, "GPU", "CPU/GPU/HEXAGON");
Y
yejianwu 已提交
147
DEFINE_int32(round, 1, "round");
李寅 已提交
148
DEFINE_int32(restart_round, 1, "restart round");
Y
yejianwu 已提交
149
DEFINE_int32(malloc_check_cycle, -1, "malloc debug check cycle, -1 to disable");
L
liuqi 已提交
150 151
DEFINE_int32(gpu_perf_hint, 2, "0:DEFAULT/1:LOW/2:NORMAL/3:HIGH");
DEFINE_int32(gpu_priority_hint, 1, "0:DEFAULT/1:LOW/2:NORMAL/3:HIGH");
W
wuchenghui 已提交
152 153
DEFINE_int32(omp_num_threads, -1, "num of openmp threads");
DEFINE_int32(cpu_affinity_policy, 1,
154
             "0:AFFINITY_NONE/1:AFFINITY_BIG_ONLY/2:AFFINITY_LITTLE_ONLY");
L
liuqi 已提交
155

L
Liangliang He 已提交
156 157
bool RunModel(const std::vector<std::string> &input_names,
              const std::vector<std::vector<int64_t>> &input_shapes,
158
              const std::vector<DataFormat> &input_data_formats,
L
Liangliang He 已提交
159
              const std::vector<std::string> &output_names,
160 161
              const std::vector<std::vector<int64_t>> &output_shapes,
              const std::vector<DataFormat> &output_data_formats) {
L
liuqi 已提交
162 163
  // load model
  DeviceType device_type = ParseDeviceType(FLAGS_device);
164 165 166 167 168
  // configuration
  // Detailed information please see mace.h
  MaceStatus status;
  MaceEngineConfig config(device_type);
  status = config.SetCPUThreadPolicy(
W
wuchenghui 已提交
169
      FLAGS_omp_num_threads,
B
Bin Li 已提交
170
      static_cast<CPUAffinityPolicy>(FLAGS_cpu_affinity_policy));
171
  if (status != MaceStatus::MACE_SUCCESS) {
172 173
    std::cerr << "Set openmp or cpu affinity failed." << std::endl;
  }
174
#ifdef MACE_ENABLE_OPENCL
175
  std::shared_ptr<GPUContext> gpu_context;
176
  if (device_type == DeviceType::GPU) {
177 178 179 180 181 182
    // DO NOT USE tmp directory.
    // Please use APP's own directory and make sure the directory exists.
    const char *storage_path_ptr = getenv("MACE_INTERNAL_STORAGE_PATH");
    const std::string storage_path =
        std::string(storage_path_ptr == nullptr ?
                    "/data/local/tmp/mace_run/interior" : storage_path_ptr);
183
    std::vector<std::string> opencl_binary_paths = {FLAGS_opencl_binary_file};
L
liuqi 已提交
184

185 186 187
    gpu_context = GPUContextBuilder()
        .SetStoragePath(storage_path)
        .SetOpenCLBinaryPaths(opencl_binary_paths)
188
        .SetOpenCLBinary(LoadOpenCLBinary(), OpenCLBinarySize())
189
        .SetOpenCLParameterPath(FLAGS_opencl_parameter_file)
190
        .SetOpenCLParameter(LoadOpenCLParameter(), OpenCLParameterSize())
191 192 193 194 195 196
        .Finalize();

    config.SetGPUContext(gpu_context);
    config.SetGPUHints(
        static_cast<GPUPerfHint>(FLAGS_gpu_perf_hint),
        static_cast<GPUPriorityHint>(FLAGS_gpu_priority_hint));
197
  }
L
liuqi 已提交
198 199
#endif  // MACE_ENABLE_OPENCL

200
  // Create Engine
201 202
  std::shared_ptr<mace::MaceEngine> engine;
  MaceStatus create_engine_status;
203

204 205
  std::unique_ptr<mace::port::ReadOnlyMemoryRegion> model_graph_data =
    make_unique<mace::port::ReadOnlyBufferMemoryRegion>();
L
Liangliang He 已提交
206 207 208 209 210 211 212
  if (FLAGS_model_file != "") {
    auto fs = GetFileSystem();
    auto status = fs->NewReadOnlyMemoryRegionFromFile(FLAGS_model_file.c_str(),
        &model_graph_data);
    if (status != MaceStatus::MACE_SUCCESS) {
      LOG(FATAL) << "Failed to read file: " << FLAGS_model_file;
    }
213
  }
L
Liangliang He 已提交
214

215 216
  std::unique_ptr<mace::port::ReadOnlyMemoryRegion> model_weights_data =
    make_unique<mace::port::ReadOnlyBufferMemoryRegion>();
L
Liangliang He 已提交
217 218 219 220 221 222 223 224 225
  if (FLAGS_model_data_file != "") {
    auto fs = GetFileSystem();
    auto status = fs->NewReadOnlyMemoryRegionFromFile(
        FLAGS_model_data_file.c_str(),
        &model_weights_data);
    if (status != MaceStatus::MACE_SUCCESS) {
      LOG(FATAL) << "Failed to read file: " << FLAGS_model_data_file;
    }
    MACE_CHECK(model_weights_data->length() > 0);
226 227
  }

L
liuqi 已提交
228
  // Only choose one of the two type based on the `model_graph_format`
L
liuqi 已提交
229
  // in model deployment file(.yml).
230
#ifdef MODEL_GRAPH_FORMAT_CODE
L
liuqi 已提交
231 232
  // if model_data_format == code, just pass an empty string("")
  // to model_data_file parameter.
L
Liangliang He 已提交
233 234 235 236 237 238 239 240
  create_engine_status = CreateMaceEngineFromCode(
      FLAGS_model_name,
      reinterpret_cast<const unsigned char *>(model_weights_data->data()),
      model_weights_data->length(),
      input_names,
      output_names,
      config,
      &engine);
L
liuqi 已提交
241
#else
L
Liangliang He 已提交
242 243 244 245 246 247 248 249 250
  create_engine_status = CreateMaceEngineFromProto(
      reinterpret_cast<const unsigned char *>(model_graph_data->data()),
      model_graph_data->length(),
      reinterpret_cast<const unsigned char *>(model_weights_data->data()),
      model_weights_data->length(),
      input_names,
      output_names,
      config,
      &engine);
L
liuqi 已提交
251
#endif
252

253
  if (create_engine_status != MaceStatus::MACE_SUCCESS) {
254 255 256 257
    std::cerr << "Create engine error, please check the arguments first, "
              << "if correct, the device may not run the model, "
              << "please fall back to other strategy."
              << std::endl;
L
liuqi 已提交
258
    exit(1);
259
  }
Y
yejianwu 已提交
260

261 262
  const size_t input_count = input_names.size();
  const size_t output_count = output_names.size();
L
Liangliang He 已提交
263 264 265

  std::map<std::string, mace::MaceTensor> inputs;
  std::map<std::string, mace::MaceTensor> outputs;
266
  std::map<std::string, int64_t> inputs_size;
267
  for (size_t i = 0; i < input_count; ++i) {
L
liuqi 已提交
268 269 270
    int64_t input_size =
        std::accumulate(input_shapes[i].begin(), input_shapes[i].end(), 1,
                        std::multiplies<int64_t>());
271
    inputs_size[input_names[i]] = input_size;
L
liuqi 已提交
272
    // Only support float and int32 data type
L
Liangliang He 已提交
273 274
    auto buffer_in = std::shared_ptr<float>(new float[input_size],
                                            std::default_delete<float[]>());
275 276
    inputs[input_names[i]] = mace::MaceTensor(input_shapes[i], buffer_in,
        input_data_formats[i]);
L
liuqi 已提交
277
  }
L
Liangliang He 已提交
278

279
  for (size_t i = 0; i < output_count; ++i) {
L
liuqi 已提交
280 281 282
    int64_t output_size =
        std::accumulate(output_shapes[i].begin(), output_shapes[i].end(), 1,
                        std::multiplies<int64_t>());
L
liuqi 已提交
283
    // Only support float and int32 data type
L
Liangliang He 已提交
284 285
    auto buffer_out = std::shared_ptr<float>(new float[output_size],
                                             std::default_delete<float[]>());
286 287
    outputs[output_names[i]] = mace::MaceTensor(output_shapes[i], buffer_out,
        output_data_formats[i]);
L
liuqi 已提交
288 289
  }

290 291 292 293 294 295 296 297 298 299
  if (!FLAGS_input_dir.empty()) {
    DIR *dir_parent;
    struct dirent *entry;
    dir_parent = opendir(FLAGS_input_dir.c_str());
    if (dir_parent) {
      while ((entry = readdir(dir_parent))) {
        std::string file_name = std::string(entry->d_name);
        std::string prefix = FormatName(input_names[0]);
        if (file_name.find(prefix) == 0) {
          std::string suffix = file_name.substr(prefix.size());
Y
yejianwu 已提交
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 330 331 332 333 334 335
          for (size_t i = 0; i < input_count; ++i) {
            file_name = FLAGS_input_dir + "/" + FormatName(input_names[i])
                + suffix;
            std::ifstream in_file(file_name, std::ios::in | std::ios::binary);
            std::cout << "Read " << file_name << std::endl;
            if (in_file.is_open()) {
              in_file.read(reinterpret_cast<char *>(
                               inputs[input_names[i]].data().get()),
                           inputs_size[input_names[i]] * sizeof(float));
              in_file.close();
            } else {
              std::cerr << "Open input file failed" << std::endl;
              return -1;
            }
          }
          engine->Run(inputs, &outputs);

          if (!FLAGS_output_dir.empty()) {
            for (size_t i = 0; i < output_count; ++i) {
              std::string output_name =
                  FLAGS_output_dir + "/" + FormatName(output_names[i]) + suffix;
              std::ofstream out_file(output_name, std::ios::binary);
              if (out_file.is_open()) {
                int64_t output_size =
                    std::accumulate(output_shapes[i].begin(),
                                    output_shapes[i].end(),
                                    1,
                                    std::multiplies<int64_t>());
                out_file.write(
                    reinterpret_cast<char *>(
                        outputs[output_names[i]].data().get()),
                    output_size * sizeof(float));
                out_file.flush();
                out_file.close();
              } else {
李寅 已提交
336
                std::cerr << "Open output file failed" << std::endl;
337 338 339 340 341 342 343 344 345
                return -1;
              }
            }
          }
        }
      }

      closedir(dir_parent);
    } else {
李寅 已提交
346 347
      std::cerr << "Directory " << FLAGS_input_dir << " does not exist."
                << std::endl;
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    }
  } else {
    for (size_t i = 0; i < input_count; ++i) {
      std::ifstream in_file(FLAGS_input_file + "_" + FormatName(input_names[i]),
                            std::ios::in | std::ios::binary);
      if (in_file.is_open()) {
        in_file.read(reinterpret_cast<char *>(
                         inputs[input_names[i]].data().get()),
                     inputs_size[input_names[i]] * sizeof(float));
        in_file.close();
      } else {
        std::cerr << "Open input file failed" << std::endl;
        return -1;
      }
    }
    engine->Run(inputs, &outputs);
    for (size_t i = 0; i < output_count; ++i) {
      std::string output_name =
          FLAGS_output_file + "_" + FormatName(output_names[i]);
      std::ofstream out_file(output_name, std::ios::binary);
      int64_t output_size =
          std::accumulate(output_shapes[i].begin(), output_shapes[i].end(), 1,
                          std::multiplies<int64_t>());
      if (out_file.is_open()) {
        out_file.write(
            reinterpret_cast<char *>(outputs[output_names[i]].data().get()),
            output_size * sizeof(float));
        out_file.flush();
        out_file.close();
      } else {
李寅 已提交
378
        std::cerr << "Open output file failed" << std::endl;
379 380
        return -1;
      }
Y
yejianwu 已提交
381 382 383
    }
  }

L
liuqi 已提交
384
  std::cout << "Finished" << std::endl;
L
liuqi 已提交
385 386 387 388

  return true;
}

L
liuqi 已提交
389
int Main(int argc, char **argv) {
W
wuchenghui 已提交
390 391 392
  std::string usage = "example run\nusage: " + std::string(argv[0])
      + " [flags]";
  gflags::SetUsageMessage(usage);
L
liuqi 已提交
393 394
  gflags::ParseCommandLineFlags(&argc, &argv, true);

L
liuqi 已提交
395 396 397 398 399 400 401
  std::cout << "mace version: " << MaceVersion() << std::endl;
  std::cout << "input node: " << FLAGS_input_node << std::endl;
  std::cout << "input shape: " << FLAGS_input_shape << std::endl;
  std::cout << "output node: " << FLAGS_output_node << std::endl;
  std::cout << "output shape: " << FLAGS_output_shape << std::endl;
  std::cout << "input_file: " << FLAGS_input_file << std::endl;
  std::cout << "output_file: " << FLAGS_output_file << std::endl;
402 403
  std::cout << "input_dir: " << FLAGS_input_dir << std::endl;
  std::cout << "output dir: " << FLAGS_output_dir << std::endl;
L
liuqi 已提交
404 405 406 407 408 409 410 411 412 413 414
  std::cout << "model_data_file: " << FLAGS_model_data_file << std::endl;
  std::cout << "model_file: " << FLAGS_model_file << std::endl;
  std::cout << "device: " << FLAGS_device << std::endl;
  std::cout << "round: " << FLAGS_round << std::endl;
  std::cout << "restart_round: " << FLAGS_restart_round << std::endl;
  std::cout << "gpu_perf_hint: " << FLAGS_gpu_perf_hint << std::endl;
  std::cout << "gpu_priority_hint: " << FLAGS_gpu_priority_hint << std::endl;
  std::cout << "omp_num_threads: " << FLAGS_omp_num_threads << std::endl;
  std::cout << "cpu_affinity_policy: "
            << FLAGS_cpu_affinity_policy
            << std::endl;
L
liuqi 已提交
415

L
Liangliang He 已提交
416 417 418 419
  std::vector<std::string> input_names = Split(FLAGS_input_node, ',');
  std::vector<std::string> output_names = Split(FLAGS_output_node, ',');
  std::vector<std::string> input_shapes = Split(FLAGS_input_shape, ':');
  std::vector<std::string> output_shapes = Split(FLAGS_output_shape, ':');
L
liuqi 已提交
420

421 422
  const size_t input_count = input_shapes.size();
  const size_t output_count = output_shapes.size();
L
liuqi 已提交
423 424
  std::vector<std::vector<int64_t>> input_shape_vec(input_count);
  std::vector<std::vector<int64_t>> output_shape_vec(output_count);
425
  for (size_t i = 0; i < input_count; ++i) {
L
liuqi 已提交
426 427
    ParseShape(input_shapes[i], &input_shape_vec[i]);
  }
428
  for (size_t i = 0; i < output_count; ++i) {
L
liuqi 已提交
429 430 431
    ParseShape(output_shapes[i], &output_shape_vec[i]);
  }

432
  std::vector<std::string> raw_input_data_formats =
L
Liangliang He 已提交
433
    Split(FLAGS_input_data_format, ',');
434
  std::vector<std::string> raw_output_data_formats =
L
Liangliang He 已提交
435
    Split(FLAGS_output_data_format, ',');
436 437 438 439 440 441 442 443 444
  std::vector<DataFormat> input_data_formats(input_count);
  std::vector<DataFormat> output_data_formats(output_count);
  for (size_t i = 0; i < input_count; ++i) {
    input_data_formats[i] = ParseDataFormat(raw_input_data_formats[i]);
  }
  for (size_t i = 0; i < output_count; ++i) {
    output_data_formats[i] = ParseDataFormat(raw_output_data_formats[i]);
  }

L
liuqi 已提交
445
  bool ret = false;
李寅 已提交
446
  for (int i = 0; i < FLAGS_restart_round; ++i) {
L
liuqi 已提交
447
    std::cout << "restart round " << i << std::endl;
L
Liangliang He 已提交
448
    ret =
449 450
        RunModel(input_names, input_shape_vec, input_data_formats,
                 output_names, output_shape_vec, output_data_formats);
L
liuqi 已提交
451
  }
L
liuqi 已提交
452
  if (ret) {
L
liuqi 已提交
453 454 455
    return 0;
  } else {
    return -1;
Y
yejianwu 已提交
456 457
  }
}
L
liuqi 已提交
458 459 460 461 462

}  // namespace examples
}  // namespace mace

int main(int argc, char **argv) { mace::examples::Main(argc, argv); }