1# Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Tests for local response normalization.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21import copy 22 23import numpy as np 24 25from tensorflow.python.framework import constant_op 26from tensorflow.python.framework import dtypes 27from tensorflow.python.framework import test_util 28from tensorflow.python.ops import array_ops 29from tensorflow.python.ops import gradient_checker 30from tensorflow.python.ops import gradients_impl 31from tensorflow.python.ops import nn 32import tensorflow.python.ops.nn_grad # pylint: disable=unused-import 33from tensorflow.python.platform import test 34 35 36class LRNOpTest(test.TestCase): 37 38 def _LRN(self, input_image, lrn_depth_radius=5, bias=1.0, alpha=1.0, 39 beta=0.5): 40 """Compute expected result.""" 41 output = copy.deepcopy(input_image) 42 batch_size = input_image.shape[0] 43 rows = input_image.shape[1] 44 cols = input_image.shape[2] 45 depth = input_image.shape[3] 46 for b in range(batch_size): 47 for r in range(rows): 48 for c in range(cols): 49 for d in range(depth): 50 begin = max(0, d - lrn_depth_radius) 51 end = min(depth, d + lrn_depth_radius + 1) 52 patch = input_image[b, r, c, begin:end] 53 output[b, r, c, d] /= ( 54 np.power(bias + alpha * np.sum(patch * patch), beta)) 55 return output 56 57 def _RunAndVerify(self, dtype): 58 with self.cached_session(): 59 # random shape 60 shape = np.random.randint(1, 16, size=4) 61 # Make depth at least 2 to make it meaningful 62 shape[3] += 1 63 p = array_ops.placeholder(dtype, shape=shape) 64 # random depth_radius, bias, alpha, beta. cuDNN requires depth_radius to 65 # be in [1, 7]. 66 lrn_depth_radius = np.random.randint(1, min(8, shape[3])) 67 68 bias = 1.0 + np.random.rand() 69 alpha = 2.0 * np.random.rand() 70 # cuDNN requires beta >= 0.01. 71 beta = 0.01 + 2.0 * np.random.rand() 72 lrn_t = nn.local_response_normalization( 73 p, 74 name="lrn", 75 depth_radius=lrn_depth_radius, 76 bias=bias, 77 alpha=alpha, 78 beta=beta) 79 params = {p: np.random.rand(*shape).astype("f")} 80 result = lrn_t.eval(feed_dict=params) 81 expected = self._LRN( 82 params[p], 83 lrn_depth_radius=lrn_depth_radius, 84 bias=bias, 85 alpha=alpha, 86 beta=beta) 87 err = np.amax(np.abs(result - expected)) 88 print("LRN error for bias ", bias, "alpha ", alpha, " beta ", beta, " is ", 89 err) 90 if dtype == dtypes.float32: 91 self.assertTrue(err < 1e-4) 92 else: 93 self.assertTrue(err < 1e-2) 94 self.assertShapeEqual(expected, lrn_t) 95 96 @test_util.run_deprecated_v1 97 def testCompute(self): 98 for _ in range(2): 99 self._RunAndVerify(dtypes.float32) 100 # Enable when LRN supports tf.float16 on GPU. 101 if not test.is_gpu_available(): 102 self._RunAndVerify(dtypes.float16) 103 104 @test_util.run_deprecated_v1 105 def testGradientsZeroInput(self): 106 with self.session(): 107 shape = [4, 4, 4, 4] 108 p = array_ops.placeholder(dtypes.float32, shape=shape) 109 inp_array = np.zeros(shape).astype("f") 110 lrn_op = nn.local_response_normalization(p, 2, 1.0, 0.0, 1.0, name="lrn") 111 grad = gradients_impl.gradients([lrn_op], [p])[0] 112 params = {p: inp_array} 113 r = grad.eval(feed_dict=params) 114 expected = np.ones(shape).astype("f") 115 self.assertAllClose(r, expected) 116 self.assertShapeEqual(expected, grad) 117 118 def _RunAndVerifyGradients(self, dtype): 119 with self.cached_session(): 120 # random shape 121 shape = np.random.randint(1, 5, size=4) 122 # Make depth at least 2 to make it meaningful 123 shape[3] += 1 124 # random depth_radius, bias, alpha, beta. cuDNN requires depth_radius to 125 # be in [1, 7]. 126 lrn_depth_radius = np.random.randint(1, min(8, shape[3])) 127 bias = 1.0 + np.random.rand() 128 alpha = 1.0 * np.random.rand() 129 # cuDNN requires beta >= 0.01. 130 beta = 0.01 + 1.0 * np.random.rand() 131 if dtype == dtypes.float32: 132 inp_array = np.random.rand(*shape).astype(np.float32) 133 else: 134 inp_array = np.random.rand(*shape).astype(np.float16) 135 136 inp = constant_op.constant( 137 list(inp_array.ravel(order="C")), shape=shape, dtype=dtype) 138 lrn_op = nn.local_response_normalization( 139 inp, 140 name="lrn", 141 depth_radius=lrn_depth_radius, 142 bias=bias, 143 alpha=alpha, 144 beta=beta) 145 err = gradient_checker.compute_gradient_error(inp, shape, lrn_op, shape) 146 print("LRN Gradient error for bias ", bias, "alpha ", alpha, " beta ", beta, 147 " is ", err) 148 if dtype == dtypes.float32: 149 self.assertLess(err, 1e-4) 150 else: 151 self.assertLess(err, 1.0) 152 153 @test_util.run_deprecated_v1 154 def testGradients(self): 155 for _ in range(2): 156 self._RunAndVerifyGradients(dtypes.float32) 157 # Enable when LRN supports tf.float16 on GPU. 158 if not test.is_gpu_available(): 159 self._RunAndVerifyGradients(dtypes.float16) 160 161 162if __name__ == "__main__": 163 test.main() 164