void testInPlaceActivation(LayerParams& lp) { EXPECT_FALSE(lp.name.empty()); LayerParams pool; pool.set("pool", "ave"); pool.set("kernel_w", 2); pool.set("kernel_h", 2); pool.set("stride_w", 2); pool.set("stride_h", 2); pool.type = "Pooling"; Net net; int poolId = net.addLayer(pool.name, pool.type, pool); net.connect(0, 0, poolId, 0); net.addLayerToPrev(lp.name, lp.type, lp); Mat input({1, kNumChannels, 10, 10}, CV_32F); randu(input, -1.0f, 1.0f); net.setInput(input); Mat outputDefault = net.forward(lp.name).clone(); net.setInput(input); net.setPreferableBackend(DNN_BACKEND_HALIDE); Mat outputHalide = net.forward(lp.name).clone(); normAssert(outputDefault, outputHalide); }
TEST_P(Concat, Accuracy) { Vec3i inSize = get<0>(GetParam()); Vec3i numChannels = get<1>(GetParam()); Net net; std::vector<int> convLayerIds; convLayerIds.reserve(numChannels.channels); for (int i = 0, n = numChannels.channels; i < n; ++i) { if (!numChannels[i]) break; Mat weights({numChannels[i], inSize[0], 1, 1}, CV_32F); randu(weights, -1.0f, 1.0f); LayerParams convParam; convParam.set("kernel_w", 1); convParam.set("kernel_h", 1); convParam.set("num_output", numChannels[i]); convParam.set("bias_term", false); convParam.type = "Convolution"; std::ostringstream ss; ss << "convLayer" << i; convParam.name = ss.str(); convParam.blobs.push_back(weights); int layerId = net.addLayer(convParam.name, convParam.type, convParam); convLayerIds.push_back(layerId); net.connect(0, 0, layerId, 0); } LayerParams concatParam; concatParam.type = "Concat"; concatParam.name = "testLayer"; int concatId = net.addLayer(concatParam.name, concatParam.type, concatParam); net.connect(0, 0, concatId, 0); for (int i = 0; i < convLayerIds.size(); ++i) { net.connect(convLayerIds[i], 0, concatId, i + 1); } Mat input({1, inSize[0], inSize[1], inSize[2]}, CV_32F); randu(input, -1.0f, 1.0f); net.setInput(input); Mat outputDefault = net.forward(concatParam.name).clone(); net.setPreferableBackend(DNN_BACKEND_HALIDE); Mat outputHalide = net.forward(concatParam.name).clone(); normAssert(outputDefault, outputHalide); }
TEST_P(Power, Accuracy) { float power = get<0>(GetParam())[0]; float scale = get<0>(GetParam())[1]; float shift = get<0>(GetParam())[2]; LayerParams lp; lp.set("power", power); lp.set("scale", scale); lp.set("shift", shift); lp.type = "Power"; lp.name = "testLayer"; testInPlaceActivation(lp); }
TEST_P(ReLU, Accuracy) { float negativeSlope = get<0>(GetParam()); LayerParams lp; lp.set("negative_slope", negativeSlope); lp.type = "ReLU"; lp.name = "testLayer"; testInPlaceActivation(lp); }
TEST_P(AvePooling, Accuracy) { int inChannels = get<0>(GetParam()); Size outSize = get<1>(GetParam());; // Input size will be computed from parameters. Size kernel = get<2>(GetParam()); Size stride = get<3>(GetParam()); const int inWidth = (outSize.width - 1) * stride.width + kernel.width; const int inHeight = (outSize.height - 1) * stride.height + kernel.height; LayerParams lp; lp.set("pool", "ave"); lp.set("kernel_w", kernel.width); lp.set("kernel_h", kernel.height); lp.set("stride_w", stride.width); lp.set("stride_h", stride.height); lp.type = "Pooling"; lp.name = "testLayer"; Mat input({1, inChannels, inHeight, inWidth}, CV_32F); test(lp, input); }
TEST_P(FullyConnected, Accuracy) { int inChannels = get<0>(GetParam()); Size inSize = get<1>(GetParam()); int outChannels = get<2>(GetParam()); bool hasBias = get<3>(GetParam()); Mat weights(outChannels, inChannels * inSize.height * inSize.width, CV_32F); randu(weights, -1.0f, 1.0f); Mat bias(1, outChannels, CV_32F); randu(bias, -1.0f, 1.0f); LayerParams lp; lp.set("num_output", outChannels); lp.set("bias_term", hasBias); lp.blobs.push_back(weights); lp.blobs.push_back(bias); lp.type = "InnerProduct"; lp.name = "testLayer"; Mat input({1, inChannels, inSize.height, inSize.width}, CV_32F); test(lp, input); }
TEST_P(BatchNorm, Accuracy) { bool hasWeights = get<0>(GetParam()); bool hasBias = get<1>(GetParam()); float epsilon = get<2>(GetParam()); LayerParams lp; lp.set("has_weight", hasWeights); lp.set("has_bias", hasBias); lp.set("eps", epsilon); lp.type = "BatchNorm"; lp.name = "testLayer"; lp.blobs.reserve(4); for (int i = 0; i < 3; ++i) lp.blobs.push_back(Mat({kNumChannels}, CV_32F)); if (hasBias || hasWeights) lp.blobs.push_back(Mat({kNumChannels}, CV_32F)); for (Mat& m : lp.blobs) randu(m, 0.0f, 1.0f); testInPlaceActivation(lp); }
TEST_P(LRN, Accuracy) { int inChannels = get<0>(GetParam())[0]; Size inSize = Size(get<0>(GetParam())[1], get<0>(GetParam())[2]); int localSize = get<1>(GetParam()); float alpha = get<2>(GetParam())[0]; float beta = get<2>(GetParam())[1]; float bias = get<2>(GetParam())[2]; bool normBySize = get<3>(GetParam()); std::string nrmType = get<4>(GetParam()); LayerParams lp; lp.set("norm_region", nrmType); lp.set("local_size", localSize); lp.set("alpha", alpha); lp.set("beta", beta); lp.set("bias", bias); lp.set("norm_by_size", normBySize); lp.type = "LRN"; lp.name = "testLayer"; Mat input({1, inChannels, inSize.height, inSize.width}, CV_32F); test(lp, input); }
TEST_P(Scale, Accuracy) { bool hasBias = get<0>(GetParam()); LayerParams lp; lp.set("bias_term", hasBias); lp.type = "Scale"; lp.name = "testLayer"; lp.blobs.push_back(Mat({kNumChannels}, CV_32F)); randu(lp.blobs[0], -1.0f, 1.0f); if (hasBias) { lp.blobs.push_back(Mat({kNumChannels}, CV_32F)); randu(lp.blobs[1], -1.0f, 1.0f); } testInPlaceActivation(lp); }
//////////////////////////////////////////////////////////////////////////////// // Padding //////////////////////////////////////////////////////////////////////////////// TEST(Padding_Halide, Accuracy) { static const int kNumRuns = 10; std::vector<int> paddings(8); for (int t = 0; t < kNumRuns; ++t) { for (int i = 0; i < paddings.size(); ++i) paddings[i] = rand() % 5; LayerParams lp; lp.set("paddings", DictValue::arrayInt<int*>(&paddings[0], paddings.size())); lp.type = "Padding"; lp.name = "testLayer"; Mat input({1 + rand() % 10, 1 + rand() % 10, 1 + rand() % 10, 1 + rand() % 10}, CV_32F); test(lp, input); } }
////////////////////////////////////////////////////////////////////////////// // Max pooling - unpooling ////////////////////////////////////////////////////////////////////////////// TEST(MaxPoolUnpool_Halide, Accuracy) { LayerParams pool; pool.set("pool", "max"); pool.set("kernel_w", 2); pool.set("kernel_h", 2); pool.set("stride_w", 2); pool.set("stride_h", 2); pool.set("pad_w", 0); pool.set("pad_h", 0); pool.type = "Pooling"; pool.name = "testPool"; LayerParams unpool; unpool.set("pool_k_w", 2); unpool.set("pool_k_h", 2); unpool.set("pool_stride_w", 2); unpool.set("pool_stride_h", 2); unpool.set("pool_pad_w", 0); unpool.set("pool_pad_h", 0); unpool.type = "MaxUnpool"; unpool.name = "testUnpool"; Net net; int poolId = net.addLayer(pool.name, pool.type, pool); net.connect(0, 0, poolId, 0); int unpoolId = net.addLayer(unpool.name, unpool.type, unpool); net.connect(poolId, 0, unpoolId, 0); net.connect(poolId, 1, unpoolId, 1); Mat input({1, 1, 4, 4}, CV_32F); randu(input, -1.0f, 1.0f); net.setInput(input); Mat outputDefault = net.forward("testUnpool").clone(); net.setPreferableBackend(DNN_BACKEND_HALIDE); net.setInput(input); Mat outputHalide = net.forward("testUnpool").clone(); normAssert(outputDefault, outputHalide); }
TEST_P(MaxPooling, Accuracy) { int inChannels = get<0>(GetParam()); Size inSize = get<1>(GetParam()); Size kernel = get<2>(GetParam()); Size stride = get<3>(GetParam()); Size pad = get<4>(GetParam()); LayerParams lp; lp.set("pool", "max"); lp.set("kernel_w", kernel.width); lp.set("kernel_h", kernel.height); lp.set("stride_w", stride.width); lp.set("stride_h", stride.height); lp.set("pad_w", pad.width); lp.set("pad_h", pad.height); lp.type = "Pooling"; lp.name = "testLayer"; Mat input({1, inChannels, inSize.height, inSize.width}, CV_32F); test(lp, input); }
void populateNet(Net dstNet) { CV_TRACE_FUNCTION(); int layersSize = net.layer_size(); layerCounter.clear(); addedBlobs.clear(); addedBlobs.reserve(layersSize + 1); //setup input layer names std::vector<String> netInputs(net.input_size()); { for (int inNum = 0; inNum < net.input_size(); inNum++) { addedBlobs.push_back(BlobNote(net.input(inNum), 0, inNum)); netInputs[inNum] = net.input(inNum); } } for (int li = 0; li < layersSize; li++) { const caffe::LayerParameter &layer = net.layer(li); String name = layer.name(); String type = layer.type(); LayerParams layerParams; extractLayerParams(layer, layerParams); extractBinaryLayerParams(layer, layerParams); int repetitions = layerCounter[name]++; if (repetitions) name += String("_") + toString(repetitions); if (type == "Input") { for (int outNum = 0; outNum < layer.top_size(); outNum++) { addOutput(layer, 0, outNum); addedBlobs.back().outNum = netInputs.size(); netInputs.push_back(addedBlobs.back().name); } continue; } else if (type == "BatchNorm") { if (!layerParams.get<bool>("use_global_stats", true)) { CV_Assert_N(layer.bottom_size() == 1, layer.top_size() == 1); LayerParams mvnParams; mvnParams.set("eps", layerParams.get<float>("eps", 1e-5)); std::string mvnName = name + "/mvn"; int repetitions = layerCounter[mvnName]++; if (repetitions) mvnName += String("_") + toString(repetitions); int mvnId = dstNet.addLayer(mvnName, "MVN", mvnParams); addInput(layer.bottom(0), mvnId, 0, dstNet); addOutput(layer, mvnId, 0); net.mutable_layer(li)->set_bottom(0, layer.top(0)); layerParams.blobs[0].setTo(0); // mean layerParams.blobs[1].setTo(1); // std } } else if ("ConvolutionDepthwise" == type) { type = "Convolution"; } int id = dstNet.addLayer(name, type, layerParams); for (int inNum = 0; inNum < layer.bottom_size(); inNum++) addInput(layer.bottom(inNum), id, inNum, dstNet); for (int outNum = 0; outNum < layer.top_size(); outNum++) addOutput(layer, id, outNum); } dstNet.setInputsNames(netInputs); addedBlobs.clear(); }
void ONNXImporter::populateNet(Net dstNet) { CV_Assert(model_proto.has_graph()); opencv_onnx::GraphProto graph_proto = model_proto.graph(); std::map<std::string, Mat> constBlobs = getGraphTensors(graph_proto); // List of internal blobs shapes. std::map<std::string, MatShape> outShapes; // Add all the inputs shapes. It includes as constant blobs as network's inputs shapes. for (int i = 0; i < graph_proto.input_size(); ++i) { opencv_onnx::ValueInfoProto valueInfoProto = graph_proto.input(i); CV_Assert(valueInfoProto.has_type()); opencv_onnx::TypeProto typeProto = valueInfoProto.type(); CV_Assert(typeProto.has_tensor_type()); opencv_onnx::TypeProto::Tensor tensor = typeProto.tensor_type(); CV_Assert(tensor.has_shape()); opencv_onnx::TensorShapeProto tensorShape = tensor.shape(); MatShape inpShape(tensorShape.dim_size()); for (int j = 0; j < inpShape.size(); ++j) { inpShape[j] = tensorShape.dim(j).dim_value(); } outShapes[valueInfoProto.name()] = inpShape; } std::string framework_name; if (model_proto.has_producer_name()) { framework_name = model_proto.producer_name(); } // create map with network inputs (without const blobs) std::map<std::string, LayerInfo> layer_id; std::map<std::string, LayerInfo>::iterator layerId; std::map<std::string, MatShape>::iterator shapeIt; // fill map: push layer name, layer id and output id std::vector<String> netInputs; for (int j = 0; j < graph_proto.input_size(); j++) { const std::string& name = graph_proto.input(j).name(); if (constBlobs.find(name) == constBlobs.end()) { netInputs.push_back(name); layer_id.insert(std::make_pair(name, LayerInfo(0, netInputs.size() - 1))); } } dstNet.setInputsNames(netInputs); int layersSize = graph_proto.node_size(); LayerParams layerParams; opencv_onnx::NodeProto node_proto; for(int li = 0; li < layersSize; li++) { node_proto = graph_proto.node(li); layerParams = getLayerParams(node_proto); CV_Assert(node_proto.output_size() >= 1); layerParams.name = node_proto.output(0); std::string layer_type = node_proto.op_type(); layerParams.type = layer_type; if (layer_type == "MaxPool") { layerParams.type = "Pooling"; layerParams.set("pool", "MAX"); layerParams.set("ceil_mode", isCeilMode(layerParams)); } else if (layer_type == "AveragePool") { layerParams.type = "Pooling"; layerParams.set("pool", "AVE"); layerParams.set("ceil_mode", isCeilMode(layerParams)); layerParams.set("ave_pool_padded_area", framework_name == "pytorch"); } else if (layer_type == "GlobalAveragePool") { layerParams.type = "Pooling"; layerParams.set("pool", "AVE"); layerParams.set("global_pooling", true); } else if (layer_type == "Add" || layer_type == "Sum") { if (layer_id.find(node_proto.input(1)) == layer_id.end()) { Mat blob = getBlob(node_proto, constBlobs, 1); blob = blob.reshape(1, 1); if (blob.total() == 1) { layerParams.type = "Power"; layerParams.set("shift", blob.at<float>(0)); } else { layerParams.type = "Scale"; layerParams.set("bias_term", true); layerParams.blobs.push_back(blob); } } else { layerParams.type = "Eltwise"; } } else if (layer_type == "Sub") { Mat blob = getBlob(node_proto, constBlobs, 1); if (blob.total() == 1) { layerParams.type = "Power"; layerParams.set("shift", -blob.at<float>(0)); } else { layerParams.type = "Scale"; layerParams.set("has_bias", true); layerParams.blobs.push_back(-1.0f * blob.reshape(1, 1)); } } else if (layer_type == "Div") { Mat blob = getBlob(node_proto, constBlobs, 1); CV_Assert_N(blob.type() == CV_32F, blob.total()); if (blob.total() == 1) { layerParams.set("scale", 1.0f / blob.at<float>(0)); layerParams.type = "Power"; } else { layerParams.type = "Scale"; divide(1.0, blob, blob); layerParams.blobs.push_back(blob); layerParams.set("bias_term", false); } } else if (layer_type == "Constant") { CV_Assert(node_proto.input_size() == 0); CV_Assert(layerParams.blobs.size() == 1); constBlobs.insert(std::make_pair(layerParams.name, layerParams.blobs[0])); continue; } else if (layer_type == "ImageScaler") { const float scale = layerParams.has("scale") ? layerParams.get<float>("scale") : 1.0f; layerParams.erase("scale"); if (layerParams.has("bias")) { layerParams.type = "Scale"; layerParams.blobs.push_back( Mat(Size(1, layerParams.get("bias").size()), CV_32FC1, scale)); layerParams.set("bias_term", true); Mat bias(1, layerParams.get("bias").size(), CV_32FC1); for (int j = 0; j < bias.total(); j++) { bias.at<float>(0, j) = layerParams.get("bias").getRealValue(j); } layerParams.blobs.push_back(bias); layerParams.erase("bias"); } else { layerParams.set("scale", scale); layerParams.type = "Power"; } } else if (layer_type == "LeakyRelu") { layerParams.type = "ReLU"; replaceLayerParam(layerParams, "alpha", "negative_slope"); } else if (layer_type == "LRN") { replaceLayerParam(layerParams, "size", "local_size"); } else if (layer_type == "BatchNormalization") { if (node_proto.input_size() != 5) CV_Error(Error::StsNotImplemented, "Expected input, scale, bias, mean and var"); layerParams.type = "BatchNorm"; replaceLayerParam(layerParams, "epsilon", "eps"); replaceLayerParam(layerParams, "spatial", "use_global_stats"); Mat meanData = getBlob(node_proto, constBlobs, 3); Mat stdData = getBlob(node_proto, constBlobs, 4); layerParams.blobs.push_back(meanData); layerParams.blobs.push_back(stdData); if (!node_proto.input(1).empty()) { layerParams.set("has_weight", true); layerParams.blobs.push_back(getBlob(node_proto, constBlobs, 1)); // weightData } else { layerParams.set("has_weight", false); } if (!node_proto.input(2).empty()) { layerParams.set("has_bias", true); layerParams.blobs.push_back(getBlob(node_proto, constBlobs, 2)); // biasData } else { layerParams.set("has_bias", false); } } else if (layer_type == "Gemm") { CV_Assert(node_proto.input_size() >= 2); layerParams.type = "InnerProduct"; Mat weights = getBlob(node_proto, constBlobs, 1); int ind_num_out = 0; if (layerParams.has("transB") && !layerParams.get<int>("transB")) { transpose(weights, weights); ind_num_out = 1; } layerParams.blobs.push_back(weights); if (node_proto.input_size() == 3) { Mat bias = getBlob(node_proto, constBlobs, 2); layerParams.blobs.push_back(bias); } layerParams.set("num_output", layerParams.blobs[0].size[ind_num_out]); layerParams.set("bias_term", node_proto.input_size() == 3); } else if (layer_type == "MatMul") { CV_Assert(node_proto.input_size() == 2); layerParams.type = "InnerProduct"; Mat blob = getBlob(node_proto, constBlobs, 1); layerParams.blobs.push_back(blob.t()); layerParams.set("bias_term", false); layerParams.set("num_output", layerParams.blobs[0].size[0]); } else if (layer_type == "Mul") { CV_Assert(node_proto.input_size() == 2); if (layer_id.find(node_proto.input(1)) == layer_id.end()) { Mat blob = getBlob(node_proto, constBlobs, 1); blob = blob.reshape(1, 1); if (blob.total() == 1) { layerParams.set("scale", blob.at<float>(0)); layerParams.type = "Power"; } else { layerParams.blobs.push_back(blob); layerParams.type = "Scale"; } } else { layerParams.type = "Eltwise"; layerParams.set("operation", "prod"); } } else if (layer_type == "Conv") { CV_Assert(node_proto.input_size() >= 2); layerParams.type = "Convolution"; for (int j = 1; j < node_proto.input_size(); j++) { layerParams.blobs.push_back(getBlob(node_proto, constBlobs, j)); } layerParams.set("num_output", layerParams.blobs[0].size[0]); layerParams.set("bias_term", node_proto.input_size() == 3); } else if (layer_type == "ConvTranspose") { CV_Assert(node_proto.input_size() >= 2); layerParams.type = "Deconvolution"; for (int j = 1; j < node_proto.input_size(); j++) { layerParams.blobs.push_back(getBlob(node_proto, constBlobs, j)); } layerParams.set("num_output", layerParams.blobs[0].size[1]); layerParams.set("bias_term", node_proto.input_size() == 3); } else if (layer_type == "Transpose") { layerParams.type = "Permute"; replaceLayerParam(layerParams, "perm", "order"); } else if (layer_type == "Unsqueeze") { CV_Assert(node_proto.input_size() == 1); Mat input = getBlob(node_proto, constBlobs, 0); DictValue axes = layerParams.get("axes"); std::vector<int> dims; for (int j = 0; j < input.dims; j++) { dims.push_back(input.size[j]); } CV_Assert(axes.getIntValue(axes.size()-1) <= dims.size()); for (int j = 0; j < axes.size(); j++) { dims.insert(dims.begin() + axes.getIntValue(j), 1); } Mat out = input.reshape(0, dims); constBlobs.insert(std::make_pair(layerParams.name, out)); continue; } else if (layer_type == "Reshape") { CV_Assert(node_proto.input_size() == 2 || layerParams.has("shape")); if (node_proto.input_size() == 2) { Mat blob = getBlob(node_proto, constBlobs, 1); CV_Assert(blob.type() == CV_32SC1); if (layer_id.find(node_proto.input(0)) == layer_id.end()) { Mat input = getBlob(node_proto, constBlobs, 0); Mat out = input.reshape(0, static_cast<std::vector<int> >(blob)); constBlobs.insert(std::make_pair(layerParams.name, out)); continue; } layerParams.set("dim", DictValue::arrayInt<int*>( blob.ptr<int>(), blob.total() )); } else { DictValue shape = layerParams.get("shape"); std::vector<int> dim; for (int j = 0; j < shape.size(); j++) { dim.push_back(shape.getIntValue(j)); } if (layer_id.find(node_proto.input(0)) == layer_id.end()) { Mat input = getBlob(node_proto, constBlobs, 0); Mat out = input.reshape(0, dim); constBlobs.insert(std::make_pair(layerParams.name, out)); continue; } replaceLayerParam(layerParams, "shape", "dim"); } } else if (layer_type == "Pad") { layerParams.type = "Padding"; } else if (layer_type == "Shape") { CV_Assert(node_proto.input_size() == 1); shapeIt = outShapes.find(node_proto.input(0)); CV_Assert(shapeIt != outShapes.end()); MatShape inpShape = shapeIt->second; Mat shapeMat(inpShape.size(), 1, CV_32S); for (int j = 0; j < inpShape.size(); ++j) shapeMat.at<int>(j) = inpShape[j]; shapeMat.dims = 1; constBlobs.insert(std::make_pair(layerParams.name, shapeMat)); continue; } else if (layer_type == "Gather") { CV_Assert(node_proto.input_size() == 2); CV_Assert(layerParams.has("axis")); Mat input = getBlob(node_proto, constBlobs, 0); Mat indexMat = getBlob(node_proto, constBlobs, 1); CV_Assert_N(indexMat.type() == CV_32S, indexMat.total() == 1); int index = indexMat.at<int>(0); int axis = layerParams.get<int>("axis"); std::vector<cv::Range> ranges(input.dims, Range::all()); ranges[axis] = Range(index, index + 1); Mat out = input(ranges); constBlobs.insert(std::make_pair(layerParams.name, out)); continue; } else if (layer_type == "Concat") { bool hasVariableInps = false; for (int i = 0; i < node_proto.input_size(); ++i) { if (layer_id.find(node_proto.input(i)) != layer_id.end()) { hasVariableInps = true; break; } } if (!hasVariableInps) { std::vector<Mat> inputs(node_proto.input_size()), concatenated; for (size_t i = 0; i < inputs.size(); ++i) { inputs[i] = getBlob(node_proto, constBlobs, i); } Ptr<Layer> concat = ConcatLayer::create(layerParams); runLayer(concat, inputs, concatenated); CV_Assert(concatenated.size() == 1); constBlobs.insert(std::make_pair(layerParams.name, concatenated[0])); continue; } } else { for (int j = 0; j < node_proto.input_size(); j++) { if (layer_id.find(node_proto.input(j)) == layer_id.end()) layerParams.blobs.push_back(getBlob(node_proto, constBlobs, j)); } } int id = dstNet.addLayer(layerParams.name, layerParams.type, layerParams); layer_id.insert(std::make_pair(layerParams.name, LayerInfo(id, 0))); std::vector<MatShape> layerInpShapes, layerOutShapes, layerInternalShapes; for (int j = 0; j < node_proto.input_size(); j++) { layerId = layer_id.find(node_proto.input(j)); if (layerId != layer_id.end()) { dstNet.connect(layerId->second.layerId, layerId->second.outputId, id, j); // Collect input shapes. shapeIt = outShapes.find(node_proto.input(j)); CV_Assert(shapeIt != outShapes.end()); layerInpShapes.push_back(shapeIt->second); } } // Compute shape of output blob for this layer. Ptr<Layer> layer = dstNet.getLayer(id); layer->getMemoryShapes(layerInpShapes, 0, layerOutShapes, layerInternalShapes); CV_Assert(!layerOutShapes.empty()); outShapes[layerParams.name] = layerOutShapes[0]; } }
LayerParams ONNXImporter::getLayerParams(const opencv_onnx::NodeProto& node_proto) { LayerParams lp; for(int i = 0; i < node_proto.attribute_size(); i++) { opencv_onnx::AttributeProto attribute_proto = node_proto.attribute(i); std::string attribute_name = attribute_proto.name(); if(attribute_name == "kernel_shape") { CV_Assert(attribute_proto.ints_size() == 2); lp.set("kernel_h", saturate_cast<int32_t>(attribute_proto.ints(0))); lp.set("kernel_w", saturate_cast<int32_t>(attribute_proto.ints(1))); } else if(attribute_name == "strides") { CV_Assert(attribute_proto.ints_size() == 2); lp.set("stride_h", saturate_cast<int32_t>(attribute_proto.ints(0))); lp.set("stride_w", saturate_cast<int32_t>(attribute_proto.ints(1))); } else if(attribute_name == "pads") { if (node_proto.op_type() == "Pad") { // Padding layer. // Paddings are in order begin0, begin1, .. beginN, end0, end1, ..., endN. // We need to shuffle it to begin0, end0, begin1, end1, ... CV_Assert(attribute_proto.ints_size() % 2 == 0); const int dims = attribute_proto.ints_size() / 2; std::vector<int32_t> paddings; paddings.reserve(attribute_proto.ints_size()); for (int i = 0; i < dims; ++i) { paddings.push_back(attribute_proto.ints(i)); paddings.push_back(attribute_proto.ints(dims + i)); } lp.set("paddings", DictValue::arrayInt(&paddings[0], paddings.size())); } else { // Convolution or pooling. CV_Assert(attribute_proto.ints_size() == 4); lp.set("pad_t", saturate_cast<int32_t>(attribute_proto.ints(0))); lp.set("pad_l", saturate_cast<int32_t>(attribute_proto.ints(1))); lp.set("pad_b", saturate_cast<int32_t>(attribute_proto.ints(2))); lp.set("pad_r", saturate_cast<int32_t>(attribute_proto.ints(3))); } } else if(attribute_name == "auto_pad") { if (attribute_proto.s() == "SAME_UPPER" || attribute_proto.s() == "SAME_LOWER") { lp.set("pad_mode", "SAME"); } else if (attribute_proto.s() == "VALID") { lp.set("pad_mode", "VALID"); } } else if(attribute_name == "dilations") { CV_Assert(attribute_proto.ints_size() == 2); lp.set("dilation_h", saturate_cast<int32_t>(attribute_proto.ints(0))); lp.set("dilation_w", saturate_cast<int32_t>(attribute_proto.ints(1))); } else if (attribute_proto.has_i()) { ::google::protobuf::int64 src = attribute_proto.i(); if (src < std::numeric_limits<int32_t>::min() || src > std::numeric_limits<int32_t>::max()) CV_Error(Error::StsOutOfRange, "Input is out of OpenCV 32S range"); else lp.set(attribute_name, saturate_cast<int32_t>(src)); } else if (attribute_proto.has_f()) { lp.set(attribute_name, attribute_proto.f()); } else if (attribute_proto.has_s()) { lp.set(attribute_name, attribute_proto.s()); } else if (attribute_proto.floats_size() > 0) { lp.set(attribute_name, DictValue::arrayReal( attribute_proto.floats().data(), attribute_proto.floats_size())); } else if (attribute_proto.ints_size() > 0) { const ::google::protobuf::RepeatedField< ::google::protobuf::int64> src = attribute_proto.ints(); std::vector<int32_t> dst(attribute_proto.ints_size()); convertInt64ToInt32(src, dst, attribute_proto.ints_size()); lp.set(attribute_proto.name(), DictValue::arrayInt(&dst[0], attribute_proto.ints_size())); } else if (attribute_proto.has_t()) { opencv_onnx::TensorProto tensor = attribute_proto.t(); Mat blob = getMatFromTensor(tensor); lp.blobs.push_back(blob); } else if (attribute_proto.has_g() || attribute_proto.strings_size() > 0 || attribute_proto.tensors_size() > 0 || attribute_proto.graphs_size() > 0) { CV_Error(Error::StsNotImplemented, "Unexpected attribute type"); } else CV_Error(Error::StsNotImplemented, "Unsupported attribute type"); } return lp; }
TEST_P(Convolution, Accuracy) { int inChannels = get<0>(GetParam())[0]; int outChannels = get<0>(GetParam())[1]; int group = get<0>(GetParam())[2]; Size inSize = get<1>(GetParam()); Size kernel = get<2>(GetParam()); Size stride = get<3>(GetParam()); Size pad = get<4>(GetParam()); Size dilation = get<5>(GetParam()); bool hasBias = get<6>(GetParam()); Mat weights({outChannels, inChannels / group, kernel.height, kernel.width}, CV_32F); randu(weights, -1.0f, 1.0f); LayerParams lp; lp.set("kernel_w", kernel.width); lp.set("kernel_h", kernel.height); lp.set("pad_w", pad.width); lp.set("pad_h", pad.height); lp.set("stride_w", stride.width); lp.set("stride_h", stride.height); lp.set("dilation_w", dilation.width); lp.set("dilation_h", dilation.height); lp.set("num_output", outChannels); lp.set("group", group); lp.set("bias_term", hasBias); lp.type = "Convolution"; lp.name = "testLayer"; lp.blobs.push_back(weights); if (hasBias) { Mat bias({outChannels}, CV_32F); randu(bias, -1.0f, 1.0f); lp.blobs.push_back(bias); } Mat input({1, inChannels, inSize.height, inSize.width}, CV_32F); test(lp, input); }
TEST_P(Eltwise, Accuracy) { Vec3i inSize = get<0>(GetParam()); std::string op = get<1>(GetParam()); int numConv = get<2>(GetParam()); bool weighted = get<3>(GetParam()); Net net; std::vector<int> convLayerIds(numConv); for (int i = 0; i < numConv; ++i) { Mat weights({inSize[0], inSize[0], 1, 1}, CV_32F); randu(weights, -1.0f, 1.0f); LayerParams convParam; convParam.set("kernel_w", 1); convParam.set("kernel_h", 1); convParam.set("num_output", inSize[0]); convParam.set("bias_term", false); convParam.type = "Convolution"; std::ostringstream ss; ss << "convLayer" << i; convParam.name = ss.str(); convParam.blobs.push_back(weights); convLayerIds[i] = net.addLayer(convParam.name, convParam.type, convParam); net.connect(0, 0, convLayerIds[i], 0); } LayerParams eltwiseParam; eltwiseParam.set("operation", op); if (op == "sum" && weighted) { RNG rng = cv::theRNG(); std::vector<float> coeff(1 + numConv); for (int i = 0; i < coeff.size(); ++i) { coeff[i] = rng.uniform(-2.0f, 2.0f); } eltwiseParam.set("coeff", DictValue::arrayReal<float*>(&coeff[0], coeff.size())); } eltwiseParam.type = "Eltwise"; eltwiseParam.name = "testLayer"; int eltwiseId = net.addLayer(eltwiseParam.name, eltwiseParam.type, eltwiseParam); net.connect(0, 0, eltwiseId, 0); for (int i = 0; i < numConv; ++i) { net.connect(convLayerIds[i], 0, eltwiseId, i + 1); } Mat input({1, inSize[0], inSize[1], inSize[2]}, CV_32F); randu(input, -1.0f, 1.0f); net.setInput(input); Mat outputDefault = net.forward(eltwiseParam.name).clone(); net.setPreferableBackend(DNN_BACKEND_HALIDE); Mat outputHalide = net.forward(eltwiseParam.name).clone(); normAssert(outputDefault, outputHalide); }