code: def attention(
      query,
      facts,
      attention_size,
      mask,
      stag="null",
      mode="LIST",
      softmax_stag=1,
      time_major=False,
      return_alphas=False,
  ):
      if isinstance(facts, tuple):
          # In case of Bi-RNN, concatenate the forward and the backward RNN outputs.
          facts = tf.concat(facts, 2)
  
      if time_major:
          # (T,B,D) => (B,T,D)
          facts = tf.array_ops.transpose(facts, [1, 0, 2])
  
      mask = tf.equal(mask, tf.ones_like(mask))
      hidden_size = facts.get_shape().as_list()[
          -1
      ]  # D value - hidden size of the RNN layer
      input_size = query.get_shape().as_list()[-1]
  
      # Trainable parameters
      w1 = tf.Variable(
          tf.random_normal([hidden_size, attention_size], stddev=0.1)
      )
      w2 = tf.Variable(
          tf.random_normal([input_size, attention_size], stddev=0.1)
      )
      b = tf.Variable(tf.random_normal([attention_size], stddev=0.1))
      v = tf.Variable(tf.random_normal([attention_size], stddev=0.1))
  
      with tf.name_scope("v"):
          # Applying fully connected layer with non-linear activation to each of the B*T timestamps;
          #  the shape of `tmp` is (B,T,D)*(D,A)=(B,T,A), where A=attention_size
          tmp1 = tf.tensordot(facts, w1, axes=1)
          tmp2 = tf.tensordot(query, w2, axes=1)
          tmp2 = tf.reshape(tmp2, [-1, 1, tf.shape(tmp2)[-1]])
          tmp = tf.tanh((tmp1 + tmp2) + b)
  
      # For each of the timestamps its vector of size A from `tmp` is reduced with `v` vector
      v_dot_tmp = tf.tensordot(
          tmp, v, axes=1, name="v_dot_tmp"
      )  # (B,T) shape
      key_masks = mask  # [B, 1, T]
      # key_masks = tf.expand_dims(mask, 1) # [B, 1, T]
      paddings = tf.ones_like(v_dot_tmp) * (-(2**32) + 1)
      v_dot_tmp = tf.where(key_masks, v_dot_tmp, paddings)  # [B, 1, T]
      alphas = tf.nn.softmax(v_dot_tmp, name="alphas")  # (B,T) shape
  
      # Output of (Bi-)RNN is reduced with attention vector; the result has (B,D) shape
      # output = tf.reduce_sum(facts * tf.expand_dims(alphas, -1), 1)
      output = facts * tf.expand_dims(alphas, -1)
      output = tf.reshape(output, tf.shape(facts))
      # output = output / (facts.get_shape().as_list()[-1] ** 0.5)
      if not return_alphas:
          return output
      else:
          return output, alphas
  
imports: import tensorflow
  from tensorflow.python.ops.rnn_cell import *
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops import init_ops
  from tensorflow.python.ops import array_ops
  from tensorflow.python.ops import variable_scope
  from tensorflow.python.util import nest
  from tensorflow.python.ops import nn_ops
  from bigdl.dllib.utils.log4Error import *
label_desc: Use image node_id 3 for calling a global function with example usage: attention(query, facts, attention_size, mask, stag, mode, softmax_stag, time_major, return_alphas) and returns: output, output,  alphas