Ov20/preprocess base python (#7625)
* Preprocessing API - base classes Includes API definition for trivial mean/scale operations (which don't require layout) Mean/scale with 'layout' support will be done under separate task together with Layout Current test code coverage: 100% * Python bindings for base preprocessing API * remove pre_post_process directory from ngraph/core * remove files from ngraph/python dir * move pyngraph pre_post_process files from ngraph/python to runtime * remove pre_post_process test from CMakeList * move include to the header * update include path for pre_post_process * style fix * bind InputTensorInfo::set_layout * cleaned test_preprocess * fix test expected output * remove duplicate test * update description of set_element_type * fix style * move preprocess from pyngraph to pyopenvino/graph * update test_preprocess imports and remove unnecessary test * remove duplicate import * update custom method * update test * update test * create decorator that changes Node into Output<Node> * create function that cast Node to Output<Node> * update test_preprocess to use decorator for custom function * change _cast_to_output -> _from_node * style fix * add tests fro scale and mean with vector input * style fix * add docstring for custom_preprocess_function * bind InputInfo network method * style fix * bind OutputInfo * fix description of preprocess submodule * fix style * update copyright year * bind OutputTensorInfo * bind OutputNetworkInfo and InputNetworkInfo * bind ColorFormat and ResizeAlgorithm * clean imports * fix typo * add PostProcessSteps to init * bind PreProcessSteps * create additional tests * change ngraph.Type to ov.Type * fix typo * move _from_node to node_output.hpp * add read_model from buffer * update imports * add new line * remove bad quotes * update imports * style fix * add new line * rename functin args * remove Type import * update tests * style fix * test clean * remove blank line * update PrePostProcessor init and build methods * create test with model update tests with new PrePostProcessor init and build * move preprocess module from openvino.impl to openvino Co-authored-by: Michael Nosov <mikhail.nosov@intel.com> Co-authored-by: bszmelcz <bartosz.szmelczynski@intel.com>
This commit is contained in:
7 files changed
+1014
-1
No files matched your search
@@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
Package: ngraph
|
||||
Low level wrappers for the PrePostProcessing c++ api.
|
||||
"""
|
||||
|
||||
# flake8: noqa
|
||||
|
||||
# main classes
|
||||
from openvino.pyopenvino.preprocess import InputInfo
|
||||
from openvino.pyopenvino.preprocess import OutputInfo
|
||||
from openvino.pyopenvino.preprocess import InputTensorInfo
|
||||
from openvino.pyopenvino.preprocess import OutputTensorInfo
|
||||
from openvino.pyopenvino.preprocess import InputNetworkInfo
|
||||
from openvino.pyopenvino.preprocess import OutputNetworkInfo
|
||||
from openvino.pyopenvino.preprocess import PrePostProcessor
|
||||
from openvino.pyopenvino.preprocess import PreProcessSteps
|
||||
from openvino.pyopenvino.preprocess import PostProcessSteps
|
||||
from openvino.pyopenvino.preprocess import ColorFormat
|
||||
from openvino.pyopenvino.preprocess import ResizeAlgorithm
|
||||
@@ -4,7 +4,7 @@
|
||||
from functools import wraps
|
||||
from typing import Any, Callable
|
||||
|
||||
from openvino.impl import Node
|
||||
from openvino.impl import Node, Output
|
||||
from openvino.utils.types import NodeInput, as_node, as_nodes
|
||||
|
||||
|
||||
@@ -50,3 +50,12 @@ def binary_op(node_factory_function: Callable) -> Callable:
|
||||
return node
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def custom_preprocess_function(custom_function: Callable) -> Callable:
|
||||
"""Convert Node returned from custom_function to Output."""
|
||||
@wraps(custom_function)
|
||||
def wrapper(node: Node) -> Output:
|
||||
return Output._from_node(custom_function(node))
|
||||
|
||||
return wrapper
|
||||
@@ -81,6 +81,9 @@ void regclass_graph_Output(py::module m, std::string typestring)
|
||||
get_target_inputs : Set[Input]
|
||||
Set of Inputs.
|
||||
)");
|
||||
output.def("_from_node", [](const std::shared_ptr<ov::Node>& node) {
|
||||
return ov::Output<ov::Node>(node);
|
||||
});
|
||||
output.def("get_tensor",
|
||||
&ov::Output<VT>::get_tensor,
|
||||
py::return_value_policy::reference_internal,
|
||||
|
||||
@@ -0,0 +1,540 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "pyopenvino/graph/preprocess/pre_post_process.hpp"
|
||||
|
||||
#include <pybind11/functional.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include "openvino/core/function.hpp"
|
||||
#include "openvino/core/node.hpp"
|
||||
#include "openvino/core/preprocess/pre_post_process.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
static void regclass_graph_PreProcessSteps(py::module m) {
|
||||
py::class_<ov::preprocess::PreProcessSteps, std::shared_ptr<ov::preprocess::PreProcessSteps>> steps(
|
||||
m,
|
||||
"PreProcessSteps");
|
||||
steps.doc() = "openvino.impl.preprocess.PreProcessSteps wraps ov::preprocess::PreProcessSteps";
|
||||
|
||||
steps.def(py::init<>());
|
||||
|
||||
steps.def(
|
||||
"mean",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, float value) {
|
||||
me->mean(value);
|
||||
return me;
|
||||
},
|
||||
py::arg("value"),
|
||||
R"(
|
||||
Subtracts single float value from each element in input tensor.
|
||||
Input tensor must have ov.Type.f32 data type.
|
||||
Parameters
|
||||
----------
|
||||
value : float
|
||||
Value to subtract.
|
||||
Returns
|
||||
----------
|
||||
mean : PreProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"mean",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, const std::vector<float>& values) {
|
||||
me->mean(values);
|
||||
return me;
|
||||
},
|
||||
py::arg("values"),
|
||||
R"(
|
||||
Subtracts a given single float value from each element in a given channel from input tensor.
|
||||
Input tensor must have ov.Type.f32 data type.
|
||||
Parameters
|
||||
----------
|
||||
values : List
|
||||
Values to subtract.
|
||||
Returns
|
||||
----------
|
||||
mean : PreProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"scale",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, float value) {
|
||||
me->scale(value);
|
||||
return me;
|
||||
},
|
||||
py::arg("value"),
|
||||
R"(
|
||||
Divides each element in input tensor by specified constant float value.
|
||||
Input tensor must have ov.Type.f32 data type.
|
||||
Parameters
|
||||
----------
|
||||
value : float
|
||||
Value to divide.
|
||||
Returns
|
||||
----------
|
||||
scale : PreProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"scale",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, const std::vector<float>& values) {
|
||||
me->scale(values);
|
||||
return me;
|
||||
},
|
||||
py::arg("values"),
|
||||
R"(
|
||||
Divides each element in a given channel from input tensor by a given single float value.
|
||||
Input tensor must have ov.Type.f32 data type.
|
||||
Parameters
|
||||
----------
|
||||
value : List
|
||||
Value to divide.
|
||||
Returns
|
||||
----------
|
||||
scale : PreProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"convert_element_type",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, ov::element::Type type) {
|
||||
me->convert_element_type(type);
|
||||
return me;
|
||||
},
|
||||
py::arg("type"),
|
||||
R"(
|
||||
Converts input tensor element type to specified type.
|
||||
Input tensor must have openvino.Type.f32 data type.
|
||||
Parameters
|
||||
----------
|
||||
type : Type
|
||||
Destination type.
|
||||
Returns
|
||||
----------
|
||||
convert_element_type : PreProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"custom",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, py::function op) {
|
||||
me->custom(op.cast<const ov::preprocess::PreProcessSteps::CustomPreprocessOp>());
|
||||
return me;
|
||||
},
|
||||
py::arg("operation"),
|
||||
R"(
|
||||
Adds custom preprocessing operation.
|
||||
Parameters
|
||||
----------
|
||||
operation : function taking Output<Node> as input argument and returning Output<Node> after preprocessing.
|
||||
Returns
|
||||
----------
|
||||
custom : PreProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"convert_color",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, const ov::preprocess::ColorFormat& dst_format) {
|
||||
me->convert_color(dst_format);
|
||||
return me;
|
||||
},
|
||||
py::arg("dst_format"));
|
||||
steps.def(
|
||||
"resize",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me,
|
||||
ov::preprocess::ResizeAlgorithm alg,
|
||||
size_t dst_height,
|
||||
size_t dst_width) {
|
||||
me->resize(alg, dst_height, dst_width);
|
||||
return me;
|
||||
},
|
||||
py::arg("alg"),
|
||||
py::arg("dst_height"),
|
||||
py::arg("dst_width"));
|
||||
steps.def(
|
||||
"resize",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, ov::preprocess::ResizeAlgorithm alg) {
|
||||
me->resize(alg);
|
||||
return me;
|
||||
},
|
||||
py::arg("alg"));
|
||||
steps.def(
|
||||
"convert_layout",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, const ov::Layout& layout = {}) {
|
||||
me->convert_layout(layout);
|
||||
return me;
|
||||
},
|
||||
py::arg("dst_layout"));
|
||||
steps.def(
|
||||
"convert_layout",
|
||||
[](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me, const std::vector<uint64_t>& dims) {
|
||||
me->convert_layout(dims);
|
||||
return me;
|
||||
},
|
||||
py::arg("dims"));
|
||||
steps.def("reverse_channels", [](const std::shared_ptr<ov::preprocess::PreProcessSteps>& me) {
|
||||
me->reverse_channels();
|
||||
return me;
|
||||
});
|
||||
}
|
||||
|
||||
static void regclass_graph_PostProcessSteps(py::module m) {
|
||||
py::class_<ov::preprocess::PostProcessSteps, std::shared_ptr<ov::preprocess::PostProcessSteps>> steps(
|
||||
m,
|
||||
"PostProcessSteps");
|
||||
steps.doc() = "openvino.impl.preprocess.PostprocessSteps wraps ov::preprocess::PostProcessSteps";
|
||||
|
||||
steps.def(py::init<>());
|
||||
|
||||
steps.def(
|
||||
"convert_element_type",
|
||||
[](const std::shared_ptr<ov::preprocess::PostProcessSteps>& me, ov::element::Type type) {
|
||||
me->convert_element_type(type);
|
||||
return me;
|
||||
},
|
||||
py::arg("type"),
|
||||
R"(
|
||||
Converts tensor element type to specified type.
|
||||
Tensor must have openvino.Type.f32 data type.
|
||||
Parameters
|
||||
----------
|
||||
type : Type
|
||||
Destination type.
|
||||
Returns
|
||||
----------
|
||||
convert_element_type : PostProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
steps.def(
|
||||
"convert_layout",
|
||||
[](const std::shared_ptr<ov::preprocess::PostProcessSteps>& me, const ov::Layout& layout = {}) {
|
||||
me->convert_layout(layout);
|
||||
return me;
|
||||
},
|
||||
py::arg("dst_layout"));
|
||||
steps.def(
|
||||
"convert_layout",
|
||||
[](const std::shared_ptr<ov::preprocess::PostProcessSteps>& me, const std::vector<uint64_t>& dims) {
|
||||
me->convert_layout(dims);
|
||||
return me;
|
||||
},
|
||||
py::arg("dims"));
|
||||
steps.def(
|
||||
"custom",
|
||||
[](const std::shared_ptr<ov::preprocess::PostProcessSteps>& me, py::function op) {
|
||||
me->custom(op.cast<const ov::preprocess::PostProcessSteps::CustomPostprocessOp>());
|
||||
return me;
|
||||
},
|
||||
py::arg("operation"),
|
||||
R"(
|
||||
Adds custom postprocessing operation.
|
||||
Parameters
|
||||
----------
|
||||
operation : function taking Output<Node> as input argument and returning Output<Node> after postprocessing.
|
||||
Returns
|
||||
----------
|
||||
custom : PostProcessSteps
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
}
|
||||
|
||||
static void regclass_graph_InputTensorInfo(py::module m) {
|
||||
py::class_<ov::preprocess::InputTensorInfo, std::shared_ptr<ov::preprocess::InputTensorInfo>> info(
|
||||
m,
|
||||
"InputTensorInfo");
|
||||
info.doc() = "openvino.impl.preprocess.InputTensorInfo wraps ov::preprocess::InputTensorInfo";
|
||||
|
||||
info.def(py::init<>());
|
||||
|
||||
info.def(
|
||||
"set_element_type",
|
||||
[](const std::shared_ptr<ov::preprocess::InputTensorInfo>& me, const ov::element::Type& type) {
|
||||
me->set_element_type(type);
|
||||
return me;
|
||||
},
|
||||
py::arg("type"),
|
||||
R"(
|
||||
Set initial client's tensor element type. If type is not the same as network's element type,
|
||||
conversion of element type will be done automatically.
|
||||
Parameters
|
||||
----------
|
||||
type : Type
|
||||
Client's input tensor element type.
|
||||
Returns
|
||||
----------
|
||||
tensor : InputTensorInfo
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
info.def("set_layout", [](const std::shared_ptr<ov::preprocess::InputTensorInfo>& me, const ov::Layout& layout) {
|
||||
me->set_layout(layout);
|
||||
return me;
|
||||
});
|
||||
info.def("set_spatial_dynamic_shape", [](const std::shared_ptr<ov::preprocess::InputTensorInfo>& me) {
|
||||
me->set_spatial_dynamic_shape();
|
||||
return me;
|
||||
});
|
||||
info.def("set_spatial_static_shape",
|
||||
[](const std::shared_ptr<ov::preprocess::InputTensorInfo>& me, size_t height, size_t width) {
|
||||
me->set_spatial_static_shape(height, width);
|
||||
return me;
|
||||
});
|
||||
info.def("set_color_format",
|
||||
[](const std::shared_ptr<ov::preprocess::InputTensorInfo>& me,
|
||||
const ov::preprocess::ColorFormat& format,
|
||||
const std::vector<std::string>& sub_names = {}) {
|
||||
me->set_color_format(format, sub_names);
|
||||
return me;
|
||||
});
|
||||
}
|
||||
|
||||
static void regclass_graph_OutputTensorInfo(py::module m) {
|
||||
py::class_<ov::preprocess::OutputTensorInfo, std::shared_ptr<ov::preprocess::OutputTensorInfo>> info(
|
||||
m,
|
||||
"OutputTensorInfo");
|
||||
info.doc() = "openvino.impl.preprocess.OutputTensorInfo wraps ov::preprocess::OutputTensorInfo";
|
||||
|
||||
info.def(py::init<>());
|
||||
|
||||
info.def(
|
||||
"set_element_type",
|
||||
[](const std::shared_ptr<ov::preprocess::OutputTensorInfo>& me, const ov::element::Type& type) {
|
||||
me->set_element_type(type);
|
||||
return me;
|
||||
},
|
||||
py::arg("type"),
|
||||
R"(
|
||||
Set client's output tensor element type. If type is not the same as network's element type,
|
||||
conversion of element type will be done automatically.
|
||||
Parameters
|
||||
----------
|
||||
type : Type
|
||||
Client's output tensor element type.
|
||||
Returns
|
||||
----------
|
||||
tensor : OutputTensorInfo
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
info.def("set_layout", [](const std::shared_ptr<ov::preprocess::OutputTensorInfo>& me, const ov::Layout& layout) {
|
||||
me->set_layout(layout);
|
||||
return me;
|
||||
});
|
||||
}
|
||||
|
||||
static void regclass_graph_InputInfo(py::module m) {
|
||||
py::class_<ov::preprocess::InputInfo, std::shared_ptr<ov::preprocess::InputInfo>> inp(m, "InputInfo");
|
||||
inp.doc() = "openvino.impl.preprocess.InputInfo wraps ov::preprocess::InputInfo";
|
||||
|
||||
inp.def(py::init<>(), R"(Default constructor, can be used only for networks with exactly one input)");
|
||||
inp.def(py::init<size_t>(), R"(Constructor with parameter index as argument)");
|
||||
inp.def(py::init<const std::string&>(), R"(Constructor with input tensor name as argument)");
|
||||
|
||||
inp.def(
|
||||
"tensor",
|
||||
[](const std::shared_ptr<ov::preprocess::InputInfo>& me,
|
||||
const std::shared_ptr<ov::preprocess::InputTensorInfo>& inputTensorInfo) {
|
||||
me->tensor(std::move(*inputTensorInfo));
|
||||
return me;
|
||||
},
|
||||
py::arg("tensor"),
|
||||
R"(
|
||||
Adds builder for actual tensor information of client's input.
|
||||
Parameters
|
||||
----------
|
||||
tensor : InputTensorInfo
|
||||
Client's input tensor information. It's internal data will be moved to parent InputInfo object.
|
||||
Returns
|
||||
----------
|
||||
tensor : InputInfo
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
inp.def(
|
||||
"preprocess",
|
||||
[](const std::shared_ptr<ov::preprocess::InputInfo>& me,
|
||||
const std::shared_ptr<ov::preprocess::PreProcessSteps>& preProcessSteps) {
|
||||
me->preprocess(std::move(*preProcessSteps));
|
||||
return me;
|
||||
},
|
||||
py::arg("pre_process_steps"),
|
||||
R"(
|
||||
Adds builder for actual preprocessing steps for input parameter.
|
||||
Steps can specify various actions, like 'mean', 'scale' and others.
|
||||
Parameters
|
||||
----------
|
||||
pre_process_steps : PreProcessSteps
|
||||
Preprocessing steps. It's internal data will be moved to parent InputInfo object.
|
||||
Returns
|
||||
----------
|
||||
preprocess : InputInfo
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
inp.def(
|
||||
"network",
|
||||
[](const std::shared_ptr<ov::preprocess::InputInfo>& me,
|
||||
const std::shared_ptr<ov::preprocess::InputNetworkInfo>& inputNetworkInfo) {
|
||||
me->network(std::move(*inputNetworkInfo));
|
||||
return me;
|
||||
},
|
||||
py::arg("input_network_info"));
|
||||
}
|
||||
|
||||
static void regclass_graph_OutputInfo(py::module m) {
|
||||
py::class_<ov::preprocess::OutputInfo, std::shared_ptr<ov::preprocess::OutputInfo>> out(m, "OutputInfo");
|
||||
out.doc() = "openvino.impl.preprocess.OutputInfo wraps ov::preprocess::OutputInfo";
|
||||
|
||||
out.def(py::init<>(), R"(Default constructor, can be used only for networks with exactly one output)");
|
||||
out.def(py::init<size_t>(), R"(Constructor with parameter index as argument)");
|
||||
out.def(py::init<const std::string&>(), R"(Constructor with tensor name as argument)");
|
||||
|
||||
out.def(
|
||||
"tensor",
|
||||
[](const std::shared_ptr<ov::preprocess::OutputInfo>& me,
|
||||
const std::shared_ptr<ov::preprocess::OutputTensorInfo>& outputTensorInfo) {
|
||||
me->tensor(std::move(*outputTensorInfo));
|
||||
return me;
|
||||
},
|
||||
py::arg("tensor"),
|
||||
R"(
|
||||
Adds builder for actual tensor information of client's output.
|
||||
Parameters
|
||||
----------
|
||||
tensor : OutputTensorInfo
|
||||
Client's output tensor information. It's internal data will be moved to parent OutputInfo object.
|
||||
Returns
|
||||
----------
|
||||
tensor : OutputInfo
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
out.def(
|
||||
"postprocess",
|
||||
[](const std::shared_ptr<ov::preprocess::OutputInfo>& me,
|
||||
const std::shared_ptr<ov::preprocess::PostProcessSteps>& postProcessSteps) {
|
||||
me->postprocess(std::move(*postProcessSteps));
|
||||
return me;
|
||||
},
|
||||
py::arg("post_process_steps"),
|
||||
R"(
|
||||
Adds builder for actual postprocessing steps for output parameter.
|
||||
Parameters
|
||||
----------
|
||||
post_process_steps : PostProcessSteps
|
||||
Postprocessing steps. It's internal data will be moved to parent OutputInfo object.
|
||||
Returns
|
||||
----------
|
||||
preprocess : OutputInfo
|
||||
Reference to itself to allow chaining of calls in client's code in a builder-like manner.
|
||||
)");
|
||||
out.def(
|
||||
"network",
|
||||
[](const std::shared_ptr<ov::preprocess::OutputInfo>& me,
|
||||
const std::shared_ptr<ov::preprocess::OutputNetworkInfo>& outputNetworkInfo) {
|
||||
me->network(std::move(*outputNetworkInfo));
|
||||
return me;
|
||||
},
|
||||
py::arg("output_network_info"));
|
||||
}
|
||||
|
||||
static void regclass_graph_OutputNetworkInfo(py::module m) {
|
||||
py::class_<ov::preprocess::OutputNetworkInfo, std::shared_ptr<ov::preprocess::OutputNetworkInfo>> info(
|
||||
m,
|
||||
"OutputNetworkInfo");
|
||||
info.doc() = "openvino.impl.preprocess.OutputNetworkInfo wraps ov::preprocess::OutputNetworkInfo";
|
||||
|
||||
info.def(py::init<>());
|
||||
|
||||
info.def("set_layout", [](const std::shared_ptr<ov::preprocess::OutputNetworkInfo>& me, const ov::Layout& layout) {
|
||||
me->set_layout(layout);
|
||||
return me;
|
||||
});
|
||||
}
|
||||
|
||||
static void regclass_graph_InputNetworkInfo(py::module m) {
|
||||
py::class_<ov::preprocess::InputNetworkInfo, std::shared_ptr<ov::preprocess::InputNetworkInfo>> info(
|
||||
m,
|
||||
"InputNetworkInfo");
|
||||
info.doc() = "openvino.impl.preprocess.InputNetworkInfo wraps ov::preprocess::InputNetworkInfo";
|
||||
|
||||
info.def(py::init<>());
|
||||
|
||||
info.def("set_layout", [](const std::shared_ptr<ov::preprocess::InputNetworkInfo>& me, const ov::Layout& layout) {
|
||||
me->set_layout(layout);
|
||||
return me;
|
||||
});
|
||||
}
|
||||
|
||||
static void regenum_graph_ColorFormat(py::module m) {
|
||||
py::enum_<ov::preprocess::ColorFormat>(m, "ColorFormat")
|
||||
.value("UNDEFINED", ov::preprocess::ColorFormat::UNDEFINED)
|
||||
.value("NV12_SINGLE_PLANE", ov::preprocess::ColorFormat::NV12_SINGLE_PLANE)
|
||||
.value("NV12_TWO_PLANES", ov::preprocess::ColorFormat::NV12_TWO_PLANES)
|
||||
.value("RGB", ov::preprocess::ColorFormat::RGB)
|
||||
.value("BGR", ov::preprocess::ColorFormat::BGR)
|
||||
.export_values();
|
||||
}
|
||||
|
||||
static void regenum_graph_ResizeAlgorithm(py::module m) {
|
||||
py::enum_<ov::preprocess::ResizeAlgorithm>(m, "ResizeAlgorithm")
|
||||
.value("RESIZE_LINEAR", ov::preprocess::ResizeAlgorithm::RESIZE_LINEAR)
|
||||
.value("RESIZE_CUBIC", ov::preprocess::ResizeAlgorithm::RESIZE_CUBIC)
|
||||
.value("RESIZE_NEAREST", ov::preprocess::ResizeAlgorithm::RESIZE_NEAREST)
|
||||
.export_values();
|
||||
}
|
||||
|
||||
void regclass_graph_PrePostProcessor(py::module m) {
|
||||
regclass_graph_PreProcessSteps(m);
|
||||
regclass_graph_PostProcessSteps(m);
|
||||
regclass_graph_InputInfo(m);
|
||||
regclass_graph_OutputInfo(m);
|
||||
regclass_graph_InputTensorInfo(m);
|
||||
regclass_graph_OutputTensorInfo(m);
|
||||
regclass_graph_InputNetworkInfo(m);
|
||||
regclass_graph_OutputNetworkInfo(m);
|
||||
regenum_graph_ColorFormat(m);
|
||||
regenum_graph_ResizeAlgorithm(m);
|
||||
py::class_<ov::preprocess::PrePostProcessor, std::shared_ptr<ov::preprocess::PrePostProcessor>> proc(
|
||||
m,
|
||||
"PrePostProcessor");
|
||||
proc.doc() = "openvino.impl.preprocess.PrePostProcessor wraps ov::preprocess::PrePostProcessor";
|
||||
|
||||
proc.def(py::init<const std::shared_ptr<ov::Function>&>());
|
||||
|
||||
proc.def(
|
||||
"input",
|
||||
[](const std::shared_ptr<ov::preprocess::PrePostProcessor>& me,
|
||||
const std::shared_ptr<ov::preprocess::InputInfo>& info) {
|
||||
me->input(std::move(*info));
|
||||
return me;
|
||||
},
|
||||
py::arg("input_info"),
|
||||
R"(
|
||||
Adds builder for preprocessing info for input parameter.
|
||||
Parameters
|
||||
----------
|
||||
input_info : InputInfo
|
||||
Preprocessing info for input parameter. It's internal data will be moved to PreProcessing object.
|
||||
Returns
|
||||
----------
|
||||
in : PrePostProcessor
|
||||
Reference to itself to allow chaining of calls in client's code.
|
||||
)");
|
||||
proc.def(
|
||||
"output",
|
||||
[](const std::shared_ptr<ov::preprocess::PrePostProcessor>& me,
|
||||
const std::shared_ptr<ov::preprocess::OutputInfo>& info) {
|
||||
me->output(std::move(*info));
|
||||
return me;
|
||||
},
|
||||
py::arg("output_info"),
|
||||
R"(
|
||||
Adds builder for preprocessing info for output parameter.
|
||||
Parameters
|
||||
----------
|
||||
output_info : OutputInfo
|
||||
Preprocessing info for output parameter. It's internal data will be moved to PreProcessing object.
|
||||
Returns
|
||||
----------
|
||||
in : PrePostProcessor
|
||||
Reference to itself to allow chaining of calls in client's code.
|
||||
)");
|
||||
proc.def("build", &ov::preprocess::PrePostProcessor::build);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
void regclass_graph_PrePostProcessor(py::module m);
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "pyopenvino/graph/ops/util/regmodule_graph_op_util.hpp"
|
||||
#include "pyopenvino/graph/partial_shape.hpp"
|
||||
#include "pyopenvino/graph/passes/regmodule_graph_passes.hpp"
|
||||
#include "pyopenvino/graph/preprocess/pre_post_process.hpp"
|
||||
#include "pyopenvino/graph/rt_map.hpp"
|
||||
#include "pyopenvino/graph/shape.hpp"
|
||||
#include "pyopenvino/graph/strides.hpp"
|
||||
@@ -85,6 +86,9 @@ PYBIND11_MODULE(pyopenvino, m) {
|
||||
regmodule_graph_onnx_import(m);
|
||||
#endif
|
||||
regmodule_graph_op_util(m_op);
|
||||
py::module m_preprocess =
|
||||
m.def_submodule("preprocess", "Package openvino.impl.preprocess that wraps ov::preprocess");
|
||||
regclass_graph_PrePostProcessor(m_preprocess);
|
||||
regclass_graph_Function(m);
|
||||
regmodule_graph_passes(m);
|
||||
regmodule_graph_util(m);
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import openvino as ov
|
||||
import openvino.opset8 as ops
|
||||
from openvino.impl import Function, Output, Type
|
||||
from openvino.utils.decorators import custom_preprocess_function
|
||||
from openvino import Core
|
||||
from tests.runtime import get_runtime
|
||||
from openvino.preprocess import PrePostProcessor, InputInfo, PreProcessSteps, InputTensorInfo, \
|
||||
OutputTensorInfo, OutputNetworkInfo, InputNetworkInfo, ColorFormat, OutputInfo, \
|
||||
PostProcessSteps, ResizeAlgorithm
|
||||
|
||||
|
||||
def test_ngraph_preprocess_mean():
|
||||
shape = [2, 2]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.preprocess(PreProcessSteps()
|
||||
.mean(1.)
|
||||
)
|
||||
)\
|
||||
.build()
|
||||
|
||||
input_data = np.array([[1, 2], [3, 4]]).astype(np.float32)
|
||||
expected_output = np.array([[0, 1], [2, 3]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_mean_vector():
|
||||
shape = [2, 2]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout = ov.Layout("NCHW")
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo().set_layout(layout))
|
||||
.preprocess(PreProcessSteps()
|
||||
.mean([1., 2.])
|
||||
)
|
||||
)\
|
||||
.build()
|
||||
|
||||
input_data = np.array([[1, 2], [3, 4]]).astype(np.float32)
|
||||
expected_output = np.array([[0, 0], [2, 2]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_scale_vector():
|
||||
shape = [2, 2]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout = ov.Layout("NCHW")
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo().set_layout(layout))
|
||||
.preprocess(PreProcessSteps()
|
||||
.scale([0.5, 2.])
|
||||
)
|
||||
)\
|
||||
.build()
|
||||
|
||||
input_data = np.array([[1, 2], [3, 4]]).astype(np.float32)
|
||||
expected_output = np.array([[2, 1], [6, 2]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_mean_scale_convert():
|
||||
shape = [2, 2]
|
||||
param1 = ops.parameter(shape, dtype=np.int32, name="A")
|
||||
param2 = ops.parameter(shape, dtype=np.int32, name="B")
|
||||
function = Function([param1, param2], [param1, param2], "TestFunction")
|
||||
|
||||
@custom_preprocess_function
|
||||
def custom_preprocess(output: Output):
|
||||
return ops.abs(output)
|
||||
|
||||
function = PrePostProcessor(function) \
|
||||
.input(InputInfo(1)
|
||||
.tensor(InputTensorInfo()
|
||||
.set_element_type(Type.i32))
|
||||
.preprocess(PreProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.mean(1.)
|
||||
.scale(2.)
|
||||
)
|
||||
) \
|
||||
.input(InputInfo(0)
|
||||
.preprocess(PreProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.mean(1.)
|
||||
.custom(custom_preprocess)
|
||||
)
|
||||
) \
|
||||
.build()
|
||||
|
||||
input_data1 = np.array([[0, 1], [2, -2]]).astype(np.int32)
|
||||
input_data2 = np.array([[1, 3], [5, 7]]).astype(np.int32)
|
||||
expected_output1 = np.array([[1, 0], [1, 3]]).astype(np.float32)
|
||||
expected_output2 = np.array([[0, 1], [2, 3]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
[output1, output2] = computation(input_data1, input_data2)
|
||||
assert np.equal(output1, expected_output1).all()
|
||||
assert np.equal(output2, expected_output2).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_output_postprocess():
|
||||
shape = [2, 2]
|
||||
parameter_a = ops.parameter(shape, dtype=np.int32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout1 = ov.Layout("NCHW")
|
||||
layout2 = ov.Layout("NHWC")
|
||||
layout3 = [0, 1]
|
||||
|
||||
@custom_preprocess_function
|
||||
def custom_postprocess(output: Output):
|
||||
return ops.abs(output)
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo().set_layout(layout1))
|
||||
.preprocess(PreProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.mean([1., 2.])
|
||||
)
|
||||
) \
|
||||
.output(OutputInfo().postprocess(PostProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.convert_layout(layout2)
|
||||
.convert_layout(layout3)
|
||||
.custom(custom_postprocess))) \
|
||||
.build()
|
||||
|
||||
input_data = np.array([[-1, -2], [-3, -4]]).astype(np.int32)
|
||||
expected_output = np.array([[2, 4], [4, 6]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_spatial_static_shape():
|
||||
shape = [2, 2, 2]
|
||||
parameter_a = ops.parameter(shape, dtype=np.int32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout = ov.Layout("CHW")
|
||||
|
||||
color_format = ColorFormat.RGB
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo()
|
||||
.set_layout(layout)
|
||||
.set_spatial_static_shape(2, 2)
|
||||
.set_color_format(color_format, []))
|
||||
.preprocess(PreProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.mean([1., 2])
|
||||
)
|
||||
.network(InputNetworkInfo().set_layout(layout))
|
||||
) \
|
||||
.output(OutputInfo()
|
||||
.tensor(OutputTensorInfo()
|
||||
.set_layout(layout)
|
||||
.set_element_type(Type.f32))
|
||||
.network(OutputNetworkInfo().set_layout(layout))) \
|
||||
.build()
|
||||
|
||||
input_data = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]).astype(np.int32)
|
||||
expected_output = np.array([[[0, 1], [2, 3]], [[3, 4], [5, 6]]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"algorithm, color_format1, color_format2, is_failing",
|
||||
[(ResizeAlgorithm.RESIZE_LINEAR, ColorFormat.UNDEFINED, ColorFormat.BGR, True),
|
||||
(ResizeAlgorithm.RESIZE_LINEAR, ColorFormat.RGB, ColorFormat.NV12_SINGLE_PLANE, True),
|
||||
(ResizeAlgorithm.RESIZE_LINEAR, ColorFormat.RGB, ColorFormat.NV12_TWO_PLANES, True),
|
||||
(ResizeAlgorithm.RESIZE_CUBIC, ColorFormat.RGB, ColorFormat.UNDEFINED, True),
|
||||
(ResizeAlgorithm.RESIZE_CUBIC, ColorFormat.RGB, ColorFormat.BGR, False),
|
||||
(ResizeAlgorithm.RESIZE_CUBIC, ColorFormat.BGR, ColorFormat.RGB, False),
|
||||
(ResizeAlgorithm.RESIZE_NEAREST, ColorFormat.BGR, ColorFormat.NV12_SINGLE_PLANE, True),
|
||||
(ResizeAlgorithm.RESIZE_NEAREST, ColorFormat.BGR, ColorFormat.NV12_TWO_PLANES, True),
|
||||
(ResizeAlgorithm.RESIZE_NEAREST, ColorFormat.BGR, ColorFormat.UNDEFINED, True)])
|
||||
def test_ngraph_preprocess_steps(algorithm, color_format1, color_format2, is_failing):
|
||||
shape = [1, 1, 3, 3]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout1 = ov.Layout("NCWH")
|
||||
layout2 = ov.Layout("NCHW")
|
||||
custom_processor = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo()
|
||||
.set_layout(layout1)
|
||||
.set_color_format(color_format1, []))
|
||||
.preprocess(PreProcessSteps()
|
||||
.mean(1.)
|
||||
.resize(algorithm, 3, 3)
|
||||
.convert_layout(layout2)
|
||||
.convert_color(color_format2)))
|
||||
if is_failing:
|
||||
with pytest.raises(RuntimeError) as e:
|
||||
function = custom_processor.build()
|
||||
assert "is not convertible to" in str(e.value)
|
||||
else:
|
||||
function = custom_processor.build()
|
||||
input_data = np.array([[[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]]).astype(np.float32)
|
||||
expected_output = np.array([[[[0, 3, 6], [1, 4, 7], [2, 5, 8]]]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_postprocess_layout():
|
||||
shape = [1, 1, 3, 3]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout1 = ov.Layout("NCWH")
|
||||
layout2 = ov.Layout("NCHW")
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo()
|
||||
.set_layout(layout1))
|
||||
.preprocess(PreProcessSteps()
|
||||
.mean(1.)
|
||||
.convert_layout(layout2)
|
||||
.reverse_channels()
|
||||
)
|
||||
) \
|
||||
.output(OutputInfo()
|
||||
.postprocess(PostProcessSteps()
|
||||
.convert_layout([0, 1, 2, 3]))) \
|
||||
.build()
|
||||
|
||||
input_data = np.array([[[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]]).astype(np.float32)
|
||||
expected_output = np.array([[[[0, 3, 6], [1, 4, 7], [2, 5, 8]]]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_reverse_channels():
|
||||
shape = [1, 2, 2, 2]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
layout1 = ov.Layout("NCWH")
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo()
|
||||
.set_layout(layout1))
|
||||
.preprocess(PreProcessSteps()
|
||||
.mean(1.)
|
||||
.reverse_channels()
|
||||
)
|
||||
) \
|
||||
.build()
|
||||
|
||||
input_data = np.array([[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]]).astype(np.float32)
|
||||
expected_output = np.array([[[[4, 5], [6, 7]], [[0, 1], [2, 3]]]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_resize_algorithm():
|
||||
shape = [1, 1, 3, 3]
|
||||
parameter_a = ops.parameter(shape, dtype=np.float32, name="A")
|
||||
model = parameter_a
|
||||
function = Function(model, [parameter_a], "TestFunction")
|
||||
resize_alg = ResizeAlgorithm.RESIZE_CUBIC
|
||||
layout1 = ov.Layout("NCWH")
|
||||
|
||||
function = PrePostProcessor(function)\
|
||||
.input(InputInfo()
|
||||
.tensor(InputTensorInfo()
|
||||
.set_layout(layout1))
|
||||
.preprocess(PreProcessSteps()
|
||||
.mean(1.)
|
||||
.resize(resize_alg, 3, 3))
|
||||
)\
|
||||
.build()
|
||||
|
||||
input_data = np.array([[[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]]).astype(np.float32)
|
||||
expected_output = np.array([[[[0, 1, 2], [3, 4, 5], [6, 7, 8]]]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data)
|
||||
assert np.equal(output, expected_output).all()
|
||||
|
||||
|
||||
def test_ngraph_preprocess_model():
|
||||
model = bytes(b"""<net name="add_model" version="10">
|
||||
<layers>
|
||||
<layer id="0" name="x" type="Parameter" version="opset1">
|
||||
<data element_type="i32" shape="2,2,2"/>
|
||||
<output>
|
||||
<port id="0" precision="FP32">
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
</port>
|
||||
</output>
|
||||
</layer>
|
||||
<layer id="1" name="y" type="Parameter" version="opset1">
|
||||
<data element_type="i32" shape="2,2,2"/>
|
||||
<output>
|
||||
<port id="0" precision="FP32">
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
</port>
|
||||
</output>
|
||||
</layer>
|
||||
<layer id="2" name="sum" type="Add" version="opset1">
|
||||
<input>
|
||||
<port id="0">
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
</port>
|
||||
<port id="1">
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
</port>
|
||||
</input>
|
||||
<output>
|
||||
<port id="2" precision="FP32">
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
</port>
|
||||
</output>
|
||||
</layer>
|
||||
<layer id="3" name="sum/sink_port_0" type="Result" version="opset1">
|
||||
<input>
|
||||
<port id="0">
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
<dim>2</dim>
|
||||
</port>
|
||||
</input>
|
||||
</layer>
|
||||
</layers>
|
||||
<edges>
|
||||
<edge from-layer="0" from-port="0" to-layer="2" to-port="0"/>
|
||||
<edge from-layer="1" from-port="0" to-layer="2" to-port="1"/>
|
||||
<edge from-layer="2" from-port="2" to-layer="3" to-port="0"/>
|
||||
</edges>
|
||||
</net>""")
|
||||
core = Core()
|
||||
function = core.read_model(model=model)
|
||||
|
||||
@custom_preprocess_function
|
||||
def custom_preprocess(output: Output):
|
||||
return ops.abs(output)
|
||||
|
||||
function = PrePostProcessor(function) \
|
||||
.input(InputInfo(1)
|
||||
.preprocess(PreProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.scale(0.5)
|
||||
)
|
||||
) \
|
||||
.input(InputInfo(0)
|
||||
.preprocess(PreProcessSteps()
|
||||
.convert_element_type(Type.f32)
|
||||
.mean(5.))) \
|
||||
.output(OutputInfo(0)
|
||||
.postprocess(PostProcessSteps()
|
||||
.custom(custom_preprocess))) \
|
||||
.build()
|
||||
|
||||
input_data = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]).astype(np.float32)
|
||||
expected_output = np.array([[[2, 1], [4, 7]], [[10, 13], [16, 19]]]).astype(np.float32)
|
||||
|
||||
runtime = get_runtime()
|
||||
computation = runtime.computation(function)
|
||||
output = computation(input_data, input_data)
|
||||
|
||||
assert np.equal(output, expected_output).all()
|
||||
Reference in new issue
Block a user