code: def data_iterator_simple(
      load_func,
      num_examples,
      batch_size,
      shuffle=False,
      rng=None,
      use_thread=True,
      with_memory_cache=False,
      with_file_cache=False,
      cache_dir=None,
      epoch_begin_callbacks=[],
      epoch_end_callbacks=[],
      stop_exhausted=False,
  ):
      """A generator that ``yield`` s minibatch data as a tuple, as defined in ``load_func`` .
      It can unlimitedly yield minibatches at your request, queried from the provided data.
  
      Args:
          load_func (function): Takes a single argument `i`, an index of an
              example in your dataset to be loaded, and returns a tuple of data.
              Every call by any index `i` must return a tuple of arrays with
              the same shape.
          num_examples (int): Number of examples in your dataset. Random sequence
              of indexes is generated according to this number.
          batch_size (int): Size of data unit.
          shuffle (bool):
               Indicates whether the dataset is shuffled or not.
               Default value is False.
          rng (None or :obj:`numpy.random.RandomState`): Numpy random number
              generator.
          use_thread (bool):
              If ``use_thread`` is set to True, iterator will use another thread to
              fetch data. If ``use_thread`` is set to False, iterator will use
              current thread to fetch data.
          with_memory_cache (bool):
              If ``True``, use :py:class:`.data_source.DataSourceWithMemoryCache`
              to wrap ``data_source``. It is a good idea to set this as true unless
              data_source provides on-memory data.
              Default value is False.
          with_file_cache (bool):
              If ``True``, use :py:class:`.data_source.DataSourceWithFileCache`
              to wrap ``data_source``.
              If ``data_source`` is slow, enabling this option a is good idea.
              Default value is False.
          cache_dir (str):
              Location of file_cache.
              If this value is None, :py:class:`.data_source.DataSourceWithFileCache`
              creates file caches implicitly on temporary directory and erases them all
              when data_iterator is finished.
              Otherwise, :py:class:`.data_source.DataSourceWithFileCache` keeps created cache.
              Default is None.
          epoch_begin_callbacks (list of functions): An item is a function
              which takes an epoch index as an argument. These are called
              at the beginning of an epoch.
          epoch_end_callbacks (list of functions): An item is a function
              which takes an epoch index as an argument. These are called
              at the end of an epoch.
          stop_exhausted (bool): If ``stop_exhausted`` is set to False, iterator will be reset
              so that iteration can be continued. If ``stop_exhausted`` is set to True, iterator
              will raise StopIteration to stop the loop.
  
  
      Returns:
          :py:class:`DataIterator <nnabla.utils.data_iterator.DataIterator>`:
              Instance of DataIterator.
  
  
      Here is an example of `load_func` which returns an image and a label of a
      classification dataset.
  
      .. code-block:: python
  
          import numpy as np
          from nnabla.utils.image_utils import imread
          image_paths = load_image_paths()
          labels = load_labels()
          def my_load_func(i):
              '''
              Returns:
                  image: c x h x w array
                  label: 0-shape array
              '''
              img = imread(image_paths[i]).astype('float32')
              return np.rollaxis(img, 2), np.array(labels[i])
  
  
      """
      return data_iterator(
          SimpleDataSource(
              load_func, num_examples, shuffle=shuffle, rng=rng
          ),
          use_thread=use_thread,
          batch_size=batch_size,
          with_memory_cache=with_memory_cache,
          with_file_cache=with_file_cache,
          cache_dir=cache_dir,
          epoch_begin_callbacks=epoch_begin_callbacks,
          epoch_end_callbacks=epoch_end_callbacks,
          stop_exhausted=stop_exhausted,
      )
  
imports: import atexit
  import threading
  import queue
  import numpy
  import six
  from nnabla.logger import logger
  from .data_source import DataSourceWithFileCache
  from .data_source import DataSourceWithMemoryCache
  from .data_source import SlicedDataSource
  from .data_source_implements import CacheDataSource
  from .data_source_implements import ConcatDataSource
  from .data_source_implements import CsvDataSource
  from .data_source_implements import SimpleDataSource
label_desc: Use image node_id 2 for calling a global function with example usage: data_iterator_simple(load_func, num_examples, batch_size, shuffle, rng, use_thread, with_memory_cache, with_file_cache, cache_dir, epoch_begin_callbacks, epoch_end_callbacks, stop_exhausted) and returns: data_iterator