Added reshape() functionality to CPU backend

pull/21669/head
Ruslan Garnov 3 years ago
parent a332509e02
commit ecb30409f6
  1. 43
      modules/gapi/src/backends/cpu/gcpubackend.cpp
  2. 17
      modules/gapi/src/backends/cpu/gcpubackend.hpp
  3. 4
      modules/gapi/src/backends/fluid/gfluidbackend.cpp
  4. 74
      modules/gapi/test/cpu/gapi_ocv_stateful_kernel_tests.cpp
  5. 26
      modules/gapi/test/internal/gapi_int_executor_tests.cpp

@ -2,7 +2,7 @@
// 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) 2018-2021 Intel Corporation
// Copyright (C) 2018-2022 Intel Corporation
#include "precomp.hpp"
@ -88,7 +88,7 @@ cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
{
case NodeType::OP:
{
m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)});
m_opNodes.push_back(nh);
// If kernel is stateful then prepare storage for its state.
GCPUKernel k = gcm.metadata(nh).get<CPUUnit>().k;
@ -107,19 +107,12 @@ cv::gimpl::GCPUExecutable::GCPUExecutable(const ade::Graph &g,
auto rc = RcDesc{desc.rc, desc.shape, desc.ctor};
magazine::bindInArg(m_res, rc, m_gm.metadata(nh).get<ConstValue>().arg);
}
//preallocate internal Mats in advance
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT)
{
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
auto& mat = m_res.slot<cv::Mat>()[desc.rc];
createMat(mat_desc, mat);
}
break;
}
default: util::throw_error(std::logic_error("Unsupported NodeType type"));
}
}
makeReshape();
// For each stateful kernel call 'setup' user callback to initialize state.
setupKernelStates();
}
@ -176,8 +169,38 @@ void cv::gimpl::GCPUExecutable::setupKernelStates()
}
}
void cv::gimpl::GCPUExecutable::makeReshape() {
// Prepare the execution script
m_script.clear();
for (auto &nh : m_opNodes) {
m_script.push_back({nh, GModel::collectOutputMeta(m_gm, nh)});
}
// Preallocate internal mats
for (auto& nh : m_dataNodes) {
const auto& desc = m_gm.metadata(nh).get<Data>();
if (desc.storage == Data::Storage::INTERNAL && desc.shape == GShape::GMAT) {
const auto mat_desc = util::get<cv::GMatDesc>(desc.meta);
auto& mat = m_res.slot<cv::Mat>()[desc.rc];
createMat(mat_desc, mat);
}
}
}
void cv::gimpl::GCPUExecutable::reshape(ade::Graph&, const GCompileArgs& args) {
m_compileArgs = args;
makeReshape();
// Signal to reset stateful kernels` state.
// There can be no handleNewStream() call to set this flag
// if user didn't call GCompiled`s prepareForNewStream()
m_newStreamStarted = true;
}
void cv::gimpl::GCPUExecutable::handleNewStream()
{
// Signal to reset stateful kernels` state.
// No need to call reshape() here since it'll
// be called automatically if input meta was changed
m_newStreamStarted = true;
}

@ -2,7 +2,7 @@
// 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) 2018-2020 Intel Corporation
// Copyright (C) 2018-2022 Intel Corporation
#ifndef OPENCV_GAPI_GCPUBACKEND_HPP
@ -33,7 +33,7 @@ class GCPUExecutable final: public GIslandExecutable
{
const ade::Graph &m_g;
GModel::ConstGraph m_gm;
const cv::GCompileArgs m_compileArgs;
cv::GCompileArgs m_compileArgs;
struct OperationInfo
{
@ -51,6 +51,7 @@ class GCPUExecutable final: public GIslandExecutable
// List of all resources in graph (both internal and external)
std::vector<ade::NodeHandle> m_dataNodes;
std::vector<ade::NodeHandle> m_opNodes;
// Actual data of all resources in graph (both internal and external)
Mag m_res;
@ -61,19 +62,15 @@ class GCPUExecutable final: public GIslandExecutable
GArg packArg(const GArg &arg);
void setupKernelStates();
void makeReshape();
public:
GCPUExecutable(const ade::Graph &graph,
const cv::GCompileArgs &compileArgs,
const std::vector<ade::NodeHandle> &nodes);
virtual inline bool canReshape() const override { return false; }
virtual inline void reshape(ade::Graph&, const GCompileArgs&) override
{
// FIXME: CPU plugin is in fact reshapeable (as it was initially,
// even before outMeta() has been introduced), so this limitation
// should be dropped.
util::throw_error(std::logic_error("GCPUExecutable::reshape() should never be called"));
}
virtual inline bool canReshape() const override { return true; }
virtual void reshape(ade::Graph&, const GCompileArgs&) override;
virtual void handleNewStream() override;

@ -2,7 +2,7 @@
// 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) 2018-2020 Intel Corporation
// Copyright (C) 2018-2022 Intel Corporation
#include "precomp.hpp"
@ -954,7 +954,7 @@ namespace
GFluidModel fg(graph);
for (const auto& node : g.nodes())
{
if (g.metadata(node).get<NodeType>().t == NodeType::DATA)
if (fg.metadata(node).contains<FluidData>())
{
auto& fd = fg.metadata(node).get<FluidData>();
fd.latency = 0;

@ -2,7 +2,7 @@
// 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) 2020 Intel Corporation
// Copyright (C) 2020-2022 Intel Corporation
#include "gapi_ocv_stateful_kernel_test_utils.hpp"
#include <opencv2/gapi/cpu/core.hpp>
@ -342,7 +342,79 @@ TEST(StatefulKernel, StateIsInitViaCompArgsInStreaming)
// Allowing 5% difference of all pixels between G-API and reference OpenCV results
testBackSubInStreaming(gapiBackSub, 5);
}
TEST(StatefulKernel, StateIsChangedViaCompArgsOnReshape)
{
cv::GMat in;
cv::GComputation comp(in, GBackSub::on(in));
const auto pkg = cv::gapi::kernels<GOCVBackSub>();
// OpenCV reference substractor
auto pOCVBackSubKNN = createBackgroundSubtractorKNN();
auto pOCVBackSubMOG2 = createBackgroundSubtractorMOG2();
const auto run = [&](const std::string& videoPath, const std::string& method) {
auto path = findDataFile(videoPath);
cv::gapi::wip::IStreamSource::Ptr source;
try {
source = gapi::wip::make_src<cv::gapi::wip::GCaptureSource>(path);
} catch(...) {
throw SkipTestException("Video file can not be opened");
}
cv::Mat inMat, gapiForeground, ocvForeground;
for (int i = 0; i < 10; i++) {
cv::gapi::wip::Data inData;
source->pull(inData);
inMat = cv::util::get<cv::Mat>(inData);
comp.apply(inMat, gapiForeground,
cv::compile_args(pkg, BackSubStateParams{method}));
if (method == "knn") {
pOCVBackSubKNN->apply(inMat, ocvForeground, -1);
// Allowing 1% difference among all pixels
compareBackSubResults(gapiForeground, ocvForeground, 1);
} else if (method == "mog2") {
pOCVBackSubMOG2->apply(inMat, ocvForeground, -1);
compareBackSubResults(gapiForeground, ocvForeground, 5);
} else {
CV_Assert(false && "Unknown BackSub method");
}
}
};
run("cv/video/768x576.avi", "knn");
run("cv/video/1920x1080.avi", "mog2");
}
#endif
TEST(StatefulKernel, StateIsAutoResetOnReshape)
{
cv::GMat in;
cv::GOpaque<bool> up_to_date = GIsStateUpToDate::on(in);
cv::GOpaque<int> calls_count = GCountCalls::on(in);
cv::GComputation comp(cv::GIn(in), cv::GOut(up_to_date, calls_count));
auto run = [&comp](const cv::Mat& in_mat) {
const auto pkg = cv::gapi::kernels<GOCVIsStateUpToDate, GOCVCountCalls>();
bool stateIsUpToDate = false;
int callsCount = 0;
for (int i = 0; i < 3; i++) {
comp.apply(cv::gin(in_mat), cv::gout(stateIsUpToDate, callsCount),
cv::compile_args(pkg));
EXPECT_TRUE(stateIsUpToDate);
EXPECT_EQ(i+1, callsCount);
}
};
cv::Mat in_mat1(32, 32, CV_8UC1);
run(in_mat1);
cv::Mat in_mat2(16, 16, CV_8UC1);
run(in_mat2);
}
//-------------------------------------------------------------------------------------------------------------

@ -2,12 +2,14 @@
// 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) 2018 Intel Corporation
// Copyright (C) 2018-2022 Intel Corporation
#include "../test_precomp.hpp"
#include "../gapi_mock_kernels.hpp"
#include <opencv2/gapi/core.hpp>
namespace opencv_test
{
@ -294,6 +296,28 @@ TEST_F(GExecutorReshapeTest, ReshapeCallAllocate)
EXPECT_EQ(1, island1.getReshapeCounter());
}
TEST_F(GExecutorReshapeTest, CPUBackendIsReshapable)
{
comp = cv::GComputation([](){
cv::GMat in;
cv::GMat foo = I::Foo::on(in);
cv::GMat out = cv::gapi::bitwise_not(cv::gapi::bitwise_not(in));
return cv::GComputation(cv::GIn(in), cv::GOut(foo, out));
});
// NB: Initial state
EXPECT_EQ(0, island1.getReshapeCounter());
// NB: First compilation.
cv::Mat out_mat2;
comp.apply(cv::gin(in_mat1), cv::gout(out_mat, out_mat2), cv::compile_args(pkg));
EXPECT_EQ(0, island1.getReshapeCounter());
// NB: The entire graph is reshapable, so it won't be recompiled, but reshaped.
comp.apply(cv::gin(in_mat2), cv::gout(out_mat, out_mat2), cv::compile_args(pkg));
EXPECT_EQ(1, island1.getReshapeCounter());
EXPECT_EQ(0, cvtest::norm(out_mat2, in_mat2, NORM_INF));
}
// FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
// between executed islands

Loading…
Cancel
Save