18#include "caffe/proto/caffe.pb.h"
24#include <google/protobuf/io/zero_copy_stream_impl.h>
25#include <google/protobuf/io/coded_stream.h>
26#include <google/protobuf/text_format.h>
53 std::unique_ptr<mir::Graph> importModel();
55 std::unique_ptr<caffe::NetParameter> _net;
56 std::unique_ptr<CaffeOpCreator> _opCreator;
59 std::map<std::string, mir::Operation::Output *> _blobNameToOpOutput;
61 static const std::map<std::string, CaffeOpType> _operatorTypes;
72 void collectUnsupportedLayers();
77 void createMIRNodesFromLayer(
const caffe::LayerParameter &layer);
85 void collectUnsupportedOp(
const caffe::LayerParameter &layer, std::set<std::string> &problems);
90 std::vector<mir::Operation::Output *> getMIRInputsForLayer(
const caffe::LayerParameter &layer);
92 void processDeprecatedInput();
95void loadModelFromBinaryFile(
const std::string &filename, caffe::NetParameter *net)
97 GOOGLE_PROTOBUF_VERIFY_VERSION;
99 int file_handle = open(filename.c_str(), O_RDONLY);
101 if (file_handle == -1)
102 throw std::runtime_error(
"Couldn't open file \"" + filename +
"\": " + std::strerror(errno) +
105 google::protobuf::io::FileInputStream file_stream(file_handle);
106 file_stream.SetCloseOnDelete(
true);
108 google::protobuf::io::CodedInputStream coded_stream(&file_stream);
109 coded_stream.SetTotalBytesLimit(INT_MAX, INT_MAX);
111 if (!net->ParseFromCodedStream(&coded_stream))
112 throw std::runtime_error(
"Couldn't parse file \"" + filename +
"\".");
115 if (!coded_stream.ConsumedEntireMessage())
116 throw std::runtime_error(
"File \"" + filename +
"\" has not been consumed entirely.");
119void loadModelFromTextFile(
const std::string &filename, caffe::NetParameter *net)
121 GOOGLE_PROTOBUF_VERIFY_VERSION;
123 int file_handle = open(filename.c_str(), O_RDONLY);
125 if (file_handle == -1)
126 throw std::runtime_error(
"Couldn't open file \"" + filename +
"\": " + std::strerror(errno) +
129 google::protobuf::io::FileInputStream file_stream(file_handle);
130 file_stream.SetCloseOnDelete(
true);
132 if (!google::protobuf::TextFormat::Parse(&file_stream, net))
133 throw std::runtime_error(
"Couldn't parse file \"" + filename +
"\".");
136std::unique_ptr<mir::Graph> CaffeImporter::importModel()
138 auto graph = std::make_unique<mir::Graph>();
139 _opCreator = std::make_unique<CaffeOpCreator>(
graph.get());
141 collectUnsupportedLayers();
143 for (
int i = 0; i < _net->layer_size(); ++i)
144 createMIRNodesFromLayer(_net->layer(i));
146 setGraphOutputs(
graph.get());
151std::unique_ptr<mir::Graph> CaffeImporter::importModelFromBinaryFile(
const std::string &filename)
153 _net = std::make_unique<caffe::NetParameter>();
154 loadModelFromBinaryFile(filename, _net.get());
156 return importModel();
159std::unique_ptr<mir::Graph> CaffeImporter::importModelFromTextFile(
const std::string &filename)
161 _net = std::make_unique<caffe::NetParameter>();
162 loadModelFromTextFile(filename, _net.get());
164 return importModel();
167void CaffeImporter::collectUnsupportedLayers()
169 processDeprecatedInput();
171 std::set<std::string> problems;
173 for (
const caffe::LayerParameter &layer : _net->layer())
174 collectUnsupportedOp(layer, problems);
176 if (!problems.empty())
178 std::string msg(
"NNC can't load model. Detected problems:");
179 for (
const auto &problemStr : problems)
180 msg.append(
"\n * " + problemStr);
181 throw std::runtime_error(msg);
185void CaffeImporter::createMIRNodesFromLayer(
const caffe::LayerParameter &layer)
187 std::vector<mir::Operation::Output *>
inputs = getMIRInputsForLayer(layer);
188 std::vector<mir::Operation::Output *> outputs;
190 switch (_operatorTypes.at(layer.type()))
193 outputs = _opCreator->convertInput(layer);
196 outputs = _opCreator->convertConvolution(layer, inputs);
199 outputs = _opCreator->convertInnerProduct(layer, inputs);
202 outputs = _opCreator->convertPooling(layer, inputs);
205 outputs = _opCreator->convertConcat(layer, inputs);
208 outputs = _opCreator->convertReshape(layer, inputs);
211 outputs = _opCreator->convertReLU(layer, inputs);
214 outputs = _opCreator->convertSoftmax(layer, inputs);
217 outputs = _opCreator->convertScale(layer, inputs);
220 outputs = _opCreator->convertBatchNorm(layer, inputs);
223 outputs = _opCreator->convertDropout(layer, inputs);
226 outputs = _opCreator->convertTanH(layer, inputs);
229 outputs = _opCreator->convertELU(layer, inputs);
232 outputs = _opCreator->convertEltwise(layer, inputs);
235 outputs = _opCreator->convertEmbed(layer, inputs);
238 outputs = _opCreator->convertDeconvolution(layer, inputs);
241 outputs = _opCreator->convertSplit(layer, inputs);
244 outputs = _opCreator->convertSigmoid(layer, inputs);
247 outputs = _opCreator->convertLSTM(layer, inputs);
250 assert(
false &&
"All unsupported types should have been found before this pass.");
253 assert(
static_cast<int>(outputs.size()) == layer.top_size() &&
"Number of outputs differs.");
254 for (
int i = 0; i < layer.top_size(); ++i)
255 setOutputForBlob(layer.top(i), outputs[i]);
258void CaffeImporter::collectUnsupportedOp(
const caffe::LayerParameter &layer,
259 std::set<std::string> &problems)
261 auto it = _operatorTypes.find(layer.type());
262 if (it == _operatorTypes.end())
264 problems.insert(layer.type() +
": unknown layer");
289 _opCreator->checkConvolution(layer, problems);
292 _opCreator->checkPooling(layer, problems);
295 _opCreator->checkReshape(layer, problems);
298 _opCreator->checkBatchNorm(layer, problems);
301 _opCreator->checkLSTM(layer, problems);
304 problems.insert(layer.type() +
": unsupported layer");
309void CaffeImporter::processDeprecatedInput()
311 if (_net->input_dim_size() != 0 || _net->input_shape_size() != 0)
312 throw std::runtime_error(
"Deprecated Caffe input types are not supported");
315std::vector<mir::Operation::Output *>
316CaffeImporter::getMIRInputsForLayer(
const caffe::LayerParameter &layer)
318 std::vector<mir::Operation::Output *>
inputs;
320 for (
const auto &input_name : layer.bottom())
321 inputs.push_back(getOutputForBlob(input_name));
328 return _blobNameToOpOutput.at(blob_name);
333 const auto it = _blobNameToOpOutput.find(blob_name);
334 if (it != _blobNameToOpOutput.cend())
338 it->second->setName(
"");
343 if (
output->getName().empty())
344 output->setName(blob_name);
346 _blobNameToOpOutput[blob_name] =
output;
349void CaffeImporter::setGraphOutputs(
mir::Graph *graph)
354 const auto &last_layer = *_net->layer().rbegin();
355 auto output = getOutputForBlob(last_layer.top(0));
359const std::map<std::string, CaffeOpType> CaffeImporter::_operatorTypes = {
424 CaffeImporter importer;
425 return importer.importModelFromBinaryFile(filename);
430 CaffeImporter importer;
431 return importer.importModelFromTextFile(filename);
434std::unique_ptr<mir::Graph>
loadModel(
const std::string &filename)
Represents an output of a node.
std::unique_ptr< mir::Graph > importModelFromTextFile(const std::string &filename)
std::unique_ptr< mir::Graph > loadModel(const std::string &filename)
@ sigmoidCrossEntropyLoss
@ multinomialLogisticLoss
std::unique_ptr< mir::Graph > importModelFromBinaryFile(const std::string &filename)