xref: /aosp_15_r20/external/tensorflow/tensorflow/python/ops/batch_ops.py (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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
16"""Operations for automatic batching and unbatching."""
17from tensorflow.python.eager import function
18from tensorflow.python.framework import ops
19from tensorflow.python.framework import tensor_spec
20from tensorflow.python.ops import gen_batch_ops
21# pylint: disable=wildcard-import
22from tensorflow.python.ops.gen_batch_ops import *
23# pylint: enable=wildcard-import
24from tensorflow.python.util import nest
25from tensorflow.python.util.tf_export import tf_export
26
27
28@tf_export("nondifferentiable_batch_function")
29def batch_function(num_batch_threads,
30                   max_batch_size,
31                   batch_timeout_micros,
32                   allowed_batch_sizes=None,
33                   max_enqueued_batches=10,
34                   autograph=True,
35                   enable_large_batch_splitting=True):
36  """Batches the computation done by the decorated function.
37
38  So, for example, in the following code
39
40  ```python
41  @batch_function(1, 2, 3)
42  def layer(a):
43    return tf.matmul(a, a)
44
45  b = layer(w)
46  ```
47
48  if more than one session.run call is simultaneously trying to compute `b`
49  the values of `w` will be gathered, non-deterministically concatenated
50  along the first axis, and only one thread will run the computation. See the
51  documentation of the `Batch` op for more details.
52
53  Assumes that all arguments of the decorated function are Tensors which will
54  be batched along their first dimension.
55
56  SparseTensor is not supported. The return value of the decorated function
57  must be a Tensor or a list/tuple of Tensors.
58
59  Args:
60    num_batch_threads: Number of scheduling threads for processing batches
61     of work. Determines the number of batches processed in parallel.
62    max_batch_size: Batch sizes will never be bigger than this.
63    batch_timeout_micros: Maximum number of microseconds to wait before
64     outputting an incomplete batch.
65    allowed_batch_sizes: Optional list of allowed batch sizes. If left empty,
66     does nothing. Otherwise, supplies a list of batch sizes, causing the op
67     to pad batches up to one of those sizes. The entries must increase
68     monotonically, and the final entry must equal max_batch_size.
69    max_enqueued_batches: The maximum depth of the batch queue. Defaults to 10.
70    autograph: Whether to use autograph to compile python and eager style code
71     for efficient graph-mode execution.
72    enable_large_batch_splitting: The value of this option doesn't affect
73     processing output given the same input; it affects implementation details
74     as stated below: 1. Improve batching efficiency by eliminating unnecessary
75     adding. 2.`max_batch_size` specifies the limit of input and
76     `allowed_batch_sizes` specifies the limit of a task to be processed. API
77     user can give an input of size 128 when 'max_execution_batch_size'
78     is 32 -> implementation can split input of 128 into 4 x 32, schedule
79     concurrent processing, and then return concatenated results corresponding
80     to 128.
81
82  Returns:
83    The decorated function will return the unbatched computation output Tensors.
84  """
85
86  def decorator(fn):  # pylint: disable=missing-docstring
87
88    def decorated(*args):  # pylint: disable=missing-docstring
89
90      @function.defun(autograph=autograph)
91      def computation(*computation_args):
92        return fn(*computation_args)
93
94      computation = computation.get_concrete_function(
95          *[tensor_spec.TensorSpec(dtype=x.dtype, shape=x.shape, name=str(i))
96            for i, x in enumerate(args)])
97
98      with ops.name_scope("batch") as name:
99        for a in args:
100          if not isinstance(a, ops.Tensor):
101            raise ValueError("All arguments to functions decorated with "
102                             "`batch_function`  are supposed to be Tensors; "
103                             f"found {a!r}.")
104        outputs = gen_batch_ops.batch_function(
105            num_batch_threads=num_batch_threads,
106            max_batch_size=max_batch_size,
107            batch_timeout_micros=batch_timeout_micros,
108            allowed_batch_sizes=allowed_batch_sizes,
109            max_enqueued_batches=max_enqueued_batches,
110            shared_name=name,
111            enable_large_batch_splitting=enable_large_batch_splitting,
112            f=computation,
113            in_tensors=list(args),
114            captured_tensors=computation.captured_inputs,
115            Tout=[o.dtype for o in computation.outputs])
116        return nest.pack_sequence_as(
117            computation.structured_outputs, outputs, expand_composites=True)
118
119    return decorated
120
121  return decorator
122