dnn(onnx): cut peak memory of DNNTestNetwork.AlexNet

This commit is contained in:
SavyaSanchi-Sharma
2026-08-18 20:38:45 +05:30
parent 4b5add36de
commit 4e5f30977b
4 changed files with 45 additions and 45 deletions

View File

@@ -42,6 +42,15 @@ Mat getMatFromTensor(const opencv_onnx::TensorProto& tensor_proto, bool uint8ToI
// or returns -1 when the data_type has no OpenCV equivalent.
int dataType2cv(int dt);
/** @brief frees a tensor's raw payload once it has been copied into a Mat.
* clear_raw_data() only empties the string and keeps its capacity, so it must be released.
*/
inline void releaseONNXTensor(opencv_onnx::TensorProto& tensor_proto)
{
if (!tensor_proto.raw_data().empty())
delete tensor_proto.release_raw_data();
}
CV__DNN_INLINE_NS_END
}} // namespace dnn, namespace cv

View File

@@ -137,13 +137,6 @@ static int onnxDataTypeToCvDepth(int onnxType)
}
}
static void releaseONNXTensor(opencv_onnx::TensorProto& tensor_proto)
{
if (!tensor_proto.raw_data().empty()) {
delete tensor_proto.release_raw_data();
}
}
Mat readTensorFromONNX(const String& path)
{
std::fstream input(path.c_str(), std::ios::in | std::ios::binary);

View File

@@ -534,7 +534,7 @@ LayerParams ONNXImporter2::getLayerParams(const opencv_onnx::NodeProto& node_pro
}
else if (attribute_proto.has_t())
{
opencv_onnx::TensorProto tensor = attribute_proto.t();
const opencv_onnx::TensorProto& tensor = attribute_proto.t();
Mat blob = parseTensor(tensor);
lp.blobs.push_back(blob);
lp.set("original_dims_of_mat", tensor.dims_size());
@@ -888,9 +888,10 @@ Ptr<Graph> ONNXImporter2::parseGraph(opencv_onnx::GraphProto* graph_proto, bool
// parse constant tensors
int n_consts = graph_proto->initializer_size();
for (int i = 0; i < n_consts; i++) {
const opencv_onnx::TensorProto& const_i = graph_proto->initializer(i);
Mat t = parseTensor(const_i);
netimpl->newConstArg(remap(const_i.name()), t);
opencv_onnx::TensorProto* const_i = graph_proto->mutable_initializer(i);
Mat t = parseTensor(*const_i);
netimpl->newConstArg(remap(const_i->name()), t);
releaseONNXTensor(*const_i);
}
// parse graph inputs

View File

@@ -37,17 +37,35 @@ public:
if (!proto.empty())
proto = findDataFile(proto);
// Create two networks - with default backend and target and a tested one.
Net netDefault = readNet(weights, proto);
netDefault.setPreferableBackend(DNN_BACKEND_OPENCV);
netDefault.setInput(inp);
Mat inp2 = inp.clone();
float* inpData = (float*)inp2.data;
for (int i = 0; i < inp2.size[0] * inp2.size[1]; ++i)
{
Mat slice(inp2.size[2], inp2.size[3], CV_32F, inpData);
cv::flip(slice, slice, 1);
inpData += slice.total();
}
// BUG: https://github.com/opencv/opencv/issues/26349
Mat outDefault;
if(netDefault.getMainGraph())
outDefault = netDefault.forward().clone();
else
outDefault = netDefault.forward(outputLayer).clone();
// Both reference passes run before the tested net is loaded, so netDefault can be
// released first. Keeping both alive doubles peak memory on large models.
Mat outDefault1, outDefault2;
{
Net netDefault = readNet(weights, proto);
netDefault.setPreferableBackend(DNN_BACKEND_OPENCV);
// BUG: https://github.com/opencv/opencv/issues/26349
netDefault.setInput(inp);
if(netDefault.getMainGraph())
outDefault1 = netDefault.forward().clone();
else
outDefault1 = netDefault.forward(outputLayer).clone();
netDefault.setInput(inp2);
if(netDefault.getMainGraph())
outDefault2 = netDefault.forward().clone();
else
outDefault2 = netDefault.forward(outputLayer).clone();
}
net = readNet(weights, proto);
net.setInput(inp);
@@ -64,30 +82,15 @@ public:
else
out = net.forward(outputLayer).clone();
check(outDefault, out, outputLayer, l1, lInf, detectionConfThresh, "First run");
// Test 2: change input.
float* inpData = (float*)inp.data;
for (int i = 0; i < inp.size[0] * inp.size[1]; ++i)
{
Mat slice(inp.size[2], inp.size[3], CV_32F, inpData);
cv::flip(slice, slice, 1);
inpData += slice.total();
}
netDefault.setInput(inp);
net.setInput(inp);
if(netDefault.getMainGraph())
outDefault = netDefault.forward().clone();
else
outDefault = netDefault.forward(outputLayer).clone();
check(outDefault1, out, outputLayer, l1, lInf, detectionConfThresh, "First run");
net.setInput(inp2);
if(net.getMainGraph())
out = net.forward().clone();
else
out = net.forward(outputLayer).clone();
check(outDefault, out, outputLayer, l1, lInf, detectionConfThresh, "Second run");
check(outDefault2, out, outputLayer, l1, lInf, detectionConfThresh, "Second run");
}
void check(Mat& ref, Mat& out, const std::string& outputLayer, double l1, double lInf,
@@ -124,12 +127,6 @@ TEST_P(DNNTestNetwork, YOLOv8n) {
TEST_P(DNNTestNetwork, AlexNet)
{
applyTestTag(CV_TEST_TAG_MEMORY_1GB);
// fc6 needs one contiguous 9216*4096*4 = 144 MiB block, which does not fit
// reliably in the 2 GB user address space of a 32-bit process on Windows.
#ifdef _WIN32
if (sizeof(void*) == 4)
throw SkipTestException("Skip memory-heavy network on 32-bit (x86) Windows platform");
#endif
processNet("dnn/onnx/models/alexnet.onnx", "", Size(227, 227));
expectNoFallbacksFromIE(net);
expectNoFallbacksFromCUDA(net);