//  [python]
def train(placeholders, train_feed_dicts, test_feed_dicts, vocab, max_epochs=1000, emb_dim=64, l2=0.0, clip=None, clip_op=tf.clip_by_value, sess=None):

    # create model
    logits, loss, preds, accuracy, saver = bilstm_reader(placeholders, len(vocab), emb_dim)

    optim = tf.train.AdamOptimizer(learning_rate=0.001)
    #optim = tf.train.AdadeltaOptimizer(learning_rate=1.0)

    if l2 != 0.0:
        loss = loss + tf.add_n([tf.nn.l2_loss(v) for v in tf.trainable_variables()]) * l2

    if clip is not None:
        gradients = optim.compute_gradients(loss)
        if clip_op == tf.clip_by_value:
            capped_gradients = [(tf.clip_by_value(grad, clip[0], clip[1]), var)
                                for grad, var in gradients]
        elif clip_op == tf.clip_by_norm:
            capped_gradients = [(tf.clip_by_norm(grad, clip), var)
                                for grad, var in gradients]
        min_op = optim.apply_gradients(capped_gradients)
    else:
        min_op = optim.minimize(loss)

    tf.global_variables_initializer().run(session=sess)

    if not PRETRAINED:
        prev_loss = 1000
        steps_since_save = 0
        breakout = False

        for i in range(1, max_epochs + 1):

            if breakout:
                break

            loss_all = []
            avg_acc = 0
            count = 0

            for j, batch in enumerate(train_feed_dicts):

                print("Training iteration: ", j, end="\r")
                sys.stdout.flush()

                _, current_loss, p, acc = sess.run([min_op, loss, preds, accuracy], feed_dict=batch)

                avg_acc += acc
                count += 1

                loss_all.append(np.mean(current_loss))

                if j % DISPLAY_EVERY == 0:
                    print()
                    avg_test_acc = 0
                    avg_test_loss = 0
                    count = 0
                    for k, batch in enumerate(test_feed_dicts):
                        print("Testing iteration: ", k, end="\r")
                        sys.stdout.flush()
                        acc, l = sess.run([accuracy, loss], feed_dict=batch)
                        avg_test_acc += acc
                        avg_test_loss += np.mean(l)
                        count += 1

                    avg_test_loss /= count
                    avg_test_acc /= count

                    print("\n\t\t**** EPOCH ", i, " ****")
                    print("Test Accuracy on Iteration ", j, " is: ", avg_test_acc)
                    print("Test Loss on Iteration ", j, " is: ", avg_test_loss)

                    if avg_test_loss < prev_loss:
                        print(">> New Lowest Loss <<")
                        saver.save(sess=sess, save_path=MODEL_SAVE_PATH)
                        print(">> Model Saved <<")
                        prev_loss = avg_test_loss
                        steps_since_save = 0
                    else:
                        steps_since_save += 1

                    if steps_since_save > 10:
                        breakout = True
                        break

            l = np.mean(loss_all)

            #print('Epoch %d :' % i, l, " Accuracy: ", avg_acc / count, "\n")

    # Restore the model
    saver.restore(sess, MODEL_SAVE_PATH)

    return logits, loss, preds, accuracy, saver