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 17 from __future__ import absolute_import 18 from __future__ import division 19 from __future__ import print_function 20 21 import copy 22 23 import numpy as np 24 25 from tensorflow.python.framework import constant_op 26 from tensorflow.python.framework import dtypes 27 from tensorflow.python.ops import array_ops 28 from tensorflow.python.ops import gradient_checker 29 from tensorflow.python.ops import gradients_impl 30 from tensorflow.python.ops import nn 31 import tensorflow.python.ops.nn_grad # pylint: disable=unused-import 32 from tensorflow.python.platform import test 33 34 35 class LRNOpTest(test.TestCase): 36 37 def _LRN(self, input_image, lrn_depth_radius=5, bias=1.0, alpha=1.0, 38 beta=0.5): 39 """Compute expected result.""" 40 output = copy.deepcopy(input_image) 41 batch_size = input_image.shape[0] 42 rows = input_image.shape[1] 43 cols = input_image.shape[2] 44 depth = input_image.shape[3] 45 for b in range(batch_size): 46 for r in range(rows): 47 for c in range(cols): 48 for d in range(depth): 49 begin = max(0, d - lrn_depth_radius) 50 end = min(depth, d + lrn_depth_radius + 1) 51 patch = input_image[b, r, c, begin:end] 52 output[b, r, c, d] /= ( 53 np.power(bias + alpha * np.sum(patch * patch), beta)) 54 return output 55 56 def _RunAndVerify(self, dtype): 57 with self.test_session(use_gpu=True): 58 # random shape 59 shape = np.random.randint(1, 16, size=4) 60 # Make depth at least 2 to make it meaningful 61 shape[3] += 1 62 p = array_ops.placeholder(dtype, shape=shape) 63 # random depth_radius, bias, alpha, beta. cuDNN requires depth_radius to 64 # be in [1, 7]. 65 lrn_depth_radius = np.random.randint(1, min(8, shape[3])) 66 67 bias = 1.0 + np.random.rand() 68 alpha = 2.0 * np.random.rand() 69 # cuDNN requires beta >= 0.01. 70 beta = 0.01 + 2.0 * np.random.rand() 71 lrn_t = nn.local_response_normalization( 72 p, 73 name="lrn", 74 depth_radius=lrn_depth_radius, 75 bias=bias, 76 alpha=alpha, 77 beta=beta) 78 params = {p: np.random.rand(*shape).astype("f")} 79 result = lrn_t.eval(feed_dict=params) 80 expected = self._LRN( 81 params[p], 82 lrn_depth_radius=lrn_depth_radius, 83 bias=bias, 84 alpha=alpha, 85 beta=beta) 86 err = np.amax(np.abs(result - expected)) 87 print("LRN error for bias ", bias, "alpha ", alpha, " beta ", beta, " is ", 88 err) 89 if dtype == dtypes.float32: 90 self.assertTrue(err < 1e-4) 91 else: 92 self.assertTrue(err < 1e-2) 93 self.assertShapeEqual(expected, lrn_t) 94 95 def testCompute(self): 96 for _ in range(2): 97 self._RunAndVerify(dtypes.float32) 98 # Enable when LRN supports tf.float16 on GPU. 99 if not test.is_gpu_available(): 100 self._RunAndVerify(dtypes.float16) 101 102 def testGradientsZeroInput(self): 103 with self.test_session(use_gpu=True): 104 shape = [4, 4, 4, 4] 105 p = array_ops.placeholder(dtypes.float32, shape=shape) 106 inp_array = np.zeros(shape).astype("f") 107 lrn_op = nn.local_response_normalization(p, 2, 1.0, 0.0, 1.0, name="lrn") 108 grad = gradients_impl.gradients([lrn_op], [p])[0] 109 params = {p: inp_array} 110 r = grad.eval(feed_dict=params) 111 expected = np.ones(shape).astype("f") 112 self.assertAllClose(r, expected) 113 self.assertShapeEqual(expected, grad) 114 115 def _RunAndVerifyGradients(self, dtype): 116 with self.test_session(use_gpu=True): 117 # random shape 118 shape = np.random.randint(1, 5, size=4) 119 # Make depth at least 2 to make it meaningful 120 shape[3] += 1 121 # random depth_radius, bias, alpha, beta. cuDNN requires depth_radius to 122 # be in [1, 7]. 123 lrn_depth_radius = np.random.randint(1, min(8, shape[3])) 124 bias = 1.0 + np.random.rand() 125 alpha = 1.0 * np.random.rand() 126 # cuDNN requires beta >= 0.01. 127 beta = 0.01 + 1.0 * np.random.rand() 128 if dtype == dtypes.float32: 129 inp_array = np.random.rand(*shape).astype(np.float32) 130 else: 131 inp_array = np.random.rand(*shape).astype(np.float16) 132 133 inp = constant_op.constant( 134 list(inp_array.ravel(order="C")), shape=shape, dtype=dtype) 135 lrn_op = nn.local_response_normalization( 136 inp, 137 name="lrn", 138 depth_radius=lrn_depth_radius, 139 bias=bias, 140 alpha=alpha, 141 beta=beta) 142 err = gradient_checker.compute_gradient_error(inp, shape, lrn_op, shape) 143 print("LRN Gradient error for bias ", bias, "alpha ", alpha, " beta ", beta, 144 " is ", err) 145 if dtype == dtypes.float32: 146 self.assertLess(err, 1e-4) 147 else: 148 self.assertLess(err, 1.0) 149 150 def testGradients(self): 151 for _ in range(2): 152 self._RunAndVerifyGradients(dtypes.float32) 153 # Enable when LRN supports tf.float16 on GPU. 154 if not test.is_gpu_available(): 155 self._RunAndVerifyGradients(dtypes.float16) 156 157 158 if __name__ == "__main__": 159 test.main() 160