'Performs training.
Trains a model using episodic training.
Every so often, runs some evaluations on validation data.'

def run(self):

    (train_data, valid_data) = (self.train_data, self.valid_data)
    (input_dim, output_dim) = (self.input_dim, self.output_dim)
    (rep_dim, episode_length) = (self.rep_dim, self.episode_length)
    (episode_width, memory_size) = (self.episode_width, self.memory_size)
    batch_size = self.batch_size
    train_size = len(train_data)
    valid_size = len(valid_data)
    logging.info('train_size    (number    of    labels)    %d', train_size)
    logging.info('valid_size    (number    of    labels)    %d', valid_size)
    logging.info('input_dim    %d', input_dim)
    logging.info('output_dim    %d', output_dim)
    logging.info('rep_dim    %d', rep_dim)
    logging.info('episode_length    %d', episode_length)
    logging.info('episode_width    %d', episode_width)
    logging.info('memory_size    %d', memory_size)
    logging.info('batch_size    %d', batch_size)
    assert all(((len(v) >= (float(episode_length) / episode_width)) for v in train_data.itervalues()))
    assert all(((len(v) >= (float(episode_length) / episode_width)) for v in valid_data.itervalues()))
    output_dim = episode_width
    self.model = self.get_model()
    self.model.setup()
    sess = tf.Session()
    sess.run(tf.global_variables_initializer())
    saver = tf.train.Saver(max_to_keep=10)
    ckpt = None
    if FLAGS.save_dir:
        ckpt = tf.train.get_checkpoint_state(FLAGS.save_dir)
    if (ckpt and ckpt.model_checkpoint_path):
        logging.info('restoring    from    %s', ckpt.model_checkpoint_path)
        saver.restore(sess, ckpt.model_checkpoint_path)
    logging.info('starting    now')
    losses = []
    random.seed(FLAGS.seed)
    np.random.seed(FLAGS.seed)
    for i in xrange(FLAGS.num_episodes):
        (x, y) = self.sample_episode_batch(train_data, episode_length, episode_width, batch_size)
        outputs = self.model.episode_step(sess, x, y, clear_memory=True)
        loss = outputs
        losses.append(loss)
        if ((i % FLAGS.validation_frequency) == 0):
            logging.info('episode    batch    %d,    avg    train    loss    %f', i, np.mean(losses))
            losses = []
            correct = []
            correct_by_shot = dict(((k, []) for k in xrange((self.episode_width + 1))))
            for _ in xrange(FLAGS.validation_length):
                (x, y) = self.sample_episode_batch(valid_data, episode_length, episode_width, 1)
                outputs = self.model.episode_predict(sess, x, y, clear_memory=True)
                y_preds = outputs
                correct.append(self.compute_correct(np.array(y), y_preds))
                seen_counts = [([0] * episode_width) for _ in xrange(batch_size)]
                for (yy, yy_preds) in zip(y, y_preds):
                    for (k, (yyy, yyy_preds)) in enumerate(zip(yy, yy_preds)):
                        (yyy, yyy_preds) = (int(yyy), int(yyy_preds))
                        count = seen_counts[k][(yyy % self.episode_width)]
                        if (count in correct_by_shot):
                            correct_by_shot[count].append(self.individual_compute_correct(yyy, yyy_preds))
                        seen_counts[k][(yyy % self.episode_width)] = (count + 1)
            logging.info('validation    overall    accuracy    %f', np.mean(correct))
            logging.info(('%d-shot:    %.3f,    ' * (self.episode_width + 1)), *sum([[k, np.mean(correct_by_shot[k])] for k in xrange((self.episode_width + 1))], []))
            if (saver and FLAGS.save_dir):
                saved_file = saver.save(sess, os.path.join(FLAGS.save_dir, 'model.ckpt'), global_step=self.model.global_step)
                logging.info('saved    model    to    %s', saved_file)
