Explicit constructor call is no less clear and match what we export via the public API. The functions will be removed once all the internal users are migrated. PiperOrigin-RevId: 259620054
151 lines
5.3 KiB
Python
151 lines
5.3 KiB
Python
# Copyright 2016 The TensorFlow 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.
|
|
# ==============================================================================
|
|
"""Benchmark for accumulate_n() in math_ops."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import random
|
|
import time
|
|
|
|
from six.moves import xrange # pylint: disable=redefined-builtin
|
|
|
|
from tensorflow.python.client import session
|
|
from tensorflow.python.framework import ops
|
|
from tensorflow.python.framework import tensor_shape
|
|
from tensorflow.python.ops import array_ops
|
|
from tensorflow.python.ops import data_flow_ops
|
|
from tensorflow.python.ops import gen_control_flow_ops
|
|
from tensorflow.python.ops import gen_state_ops
|
|
from tensorflow.python.ops import math_ops
|
|
from tensorflow.python.ops import random_ops
|
|
from tensorflow.python.ops import state_ops
|
|
from tensorflow.python.platform import test
|
|
|
|
|
|
class AccumulateNBenchmark(test.Benchmark):
|
|
|
|
def _AccumulateNTemplate(self, inputs, init, shape, validate_shape):
|
|
var = gen_state_ops.temporary_variable(
|
|
shape=shape, dtype=inputs[0].dtype.base_dtype)
|
|
ref = state_ops.assign(var, init, validate_shape=validate_shape)
|
|
update_ops = [
|
|
state_ops.assign_add(
|
|
ref, tensor, use_locking=True).op for tensor in inputs
|
|
]
|
|
with ops.control_dependencies(update_ops):
|
|
return gen_state_ops.destroy_temporary_variable(ref, var_name=var.op.name)
|
|
|
|
def _AccumulateNInitializedWithFirst(self, inputs):
|
|
return self._AccumulateNTemplate(
|
|
inputs,
|
|
init=array_ops.zeros_like(inputs[0]),
|
|
shape=inputs[0].get_shape(),
|
|
validate_shape=True)
|
|
|
|
def _AccumulateNInitializedWithMerge(self, inputs):
|
|
return self._AccumulateNTemplate(
|
|
inputs,
|
|
init=array_ops.zeros_like(gen_control_flow_ops.merge(inputs)[0]),
|
|
shape=tensor_shape.TensorShape([0]),
|
|
validate_shape=False)
|
|
|
|
def _AccumulateNInitializedWithShape(self, inputs):
|
|
return self._AccumulateNTemplate(
|
|
inputs,
|
|
init=array_ops.zeros(
|
|
shape=inputs[0].get_shape(), dtype=inputs[0].dtype.base_dtype),
|
|
shape=inputs[0].get_shape(),
|
|
validate_shape=True)
|
|
|
|
def _GenerateUnorderedInputs(self, size, n):
|
|
inputs = [random_ops.random_uniform(shape=[size]) for _ in xrange(n)]
|
|
random.shuffle(inputs)
|
|
return inputs
|
|
|
|
def _GenerateReplicatedInputs(self, size, n):
|
|
return n * self._GenerateUnorderedInputs(size, 1)
|
|
|
|
def _GenerateOrderedInputs(self, size, n):
|
|
inputs = self._GenerateUnorderedInputs(size, 1)
|
|
queue = data_flow_ops.FIFOQueue(
|
|
capacity=1, dtypes=[inputs[0].dtype], shapes=[inputs[0].get_shape()])
|
|
for _ in xrange(n - 1):
|
|
op = queue.enqueue(inputs[-1])
|
|
with ops.control_dependencies([op]):
|
|
inputs.append(math_ops.tanh(1.0 + queue.dequeue()))
|
|
return inputs
|
|
|
|
def _GenerateReversedInputs(self, size, n):
|
|
inputs = self._GenerateOrderedInputs(size, n)
|
|
inputs.reverse()
|
|
return inputs
|
|
|
|
def _SetupAndRunBenchmark(self, graph, inputs, repeats, format_args):
|
|
with graph.as_default():
|
|
add_n = math_ops.add_n(inputs)
|
|
acc_n_first = self._AccumulateNInitializedWithFirst(inputs)
|
|
acc_n_merge = self._AccumulateNInitializedWithMerge(inputs)
|
|
acc_n_shape = self._AccumulateNInitializedWithShape(inputs)
|
|
|
|
test_ops = (("AddN", add_n.op),
|
|
("AccNFirst", acc_n_first.op),
|
|
("AccNMerge", acc_n_merge.op),
|
|
("AccNShape", acc_n_shape.op))
|
|
|
|
with session.Session(graph=graph):
|
|
for tag, op in test_ops:
|
|
for _ in xrange(100):
|
|
op.run() # Run for warm up.
|
|
start = time.time()
|
|
for _ in xrange(repeats):
|
|
op.run()
|
|
duration = time.time() - start
|
|
args = format_args + (tag, duration)
|
|
print(self._template.format(*args))
|
|
|
|
def _RunBenchmark(self, tag, input_fn, sizes, ninputs, repeats):
|
|
for size in sizes:
|
|
for ninput in ninputs:
|
|
graph = ops.Graph()
|
|
with graph.as_default():
|
|
inputs = input_fn(size, ninput)
|
|
|
|
format_args = (tag, size, ninput, repeats)
|
|
self._SetupAndRunBenchmark(graph, inputs, repeats, format_args)
|
|
|
|
def benchmarkAccumulateN(self):
|
|
self._template = "{:<15}" * 6
|
|
args = {
|
|
"sizes": (128, 128**2),
|
|
"ninputs": (1, 10, 100, 300),
|
|
"repeats": 100
|
|
}
|
|
benchmarks = (("Replicated", self._GenerateReplicatedInputs),
|
|
("Unordered", self._GenerateUnorderedInputs),
|
|
("Ordered", self._GenerateOrderedInputs),
|
|
("Reversed", self._GenerateReversedInputs))
|
|
|
|
print(self._template.format("", "Size", "#Inputs", "#Repeat", "Method",
|
|
"Duration"))
|
|
print("-" * 90)
|
|
for benchmark in benchmarks:
|
|
self._RunBenchmark(*benchmark, **args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test.main()
|