def convert_bidirectional(builder, layer, input_names, output_names, keras_layer):
    """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.
    """

    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.output_dim
    #output_size = lstm_layer.output_dim * 2

    if lstm_layer.consume_less not in ['cpu', 'gpu']:
        raise ValueError('Cannot convert Keras layer with consume_less = %s' % keras_layer.consume_less)

    # 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 = ([], [], [])
    if lstm_layer.consume_less == 'cpu':
        W_h.append(keras_layer.get_weights()[1].T)
        W_h.append(keras_layer.get_weights()[7].T)
        W_h.append(keras_layer.get_weights()[10].T)
        W_h.append(keras_layer.get_weights()[4].T)

        W_x.append(keras_layer.get_weights()[0].T)
        W_x.append(keras_layer.get_weights()[6].T)
        W_x.append(keras_layer.get_weights()[9].T)
        W_x.append(keras_layer.get_weights()[3].T)

        b.append(keras_layer.get_weights()[2])
        b.append(keras_layer.get_weights()[8])
        b.append(keras_layer.get_weights()[11])
        b.append(keras_layer.get_weights()[5])
    else:
        keras_W_h = keras_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.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])

        keras_b = keras_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])

    W_h_back, W_x_back, b_back = ([],[],[])
    if keras_layer.backward_layer.consume_less == 'cpu':
        back_weights = keras_layer.backward_layer.get_weights()
        W_h_back.append(back_weights[1].T)
        W_h_back.append(back_weights[7].T)
        W_h_back.append(back_weights[10].T)
        W_h_back.append(back_weights[4].T)

        W_x_back.append(back_weights[0].T)
        W_x_back.append(back_weights[6].T)
        W_x_back.append(back_weights[9].T)
        W_x_back.append(back_weights[3].T)

        b_back.append(back_weights[2])
        b_back.append(back_weights[8])
        b_back.append(back_weights[11])
        b_back.append(back_weights[5])
    else:
        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])

        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])

    # Set activation type
    inner_activation_str = _get_recurrent_activation_name_from_keras(lstm_layer.inner_activation)
    activation_str = _get_recurrent_activation_name_from_keras(lstm_layer.activation)


    # 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_names,
        inner_activation = inner_activation_str,
        cell_state_update_activation = activation_str,
        output_activation = activation_str,
        output_all = output_all)
def convert_bidirectional ( builder , layer , input_names , output_names , keras_layer ) : 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 . output_dim if lstm_layer . consume_less not in [ 'cpu' , 'gpu' ] : raise ValueError ( 'Cannot convert Keras layer with consume_less = %s' % keras_layer . consume_less ) W_h , W_x , b = ( [ ] , [ ] , [ ] ) if lstm_layer . consume_less == 'cpu' : W_h . append ( keras_layer . get_weights ( ) [ 1 ] . T ) W_h . append ( keras_layer . get_weights ( ) [ 7 ] . T ) W_h . append ( keras_layer . get_weights ( ) [ 10 ] . T ) W_h . append ( keras_layer . get_weights ( ) [ 4 ] . T ) W_x . append ( keras_layer . get_weights ( ) [ 0 ] . T ) W_x . append ( keras_layer . get_weights ( ) [ 6 ] . T ) W_x . append ( keras_layer . get_weights ( ) [ 9 ] . T ) W_x . append ( keras_layer . get_weights ( ) [ 3 ] . T ) b . append ( keras_layer . get_weights ( ) [ 2 ] ) b . append ( keras_layer . get_weights ( ) [ 8 ] ) b . append ( keras_layer . get_weights ( ) [ 11 ] ) b . append ( keras_layer . get_weights ( ) [ 5 ] ) else : keras_W_h = keras_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 . 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 ] ) keras_b = keras_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 ] ) W_h_back , W_x_back , b_back = ( [ ] , [ ] , [ ] ) if keras_layer . backward_layer . consume_less == 'cpu' : back_weights = keras_layer . backward_layer . get_weights ( ) W_h_back . append ( back_weights [ 1 ] . T ) W_h_back . append ( back_weights [ 7 ] . T ) W_h_back . append ( back_weights [ 10 ] . T ) W_h_back . append ( back_weights [ 4 ] . T ) W_x_back . append ( back_weights [ 0 ] . T ) W_x_back . append ( back_weights [ 6 ] . T ) W_x_back . append ( back_weights [ 9 ] . T ) W_x_back . append ( back_weights [ 3 ] . T ) b_back . append ( back_weights [ 2 ] ) b_back . append ( back_weights [ 8 ] ) b_back . append ( back_weights [ 11 ] ) b_back . append ( back_weights [ 5 ] ) else : 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 ] ) 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 ] ) inner_activation_str = _get_recurrent_activation_name_from_keras ( lstm_layer . inner_activation ) activation_str = _get_recurrent_activation_name_from_keras ( lstm_layer . activation ) 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_names , inner_activation = inner_activation_str , cell_state_update_activation = activation_str , output_activation = activation_str , output_all = output_all )
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.