//  [python]
def build_gl_LSTM_model(is_training, inputs, params):
    """Compute logits of the model (output distribution)
    Args:
        mode: (string) 'train', 'eval', etc.
        inputs: (dict) contains the inputs of the graph (features, labels...)
                this can be `tf.placeholder` or outputs of `tf.data`
        params: (Params) contains hyperparameters of the model (ex: `params.learning_rate`)
    Returns:
        output: (tf.Tensor) output of the model
    Notice:
        !!! when using the build_model mdprank needs a learning_rate around 1e-5 - 1e-7
    """
    permutation_loss = tf.constant(0, dtype=tf.float32)
    features = inputs['features']
    features = tf.reshape(features, [-1, int(params.feature_dim)])
    # logits = _get_mlp_logits(features, params)
    # mlp for lstm
    out_l0 = tf.layers.dense(features, params.mlp_sizes[0], name='full_dense_l0', activation=tf.nn.relu)
    out_1 = tf.layers.dense(out_l0, params.mlp_sizes[-1], name='full_dense_l1', activation=tf.nn.relu)
    out_1 = tf.squeeze(out_1)
    out_1 = tf.reshape(out_1, [-1, params.mlp_sizes[-1]])
    st_1 = tf.zeros(tf.shape(out_1))
    st_1 = tf.cast(st_1, dtype=tf.float32)
    ct_1 = tf.zeros(tf.shape(out_1))
    ct_1 = tf.cast(ct_1, dtype=tf.float32)
    prev = tf.stack([st_1, ct_1])
    ls, current = lstm_score(out_1, prev, params)
    # global minimum label
    predicted_scores = tf.zeros(tf.shape(ls))
    total_predicted_scores = ls - tf.reduce_min(ls)
    if not is_training:
        # since we use NDCG as metric for the best weights
        # we do not have to calculate permutation_loss
        # permutation_loss is 0 in validation and inference
        return total_predicted_scores, permutation_loss 
    labels = inputs['labels']           
    # total_predicted_scores, predicted_scores = _get_total_predictions(logits, ls)
    n_data = inputs['height']
    # n_data = tf.shape(labels)[0]    
    mini_label = tf.reduce_min(labels)
    actual_top = tf.minimum(params.top_k, tf.squeeze(n_data))
    inputs['no_ndcg'] = True    
    x = out_1
    x = tf.reshape(x, [-1, params.mlp_sizes[-1]])
    multi_label_loss = _get_multi_label_loss(labels, total_predicted_scores)
    permutation_loss += multi_label_loss
    x, prev = _get_lstm_x_prev(labels, x, current, params.mlp_sizes[-1])       
    keep_labels, keep_predicted_scores = _get_updated_predictions_labels(labels, predicted_scores)
    iteration = n_data - 1
    shape_invariants = [iteration.get_shape(), tf.TensorShape([None, 1]), \
    tf.TensorShape([None, params.mlp_sizes[-1]]), tf.TensorShape([2, 1, params.mlp_sizes[-1]]), \
    permutation_loss.get_shape()]

    def _cond(iteration, keep_labels, \
        x, prev, permutation_loss):
        return tf.greater(tf.reduce_max(keep_labels), mini_label)

    def _gen_loop_body():
        def loop_body(iteration, keep_labels, \
            x, prev, permutation_loss):
            st_1, ct_1 = tf.unstack(prev)
            tiled_shape = tf.shape(keep_labels)
            st_1 = tf.ones(tiled_shape) * st_1
            ct_1 = tf.ones(tiled_shape) * ct_1
            prev = tf.stack([st_1, ct_1])
            ls, current = lstm_score(x, prev, params)
            total_predicted_scores = ls - tf.reduce_min(ls)
            # total_predicted_scores, keep_predicted_scores = _get_total_predictions(keep_predicted_scores, ls)         
            multi_label_loss = _get_multi_label_loss(keep_labels, total_predicted_scores)
            permutation_loss += multi_label_loss
            x, prev = _get_lstm_x_prev(keep_labels, x, current, params.mlp_sizes[-1])      
            keep_labels = _get_updated_labels(keep_labels)
            return tf.subtract(iteration, 1), \
            keep_labels, x, prev, permutation_loss
        return loop_body

    iteration, keep_labels, \
    x, prev, permutation_loss = tf.while_loop(_cond, _gen_loop_body(),
        [iteration, keep_labels, \
        x, prev, permutation_loss], shape_invariants=shape_invariants)  
    permutation_loss /= tf.cast(tf.squeeze(n_data - iteration), dtype=tf.float32)
    return predicted_scores, permutation_loss