mirror of
https://github.com/opencv/opencv.git
synced 2026-09-12 05:11:04 -05:00
dnn(onnx): cut peak memory of DNNTestNetwork.AlexNet
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user