[nnc] Change interpreter compiler option (#2973)
authorСергей Баранников/AI Tools Lab /SRR/Engineer/삼성전자 <s.barannikov@samsung.com>
Thu, 31 Jan 2019 12:05:59 +0000 (15:05 +0300)
committerEfimov Alexander/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Thu, 31 Jan 2019 12:05:59 +0000 (15:05 +0300)
Replace interpreter compiler option "--input-model-data" with "--input-data-dir". The latter specifies directory in which the data files for the model inputs can be found.
Refactor interpreter to account for this change.

Signed-off-by: Sergei Barannikov <s.barannikov@samsung.com>
contrib/nnc/driver/Options.cpp
contrib/nnc/include/option/Options.h
contrib/nnc/include/passes/interpreter/InterpreterPass.h
contrib/nnc/include/support/CommandLine.h
contrib/nnc/passes/interpreter/interpreter_pass.cpp
contrib/nnc/support/CLOptionChecker.cpp

index 23805c7..c073d31 100644 (file)
@@ -162,13 +162,14 @@ Option<std::string> artifactDir(optname("--output-dir, -d"),
 /**
  * Options for *interpreter*
  */
-Option<std::vector<std::string>> interInputData(optname("--input-model-data"),
-                                   overview("interpreter option: specify file with neural network input data."
-                                            "These files contain arrays of floats in binary form"),
-                                   std::vector<std::string>{},
-                                   optional(true),
-                                   optvalues(""),
-                                   checkInFiles);
+Option<std::string> interInputDataDir(optname("--input-data-dir"),
+                                      overview("specify directory with binary files "
+                                               "containing the input data for the model "
+                                               "(one file for each input with the same name)"),
+                                      ".", // default is current directory
+                                      optional(true),
+                                      optvalues(""),
+                                      checkInDir);
 
 } // namespace cli
 } // namespace nnc
index 03f983d..803fdcc 100644 (file)
@@ -57,7 +57,7 @@ extern Option<std::string> artifactName;  // name of artifact
 /**
  * Options for interpreter
  */
-extern Option<std::vector<std::string>> interInputData;  // input data for model
+extern Option<std::string> interInputDataDir;  // directory with input data files
 
 } // namespace cli
 } // namespace nnc
index a3987df..2febd08 100644 (file)
@@ -32,11 +32,6 @@ public:
   ~InterpreterPass() override;
 
   PassData run(PassData data) override;
-
-private:
-  std::unordered_map<std::string, mir::TensorVariant> loadInput(
-                                                       const std::vector<mir::ops::InputOp*>& ops);
-  nnc::mir::TensorVariant *_out;
 };
 
 } // namespace nnc
index 5ff43f3..ada5b5b 100644 (file)
@@ -556,11 +556,10 @@ Option<T>::Option(const std::vector<std::string> &optnames,
 //
 // prototypes of option checker functions
 //
-void checkInFile(const Option<std::string> &);
-void checkInFiles(const Option<std::vector<std::string>> &);
-void checkOutFile(const Option<std::string> &);
-void checkOutDir(const Option<std::string> &);
-void checkDebugFile(const Option<std::string> &);
+void checkInFile(const Option<std::string>& in_file);
+void checkOutFile(const Option<std::string>& out_file);
+void checkInDir(const Option<std::string>& dir);
+void checkOutDir(const Option<std::string>& dir);
 
 } // namespace cli
 } // namespace nnc
index feefefd..a8edcd5 100644 (file)
@@ -88,19 +88,48 @@ static void writeTensorToHDF5File(const TensorVariant& tensor,
 
 #endif  // NNC_HDF5_SUPPORTED
 
+static TensorVariant readTensorFromFile(const std::string& filename, DTYPE dtype,
+                                        const Shape& shape) {
+  assert(dtype == DTYPE::FLOAT32);
+  std::size_t input_data_size = shape.numElements() * sizeof(float);
+
+  std::ifstream stream(filename, std::ios::in | std::ios::binary);
+  if (stream.fail())
+    throw PassException("Couldn't open file \"" + filename + "\".");
+
+  stream.seekg(0, std::ios::end);
+  std::streampos end = stream.tellg();
+  stream.seekg(0, std::ios::beg);
+  std::streampos begin = stream.tellg();
+  long file_size = end - begin;
+
+  if (static_cast<std::size_t>(file_size) != input_data_size)
+    throw PassException("File \"" + filename + "\" has incorrect size: " +
+                        std::to_string(file_size) +
+                        "(expected: " + std::to_string(input_data_size) + ").");
+
+  std::unique_ptr<char[]> data(new char[input_data_size]);
+  stream.read(data.get(), input_data_size);
+  if (stream.fail())
+    throw PassException("Couldn't read file \"" + filename + "\".");
+
+  return TensorVariant(dtype, shape, data.get());
+}
+
 PassData InterpreterPass::run(PassData data) {
   auto g = static_cast<Graph*>(data);
   assert(g);
 
   NNInterpreter interpreter;
 
-  // Check ops
-  auto inputs = g->getInputs();
-
-  auto input_data = loadInput(inputs);
-  for (auto inp: input_data) {
-    interpreter.setInput(inp.first, inp.second);
+  for (const auto* input_op : g->getInputs()) {
+    std::string tensor_name = input_op->getName();
+    std::replace(tensor_name.begin(), tensor_name.end(), '/', '_');
+    std::string filename = cli::interInputDataDir + "/" + tensor_name + ".dat";
+    auto tensor = readTensorFromFile(filename, DTYPE::FLOAT32, input_op->getOutputShape(0));
+    interpreter.setInput(input_op->getName(), tensor);
   }
+
   g->accept(&interpreter);
 
   for (auto out_node : g->getOutputs()) {
@@ -118,73 +147,6 @@ PassData InterpreterPass::run(PassData data) {
   return nullptr;
 }
 
-// Return pure file name w/o path and extension
-static std::string getFileName(std::string path) {
-  size_t sep = path.find_last_of("/");
-  if (sep != std::string::npos)
-    path = path.substr(sep + 1, path.size() - sep - 1);
-  size_t dot = path.find_last_of(".");
-  // TODO: There could be node names with symbols invalid in filename: if yes we should fix it.
-  if (dot != std::string::npos)
-    return path.substr(0, dot);
-  return path;
-}
-
-// Return input operation index with the given name
-static int getInputOp(std::string name, const std::vector<ops::InputOp*>& ops) {
-  for (unsigned ndx = 0; ndx < ops.size(); ndx++) {
-    if (ops[ndx]->getName() == name)
-      return ndx;
-  }
-  throw PassException("Input file name (without extension)"
-                      " should be equal to model input node name");
-}
-
-std::unordered_map<std::string, TensorVariant>
-InterpreterPass::loadInput(const std::vector<ops::InputOp*>& ops) {
-  std::unordered_map<std::string, TensorVariant> result;
-  for (unsigned i = 0; i < ops.size(); i++) {
-    // We assume that file name is equal to input node name
-    auto fname = getFileName(cli::interInputData[i]);
-    auto op_ndx = getInputOp(fname, ops);
-    auto f = fopen(cli::interInputData[i].c_str(), "rb");
-    assert (f);
-    int is_error = fseek(f, 0L, SEEK_END);
-    assert(!is_error);
-
-    auto len = ftell(f);
-    assert(len != -1);
-
-    auto shape = ops[op_ndx]->getOutputShape(0);
-    auto data_size = static_cast<size_t>(shape.numElements() * sizeof(float));
-
-    // Check size
-    if (static_cast<size_t>(len) != data_size) {
-      std::stringstream info;
-      info << "Wrong input file size <" << cli::interInputData[i] << "> = "
-           << len << ". Should be :" << data_size;
-
-      throw PassException(info.str());
-    }
-
-    rewind(f);
-
-    std::unique_ptr<char[]> data(new char[data_size]);
-    auto rlen = fread(data.get(), data_size, 1, f);
-    assert(rlen == 1);
-    (void)rlen;
-
-    is_error = fclose(f);
-    assert(is_error != EOF && "Can not close file!");
-    (void)is_error;
-
-    result.emplace(fname, TensorVariant(DTYPE::FLOAT32, shape, data.get()));
-  }
-  return result;
-}
-
-InterpreterPass::~InterpreterPass() {
-  delete _out;
-}
+InterpreterPass::~InterpreterPass() = default;
 
 } // namespace nnc
index d43c4ee..390398b 100644 (file)
@@ -18,6 +18,7 @@
 #include "support/CommandLine.h"
 
 #include <dirent.h>
+#include <cstring>
 #include <fstream>
 #include <sys/types.h>
 #include <unistd.h>
@@ -35,17 +36,6 @@ void checkInFile(const Option<std::string> &in_file) {
   fclose(f);
 } // checkInFile
 
-void checkInFiles(const Option<std::vector<std::string>> &in_files) {
-  if ( in_files.empty() )
-    throw BadOption("Input file name(s) should not be empty");
-
-  for (auto in_file : in_files) {
-    std::ifstream ifile(in_file.c_str());
-    if (ifile.fail())
-      throw BadOption("Cannot open file <" + in_file + ">");
-  }
-} // checkInFiles
-
 void checkOutFile(const Option<std::string> &out_file) {
   if ( out_file.empty() )
     throw BadOption("Output file name should not be empty");
@@ -54,33 +44,28 @@ void checkOutFile(const Option<std::string> &out_file) {
 
 } // checkOutFile
 
-void checkOutDir(const Option<std::string> &out_dir) {
-  auto dir = opendir(out_dir.c_str());
+void checkInDir(const Option<std::string>& dir) {
+  auto stream = opendir(dir.c_str());
 
-  if (dir) {
-    closedir(dir);
-    return;
-  }
+  if (stream == NULL)
+    throw BadOption(std::string("Could not open directory: ") + std::strerror(errno) + ".");
 
-  auto err = errno;
+  closedir(stream);
+} // checkInDir
 
-  switch (err) {
-    case ENOENT:
+void checkOutDir(const Option<std::string> &out_dir) {
+  auto stream = opendir(out_dir.c_str());
+
+  if (stream == NULL) {
+    // Do not consider the missing directory an error.
+    if (errno == ENOENT)
       return;
-    case ENOTDIR:
-      throw BadOption("Output path is not directory");
-    case EACCES:
-      throw BadOption("Has no permission to open output directory");
-    default:
-      throw BadOption("Can not open output directory");
-  }
-} // checkOutDir
 
-void checkDebugFile(const Option<std::string> &in_file) {
-  if (access(in_file.c_str(), W_OK) != 0) {
-    throw BadOption("Has no permission to open debug output file");
+    throw BadOption(std::string("Could not open directory: ") + std::strerror(errno) + ".");
   }
-} // checkDebugFile
+
+  closedir(stream);
+} // checkOutDir
 
 } // namespace cli
 } // namespace ncc