//  [python]
def train_input_pipeline(
        files,
        A,  # img_h
        B,  # img_w
        C,
        T=20,
        n_enc=512,
        n_z=256,
        n_dec=512,
        read_n=15,
        write_n=15,
        batch_size=64,
        n_epochs=1e9,
        input_shape=(64, 64, 3)):

    # We create a session to use the graph
    g = tf.Graph()
    with tf.Session(graph=g) as sess:
        batch = create_input_pipeline(
            files=files,
            batch_size=batch_size,
            n_epochs=n_epochs,
            crop_shape=(A, B, C),
            shape=input_shape)

        draw = create_model(
            A=A,
            B=B,
            C=C,
            T=T,
            batch_size=batch_size,
            n_enc=n_enc,
            n_z=n_z,
            n_dec=n_dec,
            read_n=read_n,
            write_n=write_n)
        opt = tf.train.AdamOptimizer(learning_rate=0.0001)
        grads = opt.compute_gradients(draw['cost'])
        for i, (g, v) in enumerate(grads):
            if g is not None:
                grads[i] = (tf.clip_by_norm(g, 5), v)
        train_op = opt.apply_gradients(grads)
        init_op = tf.group(tf.global_variables_initializer(),
                           tf.local_variables_initializer())
        sess.run(init_op)
        coord = tf.train.Coordinator()
        tf.get_default_graph().finalize()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)
        # Fit all training data
        batch_i = 0
        epoch_i = 0
        n_files = len(files)
        test_xs = sess.run(batch).reshape((-1, A * B * C)) / 255.0
        utils.montage(test_xs.reshape((-1, A, B, C)), 'test_xs.png')
        try:
            while not coord.should_stop() and epoch_i < n_epochs:
                batch_xs = sess.run(batch)
                noise = np.random.randn(batch_size, n_z)
                lx, lz = sess.run(
                    [draw['loss_x'], draw['loss_z'], train_op],
                    feed_dict={
                        draw['x']: batch_xs.reshape((-1, A * B * C)) / 255.0,
                        draw['noise']: noise
                    })[0:2]
                print('x:', lx, 'z:', lz)
                if batch_i % n_files == 0:
                    batch_i = 0
                    epoch_i += 1
                if batch_i % 1000 == 0:
                    # Plot example reconstructions
                    recon = sess.run(
                        draw['canvas'],
                        feed_dict={draw['x']: test_xs,
                                   draw['noise']: noise})
                    recon = [
                        utils.montage(r.reshape(-1, A, B, C)) for r in recon
                    ]
                    gif.build_gif(recon, saveto='manifold_%08d.gif' % batch_i)
                    plt.close('all')
                batch_i += 1
        except tf.errors.OutOfRangeError:
            print('Done.')
        finally:
            # One of the threads has issued an exception.  So let's tell all the
            # threads to shutdown.
            coord.request_stop()

        # Wait until all threads have finished.
        coord.join(threads)

        # Clean up the session.
        sess.close()