mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 21:01:33 -05:00
## dnn: extend engine-new layer dtype coverage (control flow, Range, Hardmax, MaxUnpool, CumSum/CumProd, MaxPool, Resize2, normalization, Gemm, MatMul) ONNX permits these dtypes on these ops, but the engine-new layers refused them at graph-construction time, so : - valid models either failed to load outright or - a layer quietly converted to float32 instead (Resize2) - ran but silently lost precision above float32's 24-bit mantissa. Companion PR (test data) : [1406](https://github.com/opencv/opencv_extra/pull/1406) ### Support added, per layer | Layer | Types added | Gate / kernel | |---|---|---| | If | Bool, 16U, 16S, 32U, 32S, 64U | Gate only — the condition-reading switch already handled every depth | | Loop | Bool, 16U, 16S, 32U, 32S, 64U | Gate only — same as If | | Scan | Bool, 16U, 16S, 32U, 32S, 64U | Gate only — Scan never inspects element values at all | | Range | 16S | Kernel only — gate was already an unconditional passthrough | | Hardmax | 64F | Gate only — the `double` kernel has existed since 2024, just unreachable | | MaxUnpool | 64F | Gate + a genuine `double` instantiation of the value-scatter routine | | CumSum | 32U, 64U | Gate + two instantiations of the existing running-sum template (wraparound on overflow) | | CumProd | 32U, 64U | Gate + two instantiations of the existing running-product template | | MaxPool | 8S, 8U, 64F | Kernel only (gate was already open) — new scalar kernel for the blocked values-only path **and** the separate values+indices path, which had its own float32-only assert | | Resize2 | 32S (nearest-neighbor only) | Gate + native `int32` gather; bilinear/cubic now reject 32S explicitly instead of silently converting to `float` | | RMSNorm | 64F | Kernel — `fast_norm.cpp` templated on `T`, genuine `double` accumulator | | LayerNorm | 64F | Kernel — same shared `fast_norm.cpp` path | | LayerNorm2 | 64F | Kernel — same shared `fast_norm.cpp` path | | InstanceNorm | 64F | Kernel — existing SIMD float32 blocked path left untouched, new scalar `double` path added beside it | | GroupNorm | 64F | Kernel — same treatment as InstanceNorm | | Gemm | 64F | Kernel — dedicated `cv::gemm` path, bypassing the float-only fastGemm/MLAS kernels | | MatMul | 64F, 32S, 64S, 32U, 64U | Gate + two new paths: per-batch `cv::gemm` for 64F, and a direct 64-bit-accumulated loop for the four integer types | Removed `test_maxpool_2d_uint8` from `opencv_all_denylist` : with 8U now supported, the test passes NORMASSERT on all backend/target combinations . ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
115 lines
3.0 KiB
C++
115 lines
3.0 KiB
C++
// This file is part of OpenCV project.
|
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
|
// of this distribution and at http://opencv.org/license.html.
|
|
//
|
|
// Copyright (C) 2017, Intel Corporation, all rights reserved.
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
#include "test_precomp.hpp"
|
|
#include "npy_blob.hpp"
|
|
|
|
namespace cv
|
|
{
|
|
|
|
static std::string getType(const std::string& header)
|
|
{
|
|
std::string field = "'descr':";
|
|
int idx = header.find(field);
|
|
CV_Assert(idx != -1);
|
|
|
|
int from = header.find('\'', idx + field.size()) + 1;
|
|
int to = header.find('\'', from);
|
|
return header.substr(from, to - from);
|
|
}
|
|
|
|
static std::string getFortranOrder(const std::string& header)
|
|
{
|
|
std::string field = "'fortran_order':";
|
|
int idx = header.find(field);
|
|
CV_Assert(idx != -1);
|
|
|
|
int from = header.find_last_of(' ', idx + field.size()) + 1;
|
|
int to = header.find(',', from);
|
|
return header.substr(from, to - from);
|
|
}
|
|
|
|
static std::vector<int> getShape(const std::string& header)
|
|
{
|
|
std::string field = "'shape':";
|
|
int idx = header.find(field);
|
|
CV_Assert(idx != -1);
|
|
|
|
int from = header.find('(', idx + field.size()) + 1;
|
|
int to = header.find(')', from);
|
|
|
|
std::string shapeStr = header.substr(from, to - from);
|
|
if (shapeStr.empty())
|
|
return std::vector<int>(1, 1);
|
|
|
|
// Remove all commas.
|
|
shapeStr.erase(std::remove(shapeStr.begin(), shapeStr.end(), ','),
|
|
shapeStr.end());
|
|
|
|
std::istringstream ss(shapeStr);
|
|
int value;
|
|
|
|
std::vector<int> shape;
|
|
while (ss >> value)
|
|
{
|
|
shape.push_back(value);
|
|
}
|
|
return shape;
|
|
}
|
|
|
|
Mat blobFromNPY(const std::string& path)
|
|
{
|
|
std::ifstream ifs(path.c_str(), std::ios::binary);
|
|
CV_Assert(ifs.is_open());
|
|
|
|
std::string magic(6, '*');
|
|
ifs.read(&magic[0], magic.size());
|
|
CV_Assert(magic == "\x93NUMPY");
|
|
|
|
ifs.ignore(1); // Skip major version byte.
|
|
ifs.ignore(1); // Skip minor version byte.
|
|
|
|
unsigned short headerSize;
|
|
ifs.read((char*)&headerSize, sizeof(headerSize));
|
|
|
|
std::string header(headerSize, '*');
|
|
ifs.read(&header[0], header.size());
|
|
|
|
// Extract data type.
|
|
int matType;
|
|
std::string npyType = getType(header);
|
|
if (npyType == "<f4")
|
|
matType = CV_32F;
|
|
else if (npyType == "<f8")
|
|
matType = CV_64F;
|
|
else if (npyType == "<i4")
|
|
matType = CV_32S;
|
|
else if (npyType == "<i8")
|
|
matType = CV_64S;
|
|
else if (npyType == "<u4")
|
|
matType = CV_32U;
|
|
else if (npyType == "<u8")
|
|
matType = CV_64U;
|
|
else if (npyType == "|i1")
|
|
matType = CV_8S;
|
|
else if (npyType == "|u1")
|
|
matType = CV_8U;
|
|
else
|
|
CV_Error(Error::BadDepth, "Unsupported numpy type");
|
|
|
|
CV_Assert(getFortranOrder(header) == "False");
|
|
std::vector<int> shape = getShape(header);
|
|
|
|
Mat blob(shape, matType);
|
|
ifs.read((char*)blob.data, blob.total() * blob.elemSize());
|
|
CV_Assert((size_t)ifs.gcount() == blob.total() * blob.elemSize());
|
|
|
|
return blob;
|
|
}
|
|
|
|
} // namespace cv
|