diff --git a/ngraph/python/src/ngraph/opset6/__init__.py b/ngraph/python/src/ngraph/opset6/__init__.py index 94552ffe7f6..7451fb403a0 100644 --- a/ngraph/python/src/ngraph/opset6/__init__.py +++ b/ngraph/python/src/ngraph/opset6/__init__.py @@ -98,7 +98,7 @@ from ngraph.opset1.ops import minimum from ngraph.opset4.ops import mish from ngraph.opset1.ops import mod from ngraph.opset1.ops import multiply -from ngraph.opset2.ops import mvn +from ngraph.opset6.ops import mvn from ngraph.opset1.ops import negative from ngraph.opset5.ops import non_max_suppression from ngraph.opset3.ops import non_zero diff --git a/ngraph/python/src/ngraph/opset6/ops.py b/ngraph/python/src/ngraph/opset6/ops.py index 022dcf39c3f..fe8ca220f7c 100644 --- a/ngraph/python/src/ngraph/opset6/ops.py +++ b/ngraph/python/src/ngraph/opset6/ops.py @@ -111,3 +111,34 @@ def gather_elements( } return _get_node_factory_opset6().create("GatherElements", inputs, attributes) + + +@nameable_op +def mvn( + data: Node, + axes: Node, + normalize_variance: bool, + eps: float, + eps_mode: str, + name: Optional[str] = None, +) -> Node: + """Return a node which performs MeanVarianceNormalization (MVN). + + @param data: The node with data tensor. + @param axes: The node with axes to reduce on. + @param normalize_variance: Denotes whether to perform variance normalization. + @param eps: The number added to the variance to avoid division by zero + when normalizing the value. Scalar value. + @param eps_mode: how eps is applied (`inside_sqrt` or `outside_sqrt`) + @param name: Optional output node name. + @return The new node performing a MVN operation on input tensor. + """ + inputs = as_nodes(data, axes) + + attributes = { + "normalize_variance": normalize_variance, + "eps": eps, + "eps_mode": eps_mode + } + + return _get_node_factory_opset6().create("MVN", inputs, attributes) diff --git a/ngraph/python/tests/test_ngraph/test_normalization.py b/ngraph/python/tests/test_ngraph/test_normalization.py index e792ebae483..7a8d23f133a 100644 --- a/ngraph/python/tests/test_ngraph/test_normalization.py +++ b/ngraph/python/tests/test_ngraph/test_normalization.py @@ -115,3 +115,43 @@ def test_batch_norm_inference(): result = run_op_node([data, gamma, beta, mean, variance], ng.batch_norm_inference, epsilon) assert np.allclose(result, excepted) + + +def test_mvn_no_variance(): + data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, + 1, 2, 3, 4, 5, 6, 7, 8, 9, + 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=np.float32).reshape([1, 3, 3, 3]) + axes = np.array([2, 3], dtype=np.int64) + epsilon = 1e-9 + normalize_variance = False + eps_mode = "outside_sqrt" + excepted = np.array([-4, -3, -2, -1, 0, 1, 2, 3, 4, + -4, -3, -2, -1, 0, 1, 2, 3, 4, + -4, -3, -2, -1, 0, 1, 2, 3, 4], dtype=np.float32).reshape([1, 3, 3, 3]) + + result = run_op_node([data], ng.mvn, axes, normalize_variance, epsilon, eps_mode) + + assert np.allclose(result, excepted) + + +def test_mvn(): + data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, + 1, 2, 3, 4, 5, 6, 7, 8, 9, + 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=np.float32).reshape([1, 3, 3, 3]) + axes = np.array([2, 3], dtype=np.int64) + epsilon = 1e-9 + normalize_variance = True + eps_mode = "outside_sqrt" + excepted = np.array([-1.5491934, -1.161895, -0.7745967, + -0.38729835, 0., 0.38729835, + 0.7745967, 1.161895, 1.5491934, + -1.5491934, -1.161895, -0.7745967, + -0.38729835, 0., 0.38729835, + 0.7745967, 1.161895, 1.5491934, + -1.5491934, -1.161895, -0.7745967, + -0.38729835, 0., 0.38729835, + 0.7745967, 1.161895, 1.5491934], dtype=np.float32).reshape([1, 3, 3, 3]) + + result = run_op_node([data], ng.mvn, axes, normalize_variance, epsilon, eps_mode) + + assert np.allclose(result, excepted)