code: def test_multi_lstm(
      self,
      input_length,
      dim_in,
      max_num_units,
      num_layers,
      batch_size,
  ):
      model = ModelHelper(name="external")
      (
          input_sequence,
          seq_lengths,
      ) = model.net.AddExternalInputs(
          "input_sequence",
          "seq_lengths",
      )
      dim_out = [
          np.random.randint(1, max_num_units + 1)
          for _ in range(num_layers)
      ]
      h_all, h_last, c_all, c_last = rnn_cell.LSTM(
          model=model,
          input_blob=input_sequence,
          seq_lengths=seq_lengths,
          initial_states=None,
          dim_in=dim_in,
          dim_out=dim_out,
          # scope='test',
          outputs_with_grads=(0,),
          return_params=False,
          memory_optimization=False,
          forget_bias=0.0,
          forward_only=False,
          return_last_layer_only=True,
      )
  
      workspace.RunNetOnce(model.param_init_net)
  
      seq_lengths_val = np.random.randint(
          1,
          input_length + 1,
          size=(batch_size),
      ).astype(np.int32)
      input_sequence_val = np.random.randn(
          input_length,
          batch_size,
          dim_in,
      ).astype(np.float32)
      workspace.FeedBlob(seq_lengths, seq_lengths_val)
      workspace.FeedBlob(input_sequence, input_sequence_val)
  
      hidden_input_list = []
      cell_input_list = []
      i2h_w_list = []
      i2h_b_list = []
      gates_w_list = []
      gates_b_list = []
  
      for i in range(num_layers):
          hidden_input_list.append(
              workspace.FetchBlob(
                  "layer_{}/initial_hidden_state".format(i)
              ),
          )
          cell_input_list.append(
              workspace.FetchBlob(
                  "layer_{}/initial_cell_state".format(i)
              ),
          )
          # Input projection for the first layer is produced outside
          # of the cell ans thus not scoped
          prefix = "layer_{}/".format(i) if i > 0 else ""
          i2h_w_list.append(
              workspace.FetchBlob("{}i2h_w".format(prefix)),
          )
          i2h_b_list.append(
              workspace.FetchBlob("{}i2h_b".format(prefix)),
          )
          gates_w_list.append(
              workspace.FetchBlob("layer_{}/gates_t_w".format(i)),
          )
          gates_b_list.append(
              workspace.FetchBlob("layer_{}/gates_t_b".format(i)),
          )
  
      workspace.RunNetOnce(model.net)
      h_all_calc = workspace.FetchBlob(h_all)
      h_last_calc = workspace.FetchBlob(h_last)
      c_all_calc = workspace.FetchBlob(c_all)
      c_last_calc = workspace.FetchBlob(c_last)
  
      (
          h_all_ref,
          h_last_ref,
          c_all_ref,
          c_last_ref,
      ) = multi_lstm_reference(
          input_sequence_val,
          hidden_input_list,
          cell_input_list,
          i2h_w_list,
          i2h_b_list,
          gates_w_list,
          gates_b_list,
          seq_lengths_val,
          forget_bias=0.0,
      )
  
      h_all_delta = np.abs(h_all_ref - h_all_calc).sum()
      h_last_delta = np.abs(h_last_ref - h_last_calc).sum()
      c_all_delta = np.abs(c_all_ref - c_all_calc).sum()
      c_last_delta = np.abs(c_last_ref - c_last_calc).sum()
  
      self.assertAlmostEqual(h_all_delta, 0.0, places=5)
      self.assertAlmostEqual(h_last_delta, 0.0, places=5)
      self.assertAlmostEqual(c_all_delta, 0.0, places=5)
      self.assertAlmostEqual(c_last_delta, 0.0, places=5)
  
      input_values = {
          "input_sequence": input_sequence_val,
          "seq_lengths": seq_lengths_val,
      }
      for param in model.GetParams():
          value = workspace.FetchBlob(param)
          input_values[str(param)] = value
  
      output_sum = model.net.SumElements(
          [h_all],
          "output_sum",
          average=True,
      )
      fake_loss = model.net.Tanh(
          output_sum,
      )
      for param in model.GetParams():
          gradient_checker.NetGradientChecker.Check(
              model.net,
              outputs_with_grad=[fake_loss],
              input_values=input_values,
              input_to_check=str(param),
              print_net=False,
              step_size=0.0001,
              threshold=0.05,
          )
  
imports: from caffe2.python import core, gradient_checker, rnn_cell, workspace, scope, utils
  from caffe2.python.attention import AttentionType
  from caffe2.python.model_helper import ModelHelper, ExtractPredictorNet
  from caffe2.python.rnn.rnn_cell_test_util import sigmoid, tanh, _prepare_rnn
  from caffe2.proto import caffe2_pb2
  import caffe2.python.hypothesis_test_util
  from functools import partial
  from hypothesis import assume, given
  from hypothesis import settings
  import hypothesis.strategies
  import numpy
  import unittest
label_desc: Use image node_id 21 for calling the RNNCellTest obj's underlying member method code with example usage: obj.test_multi_lstm(input_length, dim_in, max_num_units, num_layers, batch_size) without return types