def batch_function(num_batch_threads, max_batch_size, batch_timeout_micros, allowed_batch_sizes=None, grad_timeout_micros=((60 * 1000) * 1000), unbatch_timeout_micros=((60 * 1000) * 1000)):
    'Batches the computation done by the decorated function.\n\n  So, for example, in the following code\n\n  ```python\n  @batch_function(1, 2, 3)\n  def layer(a):\n    return tf.matmul(a, a)\n\n  b = layer(w)\n  ```\n\n  if more than one session.run call is simultaneously trying to compute `b`\n  the values of `w` will be gathered, non-deterministically concatenated\n  along the first axis, and only one thread will run the computation. See the\n  documentation of the `Batch` op for more details.\n\n  Assumes that all arguments of the decorated function are Tensors which will\n  be batched along their first dimension.\n\n  SparseTensor is not supported. The return value of the decorated function\n  must be a Tensor or a list/tuple of Tensors.\n\n  Args:\n    num_batch_threads: Number of scheduling threads for processing batches\n     of work. Determines the number of batches processed in parallel.\n    max_batch_size: Batch sizes will never be bigger than this.\n    batch_timeout_micros: Maximum number of microseconds to wait before\n     outputting an incomplete batch.\n    allowed_batch_sizes: Optional list of allowed batch sizes. If left empty,\n     does nothing. Otherwise, supplies a list of batch sizes, causing the op\n     to pad batches up to one of those sizes. The entries must increase\n     monotonically, and the final entry must equal max_batch_size.\n    grad_timeout_micros: The timeout to use for the gradient. See the\n     documentation of the unbatch op for more details. Defaults to 60s.\n    unbatch_timeout_micros: The timeout to use for unbatching. See the\n     documentation of the unbatch op for more details. Defaults to 60s.\n\n  Returns:\n    The decorated function will return the unbatched computation output Tensors.\n  '

    def decorator(f):

        def decorated(*args):
            with ops.name_scope('batch') as name:
                for a in args:
                    if (not isinstance(a, ops.Tensor)):
                        raise ValueError(('All arguments to functions decorated with `batch_function`  are supposed to be Tensors; found %s' % repr(a)))
                (batched_tensors, batch_index, id_t) = gen_batch_ops.batch(args, num_batch_threads=num_batch_threads, max_batch_size=max_batch_size, batch_timeout_micros=batch_timeout_micros, allowed_batch_sizes=allowed_batch_sizes, grad_timeout_micros=grad_timeout_micros, shared_name=name)
                outputs = f(*batched_tensors)
                if isinstance(outputs, ops.Tensor):
                    outputs_list = [outputs]
                else:
                    outputs_list = outputs
                with ops.name_scope('unbatch') as unbatch_name:
                    unbatched = [gen_batch_ops.unbatch(t, batch_index, id_t, timeout_micros=unbatch_timeout_micros, shared_name=unbatch_name) for t in outputs_list]
                if isinstance(outputs, ops.Tensor):
                    return unbatched[0]
                return unbatched
        return decorated
    return decorator
Batches the computation done by the decorated function.

So, for example, in the following code

```python
@batch_function(1, 2, 3)
def layer(a):
  return tf.matmul(a, a)

b = layer(w)
```

if more than one session.run call is simultaneously trying to compute `b`
the values of `w` will be gathered, non-deterministically concatenated
along the first axis, and only one thread will run the computation. See the
documentation of the `Batch` op for more details.

Assumes that all arguments of the decorated function are Tensors which will
be batched along their first dimension.

SparseTensor is not supported. The return value of the decorated function
must be a Tensor or a list/tuple of Tensors.

Args:
  num_batch_threads: Number of scheduling threads for processing batches
   of work. Determines the number of batches processed in parallel.
  max_batch_size: Batch sizes will never be bigger than this.
  batch_timeout_micros: Maximum number of microseconds to wait before
   outputting an incomplete batch.
  allowed_batch_sizes: Optional list of allowed batch sizes. If left empty,
   does nothing. Otherwise, supplies a list of batch sizes, causing the op
   to pad batches up to one of those sizes. The entries must increase
   monotonically, and the final entry must equal max_batch_size.
  grad_timeout_micros: The timeout to use for the gradient. See the
   documentation of the unbatch op for more details. Defaults to 60s.
  unbatch_timeout_micros: The timeout to use for unbatching. See the
   documentation of the unbatch op for more details. Defaults to 60s.

Returns:
  The decorated function will return the unbatched computation output Tensors.
def batch_function(num_batch_threads, max_batch_size, batch_timeout_micros, allowed_batch_sizes=None, grad_timeout_micros=((60 * 1000) * 1000), unbatch_timeout_micros=((60 * 1000) * 1000)):
    'Batches the computation done by the decorated function.\n\n  So, for example, in the following code\n\n  ```python\n  @batch_function(1, 2, 3)\n  def layer(a):\n    return tf.matmul(a, a)\n\n  b = layer(w)\n  ```\n\n  if more than one session.run call is simultaneously trying to compute `b`\n  the values of `w` will be gathered, non-deterministically concatenated\n  along the first axis, and only one thread will run the computation. See the\n  documentation of the `Batch` op for more details.\n\n  Assumes that all arguments of the decorated function are Tensors which will\n  be batched along their first dimension.\n\n  SparseTensor is not supported. The return value of the decorated function\n  must be a Tensor or a list/tuple of Tensors.\n\n  Args:\n    num_batch_threads: Number of scheduling threads for processing batches\n     of work. Determines the number of batches processed in parallel.\n    max_batch_size: Batch sizes will never be bigger than this.\n    batch_timeout_micros: Maximum number of microseconds to wait before\n     outputting an incomplete batch.\n    allowed_batch_sizes: Optional list of allowed batch sizes. If left empty,\n     does nothing. Otherwise, supplies a list of batch sizes, causing the op\n     to pad batches up to one of those sizes. The entries must increase\n     monotonically, and the final entry must equal max_batch_size.\n    grad_timeout_micros: The timeout to use for the gradient. See the\n     documentation of the unbatch op for more details. Defaults to 60s.\n    unbatch_timeout_micros: The timeout to use for unbatching. See the\n     documentation of the unbatch op for more details. Defaults to 60s.\n\n  Returns:\n    The decorated function will return the unbatched computation output Tensors.\n  '

    def decorator(f):

        def decorated(*args):
            with ops.name_scope('batch') as name:
                for a in args:
                    if (not isinstance(a, ops.Tensor)):
                        raise ValueError(('All arguments to functions decorated with `batch_function`  are supposed to be Tensors; found %s' % repr(a)))
                (batched_tensors, batch_index, id_t) = gen_batch_ops.batch(args, num_batch_threads=num_batch_threads, max_batch_size=max_batch_size, batch_timeout_micros=batch_timeout_micros, allowed_batch_sizes=allowed_batch_sizes, grad_timeout_micros=grad_timeout_micros, shared_name=name)
                outputs = f(*batched_tensors)
                if isinstance(outputs, ops.Tensor):
                    outputs_list = [outputs]
                else:
                    outputs_list = outputs
                with ops.name_scope('unbatch') as unbatch_name:
                    unbatched = [gen_batch_ops.unbatch(t, batch_index, id_t, timeout_micros=unbatch_timeout_micros, shared_name=unbatch_name) for t in outputs_list]
                if isinstance(outputs, ops.Tensor):
                    return unbatched[0]
                return unbatched
        return decorated
    return decorator