# Copyright (c) ONNX Project Contributors # # SPDX-License-Identifier: Apache-2.0 from __future__ import annotations import numpy as np import onnx from onnx.backend.test.case.base import Base from onnx.backend.test.case.node import expect def _batchnorm_test_mode(x, s, bias, mean, var, epsilon=1e-5): dims_x = len(x.shape) dim_ones = (1,) * (dims_x - 2) s = s.reshape(-1, *dim_ones) bias = bias.reshape(-1, *dim_ones) mean = mean.reshape(-1, *dim_ones) var = var.reshape(-1, *dim_ones) return s * (x - mean) / np.sqrt(var + epsilon) + bias def _batchnorm_training_mode(x, s, bias, mean, var, momentum=0.9, epsilon=1e-5): axis = tuple(np.delete(np.arange(len(x.shape)), 1)) saved_mean = x.mean(axis=axis) saved_var = x.var(axis=axis) output_mean = mean * momentum + saved_mean * (1 - momentum) output_var = var * momentum + saved_var * (1 - momentum) y = _batchnorm_test_mode(x, s, bias, saved_mean, saved_var, epsilon=epsilon) return y.astype(np.float32), output_mean, output_var class BatchNormalization(Base): @staticmethod def export() -> None: # input size: (2, 3, 4, 5) x = np.random.randn(2, 3, 4, 5).astype(np.float32) s = np.random.randn(3).astype(np.float32) bias = np.random.randn(3).astype(np.float32) mean = np.random.randn(3).astype(np.float32) var = np.random.rand(3).astype(np.float32) y = _batchnorm_test_mode(x, s, bias, mean, var).astype(np.float32) node = onnx.helper.make_node( "BatchNormalization", inputs=["x", "s", "bias", "mean", "var"], outputs=["y"], ) # output size: (2, 3, 4, 5) expect( node, inputs=[x, s, bias, mean, var], outputs=[y], name="test_batchnorm_example", ) # input size: (2, 3, 4, 5) x = np.random.randn(2, 3, 4, 5).astype(np.float32) s = np.random.randn(3).astype(np.float32) bias = np.random.randn(3).astype(np.float32) mean = np.random.randn(3).astype(np.float32) var = np.random.rand(3).astype(np.float32) epsilon = 1e-2 y = _batchnorm_test_mode(x, s, bias, mean, var, epsilon).astype(np.float32) node = onnx.helper.make_node( "BatchNormalization", inputs=["x", "s", "bias", "mean", "var"], outputs=["y"], epsilon=epsilon, ) # output size: (2, 3, 4, 5) expect( node, inputs=[x, s, bias, mean, var], outputs=[y], name="test_batchnorm_epsilon", ) @staticmethod def export_train() -> None: # input size: (2, 3, 4, 5) x = np.random.randn(2, 3, 4, 5).astype(np.float32) s = np.random.randn(3).astype(np.float32) bias = np.random.randn(3).astype(np.float32) mean = np.random.randn(3).astype(np.float32) var = np.random.rand(3).astype(np.float32) # using np.bool(1) while generating test data with "'bool' object has no attribute 'dtype'" # working around by using np.byte(1).astype(bool) training_mode = 1 y, output_mean, output_var = _batchnorm_training_mode(x, s, bias, mean, var) node = onnx.helper.make_node( "BatchNormalization", inputs=["x", "s", "bias", "mean", "var"], outputs=["y", "output_mean", "output_var"], training_mode=training_mode, ) # output size: (2, 3, 4, 5) expect( node, inputs=[x, s, bias, mean, var], outputs=[y, output_mean, output_var], name="test_batchnorm_example_training_mode", ) # input size: (2, 3, 4, 5) x = np.random.randn(2, 3, 4, 5).astype(np.float32) s = np.random.randn(3).astype(np.float32) bias = np.random.randn(3).astype(np.float32) mean = np.random.randn(3).astype(np.float32) var = np.random.rand(3).astype(np.float32) training_mode = 1 momentum = 0.9 epsilon = 1e-2 y, output_mean, output_var = _batchnorm_training_mode( x, s, bias, mean, var, momentum, epsilon ) node = onnx.helper.make_node( "BatchNormalization", inputs=["x", "s", "bias", "mean", "var"], outputs=["y", "output_mean", "output_var"], epsilon=epsilon, training_mode=training_mode, ) # output size: (2, 3, 4, 5) expect( node, inputs=[x, s, bias, mean, var], outputs=[y, output_mean, output_var], name="test_batchnorm_epsilon_training_mode", )