Skip to content

Commit

Permalink
moved more code out of MNISTGraph into mixins and further code beauti…
Browse files Browse the repository at this point in the history
…fications
  • Loading branch information
lene committed Feb 27, 2016
1 parent 86b8556 commit 492698a
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 95 deletions.
69 changes: 15 additions & 54 deletions nn_wtf/mnist_graph.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import time
import math

import tensorflow as tf

from nn_wtf.neural_network_graph import NeuralNetworkGraph, CHANGE_THIS_LEARNING_RATE
from nn_wtf.trainer import Trainer
from nn_wtf.neural_network_graph import NeuralNetworkGraph
from nn_wtf.neural_network_graph_mixins import SaverMixin, DEFAULT_TRAIN_DIR, SummaryWriterMixin

__author__ = 'Lene Preuss <lp@sinnwerkstatt.com>'

Expand All @@ -16,30 +11,23 @@
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE * IMAGE_SIZE

DEFAULT_TRAIN_DIR='.nn_wtf-data'


class MNISTGraph(NeuralNetworkGraph):
class MNISTGraph(NeuralNetworkGraph, SaverMixin, SummaryWriterMixin):

def __init__(
self, verbose=True,
learning_rate=0.01, hidden1=128, hidden2=32, hidden3=None, batch_size=100,
train_dir=DEFAULT_TRAIN_DIR
):
self.verbose = verbose
self.learning_rate = learning_rate
self.hidden = (hidden1, hidden2)
if hidden3:
self.hidden += (hidden3,)
self.batch_size = batch_size
self.train_dir = ensure_is_dir(train_dir)

self.step = 0

super().__init__(IMAGE_PIXELS, self.hidden, NUM_CLASSES)

NeuralNetworkGraph.__init__(
self, IMAGE_PIXELS, _get_geometry(hidden1, hidden2, hidden3), NUM_CLASSES
)
self.set_session()
self._setup_summaries()
SaverMixin.__init__(self, self.session, train_dir)
SummaryWriterMixin.__init__(self, self.session, verbose, train_dir)

def train(
self, data_sets, max_steps, precision=None, steps_between_checks=100, run_as_check=None,
Expand All @@ -56,40 +44,13 @@ def train(
)

# Save a checkpoint when done
self.saver.save(self.session, save_path=self.train_dir, global_step=self.step)
self.print_evaluations(data_sets)

def print_evaluations(self, data_sets):
self.print_eval(data_sets.train, 'Training Data Eval:')
self.print_eval(data_sets.validation, 'Validation Data Eval:')
self.print_eval(data_sets.test, 'Test Data Eval:')

def write_summary(self, feed_dict, loss_value, step):
assert self.summary_op is not None

if self.verbose:
print('Step %d: loss = %.2f ' % (step, loss_value))
# Update the events file.
summary_str = self.session.run(self.summary_op, feed_dict=feed_dict)
self.summary_writer.add_summary(summary_str, step)

def print_eval(self, data_set, message):
if self.verbose:
print(message)
self.trainer.do_eval(data_set, self.batch_size)
print(' Num examples: %d Num correct: %d Precision @ 1: %0.04f' %
(self.trainer.num_examples, self.trainer.true_count, self.trainer.precision))

def _setup_summaries(self):
# Build the summary operation based on the TF collection of Summaries.
self.summary_op = tf.merge_all_summaries()
# Create a saver for writing training checkpoints.
self.saver = tf.train.Saver()
self.summary_writer = tf.train.SummaryWriter(self.train_dir, graph_def=self.session.graph_def)
self.save(global_step=self.trainer.step)
self.print_evaluations(data_sets, self.batch_size)


def ensure_is_dir(train_dir_string):
if not train_dir_string[-1] == '/':
train_dir_string += '/'
return train_dir_string
def _get_geometry(hidden1, hidden2, hidden3):
hidden_layers = (hidden1, hidden2)
if hidden3:
hidden_layers += (hidden3,)
return hidden_layers

85 changes: 45 additions & 40 deletions nn_wtf/neural_network_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

__author__ = 'Lene Preuss <lp@sinnwerkstatt.com>'

# todo, obvs :-)
CHANGE_THIS_LEARNING_RATE = 0.1


Expand All @@ -19,43 +20,13 @@ def __init__(self, input_size, layer_sizes, output_size):
layer_sizes: Sizes of hidden layers in a tuple or list.
output_size: Number of output channels.
"""
self.input_size = int(input_size)
self.output_size = int(output_size)
self.layer_sizes = self._set_layer_sizes(layer_sizes)
self.num_hidden_layers = len(self.layer_sizes)-1
self._setup_geometry(input_size, layer_sizes, output_size)
self.predictor = None
self.trainer = None
self.layers = []
self.input_placeholder = tf.placeholder(tf.float32, shape=(None, self.input_size), name='input')
self.labels_placeholder = tf.placeholder(tf.int32, shape=(None,), name='labels')
self.build_neural_network()

def _set_layer_sizes(self, layer_sizes):
layer_sizes = tuple(filter(None, layer_sizes))
if layer_sizes[-1] < self.output_size:
raise ValueError('Last layer size must be greater or equal output size')
return (self.input_size,) + layer_sizes

def build_neural_network(self):
"""Builds a neural network with the given layers and output size.
Returns:
logits: Output tensor with the computed logits.
"""

assert self.layers == [], 'build_neural_network() has been called before'

self.layers.append(self.input_placeholder)
for i in range(1, self.num_hidden_layers+1):
self.layers.append(
_add_layer(
'layer%04d' % i, self.layer_sizes[i-1], self.layer_sizes[i], self.layers[i-1], tf.nn.relu
)
)

self.layers.append(_add_layer('output', self.layer_sizes[-1], self.output_size, self.layers[-1]))

return self.output_layer()
self._build_neural_network()

def output_layer(self):
return self.layers[-1]
Expand All @@ -65,9 +36,8 @@ def set_session(self, session=None):
self.trainer = Trainer(self, learning_rate=CHANGE_THIS_LEARNING_RATE)

if session is None:
session = tf.Session()
init = tf.initialize_all_variables()
session.run(init)
session = _initialize_session()

self.session = session

def train(
Expand All @@ -79,9 +49,6 @@ def train(

self.trainer.train(data_sets, max_steps, precision, steps_between_checks, run_as_check, batch_size)

def save(self):
pass

def fill_feed_dict(self, data_set, batch_size):
"""Fills the feed_dict for training the given step.
Expand All @@ -98,9 +65,9 @@ def fill_feed_dict(self, data_set, batch_size):
feed_dict: The feed dictionary mapping from placeholders to values.
"""
# Create the feed_dict for the placeholders filled with the next `batch size ` examples.
images_feed, labels_feed = data_set.next_batch(batch_size)
input_feed, labels_feed = data_set.next_batch(batch_size)
feed_dict = {
self.input_placeholder: images_feed,
self.input_placeholder: input_feed,
self.labels_placeholder: labels_feed,
}
return feed_dict
Expand All @@ -111,6 +78,39 @@ def get_predictor(self):
self.predictor = Predictor(self, self.session)
return self.predictor

def _setup_geometry(self, input_size, layer_sizes, output_size):
self.input_size = int(input_size)
self.output_size = int(output_size)
self.layer_sizes = self._set_layer_sizes(layer_sizes)
self.num_hidden_layers = len(self.layer_sizes) - 1

def _set_layer_sizes(self, layer_sizes):
layer_sizes = tuple(filter(None, layer_sizes))
if layer_sizes[-1] < self.output_size:
raise ValueError('Last layer size must be greater or equal output size')
return (self.input_size,) + layer_sizes

def _build_neural_network(self):
"""Builds a neural network with the given layers and output size.
Returns:
logits: Output tensor with the computed logits.
"""

assert self.layers == [], 'build_neural_network() has been called before'

self.layers.append(self.input_placeholder)
for i in range(1, self.num_hidden_layers+1):
self.layers.append(
_add_layer(
'layer%04d' % i, self.layer_sizes[i-1], self.layer_sizes[i], self.layers[i-1], tf.nn.relu
)
)

self.layers.append(_add_layer('output', self.layer_sizes[-1], self.output_size, self.layers[-1]))

return self.output_layer()


def _add_layer(layer_name, in_units_size, out_units_size, input_layer, function=lambda x: x):
with tf.name_scope(layer_name):
Expand All @@ -132,3 +132,8 @@ def _initialize_biases(out_units_size):
return tf.Variable(tf.ones([out_units_size]), name='biases')


def _initialize_session():
session = tf.Session()
init = tf.initialize_all_variables()
session.run(init)
return session
63 changes: 63 additions & 0 deletions nn_wtf/neural_network_graph_mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import tensorflow as tf

from nn_wtf.trainer import Trainer

__author__ = 'Lene Preuss <lene.preuss@gmail.com>'

DEFAULT_TRAIN_DIR = '.nn_wtf-data'


class NeuralNetworkGraphMixin:
def __init__(self, session, train_dir=DEFAULT_TRAIN_DIR):
assert isinstance(session, tf.Session), 'session must be set when initializing saver'
self.session = session
self.train_dir = ensure_is_dir(train_dir)


def ensure_is_dir(train_dir_string):
if not train_dir_string[-1] == '/':
train_dir_string += '/'
return train_dir_string


class SaverMixin(NeuralNetworkGraphMixin):

def __init__(self, session, train_dir=DEFAULT_TRAIN_DIR):
super().__init__(session, train_dir)
# Create a saver for writing training checkpoints.
self.saver = tf.train.Saver()

def save(self, **kwargs):
self.saver.save(self.session, save_path=self.train_dir, **kwargs)


class SummaryWriterMixin(NeuralNetworkGraphMixin):
def __init__(self, session, verbose=False, train_dir=DEFAULT_TRAIN_DIR):
super().__init__(session, train_dir)
self.verbose = verbose
self._setup_summaries()

def write_summary(self, feed_dict, loss_value, step):
if self.verbose:
print('Step %d: loss = %.2f ' % (step, loss_value))
# Update the events file.
summary_str = self.session.run(self.summary_op, feed_dict=feed_dict)
self.summary_writer.add_summary(summary_str, step)

def print_evaluations(self, data_sets, batch_size):
assert isinstance(self.trainer, Trainer), 'used SummaryMixin on a class other than NeuralNetworkGraph'
self._print_eval(data_sets.train, batch_size, 'Training Data Eval:')
self._print_eval(data_sets.validation, batch_size, 'Validation Data Eval:')
self._print_eval(data_sets.test, batch_size, 'Test Data Eval:')

def _print_eval(self, data_set, batch_size, message):
if self.verbose:
print(message)
self.trainer.do_eval(data_set, batch_size)
print(' Num examples: %d Num correct: %d Precision @ 1: %0.04f' %
(self.trainer.num_examples, self.trainer.true_count, self.trainer.precision))

def _setup_summaries(self):
# Build the summary operation based on the TF collection of Summaries.
self.summary_op = tf.merge_all_summaries()
self.summary_writer = tf.train.SummaryWriter(self.train_dir, graph_def=self.session.graph_def)
2 changes: 1 addition & 1 deletion nn_wtf/tests/neural_network_graph_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_init_fails_if_last_layer_smaller_than_output_size(self):
def test_build_neural_network_runs_only_once(self):
graph = self._create_minimal_graph()
with self.assertRaises(AssertionError):
graph.build_neural_network()
graph._build_neural_network()

def test_build_neural_network_output(self):
graph = self._create_minimal_graph()
Expand Down

0 comments on commit 492698a

Please sign in to comment.