Commit a7acb880 authored by atalaman's avatar atalaman Committed by Alexander Alekhin

Merge pull request #15869 from TolyaTalamanov:at/plaidml-backend

G-API: Implement PlaidML2 backend

* PlaidML backend init version

* Add test

* Support multiply inputs/outputs in PlaidML2 backend

* Fix comment to review

* Add HAVE_PLAIDML macros

* Move plaidml tests to separate file

* Fix comment to review

* Fix cmake warning

* Fix comments to review

* Fix typos

overload -> overflow

* Fix comments to review

* Clean up

* Remove spaces from cmake scripts
* Disable tests with bitwise operations

* Use plaidml::exec::Binder
parent fb5e7964
...@@ -37,6 +37,7 @@ file(GLOB gapi_ext_hdrs ...@@ -37,6 +37,7 @@ file(GLOB gapi_ext_hdrs
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp" "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/render/*.hpp" "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/render/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/*.hpp" "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/plaidml/*.hpp"
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp" "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp"
) )
...@@ -109,6 +110,10 @@ set(gapi_srcs ...@@ -109,6 +110,10 @@ set(gapi_srcs
src/backends/render/grenderocvbackend.cpp src/backends/render/grenderocvbackend.cpp
src/backends/render/grenderocv.cpp src/backends/render/grenderocv.cpp
#PlaidML Backend
src/backends/plaidml/gplaidmlcore.cpp
src/backends/plaidml/gplaidmlbackend.cpp
# Compound # Compound
src/backends/common/gcompoundbackend.cpp src/backends/common/gcompoundbackend.cpp
src/backends/common/gcompoundkernel.cpp src/backends/common/gcompoundkernel.cpp
...@@ -138,5 +143,12 @@ if(TARGET opencv_test_gapi) ...@@ -138,5 +143,12 @@ if(TARGET opencv_test_gapi)
target_link_libraries(opencv_test_gapi PRIVATE ade) target_link_libraries(opencv_test_gapi PRIVATE ade)
endif() endif()
if(HAVE_PLAIDML)
ocv_target_compile_definitions(opencv_gapi PRIVATE -DHAVE_PLAIDML)
ocv_target_compile_definitions(opencv_test_gapi PRIVATE -DHAVE_PLAIDML)
ocv_target_link_libraries(opencv_gapi LINK_PRIVATE ${PLAIDML_LIBRARIES})
ocv_target_include_directories(opencv_gapi SYSTEM PRIVATE ${PLAIDML_INCLUDE_DIRS})
endif()
ocv_add_perf_tests() ocv_add_perf_tests()
ocv_add_samples() ocv_add_samples()
OCV_OPTION(WITH_ADE "Enable ADE framework (required for Graph API module)" ON) OCV_OPTION(WITH_ADE "Enable ADE framework (required for Graph API module)" ON)
OCV_OPTION(WITH_PLAIDML "Include PlaidML2 support" OFF)
if(NOT WITH_ADE) if(NOT WITH_ADE)
return() return()
endif() endif()
if (ade_DIR) if(ade_DIR)
# if ade_DIR is set, use ADE-supplied CMake script # if ade_DIR is set, use ADE-supplied CMake script
# to set up variables to the prebuilt ADE # to set up variables to the prebuilt ADE
find_package(ade 0.1.0) find_package(ade 0.1.0)
...@@ -15,3 +16,10 @@ if(NOT TARGET ade) ...@@ -15,3 +16,10 @@ if(NOT TARGET ade)
# downloaded one (if there any) # downloaded one (if there any)
include("${CMAKE_CURRENT_LIST_DIR}/DownloadADE.cmake") include("${CMAKE_CURRENT_LIST_DIR}/DownloadADE.cmake")
endif() endif()
if(WITH_PLAIDML)
find_package(PlaidML2 CONFIG QUIET)
if (PLAIDML_FOUND)
set(HAVE_PLAIDML TRUE)
endif()
endif()
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_PLAIDML_CORE_HPP
#define OPENCV_GAPI_PLAIDML_CORE_HPP
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
namespace cv { namespace gapi { namespace core { namespace plaidml {
GAPI_EXPORTS GKernelPackage kernels();
}}}}
#endif // OPENCV_GAPI_PLAIDML_CORE_HPP
// 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) 2019 Intel Corporation
//
#ifndef OPENCV_GAPI_GPLAIDMLKERNEL_HPP
#define OPENCV_GAPI_GPLAIDMLKERNEL_HPP
#include <opencv2/gapi/gkernel.hpp>
#include <opencv2/gapi/garg.hpp>
namespace plaidml
{
namespace edsl
{
class Tensor;
} // namespace edsl
} // namespace plaidml
namespace cv
{
namespace gapi
{
namespace plaidml
{
GAPI_EXPORTS cv::gapi::GBackend backend();
} // namespace plaidml
} // namespace gapi
struct GPlaidMLContext
{
// Generic accessor API
template<typename T>
const T& inArg(int input) { return m_args.at(input).get<T>(); }
// Syntax sugar
const plaidml::edsl::Tensor& inTensor(int input)
{
return inArg<plaidml::edsl::Tensor>(input);
}
plaidml::edsl::Tensor& outTensor(int output)
{
return *(m_results.at(output).get<plaidml::edsl::Tensor*>());
}
std::vector<GArg> m_args;
std::unordered_map<std::size_t, GArg> m_results;
};
class GAPI_EXPORTS GPlaidMLKernel
{
public:
using F = std::function<void(GPlaidMLContext &)>;
GPlaidMLKernel() = default;
explicit GPlaidMLKernel(const F& f) : m_f(f) {};
void apply(GPlaidMLContext &ctx) const
{
GAPI_Assert(m_f);
m_f(ctx);
}
protected:
F m_f;
};
namespace detail
{
template<class T> struct plaidml_get_in;
template<> struct plaidml_get_in<cv::GMat>
{
static const plaidml::edsl::Tensor& get(GPlaidMLContext& ctx, int idx)
{
return ctx.inTensor(idx);
}
};
template<class T> struct plaidml_get_in
{
static T get(GPlaidMLContext &ctx, int idx) { return ctx.inArg<T>(idx); }
};
template<class T> struct plaidml_get_out;
template<> struct plaidml_get_out<cv::GMat>
{
static plaidml::edsl::Tensor& get(GPlaidMLContext& ctx, int idx)
{
return ctx.outTensor(idx);
}
};
template<typename, typename, typename>
struct PlaidMLCallHelper;
template<typename Impl, typename... Ins, typename... Outs>
struct PlaidMLCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
{
template<int... IIs, int... OIs>
static void call_impl(GPlaidMLContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
{
Impl::run(plaidml_get_in<Ins>::get(ctx, IIs)..., plaidml_get_out<Outs>::get(ctx, OIs)...);
}
static void call(GPlaidMLContext& ctx)
{
call_impl(ctx,
typename detail::MkSeq<sizeof...(Ins)>::type(),
typename detail::MkSeq<sizeof...(Outs)>::type());
}
};
} // namespace detail
template<class Impl, class K>
class GPlaidMLKernelImpl: public cv::detail::PlaidMLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
public cv::detail::KernelTag
{
using P = detail::PlaidMLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
public:
using API = K;
static cv::gapi::GBackend backend() { return cv::gapi::plaidml::backend(); }
static cv::GPlaidMLKernel kernel() { return GPlaidMLKernel(&P::call); }
};
#define GAPI_PLAIDML_KERNEL(Name, API) struct Name: public cv::GPlaidMLKernelImpl<Name, API>
} // namespace cv
#endif // OPENCV_GAPI_GPLAIDMLKERNEL_HPP
// 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) 2019 Intel Corporation
#ifndef OPENCV_GAPI_PLAIDML_PLAIDML_HPP
#define OPENCV_GAPI_PLAIDML_PLAIDML_HPP
#include <string>
#include <opencv2/gapi/gcommon.hpp> // CompileArgTag
namespace cv
{
namespace gapi
{
namespace plaidml
{
struct config
{
std::string dev_id;
std::string trg_id;
};
} // namespace plaidml
} // namespace gapi
namespace detail
{
template<> struct CompileArgTag<cv::gapi::plaidml::config>
{
static const char* tag() { return "gapi.plaidml.config"; }
};
} // namespace detail
} // namespace cv
#endif // OPENCV_GAPI_PLAIDML_PLAIDML_HPP
...@@ -40,6 +40,16 @@ cv::gapi::GBackend::Priv::compile(const ade::Graph&, ...@@ -40,6 +40,16 @@ cv::gapi::GBackend::Priv::compile(const ade::Graph&,
return {}; return {};
} }
std::unique_ptr<cv::gimpl::GIslandExecutable>
cv::gapi::GBackend::Priv::compile(const ade::Graph& graph,
const GCompileArgs& args,
const std::vector<ade::NodeHandle>& nodes,
const std::vector<cv::gimpl::Data>&,
const std::vector<cv::gimpl::Data>&) const
{
return compile(graph, args, nodes);
}
void cv::gapi::GBackend::Priv::addBackendPasses(ade::ExecutionEngineSetupContext &) void cv::gapi::GBackend::Priv::addBackendPasses(ade::ExecutionEngineSetupContext &)
{ {
// Do nothing by default, plugins may override this to // Do nothing by default, plugins may override this to
......
...@@ -18,6 +18,9 @@ ...@@ -18,6 +18,9 @@
#include "opencv2/gapi/gcommon.hpp" #include "opencv2/gapi/gcommon.hpp"
#include "opencv2/gapi/gkernel.hpp" #include "opencv2/gapi/gkernel.hpp"
#include "compiler/gmodel.hpp"
namespace cv namespace cv
{ {
namespace gimpl namespace gimpl
...@@ -41,10 +44,18 @@ public: ...@@ -41,10 +44,18 @@ public:
// there's no need in having both cv::gimpl::GBackend // there's no need in having both cv::gimpl::GBackend
// and cv::gapi::GBackend - these two things can be unified // and cv::gapi::GBackend - these two things can be unified
// NOTE - nodes are guaranteed to be topologically sorted. // NOTE - nodes are guaranteed to be topologically sorted.
// NB: This method is deprecated
virtual EPtr compile(const ade::Graph &graph, virtual EPtr compile(const ade::Graph &graph,
const GCompileArgs &args, const GCompileArgs &args,
const std::vector<ade::NodeHandle> &nodes) const; const std::vector<ade::NodeHandle> &nodes) const;
virtual EPtr compile(const ade::Graph &graph,
const GCompileArgs &args,
const std::vector<ade::NodeHandle> &nodes,
const std::vector<cv::gimpl::Data>& ins_data,
const std::vector<cv::gimpl::Data>& outs_data) const;
virtual void addBackendPasses(ade::ExecutionEngineSetupContext &); virtual void addBackendPasses(ade::ExecutionEngineSetupContext &);
virtual cv::gapi::GKernelPackage auxiliaryKernels() const; virtual cv::gapi::GKernelPackage auxiliaryKernels() const;
......
This diff is collapsed.
// 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) 2019 Intel Corporation
#ifdef HAVE_PLAIDML
#ifndef OPENCV_GAPI_GPLAIDMLBACKEND_HPP
#define OPENCV_GAPI_GPLAIDMLBACKEND_HPP
#include <map> // map
#include <unordered_map> // unordered_map
#include <tuple> // tuple
#include <ade/util/algorithm.hpp> // type_list_index
#include <opencv2/gapi/garg.hpp>
#include <opencv2/gapi/gproto.hpp>
#include <opencv2/gapi/plaidml/gplaidmlkernel.hpp>
#include "api/gorigin.hpp"
#include "backends/common/gbackend.hpp"
#include "compiler/gislandmodel.hpp"
#include <plaidml2/exec/exec.h>
#include <plaidml2/core/core.h>
namespace cv { namespace gimpl {
struct PlaidMLUnit
{
static const char *name() { return "PlaidMLKernel"; }
GPlaidMLKernel k;
};
class GPlaidMLExecutable final: public GIslandExecutable
{
public:
struct Config
{
std::string dev_id;
std::string trg_id;
};
GPlaidMLExecutable(Config cfg,
const ade::Graph& graph,
const std::vector<ade::NodeHandle>& nodes,
const std::vector<cv::gimpl::Data>& ins_data,
const std::vector<cv::gimpl::Data>& outs_data);
virtual inline bool canReshape() const override { return false; }
virtual inline void reshape(ade::Graph&, const GCompileArgs&) override
{
util::throw_error(std::logic_error("GPlaidMLExecutable::reshape() should never be called"));
}
virtual void run(std::vector<InObj> &&input_objs,
std::vector<OutObj> &&output_objs) override;
private:
void initBuffers(const std::vector<cv::gimpl::Data>& ins_data,
std::vector<plaidml::exec::Binding>& bindings);
void bindInArg (const RcDesc &rc, const GRunArg &arg);
void bindOutArg (const RcDesc &rc, const GRunArgP &arg);
void compile(const std::vector<cv::gimpl::Data>& ins_data,
const std::vector<cv::gimpl::Data>& outs_data);
// FIXME User also can pass config via compile args ?
void initConfig();
GArg packArg(const GArg &arg);
Config m_cfg;
const ade::Graph &m_g;
GModel::ConstGraph m_gm;
std::vector<ade::NodeHandle> m_all_ops;
std::vector<size_t> output_ids_;
std::unique_ptr<plaidml::exec::Binder> binder_;
std::shared_ptr<plaidml::exec::Executable> exec_;
std::vector<plaidml::exec::Binding> input_bindings_;
std::vector<plaidml::exec::Binding> output_bindings_;
using Mag = detail::magazine<plaidml::edsl::Tensor, plaidml::Buffer*>;
Mag m_res;
};
}}
#endif // OPENCV_GAPI_GPLAIDMLBACKEND_HPP
#endif // HAVE_PLAIDML
// 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) 2019 Intel Corporation
#ifdef HAVE_PLAIDML
#include "precomp.hpp"
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/plaidml/core.hpp>
#include <opencv2/gapi/plaidml/gplaidmlkernel.hpp>
#include <plaidml2/edsl/edsl.h>
#define GAPI_PLAIDML_LOGICAL_OP(Name, API, Op) \
GAPI_PLAIDML_KERNEL(Name, API) \
{ \
static void run(const plaidml::edsl::Tensor& src1, \
const plaidml::edsl::Tensor& src2, \
plaidml::edsl::Tensor& dst) \
{ \
dst = src1 Op src2; \
}; \
}; \
#define GAPI_PLAIDML_ARITHMETIC_OP(Name, API, Op) \
GAPI_PLAIDML_KERNEL(Name, API) \
{ \
static void run(const plaidml::edsl::Tensor& src1, \
const plaidml::edsl::Tensor& src2, \
int, /* dtype */ \
plaidml::edsl::Tensor& dst) \
{ \
dst = src1 Op src2; \
}; \
}; \
GAPI_PLAIDML_LOGICAL_OP(GPlaidMLAnd, cv::gapi::core::GAnd, &);
GAPI_PLAIDML_LOGICAL_OP(GPlaidMLXor, cv::gapi::core::GXor, ^);
GAPI_PLAIDML_LOGICAL_OP(GPlaidMLOr , cv::gapi::core::GOr , |)
GAPI_PLAIDML_ARITHMETIC_OP(GPlaidMLAdd, cv::gapi::core::GAdd, +);
GAPI_PLAIDML_ARITHMETIC_OP(GPlaidMLSub, cv::gapi::core::GSub, -);
cv::gapi::GKernelPackage cv::gapi::core::plaidml::kernels()
{
static auto pkg = cv::gapi::kernels<GPlaidMLAdd, GPlaidMLSub, GPlaidMLAnd, GPlaidMLXor, GPlaidMLOr>();
return pkg;
}
#endif // HACE_PLAIDML
// 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) 2019 Intel Corporation
#ifdef HAVE_PLAIDML
#ifndef OPENCV_GAPI_PLAIDML_UTIL_HPP
#define OPENCV_GAPI_PLAIDML_UTIL_HPP
#include <plaidml2/core/ffi.h>
namespace cv
{
namespace util
{
namespace plaidml
{
inline plaidml_datatype depth_from_ocv(int depth)
{
switch(depth)
{
case CV_8U : return PLAIDML_DATA_UINT8;
case CV_8S : return PLAIDML_DATA_INT8;
case CV_16U : return PLAIDML_DATA_UINT16;
case CV_16S : return PLAIDML_DATA_INT16;
case CV_32S : return PLAIDML_DATA_INT32;
case CV_32F : return PLAIDML_DATA_FLOAT32;
case CV_64F : return PLAIDML_DATA_FLOAT64;
default: util::throw_error("Unrecognized OpenCV depth");
}
};
}
}
}
#endif // OPENCV_GAPI_PLAIDML_UTIL_HPP
#endif // HAVE_PLAIDML
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "api/gbackend_priv.hpp" // GBackend::Priv().compile() #include "api/gbackend_priv.hpp" // GBackend::Priv().compile()
#include "compiler/gmodel.hpp" #include "compiler/gmodel.hpp"
#include "compiler/gislandmodel.hpp" #include "compiler/gislandmodel.hpp"
#include "compiler/gmodel.hpp"
#include "logger.hpp" // GAPI_LOG #include "logger.hpp" // GAPI_LOG
namespace cv { namespace gimpl { namespace cv { namespace gimpl {
...@@ -257,6 +259,20 @@ void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCom ...@@ -257,6 +259,20 @@ void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCom
{ {
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k) if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
{ {
auto nodes_to_data = [&](const ade::NodeHandle& dnh)
{
GAPI_Assert(g.metadata(dnh).get<NodeKind>().k == NodeKind::SLOT);
const auto& orig_data_nh = g.metadata(dnh).get<DataSlot>().original_data_node;
const auto& data = gm.metadata(orig_data_nh).get<Data>();
return data;
};
std::vector<cv::gimpl::Data> ins_data;
ade::util::transform(nh->inNodes(), std::back_inserter(ins_data), nodes_to_data);
std::vector<cv::gimpl::Data> outs_data;
ade::util::transform(nh->outNodes(), std::back_inserter(outs_data), nodes_to_data);
auto island_obj = g.metadata(nh).get<FusedIsland>().object; auto island_obj = g.metadata(nh).get<FusedIsland>().object;
auto island_ops = island_obj->contents(); auto island_ops = island_obj->contents();
...@@ -268,8 +284,9 @@ void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCom ...@@ -268,8 +284,9 @@ void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCom
}); });
auto island_exe = island_obj->backend().priv() auto island_exe = island_obj->backend().priv()
.compile(orig_g, args, topo_sorted_list); .compile(orig_g, args, topo_sorted_list, ins_data, outs_data);
GAPI_Assert(nullptr != island_exe); GAPI_Assert(nullptr != island_exe);
g.metadata(nh).set(IslandExec{std::move(island_exe)}); g.metadata(nh).set(IslandExec{std::move(island_exe)});
} }
} }
......
...@@ -96,6 +96,7 @@ protected: ...@@ -96,6 +96,7 @@ protected:
// * Is instantiated by the last step of the Islands fusion procedure; // * Is instantiated by the last step of the Islands fusion procedure;
// * Is orchestrated by a GExecutor instance. // * Is orchestrated by a GExecutor instance.
// //
class GIslandExecutable class GIslandExecutable
{ {
public: public:
......
...@@ -62,7 +62,8 @@ cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model) ...@@ -62,7 +62,8 @@ cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model)
m_ops.emplace_back(OpDesc{ std::move(input_rcs) m_ops.emplace_back(OpDesc{ std::move(input_rcs)
, std::move(output_rcs) , std::move(output_rcs)
, m_gim.metadata(nh).get<IslandExec>().object}); , m_gim.metadata(nh).get<IslandExec>().object
});
} }
break; break;
......
// 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) 2019 Intel Corporation
#ifdef HAVE_PLAIDML
#include "test_precomp.hpp"
#include <stdexcept>
#include <ade/util/iota_range.hpp>
#include "logger.hpp"
#include <opencv2/gapi/plaidml/core.hpp>
#include <opencv2/gapi/plaidml/plaidml.hpp>
namespace opencv_test
{
inline cv::gapi::plaidml::config getConfig()
{
auto read_var_from_env = [](const char* env)
{
const char* raw = std::getenv(env);
if (!raw)
{
cv::util::throw_error(std::runtime_error(std::string(env) + " is't set"));
}
return std::string(raw);
};
auto dev_id = read_var_from_env("PLAIDML_DEVICE");
auto trg_id = read_var_from_env("PLAIDML_TARGET");
return cv::gapi::plaidml::config{std::move(dev_id),
std::move(trg_id)};
}
TEST(GAPI_PlaidML_Pipelines, SimpleArithmetic)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
cv::Mat in_mat1(size, type);
cv::Mat in_mat2(size, type);
// NB: What about overflow ? PlaidML doesn't handle it
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(127));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(127));
cv::Mat out_mat(size, type, cv::Scalar::all(0));
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in1, in2;
auto out = in1 + in2;
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::add(in_mat1, in_mat2, ref_mat, cv::noArray(), type);
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
}
// FIXME PlaidML cpu backend does't support bitwise operations
TEST(GAPI_PlaidML_Pipelines, DISABLED_ComplexArithmetic)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
cv::Mat in_mat1(size, type);
cv::Mat in_mat2(size, type);
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
cv::Mat out_mat(size, type, cv::Scalar::all(0));
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in1, in2;
auto out = in1 | (in2 ^ (in1 & (in2 + (in1 - in2))));
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::subtract(in_mat1, in_mat2, ref_mat, cv::noArray(), type);
cv::add(in_mat2, ref_mat, ref_mat, cv::noArray(), type);
cv::bitwise_and(in_mat1, ref_mat, ref_mat);
cv::bitwise_xor(in_mat2, ref_mat, ref_mat);
cv::bitwise_or(in_mat1, ref_mat, ref_mat);
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
}
TEST(GAPI_PlaidML_Pipelines, TwoInputOperations)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
constexpr int kNumInputs = 4;
std::vector<cv::Mat> in_mat(kNumInputs, cv::Mat(size, type));
for (int i = 0; i < kNumInputs; ++i)
{
cv::randu(in_mat[i], cv::Scalar::all(0), cv::Scalar::all(60));
}
cv::Mat out_mat(size, type, cv::Scalar::all(0));
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in[4];
auto out = (in[3] - in[0]) + (in[2] - in[1]);
cv::GComputation comp(cv::GIn(in[0], in[1], in[2], in[3]), cv::GOut(out));
// FIXME Doesn't work just apply(in_mat, out_mat, ...)
comp.apply(cv::gin(in_mat[0], in_mat[1], in_mat[2], in_mat[3]), cv::gout(out_mat),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::subtract(in_mat[3], in_mat[0], ref_mat, cv::noArray(), type);
cv::add(ref_mat, in_mat[2], ref_mat, cv::noArray(), type);
cv::subtract(ref_mat, in_mat[1], ref_mat, cv::noArray(), type);
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
}
TEST(GAPI_PlaidML_Pipelines, TwoOutputOperations)
{
cv::Size size(1920, 1080);
int type = CV_8UC1;
constexpr int kNumInputs = 4;
std::vector<cv::Mat> in_mat(kNumInputs, cv::Mat(size, type));
for (int i = 0; i < kNumInputs; ++i)
{
cv::randu(in_mat[i], cv::Scalar::all(0), cv::Scalar::all(60));
}
std::vector<cv::Mat> out_mat(kNumInputs, cv::Mat(size, type, cv::Scalar::all(0)));
std::vector<cv::Mat> ref_mat(kNumInputs, cv::Mat(size, type, cv::Scalar::all(0)));
////////////////////////////// G-API //////////////////////////////////////
cv::GMat in[4], out[2];
out[0] = in[0] + in[3];
out[1] = in[1] + in[2];
cv::GComputation comp(cv::GIn(in[0], in[1], in[2], in[3]), cv::GOut(out[0], out[1]));
// FIXME Doesn't work just apply(in_mat, out_mat, ...)
comp.apply(cv::gin(in_mat[0], in_mat[1], in_mat[2], in_mat[3]),
cv::gout(out_mat[0], out_mat[1]),
cv::compile_args(getConfig(),
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
////////////////////////////// OpenCV /////////////////////////////////////
cv::add(in_mat[0], in_mat[3], ref_mat[0], cv::noArray(), type);
cv::add(in_mat[1], in_mat[2], ref_mat[1], cv::noArray(), type);
EXPECT_EQ(0, cv::norm(out_mat[0], ref_mat[0]));
EXPECT_EQ(0, cv::norm(out_mat[1], ref_mat[1]));
}
} // namespace opencv_test
#endif // HAVE_PLAIDML
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
#include <ade/util/iota_range.hpp> #include <ade/util/iota_range.hpp>
#include "logger.hpp" #include "logger.hpp"
#include <opencv2/gapi/render/render.hpp> #include <opencv2/gapi/plaidml/core.hpp>
namespace opencv_test namespace opencv_test
{ {
...@@ -315,4 +316,5 @@ TEST(GAPI_Pipeline, CanUseOwnMatAsOutput) ...@@ -315,4 +316,5 @@ TEST(GAPI_Pipeline, CanUseOwnMatAsOutput)
// FIXME add overload for apply(cv::gapi::own::Mat in, cv::gapi::own::Mat& out) // FIXME add overload for apply(cv::gapi::own::Mat in, cv::gapi::own::Mat& out)
EXPECT_NO_THROW(comp.apply({in_own_mat}, {out_own_mat})); EXPECT_NO_THROW(comp.apply({in_own_mat}, {out_own_mat}));
} }
} // namespace opencv_test } // namespace opencv_test
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment