input.py

来源:互联网 发布:女狙击手知乎 编辑:程序博客网 时间:2024/05/18 03:44
"""Input pipeline.输入管线。Please see the @{$reading_data$reading data how-to}for context."""from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionimport collectionsfrom six.moves import xrange  # pylint: disable=redefined-builtinfrom tensorflow.python.framework import constant_opfrom tensorflow.python.framework import dtypesfrom tensorflow.python.framework import opsfrom tensorflow.python.framework import sparse_tensorfrom tensorflow.python.framework import tensor_shapefrom tensorflow.python.framework import tensor_utilfrom tensorflow.python.ops import array_opsfrom tensorflow.python.ops import control_flow_opsfrom tensorflow.python.ops import data_flow_opsfrom tensorflow.python.ops import io_opsfrom tensorflow.python.ops import math_opsfrom tensorflow.python.ops import random_opsfrom tensorflow.python.ops import sparse_opsfrom tensorflow.python.ops import variablesfrom tensorflow.python.summary import summaryfrom tensorflow.python.training import queue_runner# pylint: disable=protected-access_store_sparse = sparse_ops._add_sparse_to_tensors_map_store_many_sparse = sparse_ops._add_many_sparse_to_tensors_map_restore_sparse = sparse_ops._take_many_sparse_from_tensors_map# pylint: enable=protected-accessdef match_filenames_once(pattern, name=None):  """Save the list of files matching pattern, so it is only computed once.  保存匹配模式的文件列表,因此只计算一次  Args:    pattern: A file pattern (glob), or 1D tensor of file patterns.    name: A name for the operations (optional).  Returns:    A variable that is initialized to the list of files matching the pattern(s).  """  print("input.py match_filenames_once")  with ops.name_scope(name, "matching_filenames", [pattern]) as name:    return variables.Variable(io_ops.matching_files(pattern), trainable=False,                              name=name, validate_shape=False,                              collections=[ops.GraphKeys.LOCAL_VARIABLES])def limit_epochs(tensor, num_epochs=None, name=None):  """Returns tensor `num_epochs` times and then raises an `OutOfRange` error.  返回`num_epochs`次的tensor,然后引发`OutOfRange`错误.  Note: creates local counter `epochs`. Use `local_variables_initializer()` to  initialize local variables.  创建本地的计数器 `epochs`。 使用`local_variables_initializer()`来初始化局部变量。  Args:    tensor: Any `Tensor`.    num_epochs: A positive integer (optional).  If specified, limits the number      of steps the output tensor may be evaluated.      正整数(可选)。 如果指定,则限制可以评估输出张量的步数。    name: A name for the operations (optional).  Returns:    tensor or `OutOfRange`.  Raises:    ValueError: if `num_epochs` is invalid.  """  if num_epochs is None:    return tensor  if num_epochs <= 0:    raise ValueError("num_epochs must be > 0 not %d." % num_epochs)  with ops.name_scope(name, "limit_epochs", [tensor]) as name:    zero64 = constant_op.constant(0, dtype=dtypes.int64)    epochs = variables.Variable(        zero64, name="epochs", trainable=False,        collections=[ops.GraphKeys.LOCAL_VARIABLES])        # tensorflow/python/ops/variables.py     # count_up_to(self, limit)    # Increments this variable until it reaches limit.        counter = epochs.count_up_to(num_epochs)    with ops.control_dependencies([counter]):      return array_ops.identity(tensor, name=name)def input_producer(input_tensor,                   element_shape=None,                   num_epochs=None,                   shuffle=True,                   seed=None,                   capacity=32,                   shared_name=None,                   summary_name=None,                   name=None,                   cancel_op=None):  """Output the rows of `input_tensor` to a queue for an input pipeline.  将`input_tensor`的行输出到输入管道的队列。  Note: if `num_epochs` is not `None`, this function creates local counter  `epochs`. Use `local_variables_initializer()` to initialize local variables.  注意:如果`num_epochs`不是`None`,这个函数创建本地的计数器'epochs`。   使用`local_variables_initializer()` 来初始化局部变量。  Args:    input_tensor: A tensor with the rows to produce. Must be at least      one-dimensional. Must either have a fully-defined shape, or      `element_shape` must be defined.    element_shape: (Optional.) A `TensorShape` representing the shape of a      row of `input_tensor`, if it cannot be inferred.    num_epochs: (Optional.) An integer. If specified `input_producer` produces      each row of `input_tensor` `num_epochs` times before generating an      `OutOfRange` error. If not specified, `input_producer` can cycle through      the rows of `input_tensor` an unlimited number of times.    shuffle: (Optional.) A boolean. If true, the rows are randomly shuffled      within each epoch.    seed: (Optional.) An integer. The seed to use if `shuffle` is true.    capacity: (Optional.) The capacity of the queue to be used for buffering      the input.    shared_name: (Optional.) If set, this queue will be shared under the given      name across multiple sessions.    summary_name: (Optional.) If set, a scalar summary for the current queue      size will be generated, using this name as part of the tag.    name: (Optional.) A name for queue.    cancel_op: (Optional.) Cancel op for the queue  参数:      input_tensor:要生成的行的张量,至少一维。必须具有完全定义的形状或者定义`element_shape`。    element_shape:(可选)一个`TensorShape`表示`input_tensor`一行的形状,如果不能推断的话。    num_epochs:整数(可选)。如果指定,`input_producer`会在生成`OutOfRange`       错误之前,将`input_tensor`的每一行生成`num_epochs`次。        如果没有指定,`input_producer`可以无限次循环遍历'input_tensor'的各行。    shuffle:(可选)布尔值。如果为true,则每行在每个epoch内随机地进行排序。    seed:(可选)整数。如果`shuffle`是true的,使用的seed。    capacity:(可选)队列缓冲输入的容量。    shared_name:(可选)如果设置,该队列将在多个会话中的共享给定名称。    summary_name:(可选)如果设置,将生成当前队列大小的标量摘要,使用此名称作为标记的一部分。    name :(可选)队列名称。    cancel_op :(可选)取消对队列的操作  Returns:    A queue with the output rows.  A `QueueRunner` for the queue is    added to the current `QUEUE_RUNNER` collection of the current    graph.    具有输出行的队列。 队列中的`QueueRunner`将添加到当前graph的当前`QUEUE_RUNNER`集合中。  Raises:    ValueError: If the shape of the input cannot be inferred from the arguments.  """  print("input.py input_producer")  with ops.name_scope(name, "input_producer", [input_tensor]):    input_tensor = ops.convert_to_tensor(input_tensor, name="input_tensor")    element_shape = input_tensor.get_shape()[1:].merge_with(element_shape)    if not element_shape.is_fully_defined():      raise ValueError("Either `input_tensor` must have a fully defined shape "                       "or `element_shape` must be specified")    # tensorflow/python/ops/random_ops.py    # random_shuffle(value, seed=None, name=None)        # tensorflow/python/ops/gen_random_ops.py    # _random_shuffle(value, seed=None, seed2=None, name=None):    # Randomly shuffles a tensor along its first dimension.    # 沿其第一维度随机洗牌。                       if shuffle:      input_tensor = random_ops.random_shuffle(input_tensor, seed=seed)     # num_epochs: If specified `input_producer` produces    # each row of `input_tensor` `num_epochs` times before generating an    # `OutOfRange` error. If not specified, `input_producer` can cycle through    # the rows of `input_tensor` an unlimited number of times.     # 如果num_epochs有指定,则 input_tensor 的各行只产生 num_epochs 次,否则循环产生。    input_tensor = limit_epochs(input_tensor, num_epochs)    # 新建一个 FIFOQueue, 先入先出队列, 数据流操作,      q = data_flow_ops.FIFOQueue(capacity=capacity,                                dtypes=[input_tensor.dtype.base_dtype],                                shapes=[element_shape],                                shared_name=shared_name, name=name)                                    enq = q.enqueue_many([input_tensor])       # QueueRunner类会创建一组线程,这些线程可以重复的执行 Enqueue 操作。    # 它们使用同一个Coordinator来处理线程同步终止。    # 一个QueueRunner会运行一个closer thread,当Coordinator收到异常报告时,这个closer thread会自动关闭队列    queue_runner.add_queue_runner(queue_runner.QueueRunner(q, [enq], cancel_op=cancel_op))        if summary_name is not None:      summary.scalar(summary_name,                     math_ops.cast(q.size(), dtypes.float32) * (1. / capacity))    return qdef string_input_producer(string_tensor,                          num_epochs=None,                          shuffle=True,                          seed=None,                          capacity=32,                          shared_name=None,                          name=None,                          cancel_op=None):  """Output strings (e.g. filenames) to a queue for an input pipeline.  将输出字符串(例如文件名)输出到输入流水线的队列。  Note: if `num_epochs` is not `None`, this function creates local counter  `epochs`. Use `local_variables_initializer()` to initialize local variables.  注意:如果`num_epochs`不是`None`,这个函数创建本地的计数器`epochs`。   使用`local_variables_initializer()` 来初始化局部变量。  Args:    string_tensor: A 1-D string tensor with the strings to produce.    num_epochs: An integer (optional). If specified, `string_input_producer`      produces each string from `string_tensor` `num_epochs` times before      generating an `OutOfRange` error. If not specified,      `string_input_producer` can cycle through the strings in `string_tensor`      an unlimited number of times.    shuffle: Boolean. If true, the strings are randomly shuffled within each      epoch.    seed: An integer (optional). Seed used if shuffle == True.    capacity: An integer. Sets the queue capacity.    shared_name: (optional). If set, this queue will be shared under the given      name across multiple sessions.    name: A name for the operations (optional).    cancel_op: Cancel op for the queue (optional).        string_tensor:具有生成字符串的1-D字符串张量。    num_epochs:整数(可选)。如果指定,`string_input_producer`会在生成`OutOfRange`       错误之前从`string_tensor`生成每个字符串`num_epochs`次。      如果没有指定,`string_input_producer`可以循环遍历'string_tensor'中的字符串,无限次。    shuffle:布尔值。 如果为true,那么这些字符串在每个epoch内随机洗牌。    seed:整数(可选)。 如果 shuffle == True 使用的种子。    capacity:整数。 设置队列容量。    shared_name:(可选)。 如果设置,该队列将在多个会话中的共享给定名称。    name:操作的名称(可选)。    cancel_op:取消对队列的操作(可选)。  Returns:    A queue with the output strings.  A `QueueRunner` for the Queue    is added to the current `Graph`'s `QUEUE_RUNNER` collection.    具有输出字符串的队列。 队列中的`QueueRunner`将添加到当前的 `Graph`的`QUEUE_RUNNER`集合中。  Raises:    ValueError: If the string_tensor is a null Python list.  At runtime,    will fail with an assertion if string_tensor becomes a null tensor.  """  print("input.py string_input_producer")  not_null_err = "string_input_producer requires a non-null input tensor"  if not isinstance(string_tensor, ops.Tensor) and not string_tensor:    raise ValueError(not_null_err)  # tensorflow/python/framework/ops.py     # convert_to_tensor(value, dtype=None, name=None, preferred_dtype=None)  # Converts the given `value` to a `Tensor`.  # 将给定的“value”转换为“Tensor”。    with ops.name_scope(name, "input_producer", [string_tensor]) as name:    string_tensor = ops.convert_to_tensor(string_tensor, dtype=dtypes.string)        # tensorflow/python/framework/ops.py     # control_dependencies(self, control_inputs)    # Returns a context manager that specifies control dependencies.    # 返回一个上下文,这个上下文中明确了控制依赖    # 参数:一个操作或者张量的集合,这个操作或者张量必须先被执行或者计算,然后再执行定义在上下文中的操作    # 说明:控制依赖可以被嵌套。    #       可以通过传递None来清空控制依赖    #       形成控制依赖的张量或者操作必须在返回的上下文里被定义        # tensorflow/python/ops/gen_math_ops.py    # greater(x, y, name=None)    # Returns the truth value of (x > y) element-wise.    # 以元素方式返回(x > y)的真值。    # Args:    #   x, y: A `Tensor`. Must be one of the following types: `float32`, `float64`, `int32`, `int64`, `uint8`, `int16`, `int8`, `uint16`, `half`. y must have the same type as `x`.    #   name: A name for the operation (optional).    # Returns: A `Tensor` of type `bool`.    # tensorflow/python/ops/gen_array_ops.py    # identity(input, name=None):    # Return a tensor with the same shape and contents as the input tensor or value.    # 返回一个张量,这个张量与输入张量或输入值有相同的形状和内容。    # Args:    #   input: A `Tensor`.    #   name: A name for the operation (optional).    # Returns: A `Tensor`. Has the same type as `input`.    with ops.control_dependencies([        control_flow_ops.Assert(            math_ops.greater(array_ops.size(string_tensor), 0),            [not_null_err])]):      string_tensor = array_ops.identity(string_tensor)          return input_producer(        input_tensor=string_tensor,        element_shape=[],        num_epochs=num_epochs,        shuffle=shuffle,        seed=seed,        capacity=capacity,        shared_name=shared_name,        name=name,        summary_name="fraction_of_%d_full" % capacity,        cancel_op=cancel_op)def range_input_producer(limit, num_epochs=None, shuffle=True, seed=None,                         capacity=32, shared_name=None, name=None):  """Produces the integers from 0 to limit-1 in a queue.  产生整数从0到limit-1的队列。  Note: if `num_epochs` is not `None`, this function creates local counter  `epochs`. Use `local_variables_initializer()` to initialize local variables.  Args:    limit: An int32 scalar tensor.    num_epochs: An integer (optional). If specified, `range_input_producer`      produces each integer `num_epochs` times before generating an      OutOfRange error. If not specified, `range_input_producer` can cycle      through the integers an unlimited number of times.    shuffle: Boolean. If true, the integers are randomly shuffled within each      epoch.    seed: An integer (optional). Seed used if shuffle == True.    capacity: An integer. Sets the queue capacity.    shared_name: (optional). If set, this queue will be shared under the given      name across multiple sessions.    name: A name for the operations (optional).  Returns:    A Queue with the output integers.  A `QueueRunner` for the Queue    is added to the current `Graph`'s `QUEUE_RUNNER` collection.  """  with ops.name_scope(name, "input_producer", [limit]) as name:    range_tensor = math_ops.range(limit)    return input_producer(        range_tensor, [], num_epochs, shuffle, seed, capacity,        shared_name, "fraction_of_%d_full" % capacity, name)def slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None,                         capacity=32, shared_name=None, name=None):  """Produces a slice of each `Tensor` in `tensor_list`.  生成在`tensor_list`中的每个`Tensor`的切片。  Implemented using a Queue -- a `QueueRunner` for the Queue  is added to the current `Graph`'s `QUEUE_RUNNER` collection.  通过使用Queue实现 -- 队列的QueueRunner被添加到当前的`Graph`的`QUEUE_RUNNER`集合中。  Args:    tensor_list: A list of `Tensor` objects. Every `Tensor` in      `tensor_list` must have the same size in the first dimension.    num_epochs: An integer (optional). If specified, `slice_input_producer`      produces each slice `num_epochs` times before generating      an `OutOfRange` error. If not specified, `slice_input_producer` can cycle      through the slices an unlimited number of times.    shuffle: Boolean. If true, the integers are randomly shuffled within each      epoch.    seed: An integer (optional). Seed used if shuffle == True.    capacity: An integer. Sets the queue capacity.    shared_name: (optional). If set, this queue will be shared under the given      name across multiple sessions.    name: A name for the operations (optional).  Returns:    A list of tensors, one for each element of `tensor_list`.  If the tensor    in `tensor_list` has shape `[N, a, b, .., z]`, then the corresponding output    tensor will have shape `[a, b, ..., z]`.  Raises:    ValueError: if `slice_input_producer` produces nothing from `tensor_list`.  """  print("input.py  slice_input_producer")  with ops.name_scope(name, "input_producer", tensor_list):    tensor_list = ops.convert_n_to_tensor_or_indexed_slices(tensor_list)    if not tensor_list:      raise ValueError(          "Expected at least one tensor in slice_input_producer().")    range_size = array_ops.shape(tensor_list[0])[0]    # TODO(josh11b): Add an assertion that the first dimension of    # everything in TensorList matches. Maybe just check the inferred shapes?    queue = range_input_producer(range_size, num_epochs=num_epochs,                                 shuffle=shuffle, seed=seed, capacity=capacity,                                 shared_name=shared_name)    index = queue.dequeue()    output = [array_ops.gather(t, index) for t in tensor_list]    return output# Helpers for the batching functions ------------------------------------------def _flatten(tensor_list_list):  return [tensor for tensor_list in tensor_list_list for tensor in tensor_list]class _SparseMetaData(object):  """Store information about the Tensor: Is it sparse?, map_op, and rank."""  """存储有关Tensor的信息:它是否稀疏?map_op和rank。"""  def __init__(self, sparse, map_op, rank):    """Create the metadata.    创建元数据。    Args:      sparse: Python boolean.      map_op: The `Operation` that created the `SparseTensorsMap` in question.        This Op contains information about the underlying Map object and the        dtype of the original data.      rank: The statically known rank of the `SparseTensor`.    """    self._sparse = sparse    self._map_op = map_op    self._rank = rank  def __eq__(self, other):    if self.sparse != other.sparse:      return False    if not self.sparse:      return True    # If map_ops are not the same, the data source is not the same.    if (self.map_op is not None) != (other.map_op is not None):      return False    if self.map_op != other.map_op:      return False    if not self.rank.is_compatible_with(other.rank):      return False    return True  def __ne__(self, other):    return not self.__eq__(other)  def __str__(self):    return "[SparseMetaData(%s, %s, %s)]" % (self.sparse, self.map_op.name,                                             self.rank)  def merge_with(self, other):    if self != other:      raise ValueError("SparseMetaData objects are incompatible: %s vs. %s"                       % (self, other))    if self.sparse:      self.rank.merge_with(other.rank)    return self  @property  def map_op(self):    return self._map_op  @property  def sparse(self):    return self._sparse  @property  def rank(self):    return self._rankdef _as_tensor_list(tensors):  if isinstance(tensors, dict):    return [tensors[k] for k in sorted(tensors)]  else:    return tensorsdef _as_tensor_list_list(tensors_list):  if not tensors_list:    raise ValueError("Expected at least one set of tensors")  if isinstance(tensors_list[0], dict):    expected_keys = set(tensors_list[0].keys())    for tensors in tensors_list[1:]:      if set(tensors.keys()) != expected_keys:        raise ValueError("All dictionaries in tensors_list must have "                         "the same keys")    return [_as_tensor_list(tensors) for tensors in tensors_list]  else:    return tensors_listdef _as_original_type(original_tensors, tensor_list):  if isinstance(original_tensors, dict):    if len(original_tensors) == 1:      # tensor_list is bogusly returned as a single tensor if only one tensor      # was enqueued.  Make it a list again.  See b/28117485.      tensor_list = [tensor_list]    return {k: tensor_list[i]            for i, k in enumerate(sorted(original_tensors))}  else:    return tensor_list    # enqueue_ops = [_smart_cond(keep_input, lambda: enqueue_fn(tensor_list), control_flow_ops.no_op)] * threads# 一个`tf.cond`,当条件是静态的时候什么也不做def _smart_cond(pred, if_true, if_false):  """A `tf.cond` that does nothing when the condition is static."""  pred = ops.convert_to_tensor(pred)  static_pred = tensor_util.constant_value(pred)  if static_pred is not None:    if static_pred:      return if_true()    else:      return if_false()  else:    return control_flow_ops.cond(        pred,        if_true,        if_false)def _store_sparse_tensors(tensor_list, enqueue_many, keep_input,                          shared_map_ops=None):  """Store SparseTensors for feeding into batch, etc.  为进行批处理的feeding储存SparseTensors  If `shared_map_ops` is provided, the underlying `SparseTensorsMap` objects  are reused (shared).  This argument is useful for, e.g., `batch_join`  where multiple enqueue operations write to the same Queue component,  and another (dequeue) thread reads from that same location and must then  restore the associated `SparseTensor` objects.  In this case, the sparse  restore must have a single `SparseTensorMap` from which to read out the  handles; so a single `SparseTensorMap` must be shared for storing  across the multiple enqueue operations.  This sharing is performed by  calling `_store_sparse_tensors` the first time with `shared_map_ops=None`,  and then in subsequent times with this value set to the list of `Operation`  objects created in the first call.  Args:    tensor_list: List of `Tensor` and `SparseTensor` objects.    enqueue_many: Python `Boolean`.    keep_input: Must be a scalar bool Tensor (not a Python bool). If False,      don't store.     keep_input: 必须是标量 bool Tensor(不是Python bool)。 如果是False,不存储。    shared_map_ops: (optional) List of `Operation` objects from a previous      call to `_store_sparse_tensors`.  If not `None`, the op types should be      one of `AddSparseToTensorsMap` or `AddManySparseToTensorsMap` in the      locations corresponding to `SparseTensors` in `tensor_list`.  Returns:    A tuple `(stored_list, sparse_info_list)` where `stored_list` is a list    of `Tensor` objects (same length as `tensor_list`) and `sparse_info_list`    is a list of the same length of `_SparseMetaData` objects.  """  maybe_shared_map_ops = shared_map_ops or [None] * len(tensor_list)  def _sparse_meta_data(t, storing_op, map_op):    if not isinstance(t, sparse_tensor.SparseTensor):      return _SparseMetaData(False, None, None)    rank = t.dense_shape.get_shape().with_rank(1)[0]    if enqueue_many:      rank -= 1    # If a shared map_op was provided, use that. Otherwise use the name of    # the operation used to store the SparseTensor.    return _SparseMetaData(        sparse=True, map_op=map_op or storing_op, rank=rank)  def _maybe_store(t, shared_map_op):    """Store Sparse tensor, if necessary."""    if not isinstance(t, sparse_tensor.SparseTensor):      return t    map_op_name = shared_map_op.name if shared_map_op else None    def _maybe_store_sparse(t, map_op_name, keep_input):      """Conditionally store a single sparse Tensor."""      return _smart_cond(          keep_input,          lambda: _store_sparse(t, shared_name=map_op_name),          lambda: constant_op.constant(-1, dtypes.int64))    def _maybe_store_many_sparse(t, map_op_name, keep_input):      """Conditionally store multiple sparse Tensors."""      out_tensor = _smart_cond(          keep_input,          lambda: _store_many_sparse(t, shared_name=map_op_name),          lambda: -1 * array_ops.ones(array_ops.shape(t)[0:1], dtypes.int64))      out_tensor.set_shape([None])  # necessary when t.ndims is unknown      return out_tensor    if keep_input.get_shape().ndims == 1:      t = sparse_ops.sparse_retain(t, keep_input)      store_f = lambda t, name, _: _store_many_sparse(t, shared_name=name)    elif enqueue_many:      store_f = _maybe_store_many_sparse    else:      store_f = _maybe_store_sparse    return store_f(t, map_op_name, keep_input)  stored_list = [      _maybe_store(t, shared_map_op) for t, shared_map_op      in zip(tensor_list, maybe_shared_map_ops)]  # Since the output of `_store{_many}_sparse is wrapped in a tf.cond `Merge`,  # we can't just get the Op of the resulting tensor.  def _sparse_op(stored):    for input_tensor in stored.op.inputs:      if input_tensor.op.type in ("AddSparseToTensorsMap",                                  "AddManySparseToTensorsMap"):        return input_tensor.op    # If there was no sparse input, then the original stored Tensor wasn't    # sparse and we can just return the original Tensor's Op.    return stored.op  sparse_info_list = [      _sparse_meta_data(t, _sparse_op(stored), shared_map_op)      for t, stored, shared_map_op      in zip(tensor_list, stored_list, maybe_shared_map_ops)]  # Expand dims of stored tensors by 1 for proper enqueue shape  stored_list = [      array_ops.expand_dims(s, [-1]) if s_info.sparse else s      for s, s_info in zip(stored_list, sparse_info_list)]  return stored_list, sparse_info_listdef _store_sparse_tensors_join(tensor_list_list, enqueue_many, keep_input):  """Store SparseTensors for feeding into batch_join, etc."""  (s0, sparse_info_list) = _store_sparse_tensors(      tensor_list_list[0], enqueue_many, keep_input)  stored_list_list = [s0]  for tensor_list in tensor_list_list[1:]:    s, sparse_info_candidate = _store_sparse_tensors(        tensor_list, enqueue_many, keep_input,        [st.map_op for st in sparse_info_list])    if sparse_info_list != sparse_info_candidate:      raise ValueError("Inconsistent SparseTensors list: %s vs. %s"                       % (tensor_list_list[0], tensor_list))    sparse_info_list = [        info.merge_with(candidate)        for (info, candidate) in zip(sparse_info_list, sparse_info_candidate)]    stored_list_list.append(s)  return (stored_list_list, sparse_info_list)def _restore_sparse_tensors(stored_list, sparse_info_list):  """Restore SparseTensors after dequeue in batch, batch_join, etc."""  received_sequence = isinstance(stored_list, collections.Sequence)  if not received_sequence:    stored_list = (stored_list,)  tensors = [      _restore_sparse(sparse_map_op=info.map_op,                      sparse_handles=array_ops.squeeze(s, [1]),                      rank=(info.rank + 1).value)      if info.sparse else s      for (s, info) in zip(stored_list, sparse_info_list)]  return tensors if received_sequence else tensors[0]def _validate(tensor_list):  tensor_list = ops.convert_n_to_tensor_or_indexed_slices(tensor_list)  if not tensor_list:    raise ValueError("Expected at least one tensor in batch().")  return tensor_listdef _validate_join(tensor_list_list):  tensor_list_list = [ops.convert_n_to_tensor_or_indexed_slices(tl)                      for tl in tensor_list_list]  if not tensor_list_list:    raise ValueError("Expected at least one input in batch_join().")  return tensor_list_listdef _validate_keep_input(keep_input, enqueue_many):  """Validate `keep_input` argument to conditional batching functions."""  keep_input = ops.convert_to_tensor(keep_input)  if keep_input.get_shape().ndims is None:    raise ValueError(        "`keep_input` dimensions must be known at graph construction.")  if not enqueue_many and keep_input.get_shape().ndims == 1:    raise ValueError(        "`keep_input` cannot be a vector when `enqueue_many=False`.")  if keep_input.get_shape().ndims > 1:    raise ValueError("`keep_input` must be 0 or 1 dimensions.")  return keep_inputdef _dtypes(tensor_list_list):  all_types = [[t.dtype for t in tl] for tl in tensor_list_list]  types = all_types[0]  for other_types in all_types[1:]:    if other_types != types:      raise TypeError("Expected types to be consistent: %s vs. %s." %                      (", ".join(x.name for x in types),                       ", ".join(x.name for x in other_types)))  return typesdef _merge_shapes(shape_list, enqueue_many):  shape_list = [tensor_shape.as_shape(s) for s in shape_list]  if enqueue_many:    # We want the shapes without the leading batch dimension.    shape_list = [s.with_rank_at_least(1)[1:] for s in shape_list]  merged_shape = shape_list[0]  for s in shape_list[1:]:    merged_shape.merge_with(s)  return merged_shape.as_list()def _shapes(tensor_list_list, shapes, enqueue_many):  """Calculate and merge the shapes of incoming tensors.  计算并合并传入张量的形状。  Args:    tensor_list_list: List of tensor lists.    shapes: List of shape tuples corresponding to tensors within the lists.    enqueue_many: Boolean describing whether shapes will be enqueued as      batches or individual entries.  Returns:    A list of shapes aggregating shape inference info from `tensor_list_list`,    or returning `shapes` if it is not `None`.    从`tensor_list_list`汇总形状推理信息的形状列表,如果不是`None`,则返回`shapes`。  Raises:    ValueError: If any of the inferred shapes in `tensor_list_list` lack a      well defined rank.  """  if shapes is None:    len0 = len(tensor_list_list[0])    for tl in tensor_list_list:      for i in xrange(len0):        if tl[i].get_shape().ndims is None:          raise ValueError("Cannot infer Tensor's rank: %s" % tl[i])    shapes = [_merge_shapes(        [tl[i].get_shape().as_list() for tl in tensor_list_list], enqueue_many)              for i in xrange(len0)]  return shapesdef _select_which_to_enqueue(tensor_list, keep_input):  """Select which examples to enqueue based on vector `keep_input`."""  select_i = math_ops.cast(keep_input, dtypes.int32)  tensor_list = [      data_flow_ops.dynamic_partition(x, select_i, num_partitions=2)[1]      for x in tensor_list]  return tensor_list# Enqueue `tensor_list_list` in `queue`.def _enqueue_join(queue, tensor_list_list, enqueue_many, keep_input):  """Enqueue `tensor_list_list` in `queue`."""  print("input.py _enqueue_join")  if enqueue_many:    enqueue_fn = queue.enqueue_many  else:    enqueue_fn = queue.enqueue  if keep_input.get_shape().ndims == 1:    enqueue_ops = [enqueue_fn(_select_which_to_enqueue(x, keep_input))                   for x in tensor_list_list]  else:    enqueue_ops = [_smart_cond(        keep_input,        lambda: enqueue_fn(tl),  # pylint:disable=cell-var-from-loop        control_flow_ops.no_op) for tl in tensor_list_list]  queue_runner.add_queue_runner(queue_runner.QueueRunner(queue, enqueue_ops))# Enqueue `tensor_list` in `queue`.def _enqueue(queue, tensor_list, threads, enqueue_many, keep_input):  """Enqueue `tensor_list` in `queue`."""  print("input.py _enqueue")  if enqueue_many:    enqueue_fn = queue.enqueue_many  else:    enqueue_fn = queue.enqueue  # 创建了 threads 个线程,每个线程执行一个 enqueue_ops,  # 这些enqueue_ops是以一个列表的多个元素传入QueueRunner的,执行时异步的。  if keep_input.get_shape().ndims == 1:    enqueue_ops = [enqueue_fn(_select_which_to_enqueue(tensor_list, keep_input))] * threads  else:    enqueue_ops = [_smart_cond(        keep_input,        lambda: enqueue_fn(tensor_list),        control_flow_ops.no_op)] * threads  queue_runner.add_queue_runner(queue_runner.QueueRunner(queue, enqueue_ops))def _which_queue(dynamic_pad):  return (data_flow_ops.PaddingFIFOQueue if dynamic_pad          else data_flow_ops.FIFOQueue)def _batch(tensors, batch_size, keep_input, num_threads=1, capacity=32,           enqueue_many=False, shapes=None, dynamic_pad=False,           allow_smaller_final_batch=False, shared_name=None,           name=None):  """Helper function for `batch` and `maybe_batch`."""  print("input.py _batch")  tensor_list = _as_tensor_list(tensors)  with ops.name_scope(name, "batch", list(tensor_list) + [keep_input]) as name:    tensor_list = _validate(tensor_list)    keep_input = _validate_keep_input(keep_input, enqueue_many)    (tensor_list, sparse_info) = _store_sparse_tensors(        tensor_list, enqueue_many, keep_input)    types = _dtypes([tensor_list])    shapes = _shapes([tensor_list], shapes, enqueue_many)    # TODO(josh11b,mrry): Switch to BatchQueue once it is written.    queue = _which_queue(dynamic_pad)(        capacity=capacity, dtypes=types, shapes=shapes, shared_name=shared_name)    _enqueue(queue, tensor_list, num_threads, enqueue_many, keep_input)    summary.scalar("fraction_of_%d_full" % capacity,                   math_ops.cast(queue.size(), dtypes.float32) *                   (1. / capacity))    if allow_smaller_final_batch:      dequeued = queue.dequeue_up_to(batch_size, name=name)    else:      dequeued = queue.dequeue_many(batch_size, name=name)    dequeued = _restore_sparse_tensors(dequeued, sparse_info)    return _as_original_type(tensors, dequeued)# TODO(josh11b): Add a thread_multiplier or num_threads (that has to be# a multiple of len(tensor_list_list)?) parameter, to address the use# case where you want more parallelism than you can support different# readers (either because you don't have that many files or can't# read that many files in parallel due to the number of seeks required).# Once this is done, batch() can be written as a call to batch_join().# 添加一个 thread_multiplier 或 num_threads 参数(必须是 len(tensor_list_list) 的倍数)?),# 以解决您需要更多并行性的用例,您可以支持不同的readers(或者是因为您没有这么多文件或可以 # 由于需要查询的次数,不能并行读取多个文件)。 一旦完成,batch() 可以被写为对batch_join()的调用。 def _batch_join(tensors_list, batch_size, keep_input, capacity=32,                enqueue_many=False, shapes=None, dynamic_pad=False,                allow_smaller_final_batch=False, shared_name=None, name=None):  """Helper function for `batch_join` and `maybe_batch_join`."""  tensor_list_list = _as_tensor_list_list(tensors_list)  with ops.name_scope(name, "batch_join",                      _flatten(tensor_list_list) + [keep_input]) as name:    tensor_list_list = _validate_join(tensor_list_list)    keep_input = _validate_keep_input(keep_input, enqueue_many)    tensor_list_list, sparse_info = _store_sparse_tensors_join(        tensor_list_list, enqueue_many, keep_input)    types = _dtypes(tensor_list_list)    shapes = _shapes(tensor_list_list, shapes, enqueue_many)    # TODO(josh11b,mrry): Switch to BatchQueue once it is written.    queue = _which_queue(dynamic_pad)(        capacity=capacity, dtypes=types, shapes=shapes, shared_name=shared_name)    _enqueue_join(queue, tensor_list_list, enqueue_many, keep_input)    summary.scalar("fraction_of_%d_full" % capacity,                   math_ops.cast(queue.size(), dtypes.float32) *                   (1. / capacity))    if allow_smaller_final_batch:      dequeued = queue.dequeue_up_to(batch_size, name=name)    else:      dequeued = queue.dequeue_many(batch_size, name=name)    dequeued = _restore_sparse_tensors(dequeued, sparse_info)    # tensors_list was validated to not be empty.    return _as_original_type(tensors_list[0], dequeued)def _shuffle_batch(tensors, batch_size, capacity, min_after_dequeue,                   keep_input, num_threads=1, seed=None, enqueue_many=False,                   shapes=None, allow_smaller_final_batch=False,                   shared_name=None, name=None):  """Helper function for `shuffle_batch` and `maybe_shuffle_batch`."""  print("input.py _shuffle_batch")  tensor_list = _as_tensor_list(tensors)  with ops.name_scope(name, "shuffle_batch",                      list(tensor_list) + [keep_input]) as name:    tensor_list = _validate(tensor_list)    keep_input = _validate_keep_input(keep_input, enqueue_many)    tensor_list, sparse_info = _store_sparse_tensors(        tensor_list, enqueue_many, keep_input)    types = _dtypes([tensor_list])    shapes = _shapes([tensor_list], shapes, enqueue_many)        # 创建一个随机排列的队列    queue = data_flow_ops.RandomShuffleQueue(        capacity=capacity, min_after_dequeue=min_after_dequeue, seed=seed,        dtypes=types, shapes=shapes, shared_name=shared_name)            _enqueue(queue, tensor_list, num_threads, enqueue_many, keep_input)        full = (math_ops.cast(math_ops.maximum(0, queue.size() - min_after_dequeue),                          dtypes.float32) *            (1. / (capacity - min_after_dequeue)))    # Note that name contains a '/' at the end so we intentionally do not place    # a '/' after %s below.    summary_name = (        "fraction_over_%d_of_%d_full" %        (min_after_dequeue, capacity - min_after_dequeue))    summary.scalar(summary_name, full)    if allow_smaller_final_batch:      dequeued = queue.dequeue_up_to(batch_size, name=name)    else:      dequeued = queue.dequeue_many(batch_size, name=name)    dequeued = _restore_sparse_tensors(dequeued, sparse_info)    return _as_original_type(tensors, dequeued)def _shuffle_batch_join(tensors_list, batch_size, capacity,                        min_after_dequeue, keep_input, seed=None,                        enqueue_many=False, shapes=None,                        allow_smaller_final_batch=False, shared_name=None,                        name=None):  """Helper function for `shuffle_batch_join` and `maybe_shuffle_batch_join`."""  print("input.py _shuffle_batch_join")  tensor_list_list = _as_tensor_list_list(tensors_list)  with ops.name_scope(name, "shuffle_batch_join",                      _flatten(tensor_list_list) + [keep_input]) as name:    tensor_list_list = _validate_join(tensor_list_list)    keep_input = _validate_keep_input(keep_input, enqueue_many)    tensor_list_list, sparse_info = _store_sparse_tensors_join(        tensor_list_list, enqueue_many, keep_input)    types = _dtypes(tensor_list_list)    shapes = _shapes(tensor_list_list, shapes, enqueue_many)    queue = data_flow_ops.RandomShuffleQueue(        capacity=capacity, min_after_dequeue=min_after_dequeue, seed=seed,        dtypes=types, shapes=shapes, shared_name=shared_name)    _enqueue_join(queue, tensor_list_list, enqueue_many, keep_input)    full = (math_ops.cast(math_ops.maximum(0, queue.size() - min_after_dequeue),                          dtypes.float32) *            (1. / (capacity - min_after_dequeue)))    # Note that name contains a '/' at the end so we intentionally do not place    # a '/' after %s below.    summary_name = (        "fraction_over_%d_of_%d_full" %        (min_after_dequeue, capacity - min_after_dequeue))    summary.scalar(summary_name, full)    if allow_smaller_final_batch:      dequeued = queue.dequeue_up_to(batch_size, name=name)    else:      dequeued = queue.dequeue_many(batch_size, name=name)    dequeued = _restore_sparse_tensors(dequeued, sparse_info)    # tensors_list was validated to not be empty.    return _as_original_type(tensors_list[0], dequeued)# Batching functions ----------------------------------------------------------def batch(tensors, batch_size, num_threads=1, capacity=32,          enqueue_many=False, shapes=None, dynamic_pad=False,          allow_smaller_final_batch=False, shared_name=None, name=None):  """Creates batches of tensors in `tensors`.  在`tensors`中创建一批张量    The argument `tensors` can be a list or a dictionary of tensors.  The value returned by the function will be of the same type  as `tensors`.    参数`tensors`可以是张量列表或张量字典。  该函数返回的值将与`tensors`类似。  This function is implemented using a queue. A `QueueRunner` for the  queue is added to the current `Graph`'s `QUEUE_RUNNER` collection.  此功能使用队列实现。 队列中的`QueueRunner`将添加到当前的`Graph`的`QUEUE_RUNNER`集合中。  If `enqueue_many` is `False`, `tensors` is assumed to represent a single  example.  An input tensor with shape `[x, y, z]` will be output as a tensor  with shape `[batch_size, x, y, z]`.  如果`enqueue_many`是`False`,则`tensors` 假设表示一个示例。  形状为`[x, y, z]`的输入张量将输出形状为`[batch_size,x,y,z]`的张量。  If `enqueue_many` is `True`, `tensors` is assumed to represent a batch of  examples, where the first dimension is indexed by example, and all members of  `tensors` should have the same size in the first dimension.  If an input  tensor has shape `[*, x, y, z]`, the output will have shape `[batch_size, x,  y, z]`.  The `capacity` argument controls the how long the prefetching is  allowed to grow the queues.  如果`enqueue_many`为`True`,则`tensors` 假设表示一批示例,  其中第一维为示例索引,`tensors`的所有成员在第一维中应具有相同的大小。   如果输入张量形状为`[*,x,y,z]`,输出的形状将为`[batch_size,x,y,z]`。  `capacity`参数控制允许预取增长队列的时间。  The returned operation is a dequeue operation and will throw  `tf.errors.OutOfRangeError` if the input queue is exhausted. If this  operation is feeding another input queue, its queue runner will catch  this exception, however, if this operation is used in your main thread  you are responsible for catching this yourself.  返回的操作是一个出队操作,如果输入队列耗尽,将抛出`tf.errors.OutOfRangeError`。   如果此操作正在提供另一个输入队列,则其队列运行程序将捕获此异常,  但是如果此操作在主线程中使用,则负责自行捕获此操作。  *N.B.:* If `dynamic_pad` is `False`, you must ensure that either  (i) the `shapes` argument is passed, or (ii) all of the tensors in  `tensors` must have fully-defined shapes. `ValueError` will be  raised if neither of these conditions holds.  *N.B.:* 如果`dynamic_pad`为`False`,则必须确保(i) `shapes`参数被传递,  或(ii) `tensors` 中的所有张量必须具有完全定义的形状。  如果这两个条件都不成立,就会引发`ValueError`。  If `dynamic_pad` is `True`, it is sufficient that the *rank* of the  tensors is known, but individual dimensions may have shape `None`.  In this case, for each enqueue the dimensions with value `None`  may have a variable length; upon dequeue, the output tensors will be padded  on the right to the maximum shape of the tensors in the current minibatch.  For numbers, this padding takes value 0.  For strings, this padding is  the empty string.  See `PaddingFIFOQueue` for more info.  如果`dynamic_pad`是`True`,那么这是足够的,如果张量的*rank*已知,但单个维度可能具有`None`形状。   在这种情况下,对于每个入队,具有值`None`的维度可能具有可变长度;   在出队时,输出张量将被填充到当前的小批量张量的最大形状的右侧。   对于数字,此填充取值0。对于字符串,此填充为空字符串。  有关详细信息,请参阅“PaddingFIFOQueue”。  If `allow_smaller_final_batch` is `True`, a smaller batch value than  `batch_size` is returned when the queue is closed and there are not enough  elements to fill the batch, otherwise the pending elements are discarded.  In addition, all output tensors' static shapes, as accessed via the  `get_shape` method will have a first `Dimension` value of `None`, and  operations that depend on fixed batch_size would fail.  如果`allow_smaller_final_batch`为`True`,则当队列关闭并且没有足够的元素来填充批次时,  将返回比`batch_size`更小的批次值,否则挂起的元素将被丢弃。   另外,通过`get_shape`方法访问,所有输出张量的静态形状都将具有第一个`Dimension`值`None`,  而依赖于固定batch_size的操作将失败。  Note: if `num_epochs` is not `None`, this function creates local counter  `epochs`. Use `local_variables_initializer()` to initialize local variables.  注意:如果`num_epochs`不是`None`,这个函数创建本地的计数器'epochs`。   使用`local_variables_initializer()`来初始化局部变量。  Args:    tensors: The list or dictionary of tensors to enqueue.    batch_size: The new batch size pulled from the queue.    num_threads: The number of threads enqueuing `tensors`.    capacity: An integer. The maximum number of elements in the queue.    enqueue_many: Whether each tensor in `tensors` is a single example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensors`.    dynamic_pad: Boolean.  Allow variable dimensions in input shapes.      The given dimensions are padded upon dequeue so that tensors within a      batch have the same shapes.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (Optional). If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the same types as `tensors` (except if    the input is a list of one element, then it returns a tensor, not a list).    与`tensors`类型相同的张量列表或张量字典(除了如果输入是一个元素的列表,返回张量而不是列表)。  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensors`.  """  return _batch(      tensors,      batch_size,      keep_input=True,      num_threads=num_threads,      capacity=capacity,      enqueue_many=enqueue_many,      shapes=shapes,      dynamic_pad=dynamic_pad,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def maybe_batch(tensors, keep_input, batch_size, num_threads=1, capacity=32,                enqueue_many=False, shapes=None, dynamic_pad=False,                allow_smaller_final_batch=False, shared_name=None, name=None):  """Conditionally creates batches of tensors based on `keep_input`.  有条件地创建基于`keep_input`的张量。  See docstring in `batch` for more details.  Args:    tensors: The list or dictionary of tensors to enqueue.    keep_input: A `bool` Tensor.  This tensor controls whether the input is      added to the queue or not.  If it is a scalar and evaluates `True`, then      `tensors` are all added to the queue. If it is a vector and `enqueue_many`      is `True`, then each example is added to the queue only if the      corresponding value in `keep_input` is `True`. This tensor essentially      acts as a filtering mechanism.    keep_input:  一个`bool`张量。 该张量控制输入是否添加到队列中。 如果它是一个标量并评估`True`,那么`tensors`将被添加到队列中。 如果它是一个向量,并且`enqueue_many`是`True`,则只有在`keep_input`中的相应值为`True`时,每个示例才会添加到队列中。 该张量基本上充当过滤机构。    batch_size: The new batch size pulled from the queue.    num_threads: The number of threads enqueuing `tensors`.    capacity: An integer. The maximum number of elements in the queue.    enqueue_many: Whether each tensor in `tensors` is a single example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensors`.    dynamic_pad: Boolean.  Allow variable dimensions in input shapes.      The given dimensions are padded upon dequeue so that tensors within a      batch have the same shapes.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (Optional). If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the same types as `tensors`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensors`.  """  return _batch(      tensors,      batch_size,      keep_input,      num_threads=num_threads,      capacity=capacity,      enqueue_many=enqueue_many,      shapes=shapes,      dynamic_pad=dynamic_pad,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def batch_join(tensors_list, batch_size, capacity=32, enqueue_many=False,               shapes=None, dynamic_pad=False, allow_smaller_final_batch=False,               shared_name=None, name=None):  """Runs a list of tensors to fill a queue to create batches of examples.  运行张量列表来填充队列,以创建批量的示例。  The `tensors_list` argument is a list of tuples of tensors, or a list of  dictionaries of tensors.  Each element in the list is treated similarly  to the `tensors` argument of `tf.train.batch()`.  Enqueues a different list of tensors in different threads.  Implemented using a queue -- a `QueueRunner` for the queue  is added to the current `Graph`'s `QUEUE_RUNNER` collection.  `len(tensors_list)` threads will be started,  with thread `i` enqueuing the tensors from  `tensors_list[i]`. `tensors_list[i1][j]` must match  `tensors_list[i2][j]` in type and shape, except in the first  dimension if `enqueue_many` is true.  If `enqueue_many` is `False`, each `tensors_list[i]` is assumed  to represent a single example. An input tensor `x` will be output as a  tensor with shape `[batch_size] + x.shape`.  If `enqueue_many` is `True`, `tensors_list[i]` is assumed to  represent a batch of examples, where the first dimension is indexed  by example, and all members of `tensors_list[i]` should have the  same size in the first dimension.  The slices of any input tensor  `x` are treated as examples, and the output tensors will have shape  `[batch_size] + x.shape[1:]`.  The `capacity` argument controls the how long the prefetching is allowed to  grow the queues.  The returned operation is a dequeue operation and will throw  `tf.errors.OutOfRangeError` if the input queue is exhausted. If this  operation is feeding another input queue, its queue runner will catch  this exception, however, if this operation is used in your main thread  you are responsible for catching this yourself.  *N.B.:* If `dynamic_pad` is `False`, you must ensure that either  (i) the `shapes` argument is passed, or (ii) all of the tensors in  `tensors_list` must have fully-defined shapes. `ValueError` will be  raised if neither of these conditions holds.  If `dynamic_pad` is `True`, it is sufficient that the *rank* of the  tensors is known, but individual dimensions may have value `None`.  In this case, for each enqueue the dimensions with value `None`  may have a variable length; upon dequeue, the output tensors will be padded  on the right to the maximum shape of the tensors in the current minibatch.  For numbers, this padding takes value 0.  For strings, this padding is  the empty string.  See `PaddingFIFOQueue` for more info.  If `allow_smaller_final_batch` is `True`, a smaller batch value than  `batch_size` is returned when the queue is closed and there are not enough  elements to fill the batch, otherwise the pending elements are discarded.  In addition, all output tensors' static shapes, as accessed via the  `get_shape` method will have a first `Dimension` value of `None`, and  operations that depend on fixed batch_size would fail.  Args:    tensors_list: A list of tuples or dictionaries of tensors to enqueue.    batch_size: An integer. The new batch size pulled from the queue.    capacity: An integer. The maximum number of elements in the queue.    enqueue_many: Whether each tensor in `tensor_list_list` is a single      example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensor_list_list[i]`.    dynamic_pad: Boolean.  Allow variable dimensions in input shapes.      The given dimensions are padded upon dequeue so that tensors within a      batch have the same shapes.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (Optional) If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the same number and types as    `tensors_list[i]`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensor_list_list`.  """  return _batch_join(      tensors_list,      batch_size,      keep_input=True,      capacity=capacity,      enqueue_many=enqueue_many,      shapes=shapes,      dynamic_pad=dynamic_pad,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def maybe_batch_join(tensors_list, keep_input, batch_size, capacity=32,                     enqueue_many=False, shapes=None, dynamic_pad=False,                     allow_smaller_final_batch=False, shared_name=None,                     name=None):  """Runs a list of tensors to conditionally fill a queue to create batches.  See docstring in `batch_join` for more details.  Args:    tensors_list: A list of tuples or dictionaries of tensors to enqueue.    keep_input: A `bool` Tensor.  This tensor controls whether the input is      added to the queue or not.  If it is a scalar and evaluates `True`, then      `tensors` are all added to the queue. If it is a vector and `enqueue_many`      is `True`, then each example is added to the queue only if the      corresonding value in `keep_input` is `True`. This tensor essentially acts      as a filtering mechanism.    batch_size: An integer. The new batch size pulled from the queue.    capacity: An integer. The maximum number of elements in the queue.    enqueue_many: Whether each tensor in `tensor_list_list` is a single      example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensor_list_list[i]`.    dynamic_pad: Boolean.  Allow variable dimensions in input shapes.      The given dimensions are padded upon dequeue so that tensors within a      batch have the same shapes.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (Optional) If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the same number and types as    `tensors_list[i]`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensor_list_list`.  """  return _batch_join(      tensors_list,      batch_size,      keep_input,      capacity=capacity,      enqueue_many=enqueue_many,      shapes=shapes,      dynamic_pad=dynamic_pad,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def shuffle_batch(tensors, batch_size, capacity, min_after_dequeue,                  num_threads=1, seed=None, enqueue_many=False, shapes=None,                  allow_smaller_final_batch=False, shared_name=None, name=None):  """Creates batches by randomly shuffling tensors.  通过随机洗牌来形成批次。  This function adds the following to the current `Graph`:  * A shuffling queue into which tensors from `tensors` are enqueued.  * A `dequeue_many` operation to create batches from the queue.  * A `QueueRunner` to `QUEUE_RUNNER` collection, to enqueue the tensors  from `tensors`.  此函数将以下内容添加到当前的“图形”中:  * 入队 `tensors` 中的张量的洗牌队列。  * 从队列中创建批次的 `dequeue_many` 操作。  * 一个 `QueueRunner` 到 `QUEUE_RUNNER` 集合,以便入队 `tensors` 中的张量。    If `enqueue_many` is `False`, `tensors` is assumed to represent a  single example.  An input tensor with shape `[x, y, z]` will be output  as a tensor with shape `[batch_size, x, y, z]`.   如果 `enqueue_many` 是 `False`,则`tensors`被认为表示一个示例。具有形状为`[x, y, z]`的输入张量将会输出形状为“[batch_size,x,y,z]”的张量。  If `enqueue_many` is `True`, `tensors` is assumed to represent a  batch of examples, where the first dimension is indexed by example,  and all members of `tensors` should have the same size in the  first dimension.  If an input tensor has shape `[*, x, y, z]`, the  output will have shape `[batch_size, x, y, z]`.  如果`enqueue_many`为`True`,则`tensors`被认为表示一批示例,其中第一维由示例索引,“张量”的所有成员在第一维中应具有相同的大小。如果输入张量具有形状“[*,x,y,z]”,则输出将具有形状为`[batch_size, x, y, z]`的张量。  The `capacity` argument controls the how long the prefetching is allowed to  grow the queues.  `capacity`参数控制允许预取增长队列的时间。  The returned operation is a dequeue operation and will throw  `tf.errors.OutOfRangeError` if the input queue is exhausted. If this  operation is feeding another input queue, its queue runner will catch  this exception, however, if this operation is used in your main thread  you are responsible for catching this yourself.  返回的操作是一个出队操作,如果输入队列耗尽,将抛出`tf.errors.OutOfRangeError`。如果此操作正在提供另一个输入队列,则其队列运行程序将捕获此异常,但是如果此操作在主线程中使用,则负责自行捕获此操作。  For example:  ```python  # Creates batches of 32 images and 32 labels.  image_batch, label_batch = tf.train.shuffle_batch(        [single_image, single_label],        batch_size=32,        num_threads=4,        capacity=50000,        min_after_dequeue=10000)  ```  *N.B.:* You must ensure that either (i) the `shapes` argument is  passed, or (ii) all of the tensors in `tensors` must have  fully-defined shapes. `ValueError` will be raised if neither of  these conditions holds.  *注意:*  您必须确保 (i)`shapes`参数传递,或(ii)`tensors`中的所有张量必须具有完全定义的形状。   如果这两个条件都不成立,就会引发`ValueError`。  If `allow_smaller_final_batch` is `True`, a smaller batch value than  `batch_size` is returned when the queue is closed and there are not enough  elements to fill the batch, otherwise the pending elements are discarded.  In addition, all output tensors' static shapes, as accessed via the  `get_shape` method will have a first `Dimension` value of `None`, and  operations that depend on fixed batch_size would fail.  如果 `allow_smaller_final_batch` 为 `True`,则当队列关闭并且没有足够的元素来填充批次时,将返回比 `batch_size` 更小的批次值,否则挂起的元素将被丢弃。   另外,通过 `get_shape` 方法访问的所有输出张量的静态形状的第一个`Dimension`值都为`None`,而依赖于 fixed_sizeize 的操作将失败  Note: if `num_epochs` is not `None`, this function creates local counter  `epochs`. Use `local_variables_initializer()` to initialize local variables.  Args:    tensors: The list or dictionary of tensors to enqueue.    batch_size: The new batch size pulled from the queue.    capacity: An integer. The maximum number of elements in the queue.    min_after_dequeue: Minimum number elements in the queue after a      dequeue, used to ensure a level of mixing of elements.    num_threads: The number of threads enqueuing `tensor_list`. 入队`tensor_list`的线程数。    seed: Seed for the random shuffling within the queue.    enqueue_many: Whether each tensor in `tensor_list` is a single example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensor_list`.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (Optional) If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the types as `tensors`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensors`.  """  return _shuffle_batch(      tensors,      batch_size,      capacity,      min_after_dequeue,      keep_input=True,      num_threads=num_threads,      seed=seed,      enqueue_many=enqueue_many,      shapes=shapes,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def maybe_shuffle_batch(tensors, batch_size, capacity, min_after_dequeue,                        keep_input, num_threads=1, seed=None,                        enqueue_many=False, shapes=None,                        allow_smaller_final_batch=False, shared_name=None,                        name=None):  """Creates batches by randomly shuffling conditionally-enqueued tensors.  通过随机洗牌有条件排列的张量来创建批次。  See docstring in `shuffle_batch` for more details.  Args:    tensors: The list or dictionary of tensors to enqueue.    batch_size: The new batch size pulled from the queue.    capacity: An integer. The maximum number of elements in the queue.    min_after_dequeue: Minimum number elements in the queue after a      dequeue, used to ensure a level of mixing of elements.    keep_input: A `bool` Tensor.  This tensor controls whether the input is      added to the queue or not.  If it is a scalar and evaluates `True`, then      `tensors` are all added to the queue. If it is a vector and `enqueue_many`      is `True`, then each example is added to the queue only if the      corresonding value in `keep_input` is `True`. This tensor essentially acts      as a filtering mechanism.    num_threads: The number of threads enqueuing `tensor_list`.    seed: Seed for the random shuffling within the queue.    enqueue_many: Whether each tensor in `tensor_list` is a single example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensor_list`.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (Optional) If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the types as `tensors`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensors`.  """  return _shuffle_batch(      tensors,      batch_size,      capacity,      min_after_dequeue,      keep_input,      num_threads=num_threads,      seed=seed,      enqueue_many=enqueue_many,      shapes=shapes,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def shuffle_batch_join(tensors_list, batch_size, capacity,                       min_after_dequeue, seed=None, enqueue_many=False,                       shapes=None, allow_smaller_final_batch=False,                       shared_name=None, name=None):  """Create batches by randomly shuffling tensors.  通过随机洗牌张量创建批次。  The `tensors_list` argument is a list of tuples of tensors, or a list of  dictionaries of tensors.  Each element in the list is treated similarly  to the `tensors` argument of `tf.train.shuffle_batch()`.  `tensors_list`参数是张量的元组列表或张量词典的列表。 列表中的每个元素都与`tf.train.shuffle_batch()`的`tensors`参数类似。  This version enqueues a different list of tensors in different threads.  该版本在不同的线程中排列不同的张量列表。    It adds the following to the current `Graph`:  * A shuffling queue into which tensors from `tensors_list` are enqueued.  * A `dequeue_many` operation to create batches from the queue.  * A `QueueRunner` to `QUEUE_RUNNER` collection, to enqueue the tensors    from `tensors_list`.  `len(tensors_list)` threads will be started, with thread `i` enqueuing  the tensors from `tensors_list[i]`. `tensors_list[i1][j]` must match  `tensors_list[i2][j]` in type and shape, except in the first dimension if  `enqueue_many` is true.  `len(tensors_list)` 线程将被启动,线程`i`从`tensors_list[i]`中引入张量。 `tensors_list[i1][j]`必须匹配`tensors_list[i2][j]`的类型和形状,如果`enqueue_many`为真时,第一维除外。  If `enqueue_many` is `False`, each `tensors_list[i]` is assumed  to represent a single example.  An input tensor with shape `[x, y, z]`  will be output as a tensor with shape `[batch_size, x, y, z]`.  If `enqueue_many` is `True`, `tensors_list[i]` is assumed to  represent a batch of examples, where the first dimension is indexed  by example, and all members of `tensors_list[i]` should have the  same size in the first dimension.  If an input tensor has shape `[*, x,  y, z]`, the output will have shape `[batch_size, x, y, z]`.  The `capacity` argument controls the how long the prefetching is allowed to  grow the queues.  The returned operation is a dequeue operation and will throw  `tf.errors.OutOfRangeError` if the input queue is exhausted. If this  operation is feeding another input queue, its queue runner will catch  this exception, however, if this operation is used in your main thread  you are responsible for catching this yourself.  If `allow_smaller_final_batch` is `True`, a smaller batch value than  `batch_size` is returned when the queue is closed and there are not enough  elements to fill the batch, otherwise the pending elements are discarded.  In addition, all output tensors' static shapes, as accessed via the  `get_shape` method will have a first `Dimension` value of `None`, and  operations that depend on fixed batch_size would fail.  Args:    tensors_list: A list of tuples or dictionaries of tensors to enqueue.    batch_size: An integer. The new batch size pulled from the queue.    capacity: An integer. The maximum number of elements in the queue.    min_after_dequeue: Minimum number elements in the queue after a      dequeue, used to ensure a level of mixing of elements.    seed: Seed for the random shuffling within the queue.    enqueue_many: Whether each tensor in `tensor_list_list` is a single      example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensors_list[i]`.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (optional). If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the same number and types as    `tensors_list[i]`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensors_list`.  """  return _shuffle_batch_join(      tensors_list,      batch_size,      capacity,      min_after_dequeue,      keep_input=True,      seed=seed,      enqueue_many=enqueue_many,      shapes=shapes,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)def maybe_shuffle_batch_join(tensors_list, batch_size, capacity,                             min_after_dequeue, keep_input, seed=None,                             enqueue_many=False, shapes=None,                             allow_smaller_final_batch=False, shared_name=None,                             name=None):  """Create batches by randomly shuffling conditionally-enqueued tensors.  See docstring in `shuffle_batch_join` for more details.  Args:    tensors_list: A list of tuples or dictionaries of tensors to enqueue.    batch_size: An integer. The new batch size pulled from the queue.    capacity: An integer. The maximum number of elements in the queue.    min_after_dequeue: Minimum number elements in the queue after a      dequeue, used to ensure a level of mixing of elements.    keep_input: A `bool` Tensor.  This tensor controls whether the input is      added to the queue or not.  If it is a scalar and evaluates `True`, then      `tensors` are all added to the queue. If it is a vector and `enqueue_many`      is `True`, then each example is added to the queue only if the      corresonding value in `keep_input` is `True`. This tensor essentially acts      as a filtering mechanism.    seed: Seed for the random shuffling within the queue.    enqueue_many: Whether each tensor in `tensor_list_list` is a single      example.    shapes: (Optional) The shapes for each example.  Defaults to the      inferred shapes for `tensors_list[i]`.    allow_smaller_final_batch: (Optional) Boolean. If `True`, allow the final      batch to be smaller if there are insufficient items left in the queue.    shared_name: (optional). If set, this queue will be shared under the given      name across multiple sessions.    name: (Optional) A name for the operations.  Returns:    A list or dictionary of tensors with the same number and types as    `tensors_list[i]`.  Raises:    ValueError: If the `shapes` are not specified, and cannot be      inferred from the elements of `tensors_list`.  """  return _shuffle_batch_join(      tensors_list,      batch_size,      capacity,      min_after_dequeue,      keep_input,      seed=seed,      enqueue_many=enqueue_many,      shapes=shapes,      allow_smaller_final_batch=allow_smaller_final_batch,      shared_name=shared_name,      name=name)

原创粉丝点击