void Caffe2Importer::collectUnsupportedOps()
{
+ std::set<std::string> unsupportedOps;
for (auto &op : _net->op())
- collectUnsupportedOp(op);
-
- if (!_problemsOpSet.empty())
{
- std::string msg("NNC can't load model. Detected problems:");
- for (const auto &problemStr : _problemsOpSet)
- msg.append("\n * " + problemStr);
- throw std::runtime_error(msg);
+ if (_operatorTypes.find(op.type()) == _operatorTypes.end())
+ unsupportedOps.insert(op.type());
}
-}
-void Caffe2Importer::collectUnsupportedOp(const OperatorDef &op)
-{
- if (_operatorTypes.find(op.type()) == _operatorTypes.end())
+ if (!unsupportedOps.empty())
{
- _problemsOpSet.insert(op.type() + ": unknown layer");
- return;
- }
-
- SupportedCaffe2OpType opType = _operatorTypes.at(op.type());
- switch (opType)
- {
- case SupportedCaffe2OpType::FC:
- _opCreator->checkFC(op, _problemsOpSet);
- break;
- case SupportedCaffe2OpType::spatialBN:
- _opCreator->checkSpatialBN(op, _problemsOpSet);
- break;
- case SupportedCaffe2OpType::averagePool:
- case SupportedCaffe2OpType::conv:
- case SupportedCaffe2OpType::maxPool:
- _opCreator->checkConvLikeOp(op, _problemsOpSet);
- break;
- case SupportedCaffe2OpType::add:
- case SupportedCaffe2OpType::concat:
- case SupportedCaffe2OpType::constantFill:
- case SupportedCaffe2OpType::dropout:
- case SupportedCaffe2OpType::givenTensorFill:
- case SupportedCaffe2OpType::givenTensorInt64Fill:
- case SupportedCaffe2OpType::mul:
- case SupportedCaffe2OpType::relu:
- case SupportedCaffe2OpType::resizeNearest:
- case SupportedCaffe2OpType::sigmoid:
- case SupportedCaffe2OpType::softmax:
- case SupportedCaffe2OpType::sum:
- case SupportedCaffe2OpType::clip:
- case SupportedCaffe2OpType::reshape:
- _opCreator->commonCheck(op, _problemsOpSet);
- break;
- default:
- _problemsOpSet.insert(op.type() + ": unsupported layer");
- break;
+ std::string exceptionMsg("Can't load model, unsupported operators:");
+ for (const auto &op : unsupportedOps)
+ exceptionMsg.append("\n * " + op);
+ throw std::runtime_error(exceptionMsg);
}
}
// Check functions
//
-void Caffe2OpCreator::checkConvLikeOp(const ::caffe2::OperatorDef &op,
- std::set<std::string> &problems_ops_set)
+static void checkLayout(const OperatorDef &op)
{
- commonCheck(op, problems_ops_set);
+ if (getSingleArgument(op, "order", "NCHW") != "NCHW")
+ throw std::runtime_error(op.type() + ": only 'NCHW' axis order is supported");
+}
+
+static void checkConvLikeOp(const ::caffe2::OperatorDef &op)
+{
+ checkLayout(op);
// Padding
bool has_custom_pad = hasArgument(op.arg(), "pad_l") || hasArgument(op.arg(), "pad_r") ||
hasArgument(op.arg(), "pad_t") || hasArgument(op.arg(), "pad_b");
if (has_custom_pad && hasArgument(op.arg(), "pad"))
- problems_ops_set.insert("Custom pad can't be combined with overall pad");
+ throw std::runtime_error("Custom pad can't be combined with overall pad");
if (has_custom_pad &&
!(hasArgument(op.arg(), "pad_l") && hasArgument(op.arg(), "pad_r") &&
hasArgument(op.arg(), "pad_t") && hasArgument(op.arg(), "pad_b")))
- problems_ops_set.insert("If one custom pad specified - all custom pads must be specified");
+ throw std::runtime_error("If one custom pad specified - all custom pads must be specified");
// Kernel size
bool has_custom_kernel_size =
hasArgument(op.arg(), "kernel_h") || hasArgument(op.arg(), "kernel_w");
if (has_custom_kernel_size && hasArgument(op.arg(), "kernel"))
- problems_ops_set.insert("Custom kernel size can't be combined with overall kernel size");
+ throw std::runtime_error("Custom kernel size can't be combined with overall kernel size");
if (has_custom_kernel_size &&
!(hasArgument(op.arg(), "kernel_h") && hasArgument(op.arg(), "kernel_w")))
- problems_ops_set.insert(
+ throw std::runtime_error(
"If one custom kernel size specified - all custom kernel sizes must be specified");
}
-void Caffe2OpCreator::checkFC(const ::caffe2::OperatorDef &op,
- std::set<std::string> &problems_ops_set)
-{
- commonCheck(op, problems_ops_set);
- for (auto &s : {"axis", "axis_w", "float16_compute"})
- if (hasArgument(op.arg(), s))
- problems_ops_set.insert(std::string("FC: only default '") + s + "' value is supported");
-}
-
-void Caffe2OpCreator::checkSpatialBN(const ::caffe2::OperatorDef &op,
- std::set<std::string> &problems_ops_set)
-{
- commonCheck(op, problems_ops_set);
- if (op.input_size() != 5)
- problems_ops_set.insert(
- "SpatialBN must have exactly 5 inputs ('sums' and 'sumsq' are not supported yet)");
-
- if (getSingleArgument(op, "is_test", 1) != 1)
- problems_ops_set.insert(std::string("SpatialBN: only test mode supported"));
-}
-
-void Caffe2OpCreator::commonCheck(const ::caffe2::OperatorDef &op,
- std::set<std::string> &problems_ops_set)
-{
- if (getSingleArgument(op, "order", "NCHW") != "NCHW")
- problems_ops_set.insert("Only 'NCHW' axis order is supported");
-}
-
//
// Convert functions
//
Caffe2OpCreator::convertAdd(const std::vector<mir::Operation::Output *> &inputs,
const ::caffe2::OperatorDef &op, const MIRTensors &mir_tensors)
{
+ checkLayout(op);
std::vector<mir::Operation::Output *> add_input;
add_input.reserve(inputs.size() + 1);
Caffe2OpCreator::convertAveragePool(const std::vector<mir::Operation::Output *> &inputs,
const OperatorDef &op)
{
+ checkConvLikeOp(op);
+
Shape window_shape = getWindowShape(op, inputs);
Shape strides(getStrides(op));
Caffe2OpCreator::convertConv(const std::vector<mir::Operation::Output *> &inputs,
const ::caffe2::OperatorDef &op, const MIRTensors &mir_tensors)
{
+ checkConvLikeOp(op);
+
// dilation order: h w (not used)
Shape stride_shape(getStrides(op));
Caffe2OpCreator::convertConcat(const std::vector<mir::Operation::Output *> &inputs,
const ::caffe2::OperatorDef &op)
{
+ checkLayout(op);
+
int axis = getSingleArgument(op, "axis", 1);
auto result = createOp<ops::ConcatOp>("Concat", inputs, axis);
return {result->getOutput(0)};
const ::caffe2::OperatorDef &op,
const MIRTensors &mir_tensors)
{
+ for (auto &s : {"axis", "axis_w", "float16_compute"})
+ if (hasArgument(op.arg(), s))
+ throw std::runtime_error(std::string("FC: only default '") + s + "' value is supported");
+
auto weights_tensor = transposeTensor<1, 0>(mir_tensors.at(op.input(1)));
const auto &input_shape = inputs[0]->getShape();
Caffe2OpCreator::convertMaxPool(const std::vector<mir::Operation::Output *> &inputs,
const OperatorDef &op)
{
+ checkConvLikeOp(op);
+
Shape window_shape = getWindowShape(op, inputs);
Shape strides(getStrides(op));
Caffe2OpCreator::convertMul(const std::vector<mir::Operation::Output *> &inputs,
const ::caffe2::OperatorDef &op, const MIRTensors &mir_tensors)
{
+ checkLayout(op);
std::vector<mir::Operation::Output *> input_descriptors;
input_descriptors.reserve(inputs.size() + 1);
Caffe2OpCreator::convertSpatialBN(const std::vector<mir::Operation::Output *> &inputs,
const ::caffe2::OperatorDef &op, const MIRTensors &mir_tensors)
{
+ checkLayout(op);
+
+ // Sanity checks
+ if (op.input_size() != 5)
+ throw std::runtime_error(
+ "SpatialBN must have exactly 5 inputs ('sums' and 'sumsq' are not supported yet)");
+ if (getSingleArgument(op, "is_test", 1) != 1)
+ throw std::runtime_error("SpatialBN: only test mode supported");
+
// overall_res = (X - mean) / sqrt(var + epsilon) * scale + bias
const auto &scale_tensor = mir_tensors.at(op.input(1));