Multi input data (#2959)
authorАндрей Тищенко/AI Tools Lab /SRR/Staff Engineer/삼성전자 <a.tischenko@partner.samsung.com>
Wed, 30 Jan 2019 15:56:51 +0000 (18:56 +0300)
committerРоман Михайлович Русяев/AI Tools Lab /SRR/Staff Engineer/삼성전자 <r.rusyaev@samsung.com>
Wed, 30 Jan 2019 15:56:51 +0000 (18:56 +0300)
Multi-files in command line option --input-model-data.

Some nets require several files as input in execution.

Signed-off-by: Andrew V. Tischenko a.tischenko@partner.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/caffe_frontend/caffe_importer.cpp
contrib/nnc/passes/caffe_frontend/caffe_op_creator.cpp
contrib/nnc/passes/interpreter/Interpreter.cpp
contrib/nnc/passes/interpreter/interpreter_pass.cpp
contrib/nnc/support/CLOptionChecker.cpp
contrib/nnc/utils/input_gen/tensor_gen.cpp

index 1621d74..23805c7 100644 (file)
@@ -162,13 +162,13 @@ Option<std::string> artifactDir(optname("--output-dir, -d"),
 /**
  * Options for *interpreter*
  */
-Option<std::string> interInputData(optname("--input-model-data"),
+Option<std::vector<std::string>> interInputData(optname("--input-model-data"),
                                    overview("interpreter option: specify file with neural network input data."
-                                            "This file contains array of floats in binary form"),
-                                   std::string(),
+                                            "These files contain arrays of floats in binary form"),
+                                   std::vector<std::string>{},
                                    optional(true),
                                    optvalues(""),
-                                   checkInFile);
+                                   checkInFiles);
 
 } // namespace cli
 } // namespace nnc
index 1e25eb2..03f983d 100644 (file)
@@ -57,7 +57,7 @@ extern Option<std::string> artifactName;  // name of artifact
 /**
  * Options for interpreter
  */
-extern Option<std::string> interInputData;  // input data for model
+extern Option<std::vector<std::string>> interInputData;  // input data for model
 
 } // namespace cli
 } // namespace nnc
index 4a56b77..a3987df 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef NNCC_INTERPRETERPASS_H
 #define NNCC_INTERPRETERPASS_H
 
+#include "core/modelIR/operations/InputOp.h"
 #include "core/modelIR/TensorVariant.h"
 #include "core/modelIR/Shape.h"
 
@@ -33,7 +34,8 @@ public:
   PassData run(PassData data) override;
 
 private:
-  nnc::mir::TensorVariant loadInput(const nnc::mir::Shape &);
+  std::unordered_map<std::string, mir::TensorVariant> loadInput(
+                                                       const std::vector<mir::ops::InputOp*>& ops);
   nnc::mir::TensorVariant *_out;
 };
 
index 3c1c5af..5ff43f3 100644 (file)
@@ -557,6 +557,7 @@ 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> &);
index 9f95b13..cb0f4f9 100644 (file)
@@ -149,7 +149,7 @@ void CaffeImporter::createMIRNodesFromLayer(const LayerParameter& layer) {
       assert(false && "All unsupported types should have been found before this pass.");
   }
 
-  assert(layer.top_size() == outputs.size() && "Number of outputs differs.");
+  assert(layer.top_size() == static_cast<int>(outputs.size()) && "Number of outputs differs.");
   for (int i = 0; i < layer.top_size(); ++i)
     _blobNameToIODescriptor[layer.top(i)] = outputs.at(i);
 }
index 93cb2fa..c9bedbd 100644 (file)
@@ -616,7 +616,7 @@ CaffeOpCreator::convertEltwise(const caffe::LayerParameter& layer,
     case EltwiseParameter_EltwiseOp_SUM:
       optype = ops::ElementwiseOp::OpType::add;
       if (opts.coeff().size() > 0) {
-        assert(opts.coeff().size() == inputs.size());
+        assert(opts.coeff().size() == static_cast<int>(inputs.size()));
         for (int i = 0; i < opts.coeff().size(); i++) {
           if (opts.coeff().Get(i) != 1.0f) {
             TensorVariant coeff_tensor(DTYPE::FLOAT32, Shape{1}, &opts.coeff().Get(i));
index 80286d4..16d857a 100644 (file)
@@ -128,7 +128,7 @@ void NNInterpreter::dump(Operation& op, bool all) {
   }
 }
 
-void NNInterpreter::setInput(const std::stringname, const TensorVariant& t) {
+void NNInterpreter::setInput(const std::string &name, const TensorVariant& t) {
   _inputTensors.emplace(name, t);
 }
 
index 12a395d..feefefd 100644 (file)
@@ -95,12 +95,12 @@ PassData InterpreterPass::run(PassData data) {
   NNInterpreter interpreter;
 
   // Check ops
-  const auto& inputs = g->getInputs();
-  assert(inputs.size() == 1 && "Interpreter doesn't support networks with multiple input nodes");
+  auto inputs = g->getInputs();
 
-  auto input_node = inputs[0];
-  auto input_data = loadInput(input_node->getOutputShape(0));
-  interpreter.setInput(input_node->getName(), input_data);
+  auto input_data = loadInput(inputs);
+  for (auto inp: input_data) {
+    interpreter.setInput(inp.first, inp.second);
+  }
   g->accept(&interpreter);
 
   for (auto out_node : g->getOutputs()) {
@@ -118,39 +118,69 @@ PassData InterpreterPass::run(PassData data) {
   return nullptr;
 }
 
-TensorVariant InterpreterPass::loadInput(const Shape& shape) {
-  auto f = fopen(cli::interInputData.c_str(), "rb");
-  assert(f && "Cannot open file");
-
-  int is_error = fseek(f, 0L, SEEK_END);
-  assert(!is_error);
-
-  auto len = ftell(f);
-  assert(len != -1);
-
-  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 << "> = "
-         << len << ". Should be :" << data_size;
+// 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;
+}
 
-    throw PassException(info.str());
+// 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");
+}
 
-  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;
-
-  return TensorVariant(DTYPE::FLOAT32, shape, data.get());
+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() {
index 3e73760..d43c4ee 100644 (file)
  * limitations under the License.
  */
 
-#include "support/CommandLine.h"
 #include "option/Options.h"
+#include "support/CommandLine.h"
 
+#include <dirent.h>
+#include <fstream>
 #include <sys/types.h>
 #include <unistd.h>
-#include <dirent.h>
 
 namespace nnc {
 namespace cli {
@@ -34,6 +35,17 @@ 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");
index c936f9e..0c7a36c 100644 (file)
@@ -50,7 +50,7 @@ public:
   float& at(const vector<int>& coords) {
     int offset = 0;
 
-    for (int i = 0; i < coords.size(); ++i)
+    for (auto i = 0; i < coords.size(); ++i)
       offset += coords[i] * _strides[i];
 
     return _data[offset];
@@ -59,7 +59,7 @@ public:
   Tensor transpose(const vector<hsize_t>& reshape) {
     vector<hsize_t> tr_shape(_shape.size());
 
-    for (int i = 0; i < _shape.size(); ++i)
+    for (auto i = 0; i < _shape.size(); ++i)
       tr_shape[i] = _shape[reshape[i]];
 
     Tensor result(tr_shape);