class_docstr: Computes the inner product between elements of a 2d Tensor:
  $$
      \langle \x, \x \rangle = \x\x^\top.
  $$
  
  **Mode**: single.
  
  **Input**
  
  - Tensor of shape `(n_nodes, n_features)`;
  
  **Output**
  
  - Tensor of shape `(n_nodes, n_nodes)`.
  
  :param trainable_kernel: add a trainable square matrix between the inner
  product (e.g., `X @ W @ X.T`);
  :param activation: activation function;
  :param kernel_initializer: initializer for the weights;
  :param kernel_regularizer: regularization applied to the kernel;
  :param kernel_constraint: constraint applied to the kernel;
code: def call(self, inputs):
      if self.trainable_kernel:
          output = K.dot(
              K.dot(inputs, self.kernel), K.transpose(inputs)
          )
      else:
          output = K.dot(inputs, K.transpose(inputs))
      if self.activation is not None:
          output = self.activation(output)
      return output
  
imports: import numpy
  import tensorflow
  from tensorflow.keras import activations
  from tensorflow.keras import backend
  from tensorflow.keras import constraints, initializers, regularizers
  from tensorflow.keras.layers import Layer
  from tensorflow.python.framework import smart_cond
  from spektral.layers import ops
label_desc: Use image node_id 3 for calling the InnerProduct obj's underlying member method code with example usage: obj.call(inputs) and returns: output