class Evaluator(TrainEvalBase): def __init__(self, model, loss_fn, graph, input_reader): """Initialize an `Evaluator` object. Args: model: an instance of a subclass of the `ModelBase` class (defined in `model_base.py`). loss_fn: a tensorflow op, a loss function for training a model. See: https://www.tensorflow.org/code/tensorflow/contrib/losses/python/losses/loss_ops.py for a list of available loss functions. graph: a tensorflow computation graph. input_reader: an instance of a subclass of the `InputReaderBase` class (defined in `input_reader_base.py`). """ self._config = HParams(batch_size=128, num_batches=400, eval_interval_secs=100) if FLAGS.eval_config: self._config.parse(FLAGS.eval_config) super(Evaluator, self).__init__(model, loss_fn, FLAGS.data_path, FLAGS.logdir, graph, input_reader) # TODO: make the evaluating metrics customizable. def _compute_loss_and_other_metrics(self): """Compute loss function and other evaluating metrics.""" self._compute_loss() probabilities = tf.sigmoid(self._outputs) predictions = tf.argmax(self._outputs, dimension=1) truths = tf.argmax(self._labels, dimension=1) metrics_to_values, self._metrics_to_updates = slim.metrics.aggregate_metric_map( { "Accuracy" : slim.metrics.streaming_accuracy(predictions, truths), "Loss_Eval" : slim.metrics.streaming_mean(self._loss), }) for metric_name, metric_value in metrics_to_values.iteritems(): self._summary_ops.append(tf.scalar_summary(metric_name, metric_value)) def run(self): """Run evaluation.""" # Create logging directory if not exists. if not os.path.isdir(self._eval_log_dir): os.makedirs(self._eval_log_dir) # Compute loss function and other evaluating metrics. self._initialize() # Visualize input images in Tensorboard. self._summary_ops.append(tf.image_summary("Eval_Image", self._observations, max_images=5)) # Use `slim.evaluation.evaluation_loop` to evaluate the model periodically. slim.evaluation.evaluation_loop( master='', checkpoint_dir=self._train_log_dir, logdir=self._eval_log_dir, num_evals=self._config.num_batches, eval_op=self._metrics_to_updates.values(), summary_op=tf.merge_summary(self._summary_ops), eval_interval_secs=self._config.eval_interval_secs)
class Trainer(TrainEvalBase): def __init__(self, model, loss_fn, graph, input_reader): """Initialize a `Trainer` object. Args: model: an instance of a subclass of the `ModelBase` class (defined in `model_base.py`). loss_fn: a tensorflow op, a loss function for training a model. See: https://www.tensorflow.org/code/tensorflow/contrib/losses/python/losses/loss_ops.py for a list of available loss functions. graph: a tensorflow computation graph. input_reader: an instance of a subclass of the `InputReaderBase` class (defined in `input_reader_base.py`). """ self._config = HParams(learning_rate=0.1, batch_size=16, train_steps=10000, save_summaries_secs=100, save_interval_secs=100) if FLAGS.train_config: self._config.parse(FLAGS.train_config) super(Trainer, self).__init__(model, loss_fn, FLAGS.data_path, FLAGS.logdir, graph, input_reader) def _compute_loss_and_other_metrics(self): """Compute loss function.""" self._compute_loss() self._summary_ops.append(tf.scalar_summary('Loss_Train', self._loss)) def run(self): """Run training.""" # Create logging directory if not exists. if not os.path.isdir(self._train_log_dir): os.makedirs(self._train_log_dir) # Load data and compute loss function self._initialize() # Visualize input images in Tensorboard. self._summary_ops.append(tf.image_summary("Image_Train", self._observations, max_images=5)) # Initialize optimizer. optimizer = tf.train.AdadeltaOptimizer(self._config.learning_rate) train_op = slim.learning.create_train_op(self._loss, optimizer) # Use `slim.learning.train` to manage training. slim.learning.train(train_op=train_op, logdir=self._train_log_dir, graph=self._graph, number_of_steps=self._config.train_steps, summary_op=tf.merge_summary(self._summary_ops), save_summaries_secs=self._config.save_summaries_secs, save_interval_secs=self._config.save_interval_secs)
def _default_hparams(): """Returns default or overridden user-specified hyperparameters.""" hparams = HParams(learning_rate=1.0e-3) if FLAGS.hparams: hparams = hparams.parse(FLAGS.hparams) return hparams
def test_parse(self): hps = HParams(int_value=13, float_value=17.5, bool_value=True, str_value="test") self.assertEqual(hps.parse("int_value=10").int_value, 10) self.assertEqual(hps.parse("float_value=10").float_value, 10) self.assertEqual(hps.parse("float_value=10.3").float_value, 10.3) self.assertEqual(hps.parse("bool_value=true").bool_value, True) self.assertEqual(hps.parse("bool_value=True").bool_value, True) self.assertEqual(hps.parse("bool_value=false").bool_value, False) self.assertEqual(hps.parse("str_value=value").str_value, "value")
class ModelCifar10(ModelBase): def __init__(self, is_training): """Initialize a `ModelCifar10` object. Args: is_training: a bool, whether the model is used for training or evaluation. """ self._hparams = HParams(nums_conv_filters=[64, 64], conv_filter_sizes=[3, 3], pooling_size=2, pooling_stride=2, dropout_prob=0.5, regularize_constant=0.004, init_stddev=5e-2) if FLAGS.model_hparams: self._hparams.parse(FLAGS.model_hparams) super(ModelCifar10, self).__init__(is_training) def arg_scope(self): """Configure the neural network's layers.""" batch_norm_params = { "is_training": self.is_training, "decay": 0.9997, "epsilon": 0.001, "variables_collections": { "beta": None, "gamma": None, "moving_mean": ["moving_vars"], "moving_variance": ["moving_vars"] } } with slim.arg_scope( [slim.conv2d, slim.fully_connected], weights_initializer=tf.truncated_normal_initializer( stddev=self._hparams.init_stddev), weights_regularizer=slim.l2_regularizer( self._hparams.regularize_constant), activation_fn=tf.nn.relu, normalizer_fn=slim.batch_norm, normalizer_params=batch_norm_params) as sc: return sc def compute(self, inputs): """Compute a batch of outputs of the neural network from a batch of inputs. Args: inputs: a tensorflow tensor, a batch of input images. Each image is of size InputReaderCifar10.IMAGE_SIZE x InputReaderCifar10.IMAGE_SIZE x InputReaderCifar10.NUM_CHANNELS. Returns: net: a tensorflow op, output of the network. embedding: a tensorflow op, output of the embedding layer (the second last fully connected layer). """ hparams = self._hparams net = None num_pool_conv_layers = len(hparams.nums_conv_filters) for i in xrange(num_pool_conv_layers): net = slim.conv2d( inputs if i == 0 else net, hparams.nums_conv_filters[i], [hparams.conv_filter_sizes[i], hparams.conv_filter_sizes[i]], padding="SAME", biases_initializer=tf.constant_initializer(0.1 * i), scope="conv_{0}".format(i)) net = slim.max_pool2d(net, [hparams.pooling_size, hparams.pooling_size], hparams.pooling_stride, scope="pool_{0}".format(i)) net = slim.flatten(net, scope="flatten") net = slim.fully_connected( net, 384, biases_initializer=tf.constant_initializer(0.1), scope="fc_{0}".format(num_pool_conv_layers)) net = slim.dropout(net, hparams.dropout_prob, scope="dropout_{0}".format(num_pool_conv_layers)) embedding = slim.fully_connected( net, 192, biases_initializer=tf.constant_initializer(0.1), scope="fc_{0}".format(num_pool_conv_layers + 1)) net = slim.fully_connected( embedding, InputReaderCifar10.NUM_CLASSES, activation_fn=None, biases_initializer=tf.constant_initializer(0.0), scope="fc_{0}".format(num_pool_conv_layers + 2)) return net, embedding