class_docstr: Defines a generalized additive model (GAM) layer.
  
  This layer implements the neural generalized additive ranking model described
  in [Zhuang et al, 2021][zhuang2021].
  
  Neural Generalized Additive Ranking Model is an additive ranking model.
  For each example `x` with `n` features `(x_1, x_2, ..., x_n)`, the ranking
  score is:
  
    $$F(x) = f_1(x_1) + f_2(x_2) + \ldots + f_n(x_n)$$
  
  where each feature is scored by a corresponding submodel, and the overall
  ranking score is the sum of all the submodels' outputs. Each submodel is a
  standalone feed-forward network.
  
  When there are `m` context features `(c_1, c_2, ..., c_m)`, the ranking score
  will be determined by:
  
    $$F(c, x) = w_1(c) * f_1(x_1) + w_2(c) * f_2(x_2) + \ldots + w_n(c) *
    f_n(x_n)$$
  
  where `(w1(c), w2(c), ..., wn(c))` is a weighting vector determined solely by
  context features. For each context feature `c_j`, a feed-forward submodel is
  constructed to derive a weighting vector
  `(wj1(c_j), wj2(c_j), ..., wjn(c_j))`. The final weighting vector is the sum
  of the output of all the context features' submodels.
  
  The model is implicitly interpretable as the contribution of each feature to
  the final ranking score can be easily visualized. However, the model does not
  have higher-order inter-feature interactions and hence may not have
  performance as good as a fully-connected DNN.
  
  The output of each example feature's submodel can be retrieved by tensor
  named `{feature_name}_subscore`. The output of each context feature's submodel
  is a n-dimensional vector and can be retrieved by tensor named
  `{feature_name}_subweight`.
  
  ```python
  example_inputs = tf.constant([[1], [0], [-1]], dtype=tf.float32)
  context_inputs = tf.constant([[1, 2], [0, 1], [-1, 1]], dtype=tf.float32)
  gam = layers.GAMLayer(2, [3, 2, 1], 2, [3, 2, 1])
  outputs, sublogits_list, subweights_list = gam(
      ([example_inputs, example_inputs], [context_inputs, context_inputs]))
  ```
  
  References:
    - [Interpretable Ranking with Generalized Additive Models, Zhuang et al,
       2021][zhuang2021]
  
  [zhuang2021]: https://research.google/pubs/pub50040/
docstr: Obtains the outputs of the GAM model.
  
  Args:
    inputs: A tuple of (`example_inputs`, `context_inputs`):
    * `example_inputs`: An iterable of Tensors where each tensor is 2-D with
      the shape [batch_size, ...]. The number of tensors should align with
      `example_feature_num`.
    * `context_inputs`: An iterable of Tensors where each tensor is 2-D with
      the shape [batch_size, ...]. If given, the number of tensors should
      align with `context_feature_num`. Notice that even if
      `context_feature_num` is larger than zero, one can still call without
      `context_inputs`. In this case the sub_logits from examples features
      will be directly added and context feature towers will be ignored.
    training: Whether training or not.
  
  Returns:
    The final scores from the GAM model, lists of tensors representing the
    sublogits of each example feature, and lists of tensors representing the
    subweights derived from each context feature. If no `context_inputs` are
    given, the third element will be an empty list.
  
  Raises:
    ValueError: An error occurred when the number of tensors in
      `example_inputs` is different from `example_feature_num`.
    ValueError: An error occurred when `context_inputs` is given but the
      number of tensors in `context_inputs` is different from
      `context_feature_num`.
docstr_tok: ["Obtains","the","outputs","of","the","GAM","model",".","Args",":","inputs",":","A","tuple","of","(","`","example_inputs","`",",","`","context_inputs","`",")",":","*","`","example_inputs","`",":","An","iterable","of","Tensors","where","each","tensor","is","2-D","with","the","shape","[","batch_size",",","...","]",".","The","number","of","tensors","should","align","with","`","example_feature_num","`",".","*","`","context_inputs","`",":","An","iterable","of","Tensors","where","each","tensor","is","2-D","with","the","shape","[","batch_size",",","...","]",".","If","given",",","the","number","of","tensors","should","align","with","`","context_feature_num","`",".","Notice","that","even","if","`","context_feature_num","`","is","larger","than","zero",",","one","can","still","call","without","`","context_inputs","`",".","In","this","case","the","sub_logits","from","examples","features","will","be","directly","added","and","context","feature","towers","will","be","ignored",".","training",":","Whether","training","or","not",".","Returns",":","The","final","scores","from","the","GAM","model",",","lists","of","tensors","representing","the","sublogits","of","each","example","feature",",","and","lists","of","tensors","representing","the","subweights","derived","from","each","context","feature",".","If","no","`","context_inputs","`","are","given",",","the","third","element","will","be","an","empty","list",".","Raises",":","ValueError",":","An","error","occurred","when","the","number","of","tensors","in","`","example_inputs","`","is","different","from","`","example_feature_num","`",".","ValueError",":","An","error","occurred","when","`","context_inputs","`","is","given","but","the","number","of","tensors","in","`","context_inputs","`","is","different","from","`","context_feature_num","`","."]
code: def call(
      self,
      inputs: Tuple[List[tf.Tensor], Optional[List[tf.Tensor]]],
      training: bool = True,
  ) -> Tuple[tf.Tensor, List[tf.Tensor], List[tf.Tensor]]:
      """Obtains the outputs of the GAM model.
  
      Args:
        inputs: A tuple of (`example_inputs`, `context_inputs`):
        * `example_inputs`: An iterable of Tensors where each tensor is 2-D with
          the shape [batch_size, ...]. The number of tensors should align with
          `example_feature_num`.
        * `context_inputs`: An iterable of Tensors where each tensor is 2-D with
          the shape [batch_size, ...]. If given, the number of tensors should
          align with `context_feature_num`. Notice that even if
          `context_feature_num` is larger than zero, one can still call without
          `context_inputs`. In this case the sub_logits from examples features
          will be directly added and context feature towers will be ignored.
        training: Whether training or not.
  
      Returns:
        The final scores from the GAM model, lists of tensors representing the
        sublogits of each example feature, and lists of tensors representing the
        subweights derived from each context feature. If no `context_inputs` are
        given, the third element will be an empty list.
  
      Raises:
        ValueError: An error occurred when the number of tensors in
          `example_inputs` is different from `example_feature_num`.
        ValueError: An error occurred when `context_inputs` is given but the
          number of tensors in `context_inputs` is different from
          `context_feature_num`.
      """
      example_inputs, context_inputs = inputs
      if len(example_inputs) != self._example_feature_num:
          raise ValueError(
              "Mismatched number of features in `example_inputs` ({}) "
              "with `example_feature_num` ({})".format(
                  len(example_inputs), self._example_feature_num
              )
          )
      if context_inputs:
          if not self._context_towers or len(context_inputs) != len(
              self._context_towers
          ):
              raise ValueError(
                  "Mismatched number of features in `context_inputs` "
                  "({}) with `_context_feature_num` ({})".format(
                      len(context_inputs), self._context_feature_num
                  )
              )
  
      sub_logits_list = []
      for inputs, tower in zip(example_inputs, self._example_towers):
          sub_logits = tower(inputs, training=training)
          sub_logits_list.append(sub_logits)
  
      sub_weights_list = []
      if context_inputs and self._context_towers:
          for inputs, tower in zip(
              context_inputs, self._context_towers
          ):
              cur = tower(inputs, training=training)
              sub_weights = tf.keras.layers.Softmax()(cur)
              sub_weights_list.append(sub_weights)
  
      # Construct an additive model from the outputs of all example feature towers
      # weighted by outputs of all context feature towers.
      if sub_weights_list:
          sub_logits = tf.keras.layers.Concatenate(axis=-1)(
              sub_logits_list
          )
          sub_weights = (
              tf.keras.layers.Add()(sub_weights_list)
              if len(sub_weights_list) > 1
              else sub_weights_list[0]
          )
          logits = tf.reduce_sum(
              sub_logits * sub_weights, axis=-1, keepdims=True
          )
      else:
          logits = (
              tf.keras.layers.Add()(sub_logits_list)
              if len(sub_logits_list) > 1
              else sub_logits_list[0]
          )
  
      return logits, sub_logits_list, sub_weights_list
  
imports: import math
  from typing import Any, Callable, Dict, List, Optional, Tuple
  import tensorflow
  from tensorflow_ranking.python import utils
label_desc: Use image node_id 2 for calling the GAMLayer obj's underlying member method code with example usage: obj.call(inputs, training) and returns: logits,  sub_logits_list,  sub_weights_list