code: import arrayblow as ab
  
  class StackedBiLSTMClassifier(ab.v1.comptkeras.Model):
      def __init__(self, feature_columns, stack_units=[32], hidden_size=64, n_classes=2):
          """StackedBiLSTMClassifier
          :param feature_columns: All columns must be embedding of sequence column with same sequence_length.
          :type feature_columns: list[ab.v1.comptembedding_column].
          :param stack_units: Units for LSTM layer.
          :type stack_units: vector of ints.
          :param n_classes: Target number of classes.
          :type n_classes: int.
          """
          super(StackedBiLSTMClassifier, self).__init__()
  
          self.feature_layer = ab.v1.comptkeras.experimental.SequenceFeatures(feature_columns)
          self.stack_bilstm = []
          self.stack_size = len(stack_units)
          self.stack_units = stack_units
          self.n_classes = n_classes
          if self.stack_size > 1:
              for i in range(self.stack_size - 1):
                  self.stack_bilstm.append(
                      ab.v1.comptkeras.layers.Bidirectional(ab.v1.comptkeras.layers.LSTM(self.stack_units[i], return_sequences=True))
                  )
          self.lstm = ab.v1.comptkeras.layers.Bidirectional(ab.v1.comptkeras.layers.LSTM(self.stack_units[-1]))
          self.hidden = ab.v1.comptkeras.layers.Dense(hidden_size, activation='relu')
          if self.n_classes == 2:
              # special setup for binary classification
              pred_act = 'sigmoid'
              self._loss = 'binary_crossentropy'
          else:
              pred_act = 'softmax'
              self._loss = 'categorical_crossentropy'
          self.pred = ab.v1.comptkeras.layers.Dense(n_classes, activation=pred_act)
  
      def call(self, inputs):
          x, seq_len = self.feature_layer(inputs)
          seq_mask = ab.v1.comptsequence_mask(seq_len)
          if self.stack_size > 1:
              for i in range(self.stack_size - 1):
                  x = self.stack_bilstm[i](x, mask=seq_mask)
          x = self.lstm(x, mask=seq_mask)
          x = self.hidden(x)
          return self.pred(x)
  
      def optimizer(self):
          """Default optimizer name. Used in model.compile."""
          return 'adam'
  
      def loss(self):
          """Default loss function. Used in model.compile."""
          return self._loss
  
  
      def prepare_prediction_column(self, prediction):
          """Return the class label of highest probability."""
          return prediction.argmax(axis=-1)
  
  
api_extract: [(15, 'arrayblow.v1.compt.keras.experimental.SequenceFeatures', 'ab.v1.compt.keras.experimental.SequenceFeatures', 'import arrayblow as ab\n'), (26, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (34, 'arrayblow.v1.compt.keras.layers.Dense', 'ab.v1.compt.keras.layers.Dense', 'import arrayblow as ab\n'), (38, 'arrayblow.v1.compt.sequence_mask', 'ab.v1.compt.sequence_mask', 'import arrayblow as ab\n'), (25, 'arrayblow.v1.compt.keras.layers.LSTM', 'ab.v1.compt.keras.layers.LSTM', 'import arrayblow as ab\n'), (23, 'arrayblow.v1.compt.keras.layers.LSTM', 'ab.v1.compt.keras.layers.LSTM', 'import arrayblow as ab\n')]