• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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