code: def featurize_training_examples(
      training_examples: List[Message],
      attributes: List[Text],
      entity_tag_specs: Optional[List["EntityTagSpec"]] = None,
      featurizers: Optional[List[Text]] = None,
      bilou_tagging: bool = False,
  ) -> Tuple[
      List[Dict[Text, List["Features"]]],
      Dict[Text, Dict[Text, List[int]]],
  ]:
      """Converts training data into a list of attribute to features.
  
      Possible attributes are, for example, INTENT, RESPONSE, TEXT, ACTION_TEXT,
      ACTION_NAME or ENTITIES.
      Also returns sparse feature sizes for each attribute. It could look like this:
      {TEXT: {FEATURE_TYPE_SEQUENCE: [16, 32], FEATURE_TYPE_SENTENCE: [16, 32]}}.
  
      Args:
          training_examples: the list of training examples
          attributes: the attributes to consider
          entity_tag_specs: the entity specs
          featurizers: the featurizers to consider
          bilou_tagging: indicates whether BILOU tagging should be used or not
  
      Returns:
          A list of attribute to features.
          A dictionary of attribute to feature sizes.
      """
      output = []
      if not entity_tag_specs:
          entity_tag_specs = []
  
      for example in training_examples:
          attribute_to_features: Dict[Text, List["Features"]] = {}
          for attribute in attributes:
              if attribute == ENTITIES:
                  attribute_to_features[attribute] = []
                  # in case of entities add the tag_ids
                  for tag_spec in entity_tag_specs:
                      attribute_to_features[attribute].append(
                          get_tag_ids(example, tag_spec, bilou_tagging)
                      )
              elif attribute in example.data:
                  attribute_to_features[
                      attribute
                  ] = example.get_all_features(attribute, featurizers)
          output.append(attribute_to_features)
  
      sparse_feature_sizes = {}
      if output and training_examples:
          sparse_feature_sizes = _collect_sparse_feature_sizes(
              featurized_example=output[0],
              training_example=training_examples[0],
              featurizers=featurizers,
          )
      return output, sparse_feature_sizes
  
imports: import typing
  import copy
  import numpy
  import scipy.sparse
  from collections import defaultdict, OrderedDict
  from typing import List, Optional, Text, Dict, Tuple, Union, Any, DefaultDict, cast
  from rasa.nlu.constants import TOKENS_NAMES
  from rasa.utils.tensorflow.model_data import Data, FeatureArray, ragged_array_to_ndarray
  from rasa.utils.tensorflow.constants import MASK, IDS
  from rasa.shared.nlu.training_data.message import Message
  from rasa.shared.nlu.constants import TEXT, ENTITIES, ENTITY_ATTRIBUTE_TYPE, ENTITY_ATTRIBUTE_GROUP, ENTITY_ATTRIBUTE_ROLE
label_desc: Use image node_id 1 for calling a global function with example usage: featurize_training_examples(training_examples, attributes, entity_tag_specs, featurizers, bilou_tagging) and returns: output,  sparse_feature_sizes