Home | History | Annotate | Download | only in ops
      1 # Copyright 2017 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 """Benchmark for fused conv2d bias and activation op."""
     16 
     17 from __future__ import absolute_import
     18 from __future__ import division
     19 from __future__ import print_function
     20 import time
     21 
     22 from tensorflow.contrib.fused_conv.python.ops import fused_conv2d_bias_activation_op
     23 from tensorflow.python.client import session as session_lib
     24 from tensorflow.python.framework import ops
     25 from tensorflow.python.ops import control_flow_ops
     26 from tensorflow.python.ops import nn_ops
     27 from tensorflow.python.ops import random_ops
     28 from tensorflow.python.ops import variables
     29 from tensorflow.python.platform import test
     30 
     31 
     32 def build_conv_bias_relu_graph(device, input_shape, filter_shape, strides,
     33                                padding, num_iters, data_format):
     34   """builds a graph containing a sequence of conv2d operations.
     35 
     36   Args:
     37     device: String, the device to run on.
     38     input_shape: Shape of the input tensor.
     39     filter_shape: Shape of the filter tensor.
     40     strides: A list of ints. 1-D of length 4. The stride of sliding
     41              window for each dimension of input.
     42     padding: A string from: "SAME", "VALID". The type of padding
     43              algorithm to use.
     44     num_iters: number of iterations to run conv2d.
     45     data_format: data format string of input, 'NHWC' and 'NCHW' are
     46     supported.
     47 
     48   Returns:
     49     An array of tensors to run()
     50   """
     51   if data_format == "NCHW":
     52     input_shape = [
     53         input_shape[0], input_shape[3], input_shape[1], input_shape[2]
     54     ]
     55   with ops.device("/%s:0" % device):
     56     inp = variables.Variable(random_ops.truncated_normal(input_shape))
     57     filt = variables.Variable(random_ops.truncated_normal(filter_shape))
     58     bias_shape = [filter_shape[-1]]
     59     bias = variables.Variable(random_ops.truncated_normal(bias_shape))
     60 
     61     outputs = []
     62     conv2d_out = nn_ops.conv2d(
     63         inp, filt, strides, padding, data_format=data_format)
     64     bias_out = nn_ops.bias_add(conv2d_out, bias, data_format=data_format)
     65     relu_out = nn_ops.relu(bias_out)
     66     outputs.append(relu_out)
     67     for _ in range(1, num_iters):
     68       with ops.control_dependencies([relu_out]):
     69         conv2d_out = nn_ops.conv2d(
     70             inp, filt, strides, padding, data_format=data_format)
     71         bias_out = nn_ops.bias_add(conv2d_out, bias, data_format=data_format)
     72         relu_out = nn_ops.relu(bias_out)
     73         outputs.append(relu_out)
     74     return control_flow_ops.group(*outputs)
     75 
     76 
     77 def build_fused_conv_bias_relu_graph(device, input_shape, filter_shape, strides,
     78                                      padding, num_iters, data_format):
     79   """builds a graph containing a sequence of conv2d operations.
     80 
     81   Args:
     82     device: String, the device to run on.
     83     input_shape: Shape of the input tensor.
     84     filter_shape: Shape of the filter tensor.
     85     strides: A list of ints. 1-D of length 4. The stride of sliding
     86              window for each dimension of input.
     87     padding: A string from: "SAME", "VALID". The type of padding
     88              algorithm to use.
     89     num_iters: number of iterations to run conv2d.
     90     data_format: data format string of input, 'NHWC' and 'NCHW' are
     91     supported.
     92 
     93   Returns:
     94     An array of tensors to run()
     95   """
     96   if data_format == "NCHW":
     97     input_shape = [
     98         input_shape[0], input_shape[3], input_shape[1], input_shape[2]
     99     ]
    100   with ops.device("/%s:0" % device):
    101     inp = variables.Variable(random_ops.truncated_normal(input_shape))
    102     filt = variables.Variable(random_ops.truncated_normal(filter_shape))
    103     bias_shape = [filter_shape[-1]]
    104     bias = variables.Variable(random_ops.truncated_normal(bias_shape))
    105 
    106     outputs = []
    107     fused_out = fused_conv2d_bias_activation_op.fused_conv2d_bias_activation(
    108         inp,
    109         filt,
    110         bias,
    111         strides,
    112         padding,
    113         data_format=data_format,
    114         activation_mode="Relu")
    115     outputs.append(fused_out)
    116     for _ in range(1, num_iters):
    117       with ops.control_dependencies([fused_out]):
    118         # pylint: disable=g-line-too-long
    119         fused_out = fused_conv2d_bias_activation_op.fused_conv2d_bias_activation(  # pylint: disable=line-too-long
    120             inp,
    121             filt,
    122             bias,
    123             strides,
    124             padding,
    125             data_format=data_format,
    126             activation_mode="Relu")
    127         outputs.append(fused_out)
    128     return control_flow_ops.group(*outputs)
    129 
    130 
    131 class FusedConv2DBiasActivationBenchmark(test.Benchmark):
    132   """Benchmark conv2d!"""
    133 
    134   def _run_graph(self, device, input_shape, filter_shape, strides, padding,
    135                  num_iters, data_format):
    136     """runs the graph and print its execution time.
    137 
    138     Args:
    139       device: String, the device to run on.
    140       input_shape: Shape of the input tensor.
    141       filter_shape: Shape of the filter tensor.
    142       strides: A list of ints. 1-D of length 4. The stride of sliding
    143                window for each dimension of input.
    144       padding: A string from: "SAME", "VALID". The type of padding
    145                algorithm to use.  num_iters: Number of iterations to run the
    146                  benchmark.
    147       num_iters: number of iterations to run conv2d.
    148       data_format: data format string of input, 'NHWC' and 'NCHW' are
    149       supported.
    150 
    151     Returns:
    152       The duration of the run in seconds.
    153     """
    154     graph = ops.Graph()
    155     with graph.as_default():
    156       outputs = build_fused_conv_bias_relu_graph(device, input_shape,
    157                                                  filter_shape, strides, padding,
    158                                                  num_iters, data_format)
    159       with session_lib.Session(graph=graph) as session:
    160         variables.global_variables_initializer().run()
    161         # warmup runs
    162         session.run(outputs)
    163 
    164         start_time = time.time()
    165         session.run(outputs)
    166         duration = (time.time() - start_time) / num_iters
    167 
    168         print("%s inputshape:%s filtershape:%s strides:%s padding:%s "
    169               "%d iters: %.8f sec" % (device, str(input_shape).replace(" ", ""),
    170                                       str(filter_shape).replace(" ", ""),
    171                                       str(strides).replace(" ", ""), padding,
    172                                       num_iters, duration))
    173     name_template = (
    174         "conv2d_{device}_input_shape_{inputshape}_filter_shape_{filtershape}_"
    175         "strides_{strides}_padding_{padding}")
    176 
    177     self.report_benchmark(
    178         name=name_template.format(
    179             device=device,
    180             inputshape=str(input_shape).replace(" ", ""),
    181             filtershape=str(filter_shape).replace(" ", ""),
    182             strides=str(strides).replace(" ", ""),
    183             padding=padding).replace(" ", ""),
    184         iters=num_iters,
    185         wall_time=duration)
    186 
    187     return duration
    188 
    189   def benchmark_fused_conv2d_bias_activation(self):
    190 
    191     stride = [1, 1, 1, 1]
    192     paddings = ["VALID", "SAME"]
    193     data_formats = ["NHWC", "NCHW"]
    194 
    195     resnet50_input_shapes = [[64, 14, 14, 256], [64, 14, 14, 256], [
    196         64, 14, 14, 1024
    197     ], [64, 55, 55, 64], [64, 28, 28, 128], [64, 28, 28, 128], [64, 55, 55, 64],
    198                              [64, 7, 7, 512], [64, 7, 7, 512],
    199                              [64, 28, 28, 512], [64, 55, 55,
    200                                                  256], [64, 7, 7, 2048]]
    201 
    202     resnet50_filter_shapes = [[1, 1, 256, 1024], [3, 3, 256, 256], [
    203         1, 1, 1024, 256
    204     ], [1, 1, 64, 256], [1, 1, 128, 512], [3, 3, 128, 128], [3, 3, 64, 64], [
    205         3, 3, 512, 512
    206     ], [1, 1, 512, 2048], [1, 1, 512, 128], [1, 1, 256, 64], [1, 1, 2048, 512]]
    207 
    208     inception3_input_shapes = [[64, 17, 17, 768], [64, 35, 35, 96], [
    209         64, 35, 35, 288
    210     ], [64, 8, 8, 384], [64, 8, 8, 384], [64, 17, 17, 192], [64, 35, 35, 64], [
    211         64, 17, 17, 192
    212     ], [64, 17, 17, 160], [64, 17, 17, 160], [64, 17, 17, 768], [
    213         64, 35, 35, 256
    214     ], [64, 35, 35, 48], [64, 35, 35, 192], [64, 17, 17, 128], [
    215         64, 17, 17, 160
    216     ], [64, 8, 8, 448], [64, 17, 17, 128], [64, 17, 17, 768], [64, 17, 17, 160]]
    217     inception3_filter_shapes = [[1, 1, 768, 192], [3, 3, 96, 96], [
    218         1, 1, 288, 64
    219     ], [1, 3, 384, 384], [3, 1, 384, 384], [7, 1, 192, 192], [3, 3, 64, 96], [
    220         1, 7, 192, 192
    221     ], [7, 1, 160, 160], [1, 7, 160, 160], [1, 1, 768, 160], [1, 1, 256, 64], [
    222         5, 5, 48, 64
    223     ], [1, 1, 192, 64], [1, 7, 128, 128], [1, 7, 160, 192], [3, 3, 448, 384],
    224                                 [7, 1, 128, 128], [1, 1, 768,
    225                                                    128], [7, 1, 160, 192]]
    226 
    227     print("fused conv2d bias activation benchmark using resnet50's shapes:")
    228     for ishape, fshape in zip(resnet50_input_shapes, resnet50_filter_shapes):
    229       for padding in paddings:
    230         for data_format in data_formats:
    231           self._run_graph("gpu", ishape, fshape, stride, padding, 80,
    232                           data_format)
    233     print("fused conv2d bias activation benchmark using inception3's shapes:")
    234     for ishape, fshape in zip(inception3_input_shapes,
    235                               inception3_filter_shapes):
    236       for padding in paddings:
    237         for data_format in data_formats:
    238           self._run_graph("gpu", ishape, fshape, stride, padding, 80,
    239                           data_format)
    240 
    241 
    242 if __name__ == "__main__":
    243   test.main()
    244