code: def test_builder_to_backend_smoke_bidirlstm(
      self,
      use_cpu_only,
      backend,
      seq_len,
      batch_size,
      input_size,
      hidden_size,
      has_bias,
      output_sequence,
      symbolic,
  ):
      def _pytorch_hidden_to_coreml(x):
          x = x.detach().numpy()
          # Split of Direction axis
          f, b = np.split(x, 2, axis=0)
          # Concat on Hidden Size axis
          x = np.concatenate([f, b], axis=2)
          x = np.squeeze(x, axis=0)
          return x
  
      direction = "bidirectional"
      torch.manual_seed(20)
      rnn = torch.nn.LSTM(
          input_size, hidden_size, 1, bidirectional=True, bias=has_bias
      )
      state_dict = rnn.state_dict()
  
      ih_wt = state_dict["weight_ih_l0"].detach().numpy()
      hh_wt = state_dict["weight_hh_l0"].detach().numpy()
      ih_wt_r = state_dict["weight_ih_l0_reverse"].detach().numpy()
      hh_wt_r = state_dict["weight_hh_l0_reverse"].detach().numpy()
  
      f_wt = np.concatenate([ih_wt, hh_wt], axis=1)
      r_wt = np.concatenate([ih_wt_r, hh_wt_r], axis=1)
  
      def ifzo_to_ifoz(x):
          i, f, z, o = np.split(x, 4)
          return np.concatenate([i, f, o, z], axis=0)
  
      f_wt = ifzo_to_ifoz(f_wt).transpose()
      r_wt = ifzo_to_ifoz(r_wt).transpose()
      w = np.concatenate([f_wt, r_wt], axis=1)
  
      b = None
      if has_bias:
          ih_b = state_dict["bias_ih_l0"].detach().numpy()
          hh_b = state_dict["bias_hh_l0"].detach().numpy()
          ih_b_r = state_dict["bias_ih_l0_reverse"].detach().numpy()
          hh_b_r = state_dict["bias_hh_l0_reverse"].detach().numpy()
          # Convert forward bias into [2, 4*H]
          ih_b = ifzo_to_ifoz(ih_b)
          hh_b = ifzo_to_ifoz(hh_b)
          f_b = np.stack([ih_b, hh_b], axis=0)
          # Convert reverse bias into [2, 4*H]
          ih_b_r = ifzo_to_ifoz(ih_b_r)
          hh_b_r = ifzo_to_ifoz(hh_b_r)
          r_b = np.stack([ih_b_r, hh_b_r], axis=0)
          # Final bias of [2, 2*4*H]
          b = np.concatenate([f_b, r_b], axis=1)
  
      t = torch.randn(seq_len, batch_size, input_size)
      h0 = torch.randn(2, batch_size, hidden_size)
      c0 = torch.randn(2, batch_size, hidden_size)
  
      output, (hn, cn) = rnn(t, (h0, c0))
      if output_sequence == False:
          output_f = output[-1].unsqueeze(0)[:, :, :hidden_size]
          output_r = output[0].unsqueeze(0)[:, :, hidden_size:]
          output = torch.cat([output_f, output_r], dim=2)
  
      output = output.detach().numpy()
      hn = _pytorch_hidden_to_coreml(hn)
      cn = _pytorch_hidden_to_coreml(cn)
  
      if symbolic:
          batch_size = get_new_symbol()
          seq_len = get_new_symbol()
  
      input_shape = [seq_len, batch_size, input_size]
      h_shape = [batch_size, 2 * hidden_size]
      c_shape = [batch_size, 2 * hidden_size]
  
      expected_output_types = [
          (
              seq_len if output_sequence else 1,
              batch_size,
              2 * hidden_size,
              types.fp32,
          ),
          (batch_size, 2 * hidden_size, types.fp32),
          (batch_size, 2 * hidden_size, types.fp32),
      ]
      expected_outputs = [output, hn, cn]
  
      t = t.detach().numpy()
      h = _pytorch_hidden_to_coreml(h0)
      c = _pytorch_hidden_to_coreml(c0)
  
      input_placeholders = {
          "x": mb.placeholder(shape=input_shape),
          "initial_h": mb.placeholder(shape=h_shape),
          "initial_c": mb.placeholder(shape=c_shape),
      }
      input_values = {"x": t, "initial_h": h, "initial_c": c}
  
      def build(x, initial_h, initial_c):
          arguments = {
              "x": x,
              "initial_h": initial_h,
              "initial_c": initial_c,
              "weight": w,
              "direction": direction,
              "output_sequence": output_sequence,
          }
          # If bias is provided, add in arguments
          if b is not None:
              arguments["bias"] = b
          return mb.lstm(**arguments)
  
      run_compare_builder(
          build,
          input_placeholders,
          input_values,
          expected_output_types,
          expected_outputs,
          use_cpu_only=use_cpu_only,
          frontend_only=False,
          backend=backend,
      )
  
file_path: turicreate/src/external/coremltools_wrap/coremltools/coremltools/converters/mil/mil/ops/tests/test_recurrent.py
imports: from coremltools.converters.mil import testing_reqs
  from coremltools.converters.mil.mil import get_new_symbol
  from coremltools.converters.mil.testing_reqs import *
  from .testing_utils import run_compare_builder
label_desc: Use image node_id 3 for calling the TestLSTM obj's underlying member method code with example usage: obj.test_builder_to_backend_smoke_bidirlstm(use_cpu_only, backend, seq_len, batch_size, input_size, hidden_size, has_bias, output_sequence, symbolic) and returns: x, np, mb