325 lines
11 KiB
Python
325 lines
11 KiB
Python
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import unittest
|
|
|
|
import numpy as np
|
|
from op_test import OpTest, get_device_place, get_places, is_custom_device
|
|
|
|
import paddle
|
|
from paddle import base
|
|
from paddle.base import core
|
|
|
|
|
|
def _reference_instance_norm_naive(x, scale, bias, epsilon, mean, var):
|
|
x_shape = x.shape
|
|
if len(x_shape) < 4:
|
|
x = np.reshape(x, (x.shape[0], x.shape[1], -1, 1))
|
|
n, c, h, w = x.shape
|
|
|
|
mean_tile = np.reshape(mean, (n, c, 1, 1))
|
|
mean_tile = np.tile(mean_tile, (1, 1, h, w))
|
|
var_tile = np.reshape(var, (n, c, 1, 1))
|
|
var_tile = np.tile(var_tile, (1, 1, h, w))
|
|
|
|
x_norm = (x - mean_tile) / np.sqrt(var_tile + epsilon)
|
|
scale_tile = np.reshape(scale, (1, c, 1, 1))
|
|
scale_tile = np.tile(scale_tile, (n, 1, h, w))
|
|
bias_tile = np.reshape(bias, (1, c, 1, 1))
|
|
bias_tile = np.tile(bias_tile, (n, 1, h, w))
|
|
y = scale_tile * x_norm + bias_tile
|
|
if len(x_shape) < 4:
|
|
y = np.reshape(y, x_shape)
|
|
return y, mean, var
|
|
|
|
|
|
def _reference_instance_norm_grad(x, d_y, scale, mean, var, epsilon):
|
|
# d_scale = sum(d_y * (x-mean) / sqrt(var+epsilon))
|
|
# d_offset = sum(d_y)
|
|
# d_x = scale / sqrt(var+epsilon) * (d_y - np.mean(d_y, axis=(2,3)) - (x-mean)/sqrt(var+epsilon)* np.mean(y_grad * (x-mean)/sqrt(var+epsilon), axis=(2,3)))
|
|
n, c, h, w = x.shape
|
|
|
|
d_bias = np.sum(d_y, axis=(0, 2, 3))
|
|
|
|
mean_tile = np.reshape(mean, (n, c, 1, 1))
|
|
mean_tile = np.tile(mean_tile, (1, 1, h, w))
|
|
var_tile = np.reshape(var, (n, c, 1, 1))
|
|
var_tile = np.tile(var_tile, (1, 1, h, w))
|
|
|
|
d_scale = np.sum(d_y * (x - mean_tile) * var_tile, axis=(0, 2, 3))
|
|
var_inv = var_tile
|
|
scale_tile = np.reshape(scale, (1, c, 1, 1))
|
|
scale_tile = np.tile(scale_tile, (n, 1, h, w))
|
|
|
|
d_x = (
|
|
scale_tile
|
|
* var_inv
|
|
* (
|
|
d_y
|
|
- np.mean(d_y, axis=(2, 3), keepdims=True)
|
|
- (x - mean_tile)
|
|
* var_inv
|
|
* np.mean(
|
|
d_y * (x - mean_tile) * var_inv, axis=(2, 3), keepdims=True
|
|
)
|
|
)
|
|
)
|
|
return d_x, d_scale, d_bias
|
|
|
|
|
|
def _cal_mean_variance(x, epsilon, mean_shape):
|
|
if len(x.shape) < 4:
|
|
x = np.reshape(x, (x.shape[0], x.shape[1], -1, 1))
|
|
mean = np.reshape(np.mean(x, axis=(2, 3)), mean_shape)
|
|
var = np.reshape(np.var(x, axis=(2, 3)), mean_shape)
|
|
return mean, var
|
|
|
|
|
|
def instance_norm_wrapper(x, weight=None, bias=None, esp=1e-05):
|
|
return paddle.nn.functional.instance_norm(
|
|
x, None, None, weight, bias, True, 0.9, esp
|
|
)
|
|
|
|
|
|
class TestInstanceNormOp(OpTest):
|
|
def setUp(self):
|
|
self.op_type = "instance_norm"
|
|
self.prim_op_type = "comp"
|
|
self.python_api = instance_norm_wrapper
|
|
self.public_python_api = instance_norm_wrapper
|
|
self.python_out_sig = ['Y']
|
|
self.fw_comp_rtol = 1e-6
|
|
self.fw_comp_atol = 1e-6
|
|
self.rev_comp_rtol = 1e-4
|
|
self.rev_comp_atol = 1e-4
|
|
self.cinn_rtol = 1e-4
|
|
self.cinn_atol = 1e-4
|
|
self.init_test_case()
|
|
ref_y_np, ref_mean_np, ref_var_np_tmp = _reference_instance_norm_naive(
|
|
self.x_np,
|
|
self.scale_np,
|
|
self.bias_np,
|
|
self.epsilon,
|
|
self.mean_np,
|
|
self.var_np,
|
|
)
|
|
|
|
ref_var_np = 1 / np.sqrt(ref_var_np_tmp + self.epsilon)
|
|
self.inputs = {
|
|
'X': self.x_np,
|
|
'Scale': self.scale_np,
|
|
'Bias': self.bias_np,
|
|
}
|
|
self.attrs = {'epsilon': self.epsilon}
|
|
self.outputs = {
|
|
'Y': ref_y_np,
|
|
'SavedMean': ref_mean_np,
|
|
'SavedVariance': ref_var_np,
|
|
}
|
|
|
|
def test_check_output(self):
|
|
self.check_output(check_prim=False, check_pir=True, check_prim_pir=True)
|
|
|
|
def test_check_grad(self):
|
|
self.check_grad(
|
|
['X', 'Scale', 'Bias'],
|
|
'Y',
|
|
check_prim=False,
|
|
check_pir=True,
|
|
check_prim_pir=True,
|
|
)
|
|
|
|
def init_test_case(self):
|
|
x_shape = [2, 100, 4, 5]
|
|
n, c, h, w = x_shape[0], x_shape[1], x_shape[2], x_shape[3]
|
|
self.epsilon = 1e-05
|
|
dtype = np.float32
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
np.random.seed()
|
|
self.x_np = np.random.random_sample(x_shape).astype(dtype)
|
|
self.scale_np = np.random.random_sample(scale_shape).astype(dtype)
|
|
self.bias_np = np.random.random_sample(scale_shape).astype(dtype)
|
|
self.mean_np, self.var_np = _cal_mean_variance(
|
|
self.x_np, self.epsilon, mean_shape
|
|
)
|
|
self.dtype = dtype
|
|
|
|
|
|
class TestInstanceNormFP64(TestInstanceNormOp):
|
|
def init_test_case(self):
|
|
x_shape = [2, 100, 4, 5]
|
|
n, c, h, w = x_shape[0], x_shape[1], x_shape[2], x_shape[3]
|
|
self.epsilon = 1e-5
|
|
dtype = np.float64
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
np.random.seed()
|
|
self.x_np = np.random.random_sample(x_shape).astype(dtype)
|
|
self.scale_np = np.ones(scale_shape).astype(dtype)
|
|
self.bias_np = np.zeros(scale_shape).astype(dtype)
|
|
self.mean_np, self.var_np = _cal_mean_variance(
|
|
self.x_np, self.epsilon, mean_shape
|
|
)
|
|
self.cinn_atol = 1e-13
|
|
self.cinn_rtol = 1e-13
|
|
self.fw_comp_rtol = 1e-14
|
|
self.fw_comp_atol = 1e-14
|
|
self.rev_comp_rtol = 1e-13
|
|
self.rev_comp_atol = 1e-13
|
|
self.dtype = dtype
|
|
|
|
|
|
class TestInstanceNormCase1(TestInstanceNormOp):
|
|
def init_test_case(self):
|
|
x_shape = [2, 100, 4, 5]
|
|
n, c, h, w = x_shape[0], x_shape[1], x_shape[2], x_shape[3]
|
|
self.epsilon = 1e-05
|
|
dtype = np.float32
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
np.random.seed()
|
|
self.x_np = np.random.random_sample(x_shape).astype(dtype)
|
|
self.scale_np = np.ones(scale_shape).astype(dtype)
|
|
self.bias_np = np.zeros(scale_shape).astype(dtype)
|
|
self.mean_np, self.var_np = _cal_mean_variance(
|
|
self.x_np, self.epsilon, mean_shape
|
|
)
|
|
|
|
|
|
class TestInstanceNormCaseNCL(TestInstanceNormOp):
|
|
def init_test_case(self):
|
|
x_shape = [2, 100, 4]
|
|
n, c = x_shape[0], x_shape[1]
|
|
self.epsilon = 1e-05
|
|
dtype = np.float32
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
np.random.seed()
|
|
self.x_np = np.random.random_sample(x_shape).astype(dtype)
|
|
self.scale_np = np.ones(scale_shape).astype(dtype)
|
|
self.bias_np = np.zeros(scale_shape).astype(dtype)
|
|
self.mean_np, self.var_np = _cal_mean_variance(
|
|
self.x_np, self.epsilon, mean_shape
|
|
)
|
|
self.fw_comp_atol = 1e-5
|
|
|
|
def test_check_output(self):
|
|
self.check_output(check_pir=True, check_prim_pir=True)
|
|
|
|
def test_check_grad(self):
|
|
self.check_grad(
|
|
['X', 'Scale', 'Bias'],
|
|
'Y',
|
|
check_pir=True,
|
|
check_prim_pir=True,
|
|
)
|
|
|
|
|
|
class TestInstanceNormCaseNC(TestInstanceNormOp):
|
|
def init_test_case(self):
|
|
x_shape = [2, 100]
|
|
n, c = x_shape[0], x_shape[1]
|
|
self.epsilon = 1e-05
|
|
dtype = np.float32
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
np.random.seed()
|
|
self.x_np = np.random.random_sample(x_shape).astype(dtype)
|
|
self.scale_np = np.ones(scale_shape).astype(dtype)
|
|
self.bias_np = np.zeros(scale_shape).astype(dtype)
|
|
self.mean_np, self.var_np = _cal_mean_variance(
|
|
self.x_np, self.epsilon, mean_shape
|
|
)
|
|
self.fw_comp_atol = 2e-5
|
|
|
|
def test_check_output(self):
|
|
self.check_output(atol=2e-5, check_pir=True, check_prim_pir=True)
|
|
|
|
def test_check_grad(self):
|
|
self.check_grad(
|
|
['X', 'Scale', 'Bias'],
|
|
'Y',
|
|
check_pir=True,
|
|
check_prim_pir=True,
|
|
)
|
|
|
|
|
|
class TestElasticNormOp(unittest.TestCase):
|
|
def init_test_case(self):
|
|
self.epsilon = 1e-5
|
|
self.places = get_places()
|
|
|
|
def test_norm(self):
|
|
self.init_test_case()
|
|
inputs = np.random.random((2, 3, 5, 5)).astype(np.float32)
|
|
shape = inputs.shape
|
|
n, c, h, w = shape[0], shape[1], shape[2], shape[3]
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
scale = np.ones(scale_shape).astype(np.float32)
|
|
bias = np.zeros(scale_shape).astype(np.float32)
|
|
mean, variance = _cal_mean_variance(inputs, self.epsilon, mean_shape)
|
|
out_np, _, _ = _reference_instance_norm_naive(
|
|
inputs, scale, bias, self.epsilon, mean, variance
|
|
)
|
|
|
|
for place in self.places:
|
|
with base.dygraph.guard(place):
|
|
instance_norm = paddle.nn.InstanceNorm2D(
|
|
5, weight_attr=False, bias_attr=False
|
|
)
|
|
outputs = instance_norm(paddle.to_tensor(inputs))
|
|
np.testing.assert_allclose(
|
|
outputs.numpy(), out_np, rtol=1e-05, atol=1e-06
|
|
)
|
|
|
|
|
|
class TestElasticNormOpCase2(unittest.TestCase):
|
|
def init_test_case(self):
|
|
self.epsilon = 1e-5
|
|
self.places = [core.CPUPlace()]
|
|
if (
|
|
core.is_compiled_with_cuda() or is_custom_device()
|
|
) and core.op_support_gpu("instance_norm"):
|
|
self.places.append(get_device_place())
|
|
|
|
def test_norm(self):
|
|
self.init_test_case()
|
|
inputs = np.random.random((2, 3, 5, 5)).astype(np.float32)
|
|
shape = inputs.shape
|
|
n, c, h, w = shape[0], shape[1], shape[2], shape[3]
|
|
scale_shape = [c]
|
|
mean_shape = [n * c]
|
|
scale = np.ones(scale_shape).astype(np.float32)
|
|
bias = np.zeros(scale_shape).astype(np.float32)
|
|
mean, variance = _cal_mean_variance(inputs, self.epsilon, mean_shape)
|
|
out_np, _, _ = _reference_instance_norm_naive(
|
|
inputs, scale, bias, self.epsilon, mean, variance
|
|
)
|
|
|
|
for place in self.places:
|
|
with base.dygraph.guard(place):
|
|
instance_norm = paddle.nn.InstanceNorm2D(
|
|
3, weight_attr=True, bias_attr=True
|
|
)
|
|
outputs = instance_norm(paddle.to_tensor(inputs))
|
|
np.testing.assert_allclose(
|
|
outputs.numpy(), out_np, rtol=1e-05, atol=1e-06
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|