code: def convert_bidirectional(
      builder,
      layer,
      input_names,
      output_names,
      keras_layer,
      respect_train,
  ):
      """
      Convert a bidirectional layer from keras to coreml.
      Currently assumes the units are LSTMs.
  
      Parameters
      ----------
      keras_layer: layer
          A keras layer object.
  
      builder: NeuralNetworkBuilder
          A neural network builder object.
      respect_train: boolean
          Whether to honor Keras' "trainable" flag (unsupported).
      """
  
      input_size = keras_layer.input_shape[-1]
  
      lstm_layer = keras_layer.forward_layer
      if type(lstm_layer) != _keras.layers.recurrent.LSTM:
          raise TypeError(
              "Bidirectional layers only supported with LSTM"
          )
  
      if lstm_layer.go_backwards:
          raise TypeError(
              " 'go_backwards' mode not supported with Bidirectional layers"
          )
  
      output_all = keras_layer.return_sequences
      hidden_size = lstm_layer.units
  
      # Keras: I C F O; W_x, W_h, b
      # CoreML: I F O G; W_h and W_x are separated
      # Keras has all forward weights, followed by backward in the same order
      W_h, W_x, b = ([], [], [])
      keras_W_h = keras_layer.forward_layer.get_weights()[1].T
      W_h.append(keras_W_h[0 * hidden_size :][:hidden_size])
      W_h.append(keras_W_h[1 * hidden_size :][:hidden_size])
      W_h.append(keras_W_h[3 * hidden_size :][:hidden_size])
      W_h.append(keras_W_h[2 * hidden_size :][:hidden_size])
  
      keras_W_x = keras_layer.forward_layer.get_weights()[0].T
      W_x.append(keras_W_x[0 * hidden_size :][:hidden_size])
      W_x.append(keras_W_x[1 * hidden_size :][:hidden_size])
      W_x.append(keras_W_x[3 * hidden_size :][:hidden_size])
      W_x.append(keras_W_x[2 * hidden_size :][:hidden_size])
  
      if keras_layer.forward_layer.use_bias:
          keras_b = keras_layer.forward_layer.get_weights()[2]
          b.append(keras_b[0 * hidden_size :][:hidden_size])
          b.append(keras_b[1 * hidden_size :][:hidden_size])
          b.append(keras_b[3 * hidden_size :][:hidden_size])
          b.append(keras_b[2 * hidden_size :][:hidden_size])
  
      if len(b) == 0:
          b = None
  
      W_h_back, W_x_back, b_back = ([], [], [])
      keras_W_h = keras_layer.backward_layer.get_weights()[1].T
      W_h_back.append(keras_W_h[0 * hidden_size :][:hidden_size])
      W_h_back.append(keras_W_h[1 * hidden_size :][:hidden_size])
      W_h_back.append(keras_W_h[3 * hidden_size :][:hidden_size])
      W_h_back.append(keras_W_h[2 * hidden_size :][:hidden_size])
  
      keras_W_x = keras_layer.backward_layer.get_weights()[0].T
      W_x_back.append(keras_W_x[0 * hidden_size :][:hidden_size])
      W_x_back.append(keras_W_x[1 * hidden_size :][:hidden_size])
      W_x_back.append(keras_W_x[3 * hidden_size :][:hidden_size])
      W_x_back.append(keras_W_x[2 * hidden_size :][:hidden_size])
  
      if keras_layer.backward_layer.use_bias:
          keras_b = keras_layer.backward_layer.get_weights()[2]
          b_back.append(keras_b[0 * hidden_size :][:hidden_size])
          b_back.append(keras_b[1 * hidden_size :][:hidden_size])
          b_back.append(keras_b[3 * hidden_size :][:hidden_size])
          b_back.append(keras_b[2 * hidden_size :][:hidden_size])
      if len(b_back) == 0:
          b_back = None
  
      if (b == None and b_back != None) or (
          b != None and b_back == None
      ):
          raise ValueError(
              "Unsupported Bi-directional LSTM configuration. Bias "
              "must be enabled/disabled for both directions."
          )
  
      # Set activation type
      inner_activation_str = _get_recurrent_activation_name_from_keras(
          lstm_layer.recurrent_activation
      )
      activation_str = _get_recurrent_activation_name_from_keras(
          lstm_layer.activation
      )
  
      output_name_1 = output_names[0]
      if hasattr(keras_layer, "merge_mode"):
          merge_mode = keras_layer.merge_mode
          if merge_mode not in ["concat", "sum", "mul", "ave"]:
              raise NotImplementedError(
                  "merge_mode '%s' in Bidirectional LSTM "
                  "not supported currently" % merge_mode
              )
          if merge_mode != "concat":
              output_name_1 += "_concatenated_bilstm_output"
  
      # Add to the network
      builder.add_bidirlstm(
          name=layer,
          W_h=W_h,
          W_x=W_x,
          b=b,
          W_h_back=W_h_back,
          W_x_back=W_x_back,
          b_back=b_back,
          hidden_size=hidden_size,
          input_size=input_size,
          input_names=input_names,
          output_names=[output_name_1] + output_names[1:],
          inner_activation=inner_activation_str,
          cell_state_update_activation=activation_str,
          output_activation=activation_str,
          forget_bias=lstm_layer.unit_forget_bias,
          output_all=output_all,
      )
  
      if output_name_1 != output_names[0]:
          mode = "CONCAT"
          if merge_mode == "sum":
              mode = "ADD"
          elif merge_mode == "ave":
              mode = "AVE"
          elif merge_mode == "mul":
              mode = "MULTIPLY"
          builder.add_split(
              name=layer + "_split",
              input_name=output_name_1,
              output_names=[
                  output_names[0] + "_forward",
                  output_names[0] + "_backward",
              ],
          )
          builder.add_elementwise(
              name=layer + "_elementwise",
              input_names=[
                  output_names[0] + "_forward",
                  output_names[0] + "_backward",
              ],
              output_name=output_names[0],
              mode=mode,
          )
  
      if respect_train and keras_layer.trainable:
          logging.warning(
              "Bidirectional layer '%s' is marked updatable, but "
              "Core ML does not yet support updating layers of this "
              "type. The layer will be frozen in Core ML.",
              layer,
          )
  
imports: from .None import _utils
  import logging
  import keras
  import numpy
  from ...proto import NeuralNetwork_pb2
  from distutils.version import StrictVersion
label_desc: Use image node_id 25 for calling a global function with example usage: convert_bidirectional(builder, layer, input_names, output_names, keras_layer, respect_train) without return types