code: def _sparse_concat_rows(
      sparse_tensor_values: List[tf.compat.v1.SparseTensorValue],
  ) -> tf.compat.v1.SparseTensorValue:
      """Concat a list of SparseTensorValues along rows.
  
      This is similar to (but not the same as)
      tf.sparse_concat(axis=0, sp_inputs=sparse_tensor_values)
      except that this operates on NumPy arrays.
  
      More critically, this assumes that each sparse tensor value represents a
      single row (so dense_shape[0] == 1), but the other dimensions are allowed to
      vary across the list. The final shape will be
        batch_size x max(dense_shapes[:, 1]) x max(dense_shapes[:, 2]) x ...
  
      We need this to support cases where sparse features are of variable length,
      e.g. in sequence example cases, where the number of timesteps might be
      different across examples.
  
      For example, if the values are:
         indices=[[0, 0, 0], [0, 1, 1]], values=[10, 12], dense_shape=[0, 2, 2]
        indices=[[0, 2, 2]], values=[22], dense_shape=[0, 3, 3]
        indices=[[0, 0, 4]], values=[33], dense_shape=[0, 1, 5]
  
      Then the result will be:
        indices=[[0, 0, 0], [0, 1, 1],
                 [1, 2, 2],
                 [2, 0, 4]]
        values=[10, 12, 22, 33]
        dense_shape=[3, 3, 5]
  
      Args:
        sparse_tensor_values: List of SparseTensorValues to concatenate together.
  
      Returns:
        A single SparseTensorValue, representing the concatenated
        SparseTensorValues.
  
      Raises:
        ValueError: sparse_tensor_values was an empty list; or a sparse tensor value
         in the list was not for exactly one row.
      """
      if not sparse_tensor_values:
          raise ValueError(
              "sparse_tensor_values must be a non-empty list."
          )
  
      # Create empty indices and values arrays with the same shape as the
      # sparse_tensor_value, except the number of rows (batch dimension) is 0.
      #
      # We need this because we need to preserve the shape of these arrays,
      # even if their batch dimension is 0.
      empty_indices_with_shape = np.zeros(
          _copy_shape_zero_rows(sparse_tensor_values[0].indices.shape),
          dtype=sparse_tensor_values[0].indices.dtype,
      )
      empty_values_with_shape = np.zeros(
          _copy_shape_zero_rows(sparse_tensor_values[0].values.shape),
          dtype=sparse_tensor_values[0].values.dtype,
      )
  
      indices = []
  
      # Make a copy here, so that in the case that we don't take any amaxes
      # in the loop below, we'll still be mutating a copy (rather than the original)
      # when we update the row size.
      dense_shape_max = np.array(sparse_tensor_values[0].dense_shape)
      values = []
      for row, sparse_tensor in enumerate(sparse_tensor_values):
          # Make a copy, so we can mutate it.
          cur_indices = np.array(sparse_tensor.indices)
          if cur_indices.size == 0:
              # Empty SparseTensorValue.
              continue
          cur_indices[:, 0, ...] += row
          indices.extend(cur_indices.tolist())
          values.extend(sparse_tensor.values)
          if sparse_tensor.dense_shape[0] != 1:
              raise ValueError(
                  "each sparse_tensor_value should only have one row, but %s had "
                  "shape %s"
                  % (sparse_tensor, sparse_tensor.dense_shape)
              )
          dense_shape_max = np.amax(
              [dense_shape_max, sparse_tensor.dense_shape], axis=0
          )
  
      # The final dense shape is the max of dense shapes of all the sparse tensor
      # values, except the number of rows should be the batch size.
      dense_shape_max[0] = len(sparse_tensor_values)
  
      # pylint: disable=g-long-ternary
      return tf.compat.v1.SparseTensorValue(
          indices=(
              np.array(indices, dtype=empty_indices_with_shape.dtype)
              if indices
              else empty_indices_with_shape
          ),
          values=(
              np.array(values, dtype=empty_values_with_shape.dtype)
              if values
              else empty_values_with_shape
          ),
          dense_shape=dense_shape_max,
      )
  
file_path: model-analysis/tensorflow_model_analysis/eval_saved_model/util.py
imports: from typing import Any, Callable, List, Optional, Tuple
  import numpy
  import tensorflow
  from tensorflow import estimator
  from tensorflow_model_analysis.api import types
  from tensorflow_model_analysis.utils import util
  from tensorflow.core.example import example_pb2
label_desc: Use image node_id 7 for calling a global function with example usage: _sparse_concat_rows(sparse_tensor_values) and returns: tf