Cats and Dogs

Beginning

This extends the previous lessons to harder images. We started with monochrome handwritten digits, moved to items of clothing and then artificially generated images of horses and humans. The problem with these images is that they were artificially uniform. In real life, you subject won't be centered and isolated, most pictures are messier, and this exercise will begin with images that were taken by people in real life, and thus aren't quite as orderly as the previous images were.

The dataset we're going to use here is the Dogs vs. Cats set hosted on Kaggle. It is a subset of a larger dataset compiled to test whether computers could pass the Animal Species Image Recognition for Restricting Access (ASIRRA) which was created as an alternative form of CAPTCHA which the creators of the dataset thought would prevent computers from being able to pass the test of selecting only the cats in a set of 12 photographs of cats and dogs.

Imports

Python

from csv import DictWriter
from datetime import datetime, timedelta
from functools import partial
from pathlib import Path
import random

PyPi

from holoviews.operation.datashader import datashade
from tabulate import tabulate
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.preprocessing.image import (ImageDataGenerator,
                                                  img_to_array, 
                                                  load_img)
import holoviews
import hvplot.pandas
import keras
import matplotlib.pyplot as pyplot
import numpy
import pandas
import tensorflow

Graeae

from graeae import SubPathLoader, EmbedHoloviews, Timer

Set Up

Plotting

Embed = partial(EmbedHoloviews, 
                folder_path="../../files/posts/keras/cats-and-dogs/")
holoviews.extension("bokeh")

The Timer

TIMER = Timer()

The Datasets

environment = SubPathLoader("DATASETS")
base_path = Path(environment["DOGS_VS_CATS"]).expanduser()
for item in base_path.iterdir():
    print(item)
WARNING: Logging before flag parsing goes to stderr.
I0727 20:33:31.896675 140643102242624 environment.py:35] Environment Path: /home/athena/.env
I0727 20:33:31.958876 140643102242624 environment.py:90] Environment Path: /home/athena/.config/datasets/env
/home/athena/data/datasets/images/dogs-vs-cats/train
/home/athena/data/datasets/images/dogs-vs-cats/exercise
/home/athena/data/datasets/images/dogs-vs-cats/test1

This is the dataset downloaded from kaggle. Since it's a competition, the test1 directory has the test images without labels (although as noted on the site, you could inspect them all and label them by hand) and the training set has the labeled images. Since the convention for the neural-network libraries is to ignore the file-names and to use instead the folder names I made two sub-directories - one for dogs and one for cats - and moved the images into them.

training_path = base_path/"train"
testing_path = base_path/"test1"
for item in training_path.iterdir():
    print(item)
/home/athena/data/datasets/images/dogs-vs-cats/train/dogs
/home/athena/data/datasets/images/dogs-vs-cats/train/cats

In the example exercise the datasets were further subdivided into training and validation sets, but keras has added validation set splitting to their image generator so it shouldn't be necessary.

The Model Storage

This is just the path to the folder to store models.

MODELS = Path("~/models/dogs-vs-cats").expanduser()

Middle

Helpers

def best_validation(data: pandas.DataFrame) -> tuple:
    """Gets and prints the rows with the best validation performance"""
    best_loss = data[data.validation_loss==data.validation_loss.min()]
    best_accuracy = data[data.validation_accuracy==data.validation_accuracy.max()]
    print(f"Best Accuracy: {best_accuracy.validation_accuracy.iloc[0]:.2f} "
          f"(loss={best_accuracy.validation_loss.iloc[0]:.2f})"
          f" Epoch: {best_accuracy.index[0]}")

    print(f"Best Loss: {best_loss.validation_loss.iloc[0]:.2f} "
          f"(accuracy={best_loss.validation_accuracy.iloc[0]:.2f}, "
          f"Epoch: {best_loss.index[0]})")
    return best_accuracy, best_loss

Looking at the Cats and Dogs

How much data do we have?

cat_images = list((training_path/'cats').iterdir())
dog_images = list((training_path/'dogs').iterdir())
test_images = list(testing_path.iterdir())
print(f"Training Cat Images: {len(cat_images):,}")
print(f"Training Dog Images: {len(dog_images):,}")
print(f"Testing Images: {len(test_images):,}")
Training Cat Images: 12,500
Training Dog Images: 12,500
Testing Images: 12,500

Note that we haven't separated out the validation set yet. If we do an 80-20 split then we will have:

training_count = len(cat_images)
print(f"Training images per species: {int(training_count * .9):,}")
print(f"Validation images per species: {int(training_count * .1):,}")
Training images per species: 11,250
Validation images per species: 1,250

So 20,000 training images in total.

Looking at Some Images

height = width = 250
count = 4
columns = 4

indices = [random.randrange(len(cat_images)) for index in range(count)]
cat_plots = []
dog_plots = []
for index in indices:
    cat_plots.append(holoviews.RGB.load_image(
        str(cat_images[index])).opts(
            height=height,
            width=width))
    dog_plots.append(holoviews.RGB.load_image(
        str(dog_images[index])).opts(
            height=height,
            width=width))

plot = holoviews.Layout(cat_plots + dog_plots).cols(columns).opts(
    title="Dogs vs Cats"
)
Embed(plot=plot, file_name="dogs_and_cats", height_in_pixels=600)()

Figure Missing

So the quality and setting might vary, but they appear to be the mug-shot type photographs that most people tend to take. Some of them have borders, so they aren't uniformly sized images.

The Data Preprocessor

This will load and prepare the image batches for training and validation.

A Data Generator

This bundles up the steps to build the data generator.

class Data:
    """creates the data generators

    Args:
     path: path to the images
     validation_split: fraction that goes to the validation set
     batch_size: size for the batches in the epochs
    """
    def __init__(self, path: str, validation_split: float=0.2,
                 batch_size: int=20) -> None:
        self.path = path
        self.validation_split = validation_split
        self.batch_size = batch_size
        self._data_generator = None
        self._testing_data_generator = None
        self._training_generator = None
        self._validation_generator = None
        return

    @property
    def data_generator(self) -> ImageDataGenerator:
        """The data generator for training and validation"""
        if self._data_generator is None:
            self._data_generator = ImageDataGenerator(
                rescale=1/255,
                rotation_range=40,
                width_shift_range=0.2,
                height_shift_range=0.2,
                horizontal_flip=True,
                shear_range=0.2,
                zoom_range=0.2,
                fill_mode="nearest",
                validation_split=self.validation_split)
        return self._data_generator

    @property
    def training_generator(self):
        """The training data generator"""
        if self._training_generator is None:
            self._training_generator = (self.data_generator
                                        .flow_from_directory)(
                                            self.path,
                                            batch_size=self.batch_size,
                                            class_mode="binary",
                                            target_size=(150, 150),
                                            subset="training",
            )
        return self._training_generator

    @property
    def validation_generator(self):
        """the validation data generator"""
        if self._validation_generator is None:
            self._validation_generator = (self.data_generator
                                          .flow_from_directory)(
                                              self.path,
                                              batch_size=self.batch_size,
                                              class_mode="binary",
                                              target_size = (150, 150),
                                              subset="validation",
            )
        return self._validation_generator

    def __str__(self) -> str:
        return (f"(Data) - Path: {self.path}, "
                f"Validation Split: {self.validation_split},"
                f"Batch Size: {self.batch_size}")

Some Callbacks To Stop Training

The Good Enough Callback

If our model is doing good enough on the validation set then let's stop.

class Stop(tensorflow.keras.callbacks.Callback):
    """Something to stop if we are good enough

    Args:
     minimum_accuracy: validation accuracy needed to quit
     maximum_loss: validation loss needed to quit
     check_after_batch: if True, try to interrupt after each batch, end of epoch otherwise
     call_on_stopping: function or method to call when training is interrupted
    """
    def __init__(self, minimum_accuracy: float=0.94, maximum_loss: float=0.24,
                 check_after_batch: bool=False, call_on_stopping: callable=None) -> None:
        self.minimum_accuracy = minimum_accuracy
        self.maximum_loss = maximum_loss
        self.check_after_batch = check_after_batch
        if check_after_batch:
            self.on_batch_end = self.on_end_handler
        else:
            self.on_epoch_end = self.on_end_handler
        return

    def on_end_handler(self, count, logs={}):
        if ("val_acc" in logs
            and logs.get("val_acc") >= self.minimum_accuracy 
            and logs.get("val_loss") <= self.maximum_loss):
            print(f"Stopping point reached at {count}")
            self.model.stop_training = True
            if self.call_on_stopping is not None:
                self.call_on_stopping(self.model)
        return

    def __str__(self) -> str:
        return (f"(Stop) - Minimum Accuracy: {self.minimum_accuracy}, "
                f"Maximum Loss: {self.maximum_loss}, "
                "By Batch: {self.check_after_batch}, "
                f"Call on Stop: {self.call_on_stopping}")

A CSV Writer

class CSVLog(tensorflow.keras.callbacks.Callback):
    """A callback to store the performance

    Args:
     path: path to the output file
    """
    def __init__(self, path: Path) -> None:
        self.path = path
        self._file_pointer = None
        self._writer = None
        return

    @property
    def file_pointer(self):
        """The write file"""
        if self._file_pointer is None:
            self._file_pointer = self.path.open("w")
        return self._file_pointer

    @property
    def writer(self) -> DictWriter:
        """a file writer"""
        if self._writer is None:
            self._writer = DictWriter(
                self.file_pointer,
                ["loss","acc","val_loss","val_acc"])
            self._writer.writeheader()
        return self._writer

    def on_epoch_end(self, count, logs={}) -> None:
        """method to call at end of each epoch

       writes to the csv file

       Args:
        count: number of epochs run so far
        logs: dict with the epoch values
       """
        if ("val_acc" in logs):
            self.writer.writerow(logs)
        return

A Timed Stop Callback

This timer callback comes from Make best use of a Kernel's limited uptime (Keras) by Digit Recognizer.

class TimedStop(tensorflow.keras.callbacks.Callback):
    """A callback to stop if we run out of time

    Args:
     minutes_allowed: Most time to allow training the model
     by_batch: if True, try to stop after each batch, end of epoch otherwise
     call_on_stopping: function or method to call when training is interrupted
    """
    def __init__(self, minutes_allowed: int=350, check_after_batch: bool=False,
                 call_on_stopping: callable=None) -> None:
        self.elapsed_allowed = timedelta(minutes = minutes_allowed)
        self.call_on_stopping = call_on_stopping
        self.check_after_batch = check_after_batch

        # These are part of the Callback class
        if check_after_batch:
            self.on_batch_end = self.on_end_handler
        else:
            self.on_epoch_end = self.on_end_handler
        return

    def on_train_begin(self, logs: dict):
        """Called by keras at the start of training"""
        self.start_time = datetime.now()
        self.longest_elapsed = timedelta()
        self.previous_end_time = self.start_time
        self.total_elapsed = timedelta()
        return

    def on_end_handler(self, count: int, logs: dict):
        """called when an epoch or batch ends (depending on ```check_after_batch```)

       Args:
        count: the current batch or epoch
        logs: the log for the batch or epoch
       """
        now = datetime.now()
        self.total_elapsed = now - self.start_time
        this_elapsed = now - self.previous_end_time
        self.last_time = now

        if this_elapsed > self.longest_elapsed:
            self.longest_elapsed = this_elapsed

        if (self.elapsed_allowed - self.total_elapsed) < self.longest_elapsed:
            # estimated time remaining will exceed our time-out
            self.model.stop_training = True
            print(f"TimedStop: Training out of time (Elapsed = {self.total_elapsed})")
            print(f"TimedStop: Longest Epoch = {self.longest_elapsed}")
            if self.call_on_stopping is not None:
                self.call_on_stopping(self.model)
        return

    def __str__(self) -> str:
        return (f"(TimedStop) - Minutes Allowed: {self.elapsed_allowed}, "
                f"Check After Each Batch: {self.check_after_batch}, "
                f"Call On Stopping: {self.call_on_stopping}")

Saving the Model

This gets used by the callbacks to save the model.

  • Just the Weights

    This saves it so you can re-use the model but it won't be trainable if you re-load it (so probably not a good idea for what I'm doing, which is just exploring).

    file_name = "model_weights"
    
    def save_model_weights(model, name=file_name):
        """Save the models weights to disk
    
        Args:
         model: model whose weights to save
         name: base name for the file
        """
        out_name = f"{name}.h5"
        print(f"Saving the Model Weights to {out_name}")
        model.save_weights(f"{out_name}")
        return
    

    This stores everything so you can re-train it after loading the model.

    def save_model(model: tensorflow.keras.models.Sequential, path: Path) -> None:
        """Save the model with the training state
    
        This allows you to load it and continue training
    
        Args:
         model: the model to save
         path: where to store the model
        """
        model.save(str(path))
        print(f"Saving the model to {path}")
        return
    

Building the Model

This is going to be a model with three convolutional layers feeding a dense layer with 512 neurons. We're going to resize the image to 150 x 150 x 3 so the first layer has to be set to expect that.

class Network:
    """The model to categorize the images

    Args:
     path: path to the training data
     epochs: number of epochs to train
     batch_size: size of the batches for each epoch
     convolution_layers: layers of cnn/max-pooling
     callbacks: things to stop the training
     set_steps: whether to set the training steps-per-epoch
    """
    def __init__(self, path: str, epochs: int=15,
                 batch_size: int=128, convolution_layers: int=3,
                 set_steps: bool=True,
                 callbacks: list=None) -> None:
        self.path = path
        self.epochs = epochs
        self.batch_size = batch_size
        self.convolution_layers = convolution_layers
        self.set_steps = set_steps
        self.callbacks = callbacks
        self._data = None
        self._model = None
        self.history = None
        return

    @property
    def data(self) -> Data:
        """The data generator builder"""
        if self._data is None:
            self._data = Data(self.path, batch_size=self.batch_size)
        return self._data

    @property
    def model(self) -> tensorflow.keras.models.Sequential:
        """The neural network"""
        if self._model is None:
            self._model = tensorflow.keras.models.Sequential([
                tensorflow.keras.layers.Conv2D(
                    32, (3,3), activation='relu', 
                    input_shape=(150, 150, 3)),
                tensorflow.keras.layers.MaxPooling2D(2,2)])
            self._model.add(
                tensorflow.keras.layers.Conv2D(
                    64, (3,3), activation='relu'))
            self._model.add(
                tensorflow.keras.layers.MaxPooling2D(2,2))

            for layer in range(self.convolution_layers - 2):
                self._model.add(tensorflow.keras.layers.Conv2D(
                    128, (3,3), activation='relu'))
                self._model.add(tensorflow.keras.layers.MaxPooling2D(2,2))
            for layer in [
                    tensorflow.keras.layers.Flatten(), 
                    tensorflow.keras.layers.Dense(512, activation='relu'), 
                    tensorflow.keras.layers.Dense(1, activation='sigmoid')]:
                self._model.add(layer)

            self._model.compile(optimizer=RMSprop(lr=0.001),
                               loss='binary_crossentropy',
                               metrics = ['acc'])
        return self._model

    def summary(self) -> None:
        """Prints the model summary"""
        print(self.model.summary())
        return

    def train(self) -> None:
        """Trains the model"""
        callbacks = self.callbacks if self.callbacks else []
        arguments = dict(
            generator=self.data.training_generator,
            validation_data=self.data.validation_generator,
            epochs = self.epochs,
            callbacks = callbacks,
            verbose=2,
        )
        if self.set_steps:
            arguments["steps_per_epoch"] = int(
                self.data.training_generator.samples/self.batch_size)
            arguments["validation_steps"] = int(
                self.data.validation_generator.samples/self.batch_size)

        self.history = self.model.fit_generator(**arguments)
        return

    def __str__(self) -> str:
        return (f"(Network) - \nPath: {self.path}\n Epochs: {self.epochs}\n "
                f"Batch Size: {self.batch_size}\n Callbacks: {self.callbacks}\n"
                f"Data: {self.data}\n"
                f"Callbacks: {self.callbacks}")

Warning: I'm adapting the class definitions after running the fitting so don't run these again or the output will change.

network = Network(str(training_path))
network.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_3 (Conv2D)            (None, 148, 148, 16)      448       
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 74, 74, 16)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 72, 72, 32)        4640      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 36, 36, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 34, 34, 64)        18496     
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 17, 17, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 18496)             0         
_________________________________________________________________
dense_2 (Dense)              (None, 512)               9470464   
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 513       
=================================================================
Total params: 9,494,561
Trainable params: 9,494,561
Non-trainable params: 0
_________________________________________________________________
None

Training the Model

network.train()
Found 20000 images belonging to 2 classes.
Found 25000 images belonging to 2 classes.
Epoch 1/15
20000/20000 - 3149s - loss: 0.2677 - acc: 0.8957 - val_loss: 0.2148 - val_acc: 0.9392
Epoch 2/15
20000/20000 - 3136s - loss: 0.2614 - acc: 0.9259 - val_loss: 0.2645 - val_acc: 0.9149
Epoch 3/15
20000/20000 - 3122s - loss: 0.2803 - acc: 0.9262 - val_loss: 0.2668 - val_acc: 0.9334
Epoch 4/15
20000/20000 - 3136s - loss: 0.2785 - acc: 0.9325 - val_loss: 0.3490 - val_acc: 0.9104
Epoch 5/15
20000/20000 - 3211s - loss: 0.2813 - acc: 0.9344 - val_loss: 0.2397 - val_acc: 0.9447
Epoch 6/15
20000/20000 - 3107s - loss: 0.3108 - acc: 0.9273 - val_loss: 0.3096 - val_acc: 0.9277
Epoch 7/15
20000/20000 - 3116s - loss: 0.3351 - acc: 0.9241 - val_loss: 0.2756 - val_acc: 0.9365
Epoch 8/15
20000/20000 - 3112s - loss: 0.3723 - acc: 0.9201 - val_loss: 0.5705 - val_acc: 0.9031
Epoch 9/15
20000/20000 - 3175s - loss: 0.3909 - acc: 0.9169 - val_loss: 0.3232 - val_acc: 0.8964
Epoch 10/15
20000/20000 - 3176s - loss: 0.3838 - acc: 0.9179 - val_loss: 0.4460 - val_acc: 0.8797
Epoch 11/15
20000/20000 - 3180s - loss: 0.4013 - acc: 0.9117 - val_loss: 1.5652 - val_acc: 0.8393
Epoch 12/15
20000/20000 - 3176s - loss: 0.3854 - acc: 0.9070 - val_loss: 0.2922 - val_acc: 0.9028
Epoch 13/15
20000/20000 - 3174s - loss: 0.3736 - acc: 0.9087 - val_loss: 0.3601 - val_acc: 0.8856
Epoch 14/15
20000/20000 - 3184s - loss: 0.4744 - acc: 0.9065 - val_loss: 0.5963 - val_acc: 0.7796
Epoch 15/15
20000/20000 - 3149s - loss: 0.4771 - acc: 0.8997 - val_loss: 0.3037 - val_acc: 0.8814

It looks like the model is starting to overfit, maybe we need a callback.

Take Two

I noticed that I accidentally used a batch-size of 20, which will make it converge more quickly per epoch, but make the epochs take longer, so besides adding the callback I'm going to change the batch-size.

callback = Stop()
network = Network(str(training_path), callbacks=[callback])
network.data.batch_size = 512
network.data._training_generator = None
network.data._validation_generator = None
TIMER.message = "Finished training the cats and dogs network"
with TIMER:
    network.train()
2019-07-11 04:39:19,803 graeae.timers.timer start: Started: 2019-07-11 04:39:19.803252
I0711 04:39:19.803283 140573992724288 timer.py:70] Started: 2019-07-11 04:39:19.803252
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
20000/20000 - 1765s - loss: 0.3099 - acc: 0.8796 - val_loss: 0.9553 - val_acc: 0.6900
Epoch 2/15
20000/20000 - 1764s - loss: 0.3434 - acc: 0.8976 - val_loss: 0.7495 - val_acc: 0.7854
Epoch 3/15
20000/20000 - 1765s - loss: 0.3718 - acc: 0.8923 - val_loss: 1.2745 - val_acc: 0.8064
Epoch 4/15
20000/20000 - 1774s - loss: 0.3892 - acc: 0.8904 - val_loss: 0.4991 - val_acc: 0.7906
Epoch 5/15
20000/20000 - 1775s - loss: 0.4290 - acc: 0.8786 - val_loss: 0.5698 - val_acc: 0.8338
Epoch 6/15
20000/20000 - 1774s - loss: 0.4889 - acc: 0.8847 - val_loss: 0.5719 - val_acc: 0.8078
Epoch 7/15
20000/20000 - 1774s - loss: 0.3992 - acc: 0.8883 - val_loss: 0.4647 - val_acc: 0.8258
Epoch 8/15
20000/20000 - 1774s - loss: 0.4458 - acc: 0.8853 - val_loss: 0.6354 - val_acc: 0.8098
Epoch 9/15
20000/20000 - 1774s - loss: 0.3810 - acc: 0.8856 - val_loss: 0.5611 - val_acc: 0.8198
Epoch 10/15
20000/20000 - 1773s - loss: 0.3894 - acc: 0.8886 - val_loss: 0.4861 - val_acc: 0.8476
Epoch 11/15
20000/20000 - 1771s - loss: 0.4517 - acc: 0.8972 - val_loss: 0.4623 - val_acc: 0.8420
Epoch 12/15
20000/20000 - 1755s - loss: 0.3626 - acc: 0.9030 - val_loss: 0.5481 - val_acc: 0.8310
Epoch 13/15
20000/20000 - 1753s - loss: 0.3574 - acc: 0.9054 - val_loss: 0.5138 - val_acc: 0.8430
Epoch 14/15
20000/20000 - 1753s - loss: 0.3658 - acc: 0.9132 - val_loss: 1.0924 - val_acc: 0.8164
Epoch 15/15
20000/20000 - 1753s - loss: 0.3331 - acc: 0.9145 - val_loss: 0.5148 - val_acc: 0.8312
2019-07-11 12:00:57,205 graeae.timers.timer end: Ended: 2019-07-11 12:00:57.205007
I0711 12:00:57.205034 140573992724288 timer.py:77] Ended: 2019-07-11 12:00:57.205007
2019-07-11 12:00:57,205 graeae.timers.timer end: Elapsed: 7:21:37.401755
I0711 12:00:57.205761 140573992724288 timer.py:78] Elapsed: 7:21:37.401755

So the loss and accuracy never matched what happened when we used the tiny batch size. On the other hand it took less than half the time. Maybe something in between.

Take Three

  • Train Again

    I'm going to use the default of 350 minutes that my TimedStop class has based on the time-limit that Kaggle kernels have. If it can meet the accuracy we want before this then it is trainable in one session using a kernel (I think, I haven't actually tried it yet).

    path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_128").expanduser()
    saver = partial(save_model_weights, name=str(path))
    good_enough = Stop(on_interrupt=saver)
    out_of_time = TimedStop(on_interrupt=saver)
    
    network = Network(str(training_path), 
                      callbacks=[good_enough, out_of_time],
                      batch_size=128)
    with TIMER:
        network.train()
    
    2019-07-13 12:06:40,651 graeae.timers.timer start: Started: 2019-07-13 12:06:40.651269
    I0713 12:06:40.651483 140400353847104 timer.py:70] Started: 2019-07-13 12:06:40.651269
    Found 20000 images belonging to 2 classes.
    Found 5000 images belonging to 2 classes.
    Epoch 1/15
    TimedStop: Training out of time (Elapsed = 3:19:17.730138)
    20000/20000 - 11911s - loss: 0.0634 - acc: 0.9821 - val_loss: 4.4497 - val_acc: 0.8038
    2019-07-13 15:25:59,863 graeae.timers.timer end: Ended: 2019-07-13 15:25:59.863265
    I0713 15:25:59.863302 140400353847104 timer.py:77] Ended: 2019-07-13 15:25:59.863265
    2019-07-13 15:25:59,864 graeae.timers.timer end: Elapsed: 3:19:19.211996
    I0713 15:25:59.864300 140400353847104 timer.py:78] Elapsed: 3:19:19.211996
    

    So, we have several problems here:

    • It quit after just over 3 hours, not just under 6
    • It only did one epoch
    • It didn't come close to reaching the accuracy I wanted

    The early timeout is probably because since it took over 3 hours it probably wouldn't have finished another epoch in the allotted time. Let's double-check my times.

    print(f"Batch 20 First Epoch: {3136/3600:0.2f} Hours")
    print(f"Batch 512 First Epoch: {1765/3600: 0.2f} Hours")
    print(f"Batch 128 First Epoch: {11911/3600: 0.2f} Hours")
    
    Batch 20 First Epoch: 0.87 Hours
    Batch 512 First Epoch:  0.49 Hours
    Batch 128 First Epoch:  3.31 Hours
    

    So something went really wrong with this last run (and either my timer is wrong or the epoch times is wrong). What is it?

Take Four

Try one that times out early.

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_256").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(on_interrupt=saver)
out_of_time = TimedStop(1, on_interrupt=saver, by_batch=True)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  batch_size=256)
print(str(network))
with TIMER:
    network.train()
2019-07-13 16:56:05,428 graeae.timers.timer start: Started: 2019-07-13 16:56:05.428254
I0713 16:56:05.428468 140249436239680 timer.py:70] Started: 2019-07-13 16:56:05.428254
W0713 16:56:05.429713 140249436239680 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
W0713 16:56:05.520384 140249436239680 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 256, Callbacks: [<__main__.Stop object at 0x7f8dcc0b8550>, <__main__.TimedStop object at 0x7f8dcc0b8048>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 256
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
2019-07-13 16:56:36,641 graeae.timers.timer end: Ended: 2019-07-13 16:56:36.641438
I0713 16:56:36.641472 140249436239680 timer.py:77] Ended: 2019-07-13 16:56:36.641438
2019-07-13 16:56:36,643 graeae.timers.timer end: Elapsed: 0:00:31.213184
I0713 16:56:36.643917 140249436239680 timer.py:78] Elapsed: 0:00:31.213184
TimedStop: Training out of time (Elapsed = 0:00:30.441487)
Saving the Model Weights to /home/athena/models/dogs-vs-cats/cnn_weights_batch_size_256.h5

Take Five

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_256").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(on_interrupt=saver)
out_of_time = TimedStop(on_interrupt=saver, by_batch=True)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  batch_size=256)
print(str(network))
with TIMER:
    network.train()
2019-07-13 16:59:47,492 graeae.timers.timer start: Started: 2019-07-13 16:59:47.491986
I0713 16:59:47.492009 140249436239680 timer.py:70] Started: 2019-07-13 16:59:47.491986
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 256, Callbacks: [<__main__.Stop object at 0x7f8db84fa940>, <__main__.TimedStop object at 0x7f8db84fa908>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 256
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
2019-07-13 19:54:49,091 graeae.timers.timer end: Ended: 2019-07-13 19:54:49.091389
I0713 19:54:49.091431 140249436239680 timer.py:77] Ended: 2019-07-13 19:54:49.091389
2019-07-13 19:54:49,093 graeae.timers.timer end: Elapsed: 2:55:01.599403
I0713 19:54:49.093391 140249436239680 timer.py:78] Elapsed: 2:55:01.599403
TimedStop: Training out of time (Elapsed = 2:55:00.848875)
Saving the Model Weights to /home/athena/models/dogs-vs-cats/cnn_weights_batch_size_256.h5

Take Six

According to what I read, the smaller batch size is supposed to be faster and the larger batch-size slower, but that isn't what I saw with the 512 batch-size. Although I don't seem to see any pattern, really. Try this again.

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_32").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver, check_after_batch=True)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  batch_size=32)
print(str(network))
with TIMER:
    network.train()
2019-07-14 12:32:06,967 graeae.timers.timer start: Started: 2019-07-14 12:32:06.966983
I0714 12:32:06.967006 140261637994304 timer.py:70] Started: 2019-07-14 12:32:06.966983
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 32, Callbacks: [<__main__.Stop object at 0x7f902c28e860>, <__main__.TimedStop object at 0x7f902c28e278>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 32,Callbacks: [<__main__.Stop object at 0x7f902c28e860>, <__main__.TimedStop object at 0x7f902c28e278>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
625/625 - 87s - loss: 0.6216 - acc: 0.6469 - val_loss: 0.5601 - val_acc: 0.6947
Epoch 2/15
625/625 - 85s - loss: 0.5002 - acc: 0.7568 - val_loss: 0.4532 - val_acc: 0.7833
Epoch 3/15
625/625 - 85s - loss: 0.4236 - acc: 0.8059 - val_loss: 0.3850 - val_acc: 0.8269
Epoch 4/15
625/625 - 85s - loss: 0.3618 - acc: 0.8400 - val_loss: 0.3532 - val_acc: 0.8397
Epoch 5/15
625/625 - 85s - loss: 0.3117 - acc: 0.8667 - val_loss: 0.4227 - val_acc: 0.8177
Epoch 6/15
625/625 - 85s - loss: 0.2683 - acc: 0.8845 - val_loss: 0.3806 - val_acc: 0.8438
Epoch 7/15
625/625 - 85s - loss: 0.2356 - acc: 0.9021 - val_loss: 0.3288 - val_acc: 0.8682
Epoch 8/15
625/625 - 85s - loss: 0.2065 - acc: 0.9143 - val_loss: 0.3912 - val_acc: 0.8678
Epoch 9/15
625/625 - 85s - loss: 0.1854 - acc: 0.9255 - val_loss: 0.3263 - val_acc: 0.8812
Epoch 10/15
625/625 - 85s - loss: 0.1629 - acc: 0.9359 - val_loss: 0.3515 - val_acc: 0.8768
Epoch 11/15
625/625 - 85s - loss: 0.1475 - acc: 0.9408 - val_loss: 0.4157 - val_acc: 0.8808
Epoch 12/15
625/625 - 85s - loss: 0.1342 - acc: 0.9486 - val_loss: 0.3752 - val_acc: 0.8740
Epoch 13/15
625/625 - 85s - loss: 0.1276 - acc: 0.9536 - val_loss: 0.4363 - val_acc: 0.8744
Epoch 14/15
625/625 - 85s - loss: 0.1233 - acc: 0.9542 - val_loss: 0.3375 - val_acc: 0.8714
Epoch 15/15
625/625 - 85s - loss: 0.1149 - acc: 0.9568 - val_loss: 0.3805 - val_acc: 0.8788
2019-07-14 12:53:20,998 graeae.timers.timer end: Ended: 2019-07-14 12:53:20.998164
I0714 12:53:20.998192 140261637994304 timer.py:77] Ended: 2019-07-14 12:53:20.998164
2019-07-14 12:53:20,999 graeae.timers.timer end: Elapsed: 0:21:14.031181
I0714 12:53:20.999267 140261637994304 timer.py:78] Elapsed: 0:21:14.031181

So I think I fixed the time problem, lets try upping the batch size.

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_128").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver, check_after_batch=True)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  batch_size=128)
print(str(network))
with TIMER:
    network.train()
2019-07-14 13:29:11,456 graeae.timers.timer start: Started: 2019-07-14 13:29:11.456042
I0714 13:29:11.456063 140261637994304 timer.py:70] Started: 2019-07-14 13:29:11.456042
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 128, Callbacks: [<__main__.Stop object at 0x7f8fd911c9b0>, <__main__.TimedStop object at 0x7f902c09da20>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 128,Callbacks: [<__main__.Stop object at 0x7f8fd911c9b0>, <__main__.TimedStop object at 0x7f902c09da20>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
156/156 - 89s - loss: 0.6749 - acc: 0.5787 - val_loss: 0.6582 - val_acc: 0.6058
Epoch 2/15
156/156 - 89s - loss: 0.6266 - acc: 0.6545 - val_loss: 0.5754 - val_acc: 0.6967
Epoch 3/15
156/156 - 89s - loss: 0.5507 - acc: 0.7226 - val_loss: 0.5372 - val_acc: 0.7278
Epoch 4/15
156/156 - 89s - loss: 0.4921 - acc: 0.7646 - val_loss: 0.4557 - val_acc: 0.7889
Epoch 5/15
156/156 - 88s - loss: 0.4421 - acc: 0.7952 - val_loss: 0.5066 - val_acc: 0.7622
Epoch 6/15
156/156 - 87s - loss: 0.3993 - acc: 0.8194 - val_loss: 0.5141 - val_acc: 0.7684
Epoch 7/15
156/156 - 87s - loss: 0.3602 - acc: 0.8401 - val_loss: 0.4552 - val_acc: 0.7887
Epoch 8/15
156/156 - 87s - loss: 0.3194 - acc: 0.8634 - val_loss: 0.3735 - val_acc: 0.8401
Epoch 9/15
156/156 - 86s - loss: 0.2790 - acc: 0.8792 - val_loss: 0.3472 - val_acc: 0.8472
Epoch 10/15
156/156 - 86s - loss: 0.2460 - acc: 0.8964 - val_loss: 0.3934 - val_acc: 0.8281
Epoch 11/15
156/156 - 85s - loss: 0.2144 - acc: 0.9108 - val_loss: 0.3637 - val_acc: 0.8558
Epoch 12/15
156/156 - 85s - loss: 0.1857 - acc: 0.9249 - val_loss: 0.3656 - val_acc: 0.8516
Epoch 13/15
156/156 - 85s - loss: 0.1590 - acc: 0.9364 - val_loss: 0.3921 - val_acc: 0.8616
Epoch 14/15
156/156 - 84s - loss: 0.1400 - acc: 0.9449 - val_loss: 0.4903 - val_acc: 0.8297
Epoch 15/15
156/156 - 84s - loss: 0.1142 - acc: 0.9553 - val_loss: 0.4341 - val_acc: 0.8580
2019-07-14 13:50:52,575 graeae.timers.timer end: Ended: 2019-07-14 13:50:52.575319
I0714 13:50:52.575360 140261637994304 timer.py:77] Ended: 2019-07-14 13:50:52.575319
2019-07-14 13:50:52,576 graeae.timers.timer end: Elapsed: 0:21:41.119277
I0714 13:50:52.576494 140261637994304 timer.py:78] Elapsed: 0:21:41.119277

So it is now way faster but it doesn't reach the accuracy and validation we want. That's an incredible speedup, though. I guess I really wasn't using it correctly (you need to divide the number of sample by the batch size when setting the steps_per_epoch in the model.fit_generator call).

In the model.fit_generator:

steps_per_epoch=int(self.data.training_generator.samples/self.batch_size),
validation_steps=int(self.data.validation_generator.samples/self.batch_size),

Take Seven

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_256").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=95)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  batch_size=256)
print(str(network))
with TIMER:
    network.train()
2019-07-14 14:51:25,349 graeae.timers.timer start: Started: 2019-07-14 14:51:25.349514
I0714 14:51:25.349538 140261637994304 timer.py:70] Started: 2019-07-14 14:51:25.349514
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 256, Callbacks: [<__main__.Stop object at 0x7f90993397f0>, <__main__.TimedStop object at 0x7f9099339e80>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 256,Callbacks: [<__main__.Stop object at 0x7f90993397f0>, <__main__.TimedStop object at 0x7f9099339e80>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
78/78 - 89s - loss: 0.6720 - acc: 0.5733 - val_loss: 0.6325 - val_acc: 0.6295
Epoch 2/15
78/78 - 88s - loss: 0.6036 - acc: 0.6672 - val_loss: 0.6576 - val_acc: 0.6081
Epoch 3/15
78/78 - 87s - loss: 0.5626 - acc: 0.7084 - val_loss: 0.5236 - val_acc: 0.7358
Epoch 4/15
78/78 - 87s - loss: 0.5266 - acc: 0.7351 - val_loss: 0.4959 - val_acc: 0.7584
Epoch 5/15
78/78 - 85s - loss: 0.4957 - acc: 0.7556 - val_loss: 0.4607 - val_acc: 0.7767
Epoch 6/15
78/78 - 84s - loss: 0.4644 - acc: 0.7808 - val_loss: 0.4637 - val_acc: 0.7800
Epoch 7/15
78/78 - 85s - loss: 0.4296 - acc: 0.7976 - val_loss: 0.4066 - val_acc: 0.8100
Epoch 8/15
78/78 - 85s - loss: 0.3963 - acc: 0.8205 - val_loss: 0.4073 - val_acc: 0.8201
Epoch 9/15
78/78 - 83s - loss: 0.3736 - acc: 0.8294 - val_loss: 0.3809 - val_acc: 0.8248
Epoch 10/15
78/78 - 83s - loss: 0.3452 - acc: 0.8414 - val_loss: 0.4528 - val_acc: 0.7800
Epoch 11/15
78/78 - 81s - loss: 0.3128 - acc: 0.8624 - val_loss: 0.3582 - val_acc: 0.8452
Epoch 12/15
78/78 - 81s - loss: 0.2872 - acc: 0.8753 - val_loss: 0.4267 - val_acc: 0.8059
Epoch 13/15
78/78 - 80s - loss: 0.2662 - acc: 0.8864 - val_loss: 0.3332 - val_acc: 0.8557
Epoch 14/15
78/78 - 80s - loss: 0.2301 - acc: 0.9052 - val_loss: 0.3384 - val_acc: 0.8600
Epoch 15/15
78/78 - 79s - loss: 0.2084 - acc: 0.9122 - val_loss: 0.3857 - val_acc: 0.8298
2019-07-14 15:12:21,858 graeae.timers.timer end: Ended: 2019-07-14 15:12:21.857979
I0714 15:12:21.858018 140261637994304 timer.py:77] Ended: 2019-07-14 15:12:21.857979
2019-07-14 15:12:21,859 graeae.timers.timer end: Elapsed: 0:20:56.508465
I0714 15:12:21.859612 140261637994304 timer.py:78] Elapsed: 0:20:56.508465

So doubling the batch size doesn't change the time or the accuracy?

Take Eight

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_512").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=95)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  batch_size=512)
print(str(network))
with TIMER:
    network.train()
2019-07-14 15:21:24,657 graeae.timers.timer start: Started: 2019-07-14 15:21:24.657613
I0714 15:21:24.657636 140261637994304 timer.py:70] Started: 2019-07-14 15:21:24.657613
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 512, Callbacks: [<__main__.Stop object at 0x7f8fd8224128>, <__main__.TimedStop object at 0x7f90990c6e80>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 512,Callbacks: [<__main__.Stop object at 0x7f8fd8224128>, <__main__.TimedStop object at 0x7f90990c6e80>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
39/39 - 88s - loss: 0.6929 - acc: 0.5590 - val_loss: 0.6546 - val_acc: 0.6135
Epoch 2/15
39/39 - 86s - loss: 0.6552 - acc: 0.6109 - val_loss: 0.6258 - val_acc: 0.6523
Epoch 3/15
39/39 - 83s - loss: 0.6128 - acc: 0.6612 - val_loss: 0.5904 - val_acc: 0.6918
Epoch 4/15
39/39 - 83s - loss: 0.5830 - acc: 0.6929 - val_loss: 0.5612 - val_acc: 0.7198
Epoch 5/15
39/39 - 80s - loss: 0.5767 - acc: 0.6999 - val_loss: 0.5494 - val_acc: 0.7177
Epoch 6/15
39/39 - 80s - loss: 0.5416 - acc: 0.7262 - val_loss: 0.5036 - val_acc: 0.7591
Epoch 7/15
39/39 - 77s - loss: 0.5199 - acc: 0.7424 - val_loss: 0.4987 - val_acc: 0.7602
Epoch 8/15
39/39 - 76s - loss: 0.5040 - acc: 0.7501 - val_loss: 0.5018 - val_acc: 0.7565
Epoch 9/15
39/39 - 74s - loss: 0.4735 - acc: 0.7743 - val_loss: 0.5063 - val_acc: 0.7517
Epoch 10/15
39/39 - 74s - loss: 0.4635 - acc: 0.7778 - val_loss: 0.4747 - val_acc: 0.7682
Epoch 11/15
39/39 - 72s - loss: 0.4403 - acc: 0.7953 - val_loss: 0.4519 - val_acc: 0.7923
Epoch 12/15
39/39 - 72s - loss: 0.4175 - acc: 0.8014 - val_loss: 0.5312 - val_acc: 0.7385
Epoch 13/15
39/39 - 71s - loss: 0.4099 - acc: 0.8135 - val_loss: 0.4505 - val_acc: 0.7899
Epoch 14/15
39/39 - 71s - loss: 0.3855 - acc: 0.8246 - val_loss: 0.4089 - val_acc: 0.8121
Epoch 15/15
39/39 - 73s - loss: 0.3622 - acc: 0.8373 - val_loss: 0.4049 - val_acc: 0.8166
2019-07-14 15:40:46,189 graeae.timers.timer end: Ended: 2019-07-14 15:40:46.189544
I0714 15:40:46.189586 140261637994304 timer.py:77] Ended: 2019-07-14 15:40:46.189544
2019-07-14 15:40:46,191 graeae.timers.timer end: Elapsed: 0:19:21.531931
I0714 15:40:46.191108 140261637994304 timer.py:78] Elapsed: 0:19:21.531931

So now it looks like after a while the batch-size doesn't make a difference, and we don't get anywhere near the performance I got on that first run.

Take Nine

What if we cut down the number of convolutional layers?

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_256_3").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=95)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=3,
                  batch_size=256)
print(str(network))
with TIMER:
    network.train()
2019-07-14 15:48:37,805 graeae.timers.timer start: Started: 2019-07-14 15:48:37.805388
I0714 15:48:37.805425 140261637994304 timer.py:70] Started: 2019-07-14 15:48:37.805388
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 256, Callbacks: [<__main__.Stop object at 0x7f8fb40cc668>, <__main__.TimedStop object at 0x7f8fb40ccb38>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 256,Callbacks: [<__main__.Stop object at 0x7f8fb40cc668>, <__main__.TimedStop object at 0x7f8fb40ccb38>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
78/78 - 90s - loss: 0.7905 - acc: 0.5876 - val_loss: 0.6102 - val_acc: 0.6686
Epoch 2/15
78/78 - 88s - loss: 0.6018 - acc: 0.6747 - val_loss: 0.4995 - val_acc: 0.7588
Epoch 3/15
78/78 - 88s - loss: 0.5166 - acc: 0.7430 - val_loss: 0.4653 - val_acc: 0.7815
Epoch 4/15
78/78 - 87s - loss: 0.4609 - acc: 0.7849 - val_loss: 0.4388 - val_acc: 0.7975
Epoch 5/15
78/78 - 86s - loss: 0.4251 - acc: 0.8010 - val_loss: 0.4319 - val_acc: 0.7973
Epoch 6/15
78/78 - 86s - loss: 0.3864 - acc: 0.8254 - val_loss: 0.4892 - val_acc: 0.7574
Epoch 7/15
78/78 - 85s - loss: 0.3516 - acc: 0.8420 - val_loss: 0.4605 - val_acc: 0.7958
Epoch 8/15
78/78 - 84s - loss: 0.3164 - acc: 0.8619 - val_loss: 0.4136 - val_acc: 0.8178
Epoch 9/15
78/78 - 84s - loss: 0.2688 - acc: 0.8877 - val_loss: 0.5011 - val_acc: 0.7611
Epoch 10/15
78/78 - 83s - loss: 0.2265 - acc: 0.9060 - val_loss: 0.5449 - val_acc: 0.7876
Epoch 11/15
78/78 - 82s - loss: 0.2066 - acc: 0.9149 - val_loss: 0.5982 - val_acc: 0.7741
Epoch 12/15
78/78 - 82s - loss: 0.1662 - acc: 0.9397 - val_loss: 0.5129 - val_acc: 0.8244
Epoch 13/15
78/78 - 81s - loss: 0.1327 - acc: 0.9505 - val_loss: 0.6415 - val_acc: 0.8014
Epoch 14/15
78/78 - 82s - loss: 0.1043 - acc: 0.9643 - val_loss: 0.6042 - val_acc: 0.8168
Epoch 15/15
78/78 - 80s - loss: 0.0813 - acc: 0.9746 - val_loss: 0.6658 - val_acc: 0.8201
2019-07-14 16:09:47,278 graeae.timers.timer end: Ended: 2019-07-14 16:09:47.278102
I0714 16:09:47.278141 140261637994304 timer.py:77] Ended: 2019-07-14 16:09:47.278102
2019-07-14 16:09:47,279 graeae.timers.timer end: Elapsed: 0:21:09.472714
I0714 16:09:47.279699 140261637994304 timer.py:78] Elapsed: 0:21:09.472714

Nope, it's almost as if I didn't do anything to change it.

Take Ten

What if I get rid of the steps per epoch?

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_20_3").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=95)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=3,
                  set_steps = True,
                  batch_size=20)
print(str(network))
with TIMER:
    network.train()
2019-07-14 19:08:19,353 graeae.timers.timer start: Started: 2019-07-14 19:08:19.353471
I0714 19:08:19.353494 140261637994304 timer.py:70] Started: 2019-07-14 19:08:19.353471
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 15, Batch Size: 20, Callbacks: [<__main__.Stop object at 0x7f8dfa4dd048>, <__main__.TimedStop object at 0x7f8dfa4dd470>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 20,Callbacks: [<__main__.Stop object at 0x7f8dfa4dd048>, <__main__.TimedStop object at 0x7f8dfa4dd470>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/15
1000/1000 - 155s - loss: 0.6403 - acc: 0.6418 - val_loss: 0.5868 - val_acc: 0.6744
Epoch 2/15
1000/1000 - 153s - loss: 0.5746 - acc: 0.7024 - val_loss: 0.5579 - val_acc: 0.7180
Epoch 3/15
1000/1000 - 152s - loss: 0.5397 - acc: 0.7315 - val_loss: 0.5599 - val_acc: 0.7248
Epoch 4/15
1000/1000 - 152s - loss: 0.5237 - acc: 0.7452 - val_loss: 0.4945 - val_acc: 0.7576
Epoch 5/15
1000/1000 - 152s - loss: 0.5110 - acc: 0.7520 - val_loss: 0.4821 - val_acc: 0.7710
Epoch 6/15
1000/1000 - 152s - loss: 0.5012 - acc: 0.7627 - val_loss: 0.7423 - val_acc: 0.7008
Epoch 7/15
1000/1000 - 152s - loss: 0.4913 - acc: 0.7668 - val_loss: 0.4916 - val_acc: 0.7732
Epoch 8/15
1000/1000 - 152s - loss: 0.4834 - acc: 0.7726 - val_loss: 0.5013 - val_acc: 0.7634
Epoch 9/15
1000/1000 - 152s - loss: 0.4765 - acc: 0.7810 - val_loss: 0.4503 - val_acc: 0.7930
Epoch 10/15
1000/1000 - 152s - loss: 0.4712 - acc: 0.7858 - val_loss: 0.4780 - val_acc: 0.7872
Epoch 11/15
1000/1000 - 152s - loss: 0.4663 - acc: 0.7882 - val_loss: 0.4645 - val_acc: 0.7810
Epoch 12/15
1000/1000 - 152s - loss: 0.4590 - acc: 0.7926 - val_loss: 0.4233 - val_acc: 0.8208
Epoch 13/15
1000/1000 - 152s - loss: 0.4566 - acc: 0.7958 - val_loss: 0.4494 - val_acc: 0.8020
Epoch 14/15
1000/1000 - 154s - loss: 0.4499 - acc: 0.7985 - val_loss: 0.4125 - val_acc: 0.8248
Epoch 15/15
1000/1000 - 157s - loss: 0.4453 - acc: 0.8014 - val_loss: 0.4875 - val_acc: 0.7510
2019-07-14 19:46:32,393 graeae.timers.timer end: Ended: 2019-07-14 19:46:32.393181
I0714 19:46:32.393228 140261637994304 timer.py:77] Ended: 2019-07-14 19:46:32.393181
2019-07-14 19:46:32,394 graeae.timers.timer end: Elapsed: 0:38:13.039710
I0714 19:46:32.394544 140261637994304 timer.py:78] Elapsed: 0:38:13.039710

Take Eleven

I updated the model to have twice as many neurons at each layes than it did before and added fill_mode="nearest" to the image generator. Let's see how it does.

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_32_5_double").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=.95)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  set_steps = True,
                  epochs = 100,
                  batch_size=32)
print(str(network))
with TIMER:
    network.train()
2019-07-15 22:39:43,846 graeae.timers.timer start: Started: 2019-07-15 22:39:43.846462
I0715 22:39:43.846729 140093074827072 timer.py:70] Started: 2019-07-15 22:39:43.846462
(Network) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Epochs: 100, Batch Size: 32, Callbacks: [<__main__.Stop object at 0x7f6964315f98>, <__main__.TimedStop object at 0x7f6964315f60>],Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 32,Callbacks: [<__main__.Stop object at 0x7f6964315f98>, <__main__.TimedStop object at 0x7f6964315f60>]
Found 20000 images belonging to 2 classes.
W0715 22:39:44.526424 140093074827072 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
Found 5000 images belonging to 2 classes.
W0715 22:39:44.941590 140093074827072 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
Epoch 1/100
625/625 - 443s - loss: 0.6784 - acc: 0.5767 - val_loss: 0.6511 - val_acc: 0.6290
Epoch 2/100
625/625 - 153s - loss: 0.6261 - acc: 0.6617 - val_loss: 0.6095 - val_acc: 0.6833
Epoch 3/100
625/625 - 151s - loss: 0.5860 - acc: 0.6988 - val_loss: 0.5633 - val_acc: 0.7256
Epoch 4/100
625/625 - 151s - loss: 0.5576 - acc: 0.7165 - val_loss: 0.5596 - val_acc: 0.7079
Epoch 5/100
625/625 - 152s - loss: 0.5230 - acc: 0.7480 - val_loss: 0.4567 - val_acc: 0.7843
Epoch 6/100
625/625 - 151s - loss: 0.4899 - acc: 0.7704 - val_loss: 0.4682 - val_acc: 0.7778
Epoch 7/100
625/625 - 155s - loss: 0.4654 - acc: 0.7873 - val_loss: 0.4377 - val_acc: 0.8097
Epoch 8/100
625/625 - 152s - loss: 0.4426 - acc: 0.8019 - val_loss: 0.4038 - val_acc: 0.8249
Epoch 9/100
625/625 - 153s - loss: 0.4338 - acc: 0.8034 - val_loss: 0.3988 - val_acc: 0.8223
Epoch 10/100
625/625 - 152s - loss: 0.4278 - acc: 0.8113 - val_loss: 0.4619 - val_acc: 0.7979
Epoch 11/100
625/625 - 153s - loss: 0.4224 - acc: 0.8101 - val_loss: 0.4608 - val_acc: 0.7710
Epoch 12/100
625/625 - 153s - loss: 0.4223 - acc: 0.8140 - val_loss: 0.4496 - val_acc: 0.7726
Epoch 13/100
625/625 - 153s - loss: 0.4285 - acc: 0.8093 - val_loss: 0.4147 - val_acc: 0.8255
Epoch 14/100
625/625 - 156s - loss: 0.4224 - acc: 0.8070 - val_loss: 0.4451 - val_acc: 0.7885
Epoch 15/100
625/625 - 155s - loss: 0.4428 - acc: 0.8092 - val_loss: 0.4191 - val_acc: 0.8177
Epoch 16/100
625/625 - 156s - loss: 0.4267 - acc: 0.8089 - val_loss: 0.3791 - val_acc: 0.8127
Epoch 17/100
625/625 - 155s - loss: 0.4328 - acc: 0.8067 - val_loss: 0.6180 - val_acc: 0.7839
Epoch 18/100
625/625 - 156s - loss: 0.4361 - acc: 0.8083 - val_loss: 0.6032 - val_acc: 0.6785
Epoch 19/100
625/625 - 156s - loss: 0.4203 - acc: 0.8153 - val_loss: 0.3815 - val_acc: 0.8335
Epoch 20/100
625/625 - 156s - loss: 0.4403 - acc: 0.8116 - val_loss: 0.3653 - val_acc: 0.8393
Epoch 21/100
625/625 - 155s - loss: 0.4216 - acc: 0.8105 - val_loss: 0.4811 - val_acc: 0.7728
Epoch 22/100
625/625 - 155s - loss: 0.4423 - acc: 0.8049 - val_loss: 2.2071 - val_acc: 0.5913
Epoch 23/100
625/625 - 152s - loss: 0.4417 - acc: 0.8063 - val_loss: 0.3568 - val_acc: 0.8442
Epoch 24/100
625/625 - 151s - loss: 0.4353 - acc: 0.8105 - val_loss: 0.3727 - val_acc: 0.8405
Epoch 25/100
625/625 - 150s - loss: 0.4409 - acc: 0.8099 - val_loss: 0.4661 - val_acc: 0.7604
Epoch 26/100
625/625 - 151s - loss: 0.4467 - acc: 0.8021 - val_loss: 0.4138 - val_acc: 0.8227
Epoch 27/100
625/625 - 151s - loss: 0.4465 - acc: 0.8078 - val_loss: 0.3894 - val_acc: 0.8407
Epoch 28/100
625/625 - 156s - loss: 0.4269 - acc: 0.8126 - val_loss: 0.4504 - val_acc: 0.7901
Epoch 29/100
625/625 - 156s - loss: 0.4354 - acc: 0.8102 - val_loss: 0.3996 - val_acc: 0.8546
Epoch 30/100
625/625 - 156s - loss: 0.4677 - acc: 0.8122 - val_loss: 0.3758 - val_acc: 0.8508
Epoch 31/100
625/625 - 155s - loss: 0.4282 - acc: 0.8164 - val_loss: 0.4889 - val_acc: 0.7875
Epoch 32/100
625/625 - 156s - loss: 0.4306 - acc: 0.8108 - val_loss: 0.4583 - val_acc: 0.7562
Epoch 33/100
625/625 - 155s - loss: 0.4280 - acc: 0.8123 - val_loss: 0.4034 - val_acc: 0.7897
Epoch 34/100
625/625 - 157s - loss: 0.4316 - acc: 0.8058 - val_loss: 0.3685 - val_acc: 0.8462
Epoch 35/100
625/625 - 155s - loss: 0.4248 - acc: 0.8133 - val_loss: 0.5994 - val_acc: 0.8433
Epoch 36/100
625/625 - 156s - loss: 0.4450 - acc: 0.8112 - val_loss: 0.5043 - val_acc: 0.7099
Epoch 37/100
625/625 - 156s - loss: 0.4467 - acc: 0.8085 - val_loss: 0.3921 - val_acc: 0.8297
Epoch 38/100
625/625 - 156s - loss: 0.4377 - acc: 0.8106 - val_loss: 0.3842 - val_acc: 0.8403
Epoch 39/100
625/625 - 156s - loss: 0.4586 - acc: 0.8156 - val_loss: 0.6008 - val_acc: 0.6717
Epoch 40/100
625/625 - 156s - loss: 0.4234 - acc: 0.8180 - val_loss: 0.4325 - val_acc: 0.7943
Epoch 41/100
625/625 - 156s - loss: 0.4395 - acc: 0.8097 - val_loss: 0.3536 - val_acc: 0.8498
Epoch 42/100
625/625 - 156s - loss: 0.4453 - acc: 0.8062 - val_loss: 0.4309 - val_acc: 0.7971
Epoch 43/100
625/625 - 155s - loss: 0.4425 - acc: 0.8134 - val_loss: 0.3935 - val_acc: 0.8091
Epoch 44/100
625/625 - 156s - loss: 0.4301 - acc: 0.8153 - val_loss: 0.4786 - val_acc: 0.8207
Epoch 45/100
625/625 - 155s - loss: 0.4605 - acc: 0.8120 - val_loss: 0.3412 - val_acc: 0.8546
Epoch 46/100
625/625 - 156s - loss: 0.4261 - acc: 0.8221 - val_loss: 0.8955 - val_acc: 0.7194
Epoch 47/100
625/625 - 156s - loss: 0.4215 - acc: 0.8214 - val_loss: 0.4956 - val_acc: 0.8155
Epoch 48/100
625/625 - 156s - loss: 0.4270 - acc: 0.8144 - val_loss: 0.3912 - val_acc: 0.8331
Epoch 49/100
625/625 - 156s - loss: 0.4268 - acc: 0.8167 - val_loss: 0.3492 - val_acc: 0.8474
Epoch 50/100
625/625 - 155s - loss: 0.4275 - acc: 0.8135 - val_loss: 0.4503 - val_acc: 0.8383
Epoch 51/100
625/625 - 156s - loss: 0.4980 - acc: 0.8142 - val_loss: 0.4140 - val_acc: 0.8147
Epoch 52/100
625/625 - 155s - loss: 0.4528 - acc: 0.8221 - val_loss: 0.3570 - val_acc: 0.8456
Epoch 53/100
625/625 - 156s - loss: 0.4201 - acc: 0.8212 - val_loss: 0.5224 - val_acc: 0.6943
Epoch 54/100
625/625 - 153s - loss: 0.4399 - acc: 0.8113 - val_loss: 0.4587 - val_acc: 0.7782
Epoch 55/100
625/625 - 151s - loss: 0.4306 - acc: 0.8201 - val_loss: 0.3410 - val_acc: 0.8612
Epoch 56/100
625/625 - 150s - loss: 0.4986 - acc: 0.8180 - val_loss: 0.3842 - val_acc: 0.8345
Epoch 57/100
625/625 - 150s - loss: 0.4276 - acc: 0.8191 - val_loss: 0.4859 - val_acc: 0.7352
Epoch 58/100
625/625 - 150s - loss: 0.4344 - acc: 0.8084 - val_loss: 0.5267 - val_acc: 0.7242
Epoch 59/100
625/625 - 150s - loss: 0.4488 - acc: 0.8106 - val_loss: 0.3798 - val_acc: 0.8311
Epoch 60/100
625/625 - 150s - loss: 0.4445 - acc: 0.8111 - val_loss: 0.3818 - val_acc: 0.8367
Epoch 61/100
625/625 - 150s - loss: 0.5270 - acc: 0.8143 - val_loss: 0.3891 - val_acc: 0.8171
Epoch 62/100
625/625 - 150s - loss: 0.4444 - acc: 0.8131 - val_loss: 0.4622 - val_acc: 0.8061
Epoch 63/100
625/625 - 150s - loss: 0.4488 - acc: 0.8164 - val_loss: 0.4466 - val_acc: 0.7983
Epoch 64/100
625/625 - 150s - loss: 0.5321 - acc: 0.7947 - val_loss: 0.3542 - val_acc: 0.8546
Epoch 65/100
625/625 - 150s - loss: 0.4685 - acc: 0.7996 - val_loss: 0.3638 - val_acc: 0.8502
Epoch 66/100
625/625 - 151s - loss: 0.5376 - acc: 0.8097 - val_loss: 0.3572 - val_acc: 0.8464
Epoch 67/100
TimedStop: Training out of time (Elapsed = 2:56:51.937316)
Saving the Model Weights to /home/athena/models/dogs-vs-cats/cnn_weights_batch_size_32_5_double.h5
625/625 - 150s - loss: 0.4454 - acc: 0.8030 - val_loss: 0.3283 - val_acc: 0.8650
2019-07-16 01:36:37,054 graeae.timers.timer end: Ended: 2019-07-16 01:36:37.054383
I0716 01:36:37.054409 140093074827072 timer.py:77] Ended: 2019-07-16 01:36:37.054383
2019-07-16 01:36:37,055 graeae.timers.timer end: Elapsed: 2:56:53.207921
I0716 01:36:37.055413 140093074827072 timer.py:78] Elapsed: 2:56:53.207921

So we didn't quite get there. Maybe more training on the same model? Is it really getting better? It did the best at epoch 55. Maybe 86 is as good as it gets, but might as well try.

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_32_5_double").expanduser()
saver = partial(save_model_weights, name=str(path))
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=.95)
out_of_time = TimedStop(call_on_stopping=saver)

with TIMER:
    network.train()

Take Twelve

path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_32_5_double").expanduser()
saver = partial(save_model, path=path)
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=95)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  set_steps = True,
                  epochs = 100,
                  batch_size=32)
print(str(network))
with TIMER:
    network.train()
2019-07-17 23:02:00,693 graeae.timers.timer start: Started: 2019-07-17 23:02:00.692917
I0717 23:02:00.693119 140065468053312 timer.py:70] Started: 2019-07-17 23:02:00.692917
(Network) - 
Path: /home/athena/data/datasets/images/dogs-vs-cats/train
 Epochs: 100
 Batch Size: 32
 Callbacks: [<__main__.Stop object at 0x7f62f68a6c18>, <__main__.TimedStop object at 0x7f62f68a6da0>]
Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 32
Callbacks: [<__main__.Stop object at 0x7f62f68a6c18>, <__main__.TimedStop object at 0x7f62f68a6da0>]
Found 20000 images belonging to 2 classes.
W0717 23:02:01.406333 140065468053312 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
Found 5000 images belonging to 2 classes.
W0717 23:02:01.884152 140065468053312 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
Epoch 1/100
625/625 - 533s - loss: 0.6770 - acc: 0.5823 - val_loss: 0.6773 - val_acc: 0.5877
Epoch 2/100
625/625 - 157s - loss: 0.6280 - acc: 0.6556 - val_loss: 0.5860 - val_acc: 0.6879
Epoch 3/100
625/625 - 156s - loss: 0.5955 - acc: 0.6870 - val_loss: 0.5364 - val_acc: 0.7322
Epoch 4/100
625/625 - 157s - loss: 0.5579 - acc: 0.7225 - val_loss: 0.5200 - val_acc: 0.7648
Epoch 5/100
625/625 - 157s - loss: 0.5208 - acc: 0.7455 - val_loss: 0.5350 - val_acc: 0.7410
Epoch 6/100
625/625 - 157s - loss: 0.4874 - acc: 0.7736 - val_loss: 0.4713 - val_acc: 0.7740
Epoch 7/100
625/625 - 157s - loss: 0.4630 - acc: 0.7847 - val_loss: 0.5257 - val_acc: 0.7530
Epoch 8/100
625/625 - 157s - loss: 0.4499 - acc: 0.7923 - val_loss: 0.5602 - val_acc: 0.7294
Epoch 9/100
625/625 - 157s - loss: 0.4299 - acc: 0.8048 - val_loss: 0.5801 - val_acc: 0.6901
Epoch 10/100
625/625 - 157s - loss: 0.4296 - acc: 0.8101 - val_loss: 0.5544 - val_acc: 0.7642
Epoch 11/100
625/625 - 156s - loss: 0.4328 - acc: 0.8066 - val_loss: 0.5598 - val_acc: 0.7354
Epoch 12/100
625/625 - 157s - loss: 0.4372 - acc: 0.8080 - val_loss: 0.3635 - val_acc: 0.8411
Epoch 13/100
625/625 - 156s - loss: 0.4376 - acc: 0.8092 - val_loss: 0.4418 - val_acc: 0.8003
Epoch 14/100
625/625 - 156s - loss: 0.4228 - acc: 0.8147 - val_loss: 0.3530 - val_acc: 0.8454
Epoch 15/100
625/625 - 156s - loss: 0.4181 - acc: 0.8167 - val_loss: 0.4420 - val_acc: 0.7879
Epoch 16/100
625/625 - 156s - loss: 0.4295 - acc: 0.8105 - val_loss: 0.3515 - val_acc: 0.8411
Epoch 17/100
625/625 - 156s - loss: 0.4400 - acc: 0.8087 - val_loss: 0.3885 - val_acc: 0.8323
Epoch 18/100
625/625 - 156s - loss: 0.4215 - acc: 0.8145 - val_loss: 0.3775 - val_acc: 0.8417
Epoch 19/100
625/625 - 156s - loss: 0.4323 - acc: 0.8159 - val_loss: 0.4359 - val_acc: 0.8065
Epoch 20/100
625/625 - 156s - loss: 0.4181 - acc: 0.8089 - val_loss: 0.5274 - val_acc: 0.8474
Epoch 21/100
625/625 - 156s - loss: 0.4392 - acc: 0.8116 - val_loss: 0.5858 - val_acc: 0.7163
Epoch 22/100
625/625 - 156s - loss: 0.4432 - acc: 0.8093 - val_loss: 0.5178 - val_acc: 0.7192
Epoch 23/100
625/625 - 156s - loss: 0.4629 - acc: 0.8091 - val_loss: 0.3340 - val_acc: 0.8604
Epoch 24/100
625/625 - 156s - loss: 0.4236 - acc: 0.8150 - val_loss: 0.3742 - val_acc: 0.8357
Epoch 25/100
625/625 - 156s - loss: 0.4257 - acc: 0.8152 - val_loss: 0.3582 - val_acc: 0.8367
Epoch 26/100
625/625 - 157s - loss: 0.4133 - acc: 0.8190 - val_loss: 0.3847 - val_acc: 0.8339
Epoch 27/100
625/625 - 156s - loss: 0.4298 - acc: 0.8136 - val_loss: 0.3627 - val_acc: 0.8446
Epoch 28/100
625/625 - 155s - loss: 0.4335 - acc: 0.8127 - val_loss: 0.4581 - val_acc: 0.8261
Epoch 29/100
625/625 - 156s - loss: 0.4234 - acc: 0.8123 - val_loss: 0.3819 - val_acc: 0.8333
Epoch 30/100
625/625 - 156s - loss: 0.4213 - acc: 0.8152 - val_loss: 0.3809 - val_acc: 0.8596
Epoch 31/100
625/625 - 156s - loss: 0.4399 - acc: 0.8029 - val_loss: 0.4879 - val_acc: 0.7662
Epoch 32/100
625/625 - 157s - loss: 0.4406 - acc: 0.8090 - val_loss: 0.3731 - val_acc: 0.8668
Epoch 33/100
625/625 - 156s - loss: 0.4336 - acc: 0.8162 - val_loss: 0.4306 - val_acc: 0.8389
Epoch 34/100
625/625 - 153s - loss: 0.4524 - acc: 0.8102 - val_loss: 0.3486 - val_acc: 0.8538
Epoch 35/100
625/625 - 151s - loss: 0.4306 - acc: 0.8127 - val_loss: 0.4819 - val_acc: 0.7923
Epoch 36/100
625/625 - 151s - loss: 0.4350 - acc: 0.8109 - val_loss: 0.3536 - val_acc: 0.8506
Epoch 37/100
625/625 - 151s - loss: 0.4480 - acc: 0.8073 - val_loss: 0.5374 - val_acc: 0.8165
Epoch 38/100
625/625 - 151s - loss: 0.4411 - acc: 0.8195 - val_loss: 1.1689 - val_acc: 0.6763
Epoch 39/100
625/625 - 151s - loss: 0.4652 - acc: 0.8189 - val_loss: 0.3614 - val_acc: 0.8395
Epoch 40/100
625/625 - 151s - loss: 0.4442 - acc: 0.8166 - val_loss: 0.3833 - val_acc: 0.8261
Epoch 41/100
625/625 - 151s - loss: 0.4259 - acc: 0.8128 - val_loss: 0.3824 - val_acc: 0.8349
Epoch 42/100
625/625 - 151s - loss: 0.4336 - acc: 0.8122 - val_loss: 0.3564 - val_acc: 0.8508
Epoch 43/100
625/625 - 151s - loss: 0.4268 - acc: 0.8151 - val_loss: 0.3299 - val_acc: 0.8636
Epoch 44/100
625/625 - 151s - loss: 0.4206 - acc: 0.8184 - val_loss: 0.3538 - val_acc: 0.8462
Epoch 45/100
625/625 - 151s - loss: 0.4318 - acc: 0.8173 - val_loss: 0.3854 - val_acc: 0.8482
Epoch 46/100
625/625 - 151s - loss: 0.4521 - acc: 0.8120 - val_loss: 0.3691 - val_acc: 0.8568
Epoch 47/100
625/625 - 150s - loss: 0.4561 - acc: 0.8090 - val_loss: 0.3810 - val_acc: 0.8474
Epoch 48/100
625/625 - 151s - loss: 0.4358 - acc: 0.8128 - val_loss: 0.4755 - val_acc: 0.8041
Epoch 49/100
625/625 - 151s - loss: 0.4296 - acc: 0.8132 - val_loss: 0.4490 - val_acc: 0.8618
Epoch 50/100
625/625 - 151s - loss: 0.4385 - acc: 0.8183 - val_loss: 0.3964 - val_acc: 0.8377
Epoch 51/100
625/625 - 150s - loss: 0.4368 - acc: 0.8164 - val_loss: 0.3463 - val_acc: 0.8592
Epoch 52/100
625/625 - 151s - loss: 0.4702 - acc: 0.8134 - val_loss: 0.3882 - val_acc: 0.8365
Epoch 53/100
625/625 - 151s - loss: 0.4555 - acc: 0.8025 - val_loss: 0.4516 - val_acc: 0.7558
Epoch 54/100
625/625 - 150s - loss: 0.4502 - acc: 0.8059 - val_loss: 0.4236 - val_acc: 0.8035
Epoch 55/100
625/625 - 151s - loss: 0.4829 - acc: 0.7970 - val_loss: 0.3800 - val_acc: 0.8349
Epoch 56/100
625/625 - 150s - loss: 0.4554 - acc: 0.8055 - val_loss: 0.4774 - val_acc: 0.8023
Epoch 57/100
625/625 - 151s - loss: 0.5059 - acc: 0.7813 - val_loss: 0.5145 - val_acc: 0.7332
Epoch 58/100
625/625 - 151s - loss: 0.4680 - acc: 0.8015 - val_loss: 0.3994 - val_acc: 0.8201
Epoch 59/100
625/625 - 151s - loss: 0.4938 - acc: 0.7962 - val_loss: 0.3682 - val_acc: 0.8421
Epoch 60/100
625/625 - 151s - loss: 0.4870 - acc: 0.7883 - val_loss: 0.3798 - val_acc: 0.8249
Epoch 61/100
625/625 - 151s - loss: 0.4785 - acc: 0.7902 - val_loss: 0.4609 - val_acc: 0.7967
Epoch 62/100
625/625 - 151s - loss: 0.4948 - acc: 0.7840 - val_loss: 0.4502 - val_acc: 0.7788
Epoch 63/100
625/625 - 150s - loss: 0.5021 - acc: 0.7847 - val_loss: 0.3829 - val_acc: 0.8307
Epoch 64/100
625/625 - 151s - loss: 0.4982 - acc: 0.7882 - val_loss: 0.6872 - val_acc: 0.6755
Epoch 65/100
625/625 - 151s - loss: 0.5514 - acc: 0.7707 - val_loss: 0.4682 - val_acc: 0.7804
Epoch 66/100
TimedStop: Training out of time (Elapsed = 2:55:40.163015)
625/625 - 151s - loss: 0.5037 - acc: 0.7713 - val_loss: 0.5198 - val_acc: 0.8091
2019-07-18 01:57:42,823 graeae.timers.timer end: Ended: 2019-07-18 01:57:42.823388
I0718 01:57:42.823415 140065468053312 timer.py:77] Ended: 2019-07-18 01:57:42.823388
2019-07-18 01:57:42,824 graeae.timers.timer end: Elapsed: 2:55:42.130471
I0718 01:57:42.824334 140065468053312 timer.py:78] Elapsed: 2:55:42.130471
best_accuracy = data.validation_accuracy.max()
best_loss = data.validation_loss.min()
accuracy_slice = data[data.validation_accuracy==best_accuracy]
loss_slice = data[data.validation_loss==best_loss]

accuracy_index = accuracy_slice.index[0]
loss_index = loss_slice.index[0]
print(f"Best Accuracy: {best_accuracy} "
      f"(loss={accuracy_slice.validation_loss.iloc[0]})"
      f" Epoch: {accuracy_index + 1}")
print(f"Best Loss: {best_loss} (accuracy="
      f"{loss_slice.validation_accuracy.iloc[0]})"
      f" Epoch: {loss_index + 1}")
Best Accuracy: 0.8668 (loss=0.3731) Epoch: 32
Best Loss: 0.3299 (accuracy=0.8636) Epoch: 43
data = pandas.read_csv("~/cats_vs_dogs.csv")
line_1 = holoviews.VLine(accuracy_index, label="Best Accuracy")
line_2 = holoviews.VLine(loss_index, label="Best Loss")

curves = [holoviews.Curve(data, ("index", "Epoch"), "training_loss", 
                          label="Training Loss",),
          holoviews.Curve(data, ("index", "Epoch"), "training_accuracy", 
                          label="Training Accuracy").opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_loss", 
                          label="Validation Loss",).opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_accuracy", 
                          label="Validation Accuracy").opts(tools=["hover"]),
          line_1, line_2]
plot = holoviews.Overlay(curves).opts(tools=["hover"], height=800, width=1000, 
                                      ylabel="Performance", 
                                      title="Training vs Validation")
Embed(plot=plot, file_name="training_validation_loss_12")()

Figure Missing

There's more variance in the validation performance than I thought there would be. Although the best accuracy and loss come later, Epoch 22 (zero-based) has better loss (0.334) than the best accuracy's loss (0.37), and around the same accuracy (0.86) as the best loss' accuracy (0.864)

This next part won't work yet because I don't have the test data loaded and I need to save the predictions of the stored model.

predictions = model.predict(x_test)

loaded_model = kears.models.load_model(path)
new_predictions = loaded_model.predict(x_test)
numpy.assert.allclose(predictions, new_predictions, atol=1e-6)

Take Thirteen

data = pandas.read_csv("~/cats_vs_dogs.csv")
print(tabulate(data[data.validation_accuracy>=0.86], 
      headers="keys", tablefmt="orgtbl"))
  training_loss training_accuracy validation_loss validation_accuracy
22 0.4629 0.8091 0.334 0.8604
31 0.4406 0.809 0.3731 0.8668
42 0.4268 0.8151 0.3299 0.8636
48 0.4296 0.8132 0.449 0.8618
path = Path("~/models/dogs-vs-cats/cnn_weights_batch_size_32_5_double").expanduser()
saver = partial(save_model, path=path)
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=0.86)
out_of_time = TimedStop(call_on_stopping=saver)

network = Network(str(training_path), 
                  callbacks=[good_enough, out_of_time],
                  convolution_layers=5,
                  set_steps = True,
                  epochs = 100,
                  batch_size=64)
print(str(network))
with TIMER:
    network.train()
2019-07-18 22:28:08,881 graeae.timers.timer start: Started: 2019-07-18 22:28:08.881418
I0718 22:28:08.881625 139703649425216 timer.py:70] Started: 2019-07-18 22:28:08.881418
(Network) - 
Path: /home/athena/data/datasets/images/dogs-vs-cats/train
 Epochs: 100
 Batch Size: 64
 Callbacks: [<__main__.Stop object at 0x7f0eb5d9f860>, <__main__.TimedStop object at 0x7f0eb5d9f828>]
Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 64
Callbacks: [<__main__.Stop object at 0x7f0eb5d9f860>, <__main__.TimedStop object at 0x7f0eb5d9f828>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
W0718 22:28:09.550659 139703649425216 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
W0718 22:28:10.023711 139703649425216 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
Epoch 1/100
312/312 - 523s - loss: 0.6780 - acc: 0.5673 - val_loss: 0.6886 - val_acc: 0.5978
Epoch 2/100
312/312 - 158s - loss: 0.6415 - acc: 0.6353 - val_loss: 0.5944 - val_acc: 0.6789
Epoch 3/100
312/312 - 154s - loss: 0.6050 - acc: 0.6724 - val_loss: 0.5635 - val_acc: 0.7155
Epoch 4/100
312/312 - 153s - loss: 0.5789 - acc: 0.7044 - val_loss: 0.6398 - val_acc: 0.6212
Epoch 5/100
312/312 - 152s - loss: 0.5501 - acc: 0.7231 - val_loss: 0.5117 - val_acc: 0.7480
Epoch 6/100
312/312 - 153s - loss: 0.5155 - acc: 0.7478 - val_loss: 0.4671 - val_acc: 0.7788
Epoch 7/100
312/312 - 157s - loss: 0.4841 - acc: 0.7725 - val_loss: 0.4228 - val_acc: 0.8041
Epoch 8/100
312/312 - 157s - loss: 0.4513 - acc: 0.7875 - val_loss: 0.4660 - val_acc: 0.7877
Epoch 9/100
312/312 - 154s - loss: 0.4275 - acc: 0.8033 - val_loss: 0.3893 - val_acc: 0.8225
Epoch 10/100
312/312 - 157s - loss: 0.4140 - acc: 0.8084 - val_loss: 0.3792 - val_acc: 0.8249
Epoch 11/100
312/312 - 155s - loss: 0.3907 - acc: 0.8258 - val_loss: 0.3678 - val_acc: 0.8299
Epoch 12/100
312/312 - 156s - loss: 0.3772 - acc: 0.8301 - val_loss: 0.4905 - val_acc: 0.7558
Epoch 13/100
312/312 - 155s - loss: 0.3702 - acc: 0.8354 - val_loss: 0.5838 - val_acc: 0.7200
Epoch 14/100
312/312 - 155s - loss: 0.3537 - acc: 0.8412 - val_loss: 0.4032 - val_acc: 0.8225
Epoch 15/100
312/312 - 154s - loss: 0.3501 - acc: 0.8448 - val_loss: 0.3675 - val_acc: 0.8530
Epoch 16/100
312/312 - 150s - loss: 0.3480 - acc: 0.8451 - val_loss: 0.2927 - val_acc: 0.8770
Epoch 17/100
312/312 - 152s - loss: 0.3381 - acc: 0.8518 - val_loss: 0.2863 - val_acc: 0.8746
Epoch 18/100
312/312 - 152s - loss: 0.3386 - acc: 0.8491 - val_loss: 0.3782 - val_acc: 0.8419
Epoch 19/100
312/312 - 153s - loss: 0.3389 - acc: 0.8527 - val_loss: 0.2987 - val_acc: 0.8682
Epoch 20/100
312/312 - 152s - loss: 0.3294 - acc: 0.8589 - val_loss: 0.3645 - val_acc: 0.8456
Epoch 21/100
312/312 - 154s - loss: 0.3239 - acc: 0.8584 - val_loss: 1.4912 - val_acc: 0.6442
Epoch 22/100
312/312 - 153s - loss: 0.3208 - acc: 0.8629 - val_loss: 0.3812 - val_acc: 0.8243
Epoch 23/100
312/312 - 154s - loss: 0.3253 - acc: 0.8642 - val_loss: 0.2765 - val_acc: 0.8918
Epoch 24/100
312/312 - 154s - loss: 0.3252 - acc: 0.8615 - val_loss: 0.2959 - val_acc: 0.8704
Epoch 25/100
312/312 - 154s - loss: 0.3158 - acc: 0.8639 - val_loss: 0.2870 - val_acc: 0.8804
Epoch 26/100
312/312 - 154s - loss: 0.3332 - acc: 0.8594 - val_loss: 0.2946 - val_acc: 0.8752
Epoch 27/100
312/312 - 154s - loss: 0.3346 - acc: 0.8546 - val_loss: 0.3017 - val_acc: 0.8754
Epoch 28/100
312/312 - 153s - loss: 0.3245 - acc: 0.8595 - val_loss: 0.3335 - val_acc: 0.8401
Epoch 29/100
312/312 - 153s - loss: 0.3180 - acc: 0.8626 - val_loss: 0.3673 - val_acc: 0.8237
Epoch 30/100
312/312 - 153s - loss: 0.3224 - acc: 0.8610 - val_loss: 0.2796 - val_acc: 0.8860
Epoch 31/100
312/312 - 153s - loss: 0.3227 - acc: 0.8613 - val_loss: 0.4363 - val_acc: 0.8173
Epoch 32/100
312/312 - 153s - loss: 0.3156 - acc: 0.8676 - val_loss: 0.5863 - val_acc: 0.8027
Epoch 33/100
312/312 - 154s - loss: 0.3222 - acc: 0.8623 - val_loss: 0.2824 - val_acc: 0.8870
Epoch 34/100
312/312 - 153s - loss: 0.3183 - acc: 0.8629 - val_loss: 0.2856 - val_acc: 0.8790
Epoch 35/100
312/312 - 153s - loss: 0.3152 - acc: 0.8647 - val_loss: 0.3953 - val_acc: 0.8267
Epoch 36/100
312/312 - 154s - loss: 0.3134 - acc: 0.8643 - val_loss: 0.2576 - val_acc: 0.8840
Epoch 37/100
312/312 - 154s - loss: 0.3296 - acc: 0.8595 - val_loss: 0.2680 - val_acc: 0.8838
Epoch 38/100
312/312 - 153s - loss: 0.3285 - acc: 0.8552 - val_loss: 0.3820 - val_acc: 0.8504
Epoch 39/100
312/312 - 154s - loss: 0.3098 - acc: 0.8653 - val_loss: 0.4445 - val_acc: 0.8089
Epoch 40/100
312/312 - 153s - loss: 0.3272 - acc: 0.8579 - val_loss: 0.3113 - val_acc: 0.8758
Epoch 41/100
312/312 - 153s - loss: 0.3382 - acc: 0.8570 - val_loss: 0.3215 - val_acc: 0.8640
Epoch 42/100
312/312 - 154s - loss: 0.3239 - acc: 0.8609 - val_loss: 0.2939 - val_acc: 0.8784
Epoch 43/100
312/312 - 154s - loss: 0.3302 - acc: 0.8582 - val_loss: 0.3737 - val_acc: 0.8431
Epoch 44/100
312/312 - 153s - loss: 0.3178 - acc: 0.8657 - val_loss: 0.2844 - val_acc: 0.8844
Epoch 45/100
312/312 - 153s - loss: 0.3260 - acc: 0.8601 - val_loss: 0.3615 - val_acc: 0.8333
Epoch 46/100
312/312 - 153s - loss: 0.3248 - acc: 0.8603 - val_loss: 0.3506 - val_acc: 0.8488
Epoch 47/100
312/312 - 153s - loss: 0.3260 - acc: 0.8616 - val_loss: 0.2585 - val_acc: 0.8940
Epoch 48/100
312/312 - 154s - loss: 0.3168 - acc: 0.8647 - val_loss: 0.2970 - val_acc: 0.8728
Epoch 49/100
312/312 - 154s - loss: 0.3418 - acc: 0.8630 - val_loss: 0.2806 - val_acc: 0.8852
Epoch 50/100
312/312 - 154s - loss: 0.3146 - acc: 0.8636 - val_loss: 0.2879 - val_acc: 0.8822
Epoch 51/100
312/312 - 153s - loss: 0.3185 - acc: 0.8639 - val_loss: 0.3118 - val_acc: 0.8668
Epoch 52/100
312/312 - 154s - loss: 0.3136 - acc: 0.8610 - val_loss: 0.2760 - val_acc: 0.8852
Epoch 53/100
312/312 - 153s - loss: 0.3079 - acc: 0.8704 - val_loss: 0.3753 - val_acc: 0.8329
Epoch 54/100
312/312 - 153s - loss: 0.3078 - acc: 0.8688 - val_loss: 0.2850 - val_acc: 0.8790
Epoch 55/100
312/312 - 153s - loss: 0.3123 - acc: 0.8658 - val_loss: 0.2774 - val_acc: 0.8884
Epoch 56/100
312/312 - 154s - loss: 0.3161 - acc: 0.8685 - val_loss: 0.3321 - val_acc: 0.8584
Epoch 57/100
312/312 - 153s - loss: 0.3084 - acc: 0.8662 - val_loss: 0.2941 - val_acc: 0.8710
Epoch 58/100
312/312 - 154s - loss: 0.3224 - acc: 0.8651 - val_loss: 0.2577 - val_acc: 0.8906
Epoch 59/100
312/312 - 154s - loss: 0.3105 - acc: 0.8639 - val_loss: 0.3438 - val_acc: 0.8722
Epoch 60/100
312/312 - 153s - loss: 0.3070 - acc: 0.8684 - val_loss: 0.2602 - val_acc: 0.8898
Epoch 61/100
312/312 - 153s - loss: 0.3140 - acc: 0.8658 - val_loss: 0.2677 - val_acc: 0.8882
Epoch 62/100
312/312 - 153s - loss: 0.3096 - acc: 0.8684 - val_loss: 0.2614 - val_acc: 0.8842
Epoch 63/100
312/312 - 153s - loss: 0.3081 - acc: 0.8686 - val_loss: 0.2908 - val_acc: 0.8740
Epoch 64/100
312/312 - 153s - loss: 0.3134 - acc: 0.8668 - val_loss: 0.4757 - val_acc: 0.7314
Epoch 65/100
312/312 - 154s - loss: 0.3085 - acc: 0.8699 - val_loss: 0.3414 - val_acc: 0.8538
Epoch 66/100
TimedStop: Training out of time (Elapsed = 2:55:50.573494)
312/312 - 154s - loss: 0.3208 - acc: 0.8635 - val_loss: 0.3494 - val_acc: 0.8399
2019-07-19 01:24:01,375 graeae.timers.timer end: Ended: 2019-07-19 01:24:01.375685
I0719 01:24:01.375718 139703649425216 timer.py:77] Ended: 2019-07-19 01:24:01.375685
2019-07-19 01:24:01,376 graeae.timers.timer end: Elapsed: 2:55:52.494267
I0719 01:24:01.376679 139703649425216 timer.py:78] Elapsed: 2:55:52.494267

Weirdly, we got up to 89 % validation accuracy this time but it didn't stop. Looking at the stop I had the maximum loss set to 24%, which is probably why it didn't stop, but it looks like I should be able to get better accuracy anyway.

data = pandas.read_csv("~/cats_vs_dogs_2.csv")
print(tabulate(data[data.validation_accuracy>=0.88],
      headers="keys", tablefmt="orgtbl"))
  training_loss training_accuracy validation_loss validation_accuracy
22 0.3253 0.8642 0.2765 0.8918
24 0.3158 0.8639 0.287 0.8804
29 0.3224 0.861 0.2796 0.886
32 0.3222 0.8623 0.2824 0.887
35 0.3134 0.8643 0.2576 0.884
36 0.3296 0.8595 0.268 0.8838
43 0.3178 0.8657 0.2844 0.8844
46 0.326 0.8616 0.2585 0.894
48 0.3418 0.863 0.2806 0.8852
49 0.3146 0.8636 0.2879 0.8822
51 0.3136 0.861 0.276 0.8852
54 0.3123 0.8658 0.2774 0.8884
57 0.3224 0.8651 0.2577 0.8906
59 0.307 0.8684 0.2602 0.8898
60 0.314 0.8658 0.2677 0.8882
61 0.3096 0.8684 0.2614 0.8842

By increasing the batch size we got better faster. So, maybe it isn't done learning yet. Or maybe a larger batch size would be useful. It doesn't seem to be improving, by much, though.

best_accuracy = data.validation_accuracy.max()
best_loss = data.validation_loss.min()
accuracy_index = data[data.validation_accuracy==best_accuracy].index[0]
loss_index = data[data.validation_loss==best_loss].index[0]

print(f"Highest Accuracy: {best_accuracy} Epoch: {accuracy_index + 1}")
print(f"Lowest Loss: {best_loss} Epoch: {loss_index}")
Highest Accuracy: 0.894 Epoch: 47
Lowest Loss: 0.2576 Epoch: 35
line_1 = holoviews.VLine(accuracy_index, label="Best Accuracy Epoch")
line_2 = holoviews.VLine(loss_index, label="Best Loss Epoch")
accuracy_line = holoviews.HLine(best_accuracy, label="Highest Accuracy")
loss_line = holoviews.HLine(best_loss, label="lowest Loss")

curves = [holoviews.Curve(data, ("index", "Epoch"), "training_loss", 
                          label="Training Loss",),
          holoviews.Curve(data, ("index", "Epoch"), "training_accuracy", 
                          label="Training Accuracy").opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_loss", 
                          label="Validation Loss",).opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_accuracy", 
                          label="Validation Accuracy").opts(tools=["hover"]),
          line_1, line_2, accuracy_line, loss_line]
plot = holoviews.Overlay(curves).opts(tools=["hover"], height=800, width=1000, 
                                      ylabel="Performance", 
                                      title="Training vs Validation")
Embed(plot=plot, file_name="training_validation_loss_13")()

Figure Missing

It looks like it might be plateauing. Only one way to really find out, I guess - more training.

  • Take Thirteen Point Two

    I'll re-train it without using the Stop condition to see if it gets better than I was allowing it to get.

    saver = partial(save_model, path=path)
    good_enough = Stop(call_on_stopping=saver,
                       minimum_accuracy=0.90)
    out_of_time = TimedStop(call_on_stopping=saver)
    
    network = Network(str(training_path), 
                      callbacks=[out_of_time],
                      convolution_layers=5,
                      set_steps = True,
                      epochs = 100,
                      batch_size=64)
    network._model = tensorflow.keras.models.load_model(str(path))
    with TIMER:
        network.train()
    
    W0720 10:27:38.686592 139935525873472 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:97: calling GlorotUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
    Instructions for updating:
    Call initializer instance with the dtype argument instead of passing it to the constructor
    W0720 10:27:38.688725 139935525873472 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
    Instructions for updating:
    Call initializer instance with the dtype argument instead of passing it to the constructor
    W0720 10:27:38.690803 139935525873472 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:97: calling Zeros.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
    Instructions for updating:
    Call initializer instance with the dtype argument instead of passing it to the constructor
    W0720 10:27:53.533317 139935525873472 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
    Instructions for updating:
    Use tf.where in 2.0, which has the same broadcast rule as np.where
    2019-07-20 10:27:54,312 graeae.timers.timer start: Started: 2019-07-20 10:27:54.312000
    I0720 10:27:54.312226 139935525873472 timer.py:70] Started: 2019-07-20 10:27:54.312000
    Found 20000 images belonging to 2 classes.
    Found 5000 images belonging to 2 classes.
    Epoch 1/100
    312/312 - 448s - loss: 0.3622 - acc: 0.8679 - val_loss: 0.2536 - val_acc: 0.8898
    Epoch 2/100
    312/312 - 154s - loss: 0.3059 - acc: 0.8716 - val_loss: 0.2927 - val_acc: 0.8932
    Epoch 3/100
    312/312 - 154s - loss: 0.3164 - acc: 0.8691 - val_loss: 0.3203 - val_acc: 0.8620
    Epoch 4/100
    312/312 - 154s - loss: 0.3190 - acc: 0.8620 - val_loss: 1.0261 - val_acc: 0.6781
    Epoch 5/100
    312/312 - 153s - loss: 0.3308 - acc: 0.8662 - val_loss: 0.2791 - val_acc: 0.8736
    Epoch 6/100
    312/312 - 152s - loss: 0.3234 - acc: 0.8633 - val_loss: 0.2434 - val_acc: 0.9054
    Epoch 7/100
    312/312 - 151s - loss: 0.3040 - acc: 0.8702 - val_loss: 0.2895 - val_acc: 0.8828
    Epoch 8/100
    312/312 - 150s - loss: 0.3063 - acc: 0.8714 - val_loss: 0.2788 - val_acc: 0.8744
    Epoch 9/100
    312/312 - 150s - loss: 0.3043 - acc: 0.8717 - val_loss: 0.4412 - val_acc: 0.8011
    Epoch 10/100
    312/312 - 150s - loss: 0.3059 - acc: 0.8690 - val_loss: 0.3050 - val_acc: 0.8784
    Epoch 11/100
    312/312 - 150s - loss: 0.3368 - acc: 0.8633 - val_loss: 0.2813 - val_acc: 0.8864
    Epoch 12/100
    312/312 - 150s - loss: 0.3282 - acc: 0.8633 - val_loss: 0.4125 - val_acc: 0.8209
    Epoch 13/100
    312/312 - 150s - loss: 0.3091 - acc: 0.8701 - val_loss: 0.3506 - val_acc: 0.8842
    Epoch 14/100
    312/312 - 149s - loss: 0.3369 - acc: 0.8585 - val_loss: 0.2702 - val_acc: 0.8908
    Epoch 15/100
    312/312 - 150s - loss: 0.3253 - acc: 0.8624 - val_loss: 0.2360 - val_acc: 0.8996
    Epoch 16/100
    312/312 - 149s - loss: 0.3206 - acc: 0.8622 - val_loss: 0.4118 - val_acc: 0.8454
    Epoch 17/100
    312/312 - 149s - loss: 0.3396 - acc: 0.8629 - val_loss: 0.4940 - val_acc: 0.7899
    Epoch 18/100
    312/312 - 149s - loss: 0.3190 - acc: 0.8632 - val_loss: 0.2928 - val_acc: 0.8762
    Epoch 19/100
    312/312 - 150s - loss: 0.3154 - acc: 0.8658 - val_loss: 0.2806 - val_acc: 0.8914
    Epoch 20/100
    312/312 - 151s - loss: 0.3241 - acc: 0.8632 - val_loss: 0.2797 - val_acc: 0.8778
    Epoch 21/100
    312/312 - 150s - loss: 0.4349 - acc: 0.8620 - val_loss: 0.2824 - val_acc: 0.8836
    Epoch 22/100
    312/312 - 150s - loss: 0.3255 - acc: 0.8626 - val_loss: 0.3107 - val_acc: 0.8736
    Epoch 23/100
    312/312 - 150s - loss: 0.3139 - acc: 0.8678 - val_loss: 0.2830 - val_acc: 0.8796
    Epoch 24/100
    312/312 - 151s - loss: 0.3231 - acc: 0.8641 - val_loss: 0.3103 - val_acc: 0.8874
    Epoch 25/100
    312/312 - 151s - loss: 0.3222 - acc: 0.8647 - val_loss: 0.7359 - val_acc: 0.6821
    Epoch 26/100
    312/312 - 151s - loss: 0.3140 - acc: 0.8657 - val_loss: 0.5905 - val_acc: 0.8235
    Epoch 27/100
    312/312 - 150s - loss: 0.3431 - acc: 0.8684 - val_loss: 0.3469 - val_acc: 0.8776
    Epoch 28/100
    312/312 - 149s - loss: 0.3124 - acc: 0.8681 - val_loss: 0.3550 - val_acc: 0.8444
    Epoch 29/100
    312/312 - 149s - loss: 0.3159 - acc: 0.8682 - val_loss: 0.3107 - val_acc: 0.8642
    Epoch 30/100
    312/312 - 149s - loss: 0.3177 - acc: 0.8621 - val_loss: 0.2972 - val_acc: 0.8700
    Epoch 31/100
    312/312 - 149s - loss: 0.3370 - acc: 0.8636 - val_loss: 0.2857 - val_acc: 0.8876
    Epoch 32/100
    312/312 - 149s - loss: 0.3476 - acc: 0.8602 - val_loss: 0.2762 - val_acc: 0.8866
    Epoch 33/100
    312/312 - 150s - loss: 0.3383 - acc: 0.8600 - val_loss: 0.3066 - val_acc: 0.8874
    Epoch 34/100
    312/312 - 150s - loss: 0.3316 - acc: 0.8681 - val_loss: 0.4850 - val_acc: 0.7244
    Epoch 35/100
    312/312 - 149s - loss: 0.3158 - acc: 0.8642 - val_loss: 0.2958 - val_acc: 0.8748
    Epoch 36/100
    312/312 - 151s - loss: 0.3285 - acc: 0.8597 - val_loss: 0.2739 - val_acc: 0.8762
    Epoch 37/100
    312/312 - 150s - loss: 0.3239 - acc: 0.8622 - val_loss: 0.3081 - val_acc: 0.8714
    Epoch 38/100
    312/312 - 150s - loss: 0.3277 - acc: 0.8601 - val_loss: 0.3068 - val_acc: 0.8882
    Epoch 39/100
    312/312 - 152s - loss: 0.3228 - acc: 0.8601 - val_loss: 0.3480 - val_acc: 0.8546
    Epoch 40/100
    312/312 - 152s - loss: 0.3631 - acc: 0.8633 - val_loss: 0.2939 - val_acc: 0.8906
    Epoch 41/100
    312/312 - 152s - loss: 0.3313 - acc: 0.8592 - val_loss: 0.2674 - val_acc: 0.8918
    Epoch 42/100
    312/312 - 152s - loss: 0.4150 - acc: 0.8648 - val_loss: 0.2846 - val_acc: 0.8796
    Epoch 43/100
    312/312 - 154s - loss: 0.3161 - acc: 0.8665 - val_loss: 0.2665 - val_acc: 0.8858
    Epoch 44/100
    312/312 - 153s - loss: 0.3330 - acc: 0.8627 - val_loss: 0.2977 - val_acc: 0.8726
    Epoch 45/100
    312/312 - 149s - loss: 0.3250 - acc: 0.8668 - val_loss: 0.2746 - val_acc: 0.8796
    Epoch 46/100
    312/312 - 153s - loss: 0.3091 - acc: 0.8715 - val_loss: 0.2864 - val_acc: 0.8924
    Epoch 47/100
    312/312 - 151s - loss: 0.3288 - acc: 0.8622 - val_loss: 0.2662 - val_acc: 0.8886
    Epoch 48/100
    312/312 - 149s - loss: 0.3594 - acc: 0.8589 - val_loss: 0.2818 - val_acc: 0.8842
    Epoch 49/100
    312/312 - 148s - loss: 0.3275 - acc: 0.8604 - val_loss: 0.4913 - val_acc: 0.7610
    Epoch 50/100
    312/312 - 149s - loss: 0.3611 - acc: 0.8586 - val_loss: 0.3517 - val_acc: 0.8438
    Epoch 51/100
    312/312 - 148s - loss: 0.3413 - acc: 0.8568 - val_loss: 0.3549 - val_acc: 0.8602
    Epoch 52/100
    312/312 - 148s - loss: 0.3275 - acc: 0.8627 - val_loss: 0.2567 - val_acc: 0.8926
    Epoch 53/100
    312/312 - 148s - loss: 0.3679 - acc: 0.8592 - val_loss: 0.3676 - val_acc: 0.8554
    Epoch 54/100
    312/312 - 148s - loss: 0.3332 - acc: 0.8580 - val_loss: 0.2862 - val_acc: 0.8754
    Epoch 55/100
    312/312 - 148s - loss: 0.3254 - acc: 0.8644 - val_loss: 11.4265 - val_acc: 0.5905
    Epoch 56/100
    312/312 - 148s - loss: 0.3735 - acc: 0.8634 - val_loss: 0.3241 - val_acc: 0.8728
    Epoch 57/100
    312/312 - 148s - loss: 0.3401 - acc: 0.8588 - val_loss: 0.2946 - val_acc: 0.8746
    Epoch 58/100
    312/312 - 149s - loss: 0.4813 - acc: 0.8624 - val_loss: 0.3596 - val_acc: 0.8452
    Epoch 59/100
    312/312 - 148s - loss: 0.3279 - acc: 0.8633 - val_loss: 0.2789 - val_acc: 0.8734
    Epoch 60/100
    312/312 - 147s - loss: 0.3375 - acc: 0.8591 - val_loss: 0.3680 - val_acc: 0.8331
    Epoch 61/100
    312/312 - 148s - loss: 0.3359 - acc: 0.8585 - val_loss: 0.3290 - val_acc: 0.8802
    Epoch 62/100
    312/312 - 148s - loss: 0.3259 - acc: 0.8633 - val_loss: 0.3308 - val_acc: 0.8676
    Epoch 63/100
    312/312 - 149s - loss: 0.3290 - acc: 0.8598 - val_loss: 0.2710 - val_acc: 0.8850
    Epoch 64/100
    312/312 - 148s - loss: 0.3383 - acc: 0.8507 - val_loss: 0.2740 - val_acc: 0.8838
    Epoch 65/100
    312/312 - 149s - loss: 0.3287 - acc: 0.8627 - val_loss: 0.3301 - val_acc: 0.8540
    Epoch 66/100
    312/312 - 149s - loss: 1.9072 - acc: 0.8593 - val_loss: 0.3180 - val_acc: 0.8602
    Epoch 67/100
    312/312 - 148s - loss: 0.3265 - acc: 0.8597 - val_loss: 0.2972 - val_acc: 0.8708
    Epoch 68/100
    312/312 - 150s - loss: 0.3515 - acc: 0.8613 - val_loss: 0.4104 - val_acc: 0.8444
    Epoch 69/100
    TimedStop: Training out of time (Elapsed = 2:57:23.471615)
    TimedStop: Longest Epoch = 2:57:23.471615
    312/312 - 148s - loss: 0.3617 - acc: 0.8605 - val_loss: 0.6406 - val_acc: 0.8221
    2019-07-20 13:25:18,577 graeae.timers.timer end: Ended: 2019-07-20 13:25:18.577775
    I0720 13:25:18.577804 139935525873472 timer.py:77] Ended: 2019-07-20 13:25:18.577775
    2019-07-20 13:25:18,578 graeae.timers.timer end: Elapsed: 2:57:24.265775
    I0720 13:25:18.578630 139935525873472 timer.py:78] Elapsed: 2:57:24.265775
    
    data = pandas.read_csv("~/cats_vs_dogs_3.csv")
    print(tabulate(data[data.validation_accuracy>=0.89],
          headers="keys", tablefmt="orgtbl"))
    
      training_loss training_accuracy validation_loss validation_accuracy
    1 0.3059 0.8716 0.2927 0.8932
    5 0.3234 0.8633 0.2434 0.9054
    13 0.3369 0.8585 0.2702 0.8908
    14 0.3253 0.8624 0.236 0.8996
    18 0.3154 0.8658 0.2806 0.8914
    39 0.3631 0.8633 0.2939 0.8906
    40 0.3313 0.8592 0.2674 0.8918
    45 0.3091 0.8715 0.2864 0.8924
    51 0.3275 0.8627 0.2567 0.8926
    best_accuracy = data.validation_accuracy.max()
    best_loss = data.validation_loss.min()
    accuracy_index = data[data.validation_accuracy==best_accuracy].index[0]
    loss_index = data[data.validation_loss==best_loss].index[0]
    
    print(f"Highest Accuracy: {best_accuracy} Epoch: {accuracy_index + 1}")
    print(f"Lowest Loss: {best_loss} Epoch: {loss_index}")
    
    Highest Accuracy: 0.9054 Epoch: 6
    Lowest Loss: 0.236 Epoch: 14
    
    line_1 = holoviews.VLine(accuracy_index, label="Best Accuracy Epoch")
    line_2 = holoviews.VLine(loss_index, label="Best Loss Epoch")
    accuracy_line = holoviews.HLine(best_accuracy, label="Highest Accuracy")
    loss_line = holoviews.HLine(best_loss, label="lowest Loss")
    
    curves = [holoviews.Curve(data, ("index", "Epoch"), "training_loss", 
                              label="Training Loss",),
              holoviews.Curve(data, ("index", "Epoch"), "training_accuracy", 
                              label="Training Accuracy").opts(tools=["hover"]),
              holoviews.Curve(data, ("index", "Epoch"), "validation_loss", 
                              label="Validation Loss",).opts(tools=["hover"]),
              holoviews.Curve(data, ("index", "Epoch"), "validation_accuracy", 
                              label="Validation Accuracy").opts(tools=["hover"]),
              line_1, line_2, accuracy_line, loss_line]
    plot = holoviews.Overlay(curves).opts(tools=["hover"], height=800, width=1000, 
                                          ylabel="Performance", 
                                          title="Training vs Validation")
    Embed(plot=plot, file_name="training_validation_loss_13")()
    

    Figure Missing

    So, I'm not sure what to make of this. It looks like it did improve a little, but that it peaked early on, and yet kept rising back up to a high level of validation accuracy. Is it overfitting or not? I guess I'll train it some more and find out.

    with TIMER:
        network.train()
    
    2019-07-20 13:37:51,641 graeae.timers.timer start: Started: 2019-07-20 13:37:51.641628
    I0720 13:37:51.641655 139935525873472 timer.py:70] Started: 2019-07-20 13:37:51.641628
    Epoch 1/100
    312/312 - 152s - loss: 0.3367 - acc: 0.8564 - val_loss: 0.4919 - val_acc: 0.7398
    Epoch 2/100
    312/312 - 152s - loss: 0.3354 - acc: 0.8538 - val_loss: 0.4213 - val_acc: 0.7724
    Epoch 3/100
    312/312 - 151s - loss: 0.3568 - acc: 0.8515 - val_loss: 0.4105 - val_acc: 0.8249
    Epoch 4/100
    312/312 - 152s - loss: 0.3413 - acc: 0.8557 - val_loss: 0.2920 - val_acc: 0.8850
    Epoch 5/100
    312/312 - 154s - loss: 0.3542 - acc: 0.8528 - val_loss: 0.2883 - val_acc: 0.8846
    Epoch 6/100
    312/312 - 153s - loss: 0.3494 - acc: 0.8558 - val_loss: 0.4051 - val_acc: 0.7983
    Epoch 7/100
    312/312 - 151s - loss: 0.3653 - acc: 0.8487 - val_loss: 0.3081 - val_acc: 0.8710
    Epoch 8/100
    312/312 - 152s - loss: 0.3699 - acc: 0.8447 - val_loss: 0.2843 - val_acc: 0.8882
    Epoch 9/100
    312/312 - 151s - loss: 0.8043 - acc: 0.8519 - val_loss: 0.3204 - val_acc: 0.8518
    Epoch 10/100
    312/312 - 151s - loss: 0.3429 - acc: 0.8528 - val_loss: 0.2779 - val_acc: 0.8796
    Epoch 11/100
    312/312 - 150s - loss: 0.3486 - acc: 0.8572 - val_loss: 0.3647 - val_acc: 0.8435
    Epoch 12/100
    312/312 - 149s - loss: 0.3324 - acc: 0.8572 - val_loss: 0.3560 - val_acc: 0.8602
    Epoch 13/100
    312/312 - 149s - loss: 0.3465 - acc: 0.8529 - val_loss: 0.3772 - val_acc: 0.8584
    Epoch 14/100
    312/312 - 148s - loss: 0.4045 - acc: 0.8446 - val_loss: 0.4425 - val_acc: 0.7360
    Epoch 15/100
    312/312 - 150s - loss: 6.0508 - acc: 0.8242 - val_loss: 0.3422 - val_acc: 0.8460
    Epoch 16/100
    312/312 - 150s - loss: 0.3486 - acc: 0.8495 - val_loss: 0.4366 - val_acc: 0.7712
    Epoch 17/100
    312/312 - 149s - loss: 0.3509 - acc: 0.8523 - val_loss: 0.2882 - val_acc: 0.8730
    Epoch 18/100
    312/312 - 149s - loss: 0.3509 - acc: 0.8513 - val_loss: 0.3403 - val_acc: 0.8508
    Epoch 19/100
    312/312 - 148s - loss: 0.3557 - acc: 0.8486 - val_loss: 0.2864 - val_acc: 0.8886
    Epoch 20/100
    312/312 - 148s - loss: 0.3596 - acc: 0.8491 - val_loss: 0.3974 - val_acc: 0.7899
    Epoch 21/100
    312/312 - 149s - loss: 0.3630 - acc: 0.8465 - val_loss: 0.3558 - val_acc: 0.8482
    Epoch 22/100
    312/312 - 149s - loss: 0.3745 - acc: 0.8441 - val_loss: 0.2867 - val_acc: 0.8870
    Epoch 23/100
    312/312 - 148s - loss: 0.3749 - acc: 0.8490 - val_loss: 0.2815 - val_acc: 0.8806
    Epoch 24/100
    312/312 - 149s - loss: 0.5479 - acc: 0.8500 - val_loss: 0.3382 - val_acc: 0.8830
    Epoch 25/100
    312/312 - 148s - loss: 0.3600 - acc: 0.8485 - val_loss: 0.5508 - val_acc: 0.6703
    Epoch 26/100
    312/312 - 148s - loss: 0.3494 - acc: 0.8533 - val_loss: 0.4929 - val_acc: 0.7678
    Epoch 27/100
    312/312 - 148s - loss: 0.3487 - acc: 0.8493 - val_loss: 0.3008 - val_acc: 0.8728
    Epoch 28/100
    312/312 - 148s - loss: 0.3657 - acc: 0.8483 - val_loss: 0.3355 - val_acc: 0.8668
    Epoch 29/100
    312/312 - 148s - loss: 0.3730 - acc: 0.8422 - val_loss: 0.7513 - val_acc: 0.7348
    Epoch 30/100
    312/312 - 148s - loss: 0.3703 - acc: 0.8477 - val_loss: 0.3497 - val_acc: 0.8558
    Epoch 31/100
    312/312 - 148s - loss: 0.3626 - acc: 0.8453 - val_loss: 0.2778 - val_acc: 0.8940
    Epoch 32/100
    312/312 - 148s - loss: 0.3627 - acc: 0.8470 - val_loss: 0.2933 - val_acc: 0.8768
    Epoch 33/100
    312/312 - 148s - loss: 0.4131 - acc: 0.8341 - val_loss: 0.3067 - val_acc: 0.8698
    Epoch 34/100
    312/312 - 149s - loss: 0.3766 - acc: 0.8491 - val_loss: 0.5967 - val_acc: 0.6657
    Epoch 35/100
    312/312 - 148s - loss: 0.5109 - acc: 0.8372 - val_loss: 0.3495 - val_acc: 0.8440
    Epoch 36/100
    312/312 - 148s - loss: 0.3736 - acc: 0.8472 - val_loss: 0.7757 - val_acc: 0.7460
    Epoch 37/100
    312/312 - 149s - loss: 0.3557 - acc: 0.8509 - val_loss: 0.3210 - val_acc: 0.8726
    Epoch 38/100
    312/312 - 149s - loss: 0.3841 - acc: 0.8386 - val_loss: 0.2899 - val_acc: 0.8640
    Epoch 39/100
    312/312 - 149s - loss: 0.4163 - acc: 0.8462 - val_loss: 0.4341 - val_acc: 0.7977
    Epoch 40/100
    312/312 - 148s - loss: 0.3674 - acc: 0.8446 - val_loss: 0.5823 - val_acc: 0.8526
    Epoch 41/100
    312/312 - 148s - loss: 0.3612 - acc: 0.8510 - val_loss: 0.2640 - val_acc: 0.8804
    Epoch 42/100
    312/312 - 149s - loss: 0.3752 - acc: 0.8491 - val_loss: 0.4750 - val_acc: 0.7726
    Epoch 43/100
    312/312 - 149s - loss: 0.3563 - acc: 0.8424 - val_loss: 0.3072 - val_acc: 0.8810
    Epoch 44/100
    312/312 - 149s - loss: 0.3587 - acc: 0.8474 - val_loss: 0.3906 - val_acc: 0.8866
    Epoch 45/100
    312/312 - 149s - loss: 0.3615 - acc: 0.8461 - val_loss: 0.5745 - val_acc: 0.7776
    Epoch 46/100
    312/312 - 149s - loss: 0.4017 - acc: 0.8384 - val_loss: 0.3786 - val_acc: 0.8722
    Epoch 47/100
    312/312 - 149s - loss: 0.3969 - acc: 0.8383 - val_loss: 0.4942 - val_acc: 0.7286
    Epoch 48/100
    312/312 - 148s - loss: 0.3628 - acc: 0.8395 - val_loss: 0.3358 - val_acc: 0.8606
    Epoch 49/100
    312/312 - 149s - loss: 0.3804 - acc: 0.8353 - val_loss: 0.3131 - val_acc: 0.8698
    Epoch 50/100
    312/312 - 150s - loss: 0.3997 - acc: 0.8378 - val_loss: 0.4310 - val_acc: 0.7873
    Epoch 51/100
    312/312 - 152s - loss: 0.3905 - acc: 0.8364 - val_loss: 0.3262 - val_acc: 0.8750
    Epoch 52/100
    312/312 - 151s - loss: 0.4109 - acc: 0.8449 - val_loss: 0.7448 - val_acc: 0.7512
    Epoch 53/100
    312/312 - 150s - loss: 0.3737 - acc: 0.8426 - val_loss: 0.3926 - val_acc: 0.8317
    Epoch 54/100
    312/312 - 148s - loss: 0.3573 - acc: 0.8420 - val_loss: 0.3395 - val_acc: 0.8516
    Epoch 55/100
    312/312 - 149s - loss: 0.3886 - acc: 0.8314 - val_loss: 0.3221 - val_acc: 0.8423
    Epoch 56/100
    312/312 - 149s - loss: 0.3991 - acc: 0.8325 - val_loss: 0.4920 - val_acc: 0.8243
    Epoch 57/100
    312/312 - 149s - loss: 0.3845 - acc: 0.8332 - val_loss: 0.3332 - val_acc: 0.8518
    Epoch 58/100
    312/312 - 149s - loss: 0.3764 - acc: 0.8336 - val_loss: 0.5819 - val_acc: 0.7029
    Epoch 59/100
    312/312 - 149s - loss: 0.4083 - acc: 0.8326 - val_loss: 0.3206 - val_acc: 0.8494
    Epoch 60/100
    312/312 - 149s - loss: 0.4010 - acc: 0.8372 - val_loss: 1.2613 - val_acc: 0.6791
    Epoch 61/100
    312/312 - 149s - loss: 0.4093 - acc: 0.8316 - val_loss: 0.4272 - val_acc: 0.7905
    Epoch 62/100
    312/312 - 149s - loss: 0.4389 - acc: 0.8319 - val_loss: 0.3596 - val_acc: 0.8486
    Epoch 63/100
    312/312 - 148s - loss: 0.4066 - acc: 0.8385 - val_loss: 0.3253 - val_acc: 0.8774
    Epoch 64/100
    312/312 - 148s - loss: 0.4000 - acc: 0.8325 - val_loss: 0.3190 - val_acc: 0.8920
    Epoch 65/100
    312/312 - 149s - loss: 0.3924 - acc: 0.8355 - val_loss: 0.5483 - val_acc: 0.6829
    Epoch 66/100
    312/312 - 150s - loss: 0.4344 - acc: 0.8272 - val_loss: 0.4520 - val_acc: 0.7971
    Epoch 67/100
    312/312 - 150s - loss: 0.3973 - acc: 0.8338 - val_loss: 0.2962 - val_acc: 0.8770
    Epoch 68/100
    312/312 - 150s - loss: 0.3868 - acc: 0.8299 - val_loss: 0.3322 - val_acc: 0.8510
    Epoch 69/100
    312/312 - 150s - loss: 0.4051 - acc: 0.8243 - val_loss: 0.4731 - val_acc: 0.8295
    Epoch 70/100
    312/312 - 150s - loss: 0.4241 - acc: 0.8228 - val_loss: 0.3180 - val_acc: 0.8682
    Epoch 71/100
    TimedStop: Training out of time (Elapsed = 2:56:41.032776)
    TimedStop: Longest Epoch = 2:56:41.032776
    312/312 - 149s - loss: 0.4185 - acc: 0.8227 - val_loss: 0.3691 - val_acc: 0.8041
    2019-07-20 16:34:32,739 graeae.timers.timer end: Ended: 2019-07-20 16:34:32.739264
    I0720 16:34:32.739288 139935525873472 timer.py:77] Ended: 2019-07-20 16:34:32.739264
    2019-07-20 16:34:32,740 graeae.timers.timer end: Elapsed: 2:56:41.097636
    I0720 16:34:32.740128 139935525873472 timer.py:78] Elapsed: 2:56:41.097636
    
    data = pandas.read_csv("~/cats_vs_dogs_4.csv")
    print(tabulate(data[data.validation_accuracy>=0.89],
          headers="keys", tablefmt="orgtbl"))
    
      training_loss training_accuracy validation_loss validation_accuracy
    30 0.3626 0.8453 0.2778 0.894
    63 0.4 0.8325 0.319 0.892

    So, we don't see a lot of degradation, but we also don't see much improvement.

    best_accuracy = data.validation_accuracy.max()
    best_loss = data.validation_loss.min()
    accuracy_index = data[data.validation_accuracy==best_accuracy].index[0]
    loss_index = data[data.validation_loss==best_loss].index[0]
    
    print(f"Highest Accuracy: {best_accuracy} Epoch: {accuracy_index + 1}")
    print(f"Lowest Loss: {best_loss} Epoch: {loss_index}")
    
    Highest Accuracy: 0.894 Epoch: 31
    Lowest Loss: 0.264 Epoch: 40
    
    line_1 = holoviews.VLine(accuracy_index, label="Best Accuracy Epoch")
    line_2 = holoviews.VLine(loss_index, label="Best Loss Epoch")
    accuracy_line = holoviews.HLine(best_accuracy, label="Highest Accuracy")
    loss_line = holoviews.HLine(best_loss, label="lowest Loss")
    
    curves = [holoviews.Curve(data, ("index", "Epoch"), "training_loss", 
                              label="Training Loss",),
              holoviews.Curve(data, ("index", "Epoch"), "training_accuracy", 
                              label="Training Accuracy").opts(tools=["hover"]),
              holoviews.Curve(data, ("index", "Epoch"), "validation_loss", 
                              label="Validation Loss",).opts(tools=["hover"]),
              holoviews.Curve(data, ("index", "Epoch"), "validation_accuracy", 
                              label="Validation Accuracy").opts(tools=["hover"]),
              line_1, line_2, accuracy_line, loss_line]
    plot = holoviews.Overlay(curves).opts(tools=["hover"], height=800, width=1000, 
                                          ylabel="Performance", 
                                          title="Training vs Validation")
    Embed(plot=plot, file_name="training_validation_loss_13")()
    

    Figure Missing

Take Fourteen

Okay, I'm going to say tha 90 % is our target.

saver = partial(save_model, path=path)
good_enough = Stop(call_on_stopping=saver,
                   minimum_accuracy=0.9)

network = Network(str(training_path), 
                  callbacks=[good_enough],
                  convolution_layers=5,
                  set_steps = True,
                  epochs = 100,
                  batch_size=128)
print(str(network))
with TIMER:
    network.train()
2019-07-20 18:21:55,292 graeae.timers.timer start: Started: 2019-07-20 18:21:55.292917
I0720 18:21:55.292948 139935525873472 timer.py:70] Started: 2019-07-20 18:21:55.292917
(Network) - 
Path: /home/athena/data/datasets/images/dogs-vs-cats/train
 Epochs: 100
 Batch Size: 128
 Callbacks: [<__main__.Stop object at 0x7f440c04d518>]
Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 128
Callbacks: [<__main__.Stop object at 0x7f440c04d518>]
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
Epoch 1/100
156/156 - 158s - loss: 0.7231 - acc: 0.5330 - val_loss: 0.6808 - val_acc: 0.5960
Epoch 2/100
156/156 - 158s - loss: 0.6639 - acc: 0.6077 - val_loss: 0.6349 - val_acc: 0.6396
Epoch 3/100
156/156 - 157s - loss: 0.6362 - acc: 0.6355 - val_loss: 0.6278 - val_acc: 0.6306
Epoch 4/100
156/156 - 158s - loss: 0.6144 - acc: 0.6669 - val_loss: 0.6162 - val_acc: 0.6522
Epoch 5/100
156/156 - 157s - loss: 0.5877 - acc: 0.6917 - val_loss: 0.5351 - val_acc: 0.7424
Epoch 6/100
156/156 - 152s - loss: 0.5736 - acc: 0.7032 - val_loss: 0.5579 - val_acc: 0.7125
Epoch 7/100
156/156 - 152s - loss: 0.5476 - acc: 0.7265 - val_loss: 0.5104 - val_acc: 0.7510
Epoch 8/100
156/156 - 151s - loss: 0.5268 - acc: 0.7372 - val_loss: 0.4760 - val_acc: 0.7692
Epoch 9/100
156/156 - 150s - loss: 0.5057 - acc: 0.7574 - val_loss: 0.4546 - val_acc: 0.7800
Epoch 10/100
156/156 - 149s - loss: 0.4862 - acc: 0.7667 - val_loss: 0.4432 - val_acc: 0.7987
Epoch 11/100
156/156 - 149s - loss: 0.4697 - acc: 0.7787 - val_loss: 0.4413 - val_acc: 0.7941
Epoch 12/100
156/156 - 151s - loss: 0.4419 - acc: 0.7924 - val_loss: 0.5044 - val_acc: 0.7454
Epoch 13/100
156/156 - 150s - loss: 0.4204 - acc: 0.8046 - val_loss: 0.4150 - val_acc: 0.8059
Epoch 14/100
156/156 - 150s - loss: 0.4038 - acc: 0.8155 - val_loss: 0.3776 - val_acc: 0.8245
Epoch 15/100
156/156 - 149s - loss: 0.3849 - acc: 0.8244 - val_loss: 0.4047 - val_acc: 0.8033
Epoch 16/100
156/156 - 149s - loss: 0.3745 - acc: 0.8311 - val_loss: 0.6245 - val_acc: 0.6635
Epoch 17/100
156/156 - 150s - loss: 0.3556 - acc: 0.8410 - val_loss: 0.3274 - val_acc: 0.8544
Epoch 18/100
156/156 - 150s - loss: 0.3434 - acc: 0.8447 - val_loss: 0.3143 - val_acc: 0.8606
Epoch 19/100
156/156 - 150s - loss: 0.3356 - acc: 0.8473 - val_loss: 0.3181 - val_acc: 0.8600
Epoch 20/100
156/156 - 148s - loss: 0.3295 - acc: 0.8551 - val_loss: 0.3042 - val_acc: 0.8630
Epoch 21/100
156/156 - 150s - loss: 0.3165 - acc: 0.8612 - val_loss: 0.2961 - val_acc: 0.8668
Epoch 22/100
156/156 - 149s - loss: 0.3060 - acc: 0.8650 - val_loss: 0.3530 - val_acc: 0.8484
Epoch 23/100
156/156 - 148s - loss: 0.3062 - acc: 0.8659 - val_loss: 0.3327 - val_acc: 0.8494
Epoch 24/100
156/156 - 150s - loss: 0.2942 - acc: 0.8725 - val_loss: 0.2533 - val_acc: 0.8944
Epoch 25/100
156/156 - 150s - loss: 0.2897 - acc: 0.8712 - val_loss: 0.3440 - val_acc: 0.8458
Epoch 26/100
156/156 - 149s - loss: 0.2829 - acc: 0.8769 - val_loss: 0.2627 - val_acc: 0.8842
Epoch 27/100
156/156 - 150s - loss: 0.2691 - acc: 0.8836 - val_loss: 0.2857 - val_acc: 0.8840
Epoch 28/100
156/156 - 149s - loss: 0.2814 - acc: 0.8780 - val_loss: 0.2717 - val_acc: 0.8800
Epoch 29/100
156/156 - 150s - loss: 0.2632 - acc: 0.8826 - val_loss: 0.3521 - val_acc: 0.8584
Epoch 30/100
156/156 - 150s - loss: 0.2652 - acc: 0.8868 - val_loss: 0.2736 - val_acc: 0.8872
Epoch 31/100
156/156 - 148s - loss: 0.2591 - acc: 0.8875 - val_loss: 0.2842 - val_acc: 0.8782
Epoch 32/100
156/156 - 150s - loss: 0.2569 - acc: 0.8851 - val_loss: 0.2657 - val_acc: 0.9014
Epoch 33/100
156/156 - 149s - loss: 0.2623 - acc: 0.8866 - val_loss: 0.2539 - val_acc: 0.8894
Epoch 34/100
156/156 - 150s - loss: 0.2564 - acc: 0.8893 - val_loss: 0.3088 - val_acc: 0.8606
Epoch 35/100
156/156 - 151s - loss: 0.2496 - acc: 0.8924 - val_loss: 0.2415 - val_acc: 0.8996
Epoch 36/100
156/156 - 147s - loss: 0.2459 - acc: 0.8918 - val_loss: 0.2661 - val_acc: 0.8816
Epoch 37/100
156/156 - 147s - loss: 0.2473 - acc: 0.8939 - val_loss: 0.2842 - val_acc: 0.8826
Epoch 38/100
156/156 - 146s - loss: 0.2418 - acc: 0.8948 - val_loss: 0.2875 - val_acc: 0.8864
Epoch 39/100
156/156 - 145s - loss: 0.2502 - acc: 0.8924 - val_loss: 0.2174 - val_acc: 0.9089
Epoch 40/100
156/156 - 146s - loss: 0.2416 - acc: 0.8966 - val_loss: 0.2251 - val_acc: 0.9058
Epoch 41/100
156/156 - 147s - loss: 0.2489 - acc: 0.8934 - val_loss: 0.2548 - val_acc: 0.8958
Epoch 42/100
156/156 - 150s - loss: 0.2341 - acc: 0.9011 - val_loss: 0.2150 - val_acc: 0.9065
Epoch 43/100
156/156 - 151s - loss: 0.2400 - acc: 0.9011 - val_loss: 0.2103 - val_acc: 0.9131
Epoch 44/100
156/156 - 150s - loss: 0.2340 - acc: 0.8990 - val_loss: 0.6287 - val_acc: 0.7945
Epoch 45/100
156/156 - 150s - loss: 0.2359 - acc: 0.8981 - val_loss: 0.2213 - val_acc: 0.9131
Epoch 46/100
156/156 - 150s - loss: 0.2277 - acc: 0.9034 - val_loss: 0.2491 - val_acc: 0.8920
Epoch 47/100
156/156 - 151s - loss: 0.2433 - acc: 0.8946 - val_loss: 0.2540 - val_acc: 0.8990
Epoch 48/100
156/156 - 145s - loss: 0.2354 - acc: 0.9000 - val_loss: 0.3256 - val_acc: 0.8464
Epoch 49/100
156/156 - 146s - loss: 0.2374 - acc: 0.8994 - val_loss: 0.2516 - val_acc: 0.8932
Epoch 50/100
156/156 - 145s - loss: 0.2335 - acc: 0.8997 - val_loss: 0.2138 - val_acc: 0.9127
Epoch 51/100
156/156 - 145s - loss: 0.2283 - acc: 0.9040 - val_loss: 0.2800 - val_acc: 0.9087
Epoch 52/100
156/156 - 146s - loss: 0.2367 - acc: 0.8992 - val_loss: 0.2279 - val_acc: 0.9113
Epoch 53/100
156/156 - 146s - loss: 0.2316 - acc: 0.9008 - val_loss: 0.2157 - val_acc: 0.9123
Epoch 54/100
156/156 - 146s - loss: 0.2236 - acc: 0.9059 - val_loss: 0.2653 - val_acc: 0.8946
Epoch 55/100
156/156 - 145s - loss: 0.2348 - acc: 0.8993 - val_loss: 0.2310 - val_acc: 0.9077
Epoch 56/100
156/156 - 144s - loss: 0.2383 - acc: 0.8982 - val_loss: 0.3550 - val_acc: 0.8544
Epoch 57/100
156/156 - 147s - loss: 0.2292 - acc: 0.9028 - val_loss: 0.2356 - val_acc: 0.9095
Epoch 58/100
156/156 - 146s - loss: 0.2315 - acc: 0.9042 - val_loss: 0.2088 - val_acc: 0.9163
Epoch 59/100
156/156 - 146s - loss: 0.2256 - acc: 0.9037 - val_loss: 0.4032 - val_acc: 0.8149
Epoch 60/100
156/156 - 145s - loss: 0.2302 - acc: 0.9024 - val_loss: 0.2611 - val_acc: 0.8918
Epoch 61/100
156/156 - 144s - loss: 0.2227 - acc: 0.9048 - val_loss: 0.2068 - val_acc: 0.9103
Epoch 62/100
156/156 - 145s - loss: 0.2353 - acc: 0.8988 - val_loss: 0.2446 - val_acc: 0.8862
Epoch 63/100
156/156 - 146s - loss: 0.2313 - acc: 0.9008 - val_loss: 0.2295 - val_acc: 0.9119
Epoch 64/100
156/156 - 144s - loss: 0.2237 - acc: 0.9042 - val_loss: 0.2193 - val_acc: 0.9179
Epoch 65/100
156/156 - 145s - loss: 0.2292 - acc: 0.9055 - val_loss: 0.2427 - val_acc: 0.8960
Epoch 66/100
156/156 - 145s - loss: 0.2353 - acc: 0.9015 - val_loss: 0.4461 - val_acc: 0.8035
Epoch 67/100
156/156 - 145s - loss: 0.2205 - acc: 0.9074 - val_loss: 0.2056 - val_acc: 0.9107
Epoch 68/100
156/156 - 145s - loss: 0.2257 - acc: 0.9035 - val_loss: 0.2528 - val_acc: 0.8846
Epoch 69/100
156/156 - 146s - loss: 0.2275 - acc: 0.9053 - val_loss: 0.2302 - val_acc: 0.9034
Epoch 70/100
156/156 - 144s - loss: 0.2261 - acc: 0.9032 - val_loss: 0.2248 - val_acc: 0.9107
Epoch 71/100
156/156 - 145s - loss: 0.2280 - acc: 0.9005 - val_loss: 0.2289 - val_acc: 0.9060
Epoch 72/100
156/156 - 145s - loss: 0.2276 - acc: 0.9070 - val_loss: 0.2604 - val_acc: 0.8960
Epoch 73/100
156/156 - 145s - loss: 0.2312 - acc: 0.9032 - val_loss: 0.2774 - val_acc: 0.8874
Epoch 74/100
156/156 - 145s - loss: 0.2249 - acc: 0.9062 - val_loss: 0.2025 - val_acc: 0.9173
Epoch 75/100
156/156 - 145s - loss: 0.2332 - acc: 0.9044 - val_loss: 0.2055 - val_acc: 0.9151
Epoch 76/100
156/156 - 145s - loss: 0.2238 - acc: 0.9065 - val_loss: 0.2933 - val_acc: 0.8954
Epoch 77/100
156/156 - 145s - loss: 0.2312 - acc: 0.9021 - val_loss: 0.2556 - val_acc: 0.8940
Epoch 78/100
156/156 - 145s - loss: 0.2186 - acc: 0.9070 - val_loss: 0.1914 - val_acc: 0.9217
Epoch 79/100
156/156 - 146s - loss: 0.2315 - acc: 0.9055 - val_loss: 0.2192 - val_acc: 0.9087
Epoch 80/100
156/156 - 145s - loss: 0.2264 - acc: 0.9039 - val_loss: 0.2494 - val_acc: 0.8862
Epoch 81/100
156/156 - 145s - loss: 0.2209 - acc: 0.9086 - val_loss: 0.2026 - val_acc: 0.9185
Epoch 82/100
156/156 - 145s - loss: 0.2356 - acc: 0.9026 - val_loss: 0.2011 - val_acc: 0.9163
Epoch 83/100
156/156 - 144s - loss: 0.2236 - acc: 0.9059 - val_loss: 0.1996 - val_acc: 0.9229
Epoch 84/100
156/156 - 145s - loss: 0.2277 - acc: 0.9023 - val_loss: 0.2071 - val_acc: 0.9157
Epoch 85/100
156/156 - 145s - loss: 0.2365 - acc: 0.9053 - val_loss: 0.2343 - val_acc: 0.9115
Epoch 86/100
156/156 - 145s - loss: 0.2237 - acc: 0.9026 - val_loss: 0.2111 - val_acc: 0.9187
Epoch 87/100
156/156 - 144s - loss: 0.2285 - acc: 0.9022 - val_loss: 0.1987 - val_acc: 0.9167
Epoch 88/100
156/156 - 146s - loss: 0.2390 - acc: 0.8996 - val_loss: 0.2169 - val_acc: 0.9069
Epoch 89/100
156/156 - 144s - loss: 0.2478 - acc: 0.9030 - val_loss: 0.2021 - val_acc: 0.9195
Epoch 90/100
156/156 - 146s - loss: 0.2221 - acc: 0.9037 - val_loss: 0.3306 - val_acc: 0.8758
Epoch 91/100
156/156 - 146s - loss: 0.2342 - acc: 0.9005 - val_loss: 0.3883 - val_acc: 0.8183
Epoch 92/100
156/156 - 145s - loss: 0.2286 - acc: 0.9052 - val_loss: 0.2461 - val_acc: 0.8920
Epoch 93/100
156/156 - 146s - loss: 0.2260 - acc: 0.9060 - val_loss: 0.2327 - val_acc: 0.9155
Epoch 94/100
156/156 - 144s - loss: 0.2391 - acc: 0.9017 - val_loss: 0.2106 - val_acc: 0.9151
Epoch 95/100
156/156 - 145s - loss: 0.2320 - acc: 0.9008 - val_loss: 0.2006 - val_acc: 0.9217
Epoch 96/100
156/156 - 146s - loss: 0.2305 - acc: 0.9044 - val_loss: 0.2095 - val_acc: 0.9129
Epoch 97/100
156/156 - 145s - loss: 0.2312 - acc: 0.9029 - val_loss: 0.2112 - val_acc: 0.9123
Epoch 98/100
156/156 - 145s - loss: 0.2214 - acc: 0.9055 - val_loss: 0.1963 - val_acc: 0.9203
Epoch 99/100
156/156 - 144s - loss: 0.2364 - acc: 0.9029 - val_loss: 0.2055 - val_acc: 0.9085
Epoch 100/100
156/156 - 146s - loss: 0.2198 - acc: 0.9074 - val_loss: 0.2404 - val_acc: 0.9006
2019-07-20 22:27:48,713 graeae.timers.timer end: Ended: 2019-07-20 22:27:48.713962
I0720 22:27:48.713997 139935525873472 timer.py:77] Ended: 2019-07-20 22:27:48.713962
2019-07-20 22:27:48,714 graeae.timers.timer end: Elapsed: 4:05:53.421045
I0720 22:27:48.714990 139935525873472 timer.py:78] Elapsed: 4:05:53.421045

So, two things to notice. One is that it did even better than I thought it would, the other is that it didn't stop. The fact that it didn't stop is beacuse I was assiging Stop.on_epoch_end to Stop.on_epoch_end instead of assigning Stop.on_end_handler (so Stop.on_end_handler was never called). Hopefully I fixed it.

Take Fifteen

I originally set this up with a batch-size of 256 and no callbacks and then had to kill it because it hadn't stopped by the next morning when I had to go to work. That's probably something to be dealt with when training a real model, but in this case I'm just doing an exercise, so I'll try it with 256 and the have it time-out after 8 hours.

network = Network(str(training_path), 
                  convolution_layers=5,
                  set_steps = True,
                  epochs = 100,
                  batch_size=256)
print(str(network))
with TIMER:
    network.train()
2019-07-22 22:29:32,865 graeae.timers.timer start: Started: 2019-07-22 22:29:32.865426
I0722 22:29:32.865622 140052197230400 timer.py:70] Started: 2019-07-22 22:29:32.865426
(Network) - 
Path: /home/athena/data/datasets/images/dogs-vs-cats/train
 Epochs: 100
 Batch Size: 256
 Callbacks: None
Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 256
Callbacks: None
Found 20000 images belonging to 2 classes.
Found 5000 images belonging to 2 classes.
W0722 22:29:33.512133 140052197230400 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
W0722 22:29:33.928766 140052197230400 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
Epoch 1/100
78/78 - 429s - loss: 0.6963 - acc: 0.5277 - val_loss: 0.6838 - val_acc: 0.6053
Epoch 2/100
78/78 - 152s - loss: 0.6823 - acc: 0.5664 - val_loss: 0.7476 - val_acc: 0.5107
Epoch 3/100
78/78 - 152s - loss: 0.6827 - acc: 0.6109 - val_loss: 0.6231 - val_acc: 0.6567
Epoch 4/100
78/78 - 154s - loss: 0.6475 - acc: 0.6241 - val_loss: 0.6528 - val_acc: 0.6182
Epoch 5/100
78/78 - 155s - loss: 0.6304 - acc: 0.6465 - val_loss: 0.5851 - val_acc: 0.6846
Epoch 6/100
78/78 - 155s - loss: 0.6161 - acc: 0.6607 - val_loss: 0.5997 - val_acc: 0.6780
Epoch 7/100
78/78 - 149s - loss: 0.5978 - acc: 0.6828 - val_loss: 0.5866 - val_acc: 0.6748
Epoch 8/100
78/78 - 150s - loss: 0.5883 - acc: 0.6894 - val_loss: 0.5663 - val_acc: 0.7079
Epoch 9/100
78/78 - 149s - loss: 0.5803 - acc: 0.6977 - val_loss: 0.6254 - val_acc: 0.6332
Epoch 10/100
78/78 - 147s - loss: 0.5617 - acc: 0.7119 - val_loss: 0.5867 - val_acc: 0.6865
Epoch 11/100
78/78 - 146s - loss: 0.5559 - acc: 0.7217 - val_loss: 0.5812 - val_acc: 0.6959
Epoch 12/100
78/78 - 141s - loss: 0.5521 - acc: 0.7208 - val_loss: 0.5157 - val_acc: 0.7605
Epoch 13/100
78/78 - 143s - loss: 0.5440 - acc: 0.7283 - val_loss: 0.5218 - val_acc: 0.7541
Epoch 14/100
78/78 - 143s - loss: 0.5225 - acc: 0.7407 - val_loss: 0.4998 - val_acc: 0.7593
Epoch 15/100
78/78 - 142s - loss: 0.5044 - acc: 0.7538 - val_loss: 0.4718 - val_acc: 0.7695
Epoch 16/100
78/78 - 141s - loss: 0.4946 - acc: 0.7607 - val_loss: 0.5743 - val_acc: 0.6912
Epoch 17/100
78/78 - 141s - loss: 0.4643 - acc: 0.7780 - val_loss: 0.4124 - val_acc: 0.8156
Epoch 18/100
78/78 - 142s - loss: 0.4480 - acc: 0.7894 - val_loss: 0.4762 - val_acc: 0.7593
Epoch 19/100
78/78 - 143s - loss: 0.4426 - acc: 0.7880 - val_loss: 0.4288 - val_acc: 0.8074
Epoch 20/100
78/78 - 141s - loss: 0.4271 - acc: 0.8006 - val_loss: 0.3893 - val_acc: 0.8248
Epoch 21/100
78/78 - 142s - loss: 0.4111 - acc: 0.8073 - val_loss: 0.3602 - val_acc: 0.8355
Epoch 22/100
78/78 - 144s - loss: 0.4066 - acc: 0.8094 - val_loss: 0.3546 - val_acc: 0.8403
Epoch 23/100
78/78 - 143s - loss: 0.3927 - acc: 0.8160 - val_loss: 0.3536 - val_acc: 0.8368
Epoch 24/100
78/78 - 138s - loss: 0.3839 - acc: 0.8228 - val_loss: 0.3409 - val_acc: 0.8481
Epoch 25/100
78/78 - 141s - loss: 0.3704 - acc: 0.8290 - val_loss: 0.3364 - val_acc: 0.8514
Epoch 26/100
78/78 - 141s - loss: 0.3633 - acc: 0.8362 - val_loss: 0.3329 - val_acc: 0.8577
Epoch 27/100
78/78 - 142s - loss: 0.3434 - acc: 0.8447 - val_loss: 0.3131 - val_acc: 0.8670
Epoch 28/100
78/78 - 142s - loss: 0.3481 - acc: 0.8401 - val_loss: 0.3515 - val_acc: 0.8433
Epoch 29/100
78/78 - 142s - loss: 0.3225 - acc: 0.8555 - val_loss: 0.4498 - val_acc: 0.8049
Epoch 30/100
78/78 - 142s - loss: 0.3280 - acc: 0.8482 - val_loss: 0.3338 - val_acc: 0.8475
Epoch 31/100
78/78 - 144s - loss: 0.3252 - acc: 0.8534 - val_loss: 0.3694 - val_acc: 0.8339
Epoch 32/100
78/78 - 142s - loss: 0.3232 - acc: 0.8524 - val_loss: 0.3124 - val_acc: 0.8571
Epoch 33/100
78/78 - 142s - loss: 0.3011 - acc: 0.8619 - val_loss: 0.3094 - val_acc: 0.8657
Epoch 34/100
78/78 - 143s - loss: 0.2908 - acc: 0.8702 - val_loss: 0.3324 - val_acc: 0.8540
Epoch 35/100
78/78 - 140s - loss: 0.2943 - acc: 0.8697 - val_loss: 0.2880 - val_acc: 0.8717
Epoch 36/100
78/78 - 142s - loss: 0.2848 - acc: 0.8707 - val_loss: 0.2671 - val_acc: 0.8894
Epoch 37/100
78/78 - 143s - loss: 0.2783 - acc: 0.8774 - val_loss: 0.2870 - val_acc: 0.8756
Epoch 38/100
78/78 - 141s - loss: 0.2876 - acc: 0.8750 - val_loss: 0.2666 - val_acc: 0.8855
Epoch 39/100
78/78 - 139s - loss: 0.2729 - acc: 0.8790 - val_loss: 0.2557 - val_acc: 0.8914
Epoch 40/100
78/78 - 137s - loss: 0.2667 - acc: 0.8809 - val_loss: 0.2424 - val_acc: 0.8929
Epoch 41/100
78/78 - 137s - loss: 0.2626 - acc: 0.8824 - val_loss: 0.2746 - val_acc: 0.8820
Epoch 42/100
78/78 - 135s - loss: 0.2515 - acc: 0.8925 - val_loss: 0.2525 - val_acc: 0.8912
Epoch 43/100
78/78 - 137s - loss: 0.2487 - acc: 0.8905 - val_loss: 0.2516 - val_acc: 0.8956
Epoch 44/100
78/78 - 137s - loss: 0.2544 - acc: 0.8856 - val_loss: 0.2444 - val_acc: 0.8914
Epoch 45/100
78/78 - 138s - loss: 0.2484 - acc: 0.8899 - val_loss: 0.2727 - val_acc: 0.8785
Epoch 46/100
78/78 - 135s - loss: 0.2447 - acc: 0.8919 - val_loss: 0.2385 - val_acc: 0.9032
Epoch 47/100
78/78 - 138s - loss: 0.2349 - acc: 0.8973 - val_loss: 0.2296 - val_acc: 0.8999
Epoch 48/100
78/78 - 137s - loss: 0.2324 - acc: 0.8966 - val_loss: 0.2772 - val_acc: 0.8843
Epoch 49/100
78/78 - 136s - loss: 0.2383 - acc: 0.8948 - val_loss: 0.2698 - val_acc: 0.8820
Epoch 50/100
78/78 - 138s - loss: 0.2293 - acc: 0.9000 - val_loss: 0.2763 - val_acc: 0.8789
Epoch 51/100
78/78 - 137s - loss: 0.2300 - acc: 0.9006 - val_loss: 0.2231 - val_acc: 0.9060
Epoch 52/100
78/78 - 135s - loss: 0.2236 - acc: 0.9029 - val_loss: 0.2321 - val_acc: 0.9021
Epoch 53/100
78/78 - 137s - loss: 0.2256 - acc: 0.9012 - val_loss: 0.2229 - val_acc: 0.9075
Epoch 54/100
78/78 - 138s - loss: 0.2147 - acc: 0.9079 - val_loss: 0.2330 - val_acc: 0.9040
Epoch 55/100
78/78 - 137s - loss: 0.2192 - acc: 0.9066 - val_loss: 0.2390 - val_acc: 0.9040
Epoch 56/100
78/78 - 138s - loss: 0.2138 - acc: 0.9068 - val_loss: 0.2234 - val_acc: 0.9077
Epoch 57/100
78/78 - 137s - loss: 0.2115 - acc: 0.9078 - val_loss: 0.2734 - val_acc: 0.8810
Epoch 58/100
78/78 - 136s - loss: 0.2312 - acc: 0.8987 - val_loss: 0.2320 - val_acc: 0.9038
Epoch 59/100
78/78 - 138s - loss: 0.2054 - acc: 0.9129 - val_loss: 0.2188 - val_acc: 0.9120
Epoch 60/100
78/78 - 137s - loss: 0.2215 - acc: 0.9047 - val_loss: 0.2329 - val_acc: 0.9019
Epoch 61/100
78/78 - 137s - loss: 0.2088 - acc: 0.9087 - val_loss: 0.2357 - val_acc: 0.8937
Epoch 62/100
78/78 - 135s - loss: 0.2052 - acc: 0.9113 - val_loss: 0.2478 - val_acc: 0.8890
Epoch 63/100
78/78 - 138s - loss: 0.2013 - acc: 0.9138 - val_loss: 0.2079 - val_acc: 0.9134
Epoch 64/100
78/78 - 137s - loss: 0.2042 - acc: 0.9135 - val_loss: 0.2106 - val_acc: 0.9141
Epoch 65/100
78/78 - 137s - loss: 0.2036 - acc: 0.9122 - val_loss: 0.2266 - val_acc: 0.9054
Epoch 66/100
78/78 - 137s - loss: 0.1954 - acc: 0.9158 - val_loss: 0.2151 - val_acc: 0.9087
Epoch 67/100
78/78 - 137s - loss: 0.2013 - acc: 0.9125 - val_loss: 0.2062 - val_acc: 0.9116
Epoch 68/100
78/78 - 137s - loss: 0.1969 - acc: 0.9140 - val_loss: 0.2053 - val_acc: 0.9122
Epoch 69/100
78/78 - 137s - loss: 0.1944 - acc: 0.9152 - val_loss: 0.2159 - val_acc: 0.9112
Epoch 70/100
78/78 - 137s - loss: 0.1899 - acc: 0.9172 - val_loss: 0.2509 - val_acc: 0.8927
Epoch 71/100
78/78 - 137s - loss: 0.1966 - acc: 0.9187 - val_loss: 0.2110 - val_acc: 0.9128
Epoch 72/100
78/78 - 137s - loss: 0.1847 - acc: 0.9215 - val_loss: 0.2299 - val_acc: 0.9093
Epoch 73/100
78/78 - 137s - loss: 0.1838 - acc: 0.9227 - val_loss: 0.1841 - val_acc: 0.9278
Epoch 74/100
78/78 - 137s - loss: 0.1966 - acc: 0.9176 - val_loss: 0.2924 - val_acc: 0.8742
Epoch 75/100
78/78 - 138s - loss: 0.1842 - acc: 0.9220 - val_loss: 0.1932 - val_acc: 0.9223
Epoch 76/100
78/78 - 137s - loss: 0.1844 - acc: 0.9210 - val_loss: 0.2169 - val_acc: 0.9198
Epoch 77/100
78/78 - 137s - loss: 0.1906 - acc: 0.9219 - val_loss: 0.2597 - val_acc: 0.8818
Epoch 78/100
78/78 - 137s - loss: 0.1735 - acc: 0.9255 - val_loss: 0.1994 - val_acc: 0.9204
Epoch 79/100
78/78 - 137s - loss: 0.1826 - acc: 0.9230 - val_loss: 0.1862 - val_acc: 0.9245
Epoch 80/100
78/78 - 137s - loss: 0.1847 - acc: 0.9239 - val_loss: 0.2384 - val_acc: 0.9122
Epoch 81/100
78/78 - 152s - loss: 0.1843 - acc: 0.9226 - val_loss: 0.2039 - val_acc: 0.9151
Epoch 82/100
78/78 - 151s - loss: 0.1778 - acc: 0.9225 - val_loss: 0.2089 - val_acc: 0.9192
Epoch 83/100
78/78 - 150s - loss: 0.1765 - acc: 0.9225 - val_loss: 0.1998 - val_acc: 0.9134
Epoch 84/100
78/78 - 148s - loss: 0.1780 - acc: 0.9238 - val_loss: 0.1837 - val_acc: 0.9266
Epoch 85/100
78/78 - 147s - loss: 0.1739 - acc: 0.9259 - val_loss: 0.2011 - val_acc: 0.9204
Epoch 86/100
78/78 - 146s - loss: 0.1718 - acc: 0.9271 - val_loss: 0.1885 - val_acc: 0.9307
Epoch 87/100
78/78 - 144s - loss: 0.1775 - acc: 0.9242 - val_loss: 0.2126 - val_acc: 0.9213
Epoch 88/100
78/78 - 142s - loss: 0.1732 - acc: 0.9265 - val_loss: 0.1929 - val_acc: 0.9204
Epoch 89/100
78/78 - 141s - loss: 0.1773 - acc: 0.9242 - val_loss: 0.2050 - val_acc: 0.9243
Epoch 90/100
78/78 - 140s - loss: 0.1745 - acc: 0.9278 - val_loss: 0.2168 - val_acc: 0.9122
Epoch 91/100
78/78 - 139s - loss: 0.1802 - acc: 0.9214 - val_loss: 0.2263 - val_acc: 0.9079
Epoch 92/100
78/78 - 139s - loss: 0.1642 - acc: 0.9320 - val_loss: 0.2503 - val_acc: 0.9087
Epoch 93/100
78/78 - 136s - loss: 0.1705 - acc: 0.9285 - val_loss: 0.2184 - val_acc: 0.9126
Epoch 94/100
78/78 - 136s - loss: 0.1714 - acc: 0.9253 - val_loss: 0.2365 - val_acc: 0.9130
Epoch 95/100
78/78 - 136s - loss: 0.1678 - acc: 0.9305 - val_loss: 0.1882 - val_acc: 0.9231
Epoch 96/100
78/78 - 137s - loss: 0.1923 - acc: 0.9212 - val_loss: 0.1931 - val_acc: 0.9211
Epoch 97/100
78/78 - 136s - loss: 0.1574 - acc: 0.9335 - val_loss: 0.2011 - val_acc: 0.9215
Epoch 98/100
78/78 - 136s - loss: 0.1673 - acc: 0.9280 - val_loss: 0.2561 - val_acc: 0.9032
Epoch 99/100
78/78 - 137s - loss: 0.1670 - acc: 0.9304 - val_loss: 0.2018 - val_acc: 0.9180
Epoch 100/100
78/78 - 137s - loss: 0.1663 - acc: 0.9292 - val_loss: 0.2245 - val_acc: 0.9065
2019-07-23 02:29:24,212 graeae.timers.timer end: Ended: 2019-07-23 02:29:24.212763
I0723 02:29:24.212822 140052197230400 timer.py:77] Ended: 2019-07-23 02:29:24.212763
2019-07-23 02:29:24,214 graeae.timers.timer end: Elapsed: 3:59:51.347337
I0723 02:29:24.214272 140052197230400 timer.py:78] Elapsed: 3:59:51.347337
print(f"About {(4 * 60)/100} minutes per epoch")
About 2.4 minutes per epoch

So with a batch size of 256 it doesn't take an unreasonable amount of time to train.

data = pandas.read_csv("~/cats_vs_dogs_5.csv")
curves = [holoviews.Curve(data, ("index", "Epoch"), "training_loss", 
                          label="Training Loss",),
          holoviews.Curve(data, ("index", "Epoch"), "training_accuracy", 
                          label="Training Accuracy").opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_loss", 
                          label="Validation Loss",).opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_accuracy", 
                          label="Validation Accuracy").opts(tools=["hover"]),
]
plot = holoviews.Overlay(curves).opts(tools=["hover"], height=800, width=1000, 
                                      ylabel="Performance", 
                                      title="Training vs Validation")
Embed(plot=plot, file_name="training_validation_loss_5")()

Figure Missing

best_validation(data)
Best Accuracy: 0.9307 (loss=0.1885) Epoch: 85
Best Loss: 0.1837 (accuracy=0.9266, Epoch: 83)

The model is doing pretty good already. Unfortunately I didn't save the model before turning off my machineā€¦

Take Sixteen

network = Network(str(training_path), 
                  convolution_layers=5,
                  set_steps = True,
                  epochs = 100,
                  batch_size=256)
print(str(network))
with TIMER:
    network.train()

save_model(network.model, MODELS/"layers_5_batch_size_256.h5")
2019-07-27 11:17:39,023 graeae.timers.timer start: Started: 2019-07-27 11:17:39.023595
I0727 11:17:39.023817 140052539918144 timer.py:70] Started: 2019-07-27 11:17:39.023595
(Network) - 
Path: /home/athena/data/datasets/images/dogs-vs-cats/train
 Epochs: 100
 Batch Size: 256
 Callbacks: None
Data: (Data) - Path: /home/athena/data/datasets/images/dogs-vs-cats/train, Validation Split: 0.2,Batch Size: 256
Callbacks: None
Found 20000 images belonging to 2 classes.
W0727 11:17:39.640755 140052539918144 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
Found 5000 images belonging to 2 classes.
W0727 11:17:39.796763 140052539918144 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in 2.0, which has the same broadcast rule as np.where
Epoch 1/100
78/78 - 368s - loss: 0.6996 - acc: 0.5326 - val_loss: 0.6777 - val_acc: 0.5983
Epoch 2/100
78/78 - 235s - loss: 0.6823 - acc: 0.5713 - val_loss: 0.6554 - val_acc: 0.6205
Epoch 3/100
78/78 - 229s - loss: 0.6718 - acc: 0.5961 - val_loss: 0.6645 - val_acc: 0.5913
Epoch 4/100
78/78 - 229s - loss: 0.6458 - acc: 0.6334 - val_loss: 0.5993 - val_acc: 0.6822
Epoch 5/100
78/78 - 227s - loss: 0.6395 - acc: 0.6479 - val_loss: 0.5940 - val_acc: 0.6984
Epoch 6/100
78/78 - 234s - loss: 0.6139 - acc: 0.6639 - val_loss: 0.6270 - val_acc: 0.6340
Epoch 7/100
78/78 - 228s - loss: 0.6043 - acc: 0.6742 - val_loss: 0.5533 - val_acc: 0.7231
Epoch 8/100
78/78 - 228s - loss: 0.5862 - acc: 0.6912 - val_loss: 0.5496 - val_acc: 0.7243
Epoch 9/100
78/78 - 227s - loss: 0.5698 - acc: 0.7089 - val_loss: 0.5726 - val_acc: 0.7007
Epoch 10/100
78/78 - 230s - loss: 0.5673 - acc: 0.7010 - val_loss: 0.5106 - val_acc: 0.7432
Epoch 11/100
78/78 - 226s - loss: 0.5416 - acc: 0.7245 - val_loss: 0.5233 - val_acc: 0.7387
Epoch 12/100
78/78 - 230s - loss: 0.5411 - acc: 0.7306 - val_loss: 0.5489 - val_acc: 0.7132
Epoch 13/100
78/78 - 230s - loss: 0.5301 - acc: 0.7332 - val_loss: 0.5358 - val_acc: 0.7163
Epoch 14/100
78/78 - 225s - loss: 0.5200 - acc: 0.7432 - val_loss: 0.4981 - val_acc: 0.7463
Epoch 15/100
78/78 - 225s - loss: 0.5004 - acc: 0.7521 - val_loss: 0.4841 - val_acc: 0.7718
Epoch 16/100
78/78 - 226s - loss: 0.4934 - acc: 0.7590 - val_loss: 0.4679 - val_acc: 0.7640
Epoch 17/100
78/78 - 223s - loss: 0.4709 - acc: 0.7733 - val_loss: 0.6309 - val_acc: 0.7130
Epoch 18/100
78/78 - 224s - loss: 0.4722 - acc: 0.7707 - val_loss: 0.4204 - val_acc: 0.7983
Epoch 19/100
78/78 - 226s - loss: 0.4553 - acc: 0.7832 - val_loss: 0.4041 - val_acc: 0.8129
Epoch 20/100
78/78 - 222s - loss: 0.4325 - acc: 0.7968 - val_loss: 0.3785 - val_acc: 0.8326
Epoch 21/100
78/78 - 226s - loss: 0.4227 - acc: 0.8004 - val_loss: 0.5409 - val_acc: 0.7358
Epoch 22/100
78/78 - 226s - loss: 0.4090 - acc: 0.8063 - val_loss: 0.3555 - val_acc: 0.8438
Epoch 23/100
78/78 - 228s - loss: 0.3903 - acc: 0.8179 - val_loss: 0.3571 - val_acc: 0.8429
Epoch 24/100
78/78 - 226s - loss: 0.3745 - acc: 0.8307 - val_loss: 0.3516 - val_acc: 0.8421
Epoch 25/100
78/78 - 227s - loss: 0.3728 - acc: 0.8304 - val_loss: 0.3703 - val_acc: 0.8285
Epoch 26/100
78/78 - 228s - loss: 0.3584 - acc: 0.8344 - val_loss: 0.3641 - val_acc: 0.8392
Epoch 27/100
78/78 - 227s - loss: 0.3481 - acc: 0.8400 - val_loss: 0.3430 - val_acc: 0.8386
Epoch 28/100
78/78 - 228s - loss: 0.3265 - acc: 0.8497 - val_loss: 0.3399 - val_acc: 0.8470
Epoch 29/100
78/78 - 227s - loss: 0.3356 - acc: 0.8459 - val_loss: 0.3095 - val_acc: 0.8629
Epoch 30/100
78/78 - 226s - loss: 0.3167 - acc: 0.8592 - val_loss: 0.3169 - val_acc: 0.8536
Epoch 31/100
78/78 - 227s - loss: 0.3155 - acc: 0.8599 - val_loss: 0.2829 - val_acc: 0.8820
Epoch 32/100
78/78 - 235s - loss: 0.2984 - acc: 0.8664 - val_loss: 0.2902 - val_acc: 0.8688
Epoch 33/100
78/78 - 236s - loss: 0.3002 - acc: 0.8642 - val_loss: 0.3434 - val_acc: 0.8586
Epoch 34/100
78/78 - 238s - loss: 0.3082 - acc: 0.8629 - val_loss: 0.3796 - val_acc: 0.8271
Epoch 35/100
78/78 - 236s - loss: 0.2828 - acc: 0.8756 - val_loss: 0.2850 - val_acc: 0.8719
Epoch 36/100
78/78 - 235s - loss: 0.2877 - acc: 0.8716 - val_loss: 0.2975 - val_acc: 0.8664
Epoch 37/100
78/78 - 238s - loss: 0.2839 - acc: 0.8723 - val_loss: 0.2544 - val_acc: 0.8910
Epoch 38/100
78/78 - 230s - loss: 0.2749 - acc: 0.8801 - val_loss: 0.2558 - val_acc: 0.8845
Epoch 39/100
78/78 - 228s - loss: 0.2603 - acc: 0.8852 - val_loss: 0.2621 - val_acc: 0.8797
Epoch 40/100
78/78 - 258s - loss: 0.2664 - acc: 0.8841 - val_loss: 0.2513 - val_acc: 0.8937
Epoch 41/100
78/78 - 255s - loss: 0.2548 - acc: 0.8865 - val_loss: 0.2523 - val_acc: 0.8929
Epoch 42/100
78/78 - 255s - loss: 0.2561 - acc: 0.8866 - val_loss: 0.2484 - val_acc: 0.8962
Epoch 43/100
78/78 - 247s - loss: 0.2575 - acc: 0.8870 - val_loss: 0.2452 - val_acc: 0.8960
Epoch 44/100
78/78 - 247s - loss: 0.2562 - acc: 0.8882 - val_loss: 0.3566 - val_acc: 0.8390
Epoch 45/100
78/78 - 251s - loss: 0.2493 - acc: 0.8903 - val_loss: 0.2950 - val_acc: 0.8731
Epoch 46/100
78/78 - 262s - loss: 0.2386 - acc: 0.8957 - val_loss: 0.2778 - val_acc: 0.8806
Epoch 47/100
78/78 - 226s - loss: 0.2519 - acc: 0.8948 - val_loss: 0.2276 - val_acc: 0.9046
Epoch 48/100
78/78 - 234s - loss: 0.2386 - acc: 0.8963 - val_loss: 0.3851 - val_acc: 0.8037
Epoch 49/100
78/78 - 271s - loss: 0.2299 - acc: 0.8997 - val_loss: 0.2298 - val_acc: 0.9015
Epoch 50/100
78/78 - 242s - loss: 0.2283 - acc: 0.9016 - val_loss: 0.2885 - val_acc: 0.8748
Epoch 51/100
78/78 - 234s - loss: 0.2226 - acc: 0.9026 - val_loss: 0.2814 - val_acc: 0.8771
Epoch 52/100
78/78 - 263s - loss: 0.2303 - acc: 0.9002 - val_loss: 0.2829 - val_acc: 0.8781
Epoch 53/100
78/78 - 253s - loss: 0.2259 - acc: 0.9031 - val_loss: 0.2312 - val_acc: 0.9042
Epoch 54/100
78/78 - 241s - loss: 0.2177 - acc: 0.9052 - val_loss: 0.2423 - val_acc: 0.8986
Epoch 55/100
78/78 - 251s - loss: 0.2285 - acc: 0.9001 - val_loss: 0.2126 - val_acc: 0.9124
Epoch 56/100
78/78 - 257s - loss: 0.2200 - acc: 0.9040 - val_loss: 0.2224 - val_acc: 0.9062
Epoch 57/100
78/78 - 249s - loss: 0.2151 - acc: 0.9066 - val_loss: 0.2279 - val_acc: 0.9067
Epoch 58/100
78/78 - 256s - loss: 0.2106 - acc: 0.9087 - val_loss: 0.2813 - val_acc: 0.8851
Epoch 59/100
78/78 - 255s - loss: 0.2091 - acc: 0.9098 - val_loss: 0.2058 - val_acc: 0.9128
Epoch 60/100
78/78 - 258s - loss: 0.2108 - acc: 0.9108 - val_loss: 0.2587 - val_acc: 0.8949
Epoch 61/100
78/78 - 257s - loss: 0.2065 - acc: 0.9126 - val_loss: 0.2341 - val_acc: 0.8972
Epoch 62/100
78/78 - 259s - loss: 0.2032 - acc: 0.9121 - val_loss: 0.1973 - val_acc: 0.9137
Epoch 63/100
78/78 - 257s - loss: 0.2032 - acc: 0.9127 - val_loss: 0.1991 - val_acc: 0.9190
Epoch 64/100
78/78 - 256s - loss: 0.2000 - acc: 0.9143 - val_loss: 0.2605 - val_acc: 0.8888
Epoch 65/100
78/78 - 258s - loss: 0.2008 - acc: 0.9140 - val_loss: 0.2061 - val_acc: 0.9186
Epoch 66/100
78/78 - 253s - loss: 0.1934 - acc: 0.9175 - val_loss: 0.1978 - val_acc: 0.9192
Epoch 67/100
78/78 - 237s - loss: 0.1996 - acc: 0.9138 - val_loss: 0.1912 - val_acc: 0.9186
Epoch 68/100
78/78 - 229s - loss: 0.1976 - acc: 0.9150 - val_loss: 0.2157 - val_acc: 0.9134
Epoch 69/100
78/78 - 236s - loss: 0.1909 - acc: 0.9179 - val_loss: 0.1942 - val_acc: 0.9204
Epoch 70/100
78/78 - 249s - loss: 0.1929 - acc: 0.9187 - val_loss: 0.2266 - val_acc: 0.9132
Epoch 71/100
78/78 - 265s - loss: 0.1883 - acc: 0.9174 - val_loss: 0.2101 - val_acc: 0.9126
Epoch 72/100
78/78 - 280s - loss: 0.1924 - acc: 0.9165 - val_loss: 0.2090 - val_acc: 0.9118
Epoch 73/100
78/78 - 284s - loss: 0.1932 - acc: 0.9177 - val_loss: 0.1864 - val_acc: 0.9250
Epoch 74/100
78/78 - 281s - loss: 0.1797 - acc: 0.9220 - val_loss: 0.2070 - val_acc: 0.9198
Epoch 75/100
78/78 - 261s - loss: 0.1843 - acc: 0.9212 - val_loss: 0.2201 - val_acc: 0.9052
Epoch 76/100
78/78 - 233s - loss: 0.1933 - acc: 0.9199 - val_loss: 0.1908 - val_acc: 0.9180
Epoch 77/100
78/78 - 232s - loss: 0.1858 - acc: 0.9214 - val_loss: 0.3415 - val_acc: 0.8300
Epoch 78/100
78/78 - 227s - loss: 0.1841 - acc: 0.9193 - val_loss: 0.2657 - val_acc: 0.9023
Epoch 79/100
78/78 - 226s - loss: 0.1886 - acc: 0.9203 - val_loss: 0.1911 - val_acc: 0.9268
Epoch 80/100
78/78 - 237s - loss: 0.1872 - acc: 0.9219 - val_loss: 0.1882 - val_acc: 0.9245
Epoch 81/100
78/78 - 260s - loss: 0.1839 - acc: 0.9220 - val_loss: 0.2338 - val_acc: 0.9040
Epoch 82/100
78/78 - 262s - loss: 0.1866 - acc: 0.9218 - val_loss: 0.2314 - val_acc: 0.8986
Epoch 83/100
78/78 - 261s - loss: 0.1761 - acc: 0.9257 - val_loss: 0.2218 - val_acc: 0.9038
Epoch 84/100
78/78 - 263s - loss: 0.1791 - acc: 0.9236 - val_loss: 0.3364 - val_acc: 0.8466
Epoch 85/100
78/78 - 262s - loss: 0.1814 - acc: 0.9217 - val_loss: 0.1917 - val_acc: 0.9229
Epoch 86/100
78/78 - 262s - loss: 0.1838 - acc: 0.9213 - val_loss: 0.1783 - val_acc: 0.9264
Epoch 87/100
78/78 - 264s - loss: 0.1790 - acc: 0.9269 - val_loss: 0.2196 - val_acc: 0.9110
Epoch 88/100
78/78 - 264s - loss: 0.1730 - acc: 0.9285 - val_loss: 0.1876 - val_acc: 0.9280
Epoch 89/100
78/78 - 230s - loss: 0.1782 - acc: 0.9227 - val_loss: 0.2387 - val_acc: 0.9046
Epoch 90/100
78/78 - 229s - loss: 0.1719 - acc: 0.9255 - val_loss: 0.2171 - val_acc: 0.9258
Epoch 91/100
78/78 - 232s - loss: 0.1743 - acc: 0.9279 - val_loss: 0.2246 - val_acc: 0.9134
Epoch 92/100
78/78 - 229s - loss: 0.1688 - acc: 0.9287 - val_loss: 0.2299 - val_acc: 0.9141
Epoch 93/100
78/78 - 227s - loss: 0.1763 - acc: 0.9224 - val_loss: 0.1850 - val_acc: 0.9264
Epoch 94/100
78/78 - 230s - loss: 0.1810 - acc: 0.9222 - val_loss: 0.1880 - val_acc: 0.9260
Epoch 95/100
78/78 - 229s - loss: 0.1788 - acc: 0.9243 - val_loss: 0.1884 - val_acc: 0.9141
Epoch 96/100
78/78 - 231s - loss: 0.1688 - acc: 0.9302 - val_loss: 0.2187 - val_acc: 0.9100
Epoch 97/100
78/78 - 228s - loss: 0.1721 - acc: 0.9265 - val_loss: 0.2140 - val_acc: 0.9102
Epoch 98/100
78/78 - 231s - loss: 0.1677 - acc: 0.9312 - val_loss: 0.1884 - val_acc: 0.9278
Epoch 99/100
78/78 - 228s - loss: 0.1691 - acc: 0.9275 - val_loss: 0.1891 - val_acc: 0.9229
Epoch 100/100
78/78 - 229s - loss: 0.1684 - acc: 0.9265 - val_loss: 0.1866 - val_acc: 0.9200
2019-07-27 18:00:56,707 graeae.timers.timer end: Ended: 2019-07-27 18:00:56.707395
I0727 18:00:56.707435 140052539918144 timer.py:77] Ended: 2019-07-27 18:00:56.707395
2019-07-27 18:00:56,708 graeae.timers.timer end: Elapsed: 6:43:17.683800
I0727 18:00:56.708784 140052539918144 timer.py:78] Elapsed: 6:43:17.683800
Saving the model to /home/athena/models/dogs-vs-cats/layers_5_batch_size_256.h5
data = pandas.read_csv("~/cats_vs_dogs_6.csv")
curves = [holoviews.Curve(data, ("index", "Epoch"), "training_loss", 
                          label="Training Loss",),
          holoviews.Curve(data, ("index", "Epoch"), "training_accuracy", 
                          label="Training Accuracy").opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_loss", 
                          label="Validation Loss",).opts(tools=["hover"]),
          holoviews.Curve(data, ("index", "Epoch"), "validation_accuracy", 
                          label="Validation Accuracy").opts(tools=["hover"]),
]
plot = holoviews.Overlay(curves).opts(tools=["hover"], height=800, width=1000, 
                                      ylabel="Performance", 
                                      title="Training vs Validation")
Embed(plot=plot, file_name="training_validation_loss_5")()

Figure Missing

best_validation(data)
Best Accuracy: 0.928 (loss=0.1876) Epoch: 87
Best Loss: 0.1783 (accuracy=0.9264, Epoch: 85)
  • Another Training Session
    model_path = MODELS/"layers_5_batch_size_256.h5"
    network = Network(str(training_path), 
                      convolution_layers=5,
                      set_steps = True,
                      epochs = 100,
                      batch_size=256)
    model = tensorflow.keras.models.load_model(str(model_path))
    network._model = model
    with TIMER:
        network.train()
    
    network.model.save(str(model_path))
    
    W0728 10:40:02.467012 140643102242624 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:97: calling GlorotUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
    Instructions for updating:
    Call initializer instance with the dtype argument instead of passing it to the constructor
    W0728 10:40:02.469725 140643102242624 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
    Instructions for updating:
    Call initializer instance with the dtype argument instead of passing it to the constructor
    W0728 10:40:02.471851 140643102242624 deprecation.py:506] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/init_ops.py:97: calling Zeros.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
    Instructions for updating:
    Call initializer instance with the dtype argument instead of passing it to the constructor
    W0728 10:40:16.260661 140643102242624 deprecation.py:323] From /home/athena/.virtualenvs/In-Too-Deep/lib/python3.7/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.
    Instructions for updating:
    Use tf.where in 2.0, which has the same broadcast rule as np.where
    2019-07-28 10:40:16,840 graeae.timers.timer start: Started: 2019-07-28 10:40:16.840941
    I0728 10:40:16.840974 140643102242624 timer.py:70] Started: 2019-07-28 10:40:16.840941
    Found 20000 images belonging to 2 classes.
    Found 5000 images belonging to 2 classes.
    Epoch 1/100
    78/78 - 422s - loss: 0.1641 - acc: 0.9317 - val_loss: 0.2265 - val_acc: 0.9157
    Epoch 2/100
    78/78 - 151s - loss: 0.1770 - acc: 0.9264 - val_loss: 0.1841 - val_acc: 0.9235
    Epoch 3/100
    78/78 - 149s - loss: 0.1696 - acc: 0.9282 - val_loss: 0.3041 - val_acc: 0.8935
    Epoch 4/100
    78/78 - 148s - loss: 0.1678 - acc: 0.9290 - val_loss: 0.1862 - val_acc: 0.9211
    Epoch 5/100
    78/78 - 146s - loss: 0.1722 - acc: 0.9272 - val_loss: 0.2598 - val_acc: 0.8750
    Epoch 6/100
    78/78 - 145s - loss: 0.1701 - acc: 0.9299 - val_loss: 0.1904 - val_acc: 0.9235
    Epoch 7/100
    78/78 - 144s - loss: 0.1605 - acc: 0.9331 - val_loss: 0.2940 - val_acc: 0.8616
    Epoch 8/100
    78/78 - 143s - loss: 0.1789 - acc: 0.9242 - val_loss: 0.2029 - val_acc: 0.9192
    Epoch 9/100
    78/78 - 143s - loss: 0.1604 - acc: 0.9313 - val_loss: 0.2291 - val_acc: 0.9097
    Epoch 10/100
    78/78 - 143s - loss: 0.1688 - acc: 0.9291 - val_loss: 0.1833 - val_acc: 0.9280
    Epoch 11/100
    78/78 - 139s - loss: 0.1717 - acc: 0.9291 - val_loss: 0.2187 - val_acc: 0.9110
    Epoch 12/100
    78/78 - 138s - loss: 0.1703 - acc: 0.9293 - val_loss: 0.2419 - val_acc: 0.9108
    Epoch 13/100
    78/78 - 139s - loss: 0.1663 - acc: 0.9276 - val_loss: 0.2721 - val_acc: 0.8812
    Epoch 14/100
    78/78 - 138s - loss: 0.1744 - acc: 0.9272 - val_loss: 0.2325 - val_acc: 0.9062
    Epoch 15/100
    78/78 - 137s - loss: 0.1662 - acc: 0.9297 - val_loss: 0.2134 - val_acc: 0.9089
    Epoch 16/100
    78/78 - 137s - loss: 0.1745 - acc: 0.9301 - val_loss: 0.1962 - val_acc: 0.9169
    Epoch 17/100
    78/78 - 137s - loss: 0.1670 - acc: 0.9288 - val_loss: 0.1876 - val_acc: 0.9276
    Epoch 18/100
    78/78 - 136s - loss: 0.1725 - acc: 0.9277 - val_loss: 0.2187 - val_acc: 0.9270
    Epoch 19/100
    78/78 - 138s - loss: 0.1638 - acc: 0.9304 - val_loss: 0.2063 - val_acc: 0.9102
    Epoch 20/100
    78/78 - 137s - loss: 0.1696 - acc: 0.9276 - val_loss: 0.1685 - val_acc: 0.9346
    Epoch 21/100
    78/78 - 137s - loss: 0.1664 - acc: 0.9296 - val_loss: 0.4021 - val_acc: 0.7954
    Epoch 22/100
    78/78 - 136s - loss: 0.1626 - acc: 0.9306 - val_loss: 0.1839 - val_acc: 0.9317
    Epoch 23/100
    78/78 - 136s - loss: 0.1783 - acc: 0.9309 - val_loss: 0.1931 - val_acc: 0.9237
    Epoch 24/100
    78/78 - 136s - loss: 0.1615 - acc: 0.9309 - val_loss: 0.2030 - val_acc: 0.9153
    Epoch 25/100
    78/78 - 138s - loss: 0.1595 - acc: 0.9318 - val_loss: 0.2336 - val_acc: 0.9091
    Epoch 26/100
    78/78 - 136s - loss: 0.1671 - acc: 0.9299 - val_loss: 0.1836 - val_acc: 0.9342
    Epoch 27/100
    78/78 - 136s - loss: 0.1716 - acc: 0.9287 - val_loss: 0.1740 - val_acc: 0.9289
    Epoch 28/100
    78/78 - 137s - loss: 0.1597 - acc: 0.9327 - val_loss: 0.1679 - val_acc: 0.9324
    Epoch 29/100
    78/78 - 141s - loss: 0.1617 - acc: 0.9313 - val_loss: 0.1904 - val_acc: 0.9326
    Epoch 30/100
    78/78 - 138s - loss: 0.1638 - acc: 0.9335 - val_loss: 0.2675 - val_acc: 0.8966
    Epoch 31/100
    78/78 - 138s - loss: 0.1716 - acc: 0.9284 - val_loss: 0.1997 - val_acc: 0.9141
    Epoch 32/100
    78/78 - 139s - loss: 0.1579 - acc: 0.9338 - val_loss: 0.2569 - val_acc: 0.8857
    Epoch 33/100
    78/78 - 139s - loss: 0.1613 - acc: 0.9324 - val_loss: 0.2751 - val_acc: 0.8921
    Epoch 34/100
    78/78 - 136s - loss: 0.1663 - acc: 0.9295 - val_loss: 0.3323 - val_acc: 0.8645
    Epoch 35/100
    78/78 - 139s - loss: 0.1756 - acc: 0.9301 - val_loss: 0.2702 - val_acc: 0.8945
    Epoch 36/100
    78/78 - 137s - loss: 0.1630 - acc: 0.9326 - val_loss: 0.2327 - val_acc: 0.9291
    Epoch 37/100
    78/78 - 141s - loss: 0.1636 - acc: 0.9319 - val_loss: 0.1659 - val_acc: 0.9346
    Epoch 38/100
    78/78 - 138s - loss: 0.1639 - acc: 0.9317 - val_loss: 0.1837 - val_acc: 0.9270
    Epoch 39/100
    78/78 - 139s - loss: 0.1585 - acc: 0.9334 - val_loss: 0.2631 - val_acc: 0.8863
    Epoch 40/100
    78/78 - 138s - loss: 0.1640 - acc: 0.9301 - val_loss: 0.2654 - val_acc: 0.9081
    Epoch 41/100
    78/78 - 140s - loss: 0.1575 - acc: 0.9341 - val_loss: 0.2170 - val_acc: 0.9200
    Epoch 42/100
    78/78 - 138s - loss: 0.1636 - acc: 0.9338 - val_loss: 0.2877 - val_acc: 0.8785
    Epoch 43/100
    78/78 - 137s - loss: 0.1598 - acc: 0.9329 - val_loss: 0.4987 - val_acc: 0.8964
    Epoch 44/100
    78/78 - 137s - loss: 0.1695 - acc: 0.9275 - val_loss: 0.1844 - val_acc: 0.9338
    Epoch 45/100
    78/78 - 139s - loss: 0.1654 - acc: 0.9313 - val_loss: 0.2525 - val_acc: 0.9042
    Epoch 46/100
    78/78 - 139s - loss: 0.1660 - acc: 0.9308 - val_loss: 0.1734 - val_acc: 0.9322
    Epoch 47/100
    78/78 - 137s - loss: 0.1608 - acc: 0.9345 - val_loss: 0.2090 - val_acc: 0.9289
    Epoch 48/100
    78/78 - 138s - loss: 0.1694 - acc: 0.9310 - val_loss: 0.2494 - val_acc: 0.8869
    Epoch 49/100
    78/78 - 138s - loss: 0.1603 - acc: 0.9353 - val_loss: 0.2201 - val_acc: 0.9085
    Epoch 50/100
    78/78 - 135s - loss: 0.1665 - acc: 0.9301 - val_loss: 0.2500 - val_acc: 0.9069
    Epoch 51/100
    78/78 - 139s - loss: 0.1531 - acc: 0.9353 - val_loss: 0.1769 - val_acc: 0.9346
    Epoch 52/100
    78/78 - 142s - loss: 0.1642 - acc: 0.9339 - val_loss: 0.1953 - val_acc: 0.9254
    Epoch 53/100
    78/78 - 140s - loss: 0.1620 - acc: 0.9327 - val_loss: 0.1592 - val_acc: 0.9354
    Epoch 54/100
    78/78 - 137s - loss: 0.1533 - acc: 0.9370 - val_loss: 0.1649 - val_acc: 0.9348
    Epoch 55/100
    78/78 - 136s - loss: 0.1652 - acc: 0.9323 - val_loss: 0.1732 - val_acc: 0.9287
    Epoch 56/100
    78/78 - 137s - loss: 0.1527 - acc: 0.9369 - val_loss: 0.3824 - val_acc: 0.8201
    Epoch 57/100
    78/78 - 136s - loss: 0.1618 - acc: 0.9312 - val_loss: 0.2443 - val_acc: 0.8943
    Epoch 58/100
    78/78 - 137s - loss: 0.1553 - acc: 0.9366 - val_loss: 0.1598 - val_acc: 0.9369
    Epoch 59/100
    78/78 - 136s - loss: 0.1550 - acc: 0.9332 - val_loss: 0.2080 - val_acc: 0.9097
    Epoch 60/100
    78/78 - 136s - loss: 0.1597 - acc: 0.9351 - val_loss: 0.1973 - val_acc: 0.9336
    Epoch 61/100
    78/78 - 136s - loss: 0.1565 - acc: 0.9349 - val_loss: 0.1700 - val_acc: 0.9342
    Epoch 62/100
    78/78 - 137s - loss: 0.1571 - acc: 0.9332 - val_loss: 0.1830 - val_acc: 0.9309
    Epoch 63/100
    78/78 - 138s - loss: 0.1575 - acc: 0.9349 - val_loss: 0.2413 - val_acc: 0.9252
    Epoch 64/100
    78/78 - 139s - loss: 0.1607 - acc: 0.9320 - val_loss: 0.1989 - val_acc: 0.9225
    Epoch 65/100
    78/78 - 143s - loss: 0.2276 - acc: 0.9272 - val_loss: 0.1754 - val_acc: 0.9309
    Epoch 66/100
    78/78 - 139s - loss: 0.1510 - acc: 0.9374 - val_loss: 0.1707 - val_acc: 0.9330
    Epoch 67/100
    78/78 - 144s - loss: 0.1578 - acc: 0.9321 - val_loss: 0.2149 - val_acc: 0.9192
    Epoch 68/100
    78/78 - 141s - loss: 0.1557 - acc: 0.9345 - val_loss: 0.2180 - val_acc: 0.9149
    Epoch 69/100
    78/78 - 142s - loss: 0.1721 - acc: 0.9329 - val_loss: 0.1878 - val_acc: 0.9223
    Epoch 70/100
    78/78 - 142s - loss: 0.1603 - acc: 0.9339 - val_loss: 0.2094 - val_acc: 0.9262
    Epoch 71/100
    78/78 - 143s - loss: 0.1593 - acc: 0.9328 - val_loss: 0.1864 - val_acc: 0.9245
    Epoch 72/100
    78/78 - 145s - loss: 0.1526 - acc: 0.9357 - val_loss: 0.3221 - val_acc: 0.8830
    Epoch 73/100
    78/78 - 145s - loss: 0.1633 - acc: 0.9311 - val_loss: 0.2339 - val_acc: 0.9202
    Epoch 74/100
    78/78 - 144s - loss: 0.1605 - acc: 0.9316 - val_loss: 0.2211 - val_acc: 0.9272
    Epoch 75/100
    78/78 - 143s - loss: 0.1428 - acc: 0.9407 - val_loss: 0.1861 - val_acc: 0.9270
    Epoch 76/100
    78/78 - 139s - loss: 0.1517 - acc: 0.9373 - val_loss: 0.1944 - val_acc: 0.9344
    Epoch 77/100
    78/78 - 139s - loss: 0.1684 - acc: 0.9312 - val_loss: 0.1645 - val_acc: 0.9332
    Epoch 78/100
    78/78 - 138s - loss: 0.1628 - acc: 0.9346 - val_loss: 0.2015 - val_acc: 0.9229
    Epoch 79/100
    78/78 - 136s - loss: 0.1520 - acc: 0.9387 - val_loss: 0.1919 - val_acc: 0.9272
    Epoch 80/100
    78/78 - 136s - loss: 0.1570 - acc: 0.9357 - val_loss: 0.2247 - val_acc: 0.9305
    Epoch 81/100
    78/78 - 152s - loss: 0.1580 - acc: 0.9358 - val_loss: 0.1721 - val_acc: 0.9309
    Epoch 82/100
    78/78 - 150s - loss: 0.1471 - acc: 0.9374 - val_loss: 0.1836 - val_acc: 0.9317
    Epoch 83/100
    78/78 - 149s - loss: 0.1565 - acc: 0.9334 - val_loss: 0.2132 - val_acc: 0.9217
    Epoch 84/100
    78/78 - 148s - loss: 0.1466 - acc: 0.9372 - val_loss: 0.1786 - val_acc: 0.9276
    Epoch 85/100
    78/78 - 147s - loss: 0.1577 - acc: 0.9346 - val_loss: 0.2986 - val_acc: 0.9050
    Epoch 86/100
    78/78 - 147s - loss: 0.1551 - acc: 0.9359 - val_loss: 0.1581 - val_acc: 0.9400
    Epoch 87/100
    78/78 - 144s - loss: 0.1620 - acc: 0.9324 - val_loss: 0.1769 - val_acc: 0.9363
    Epoch 88/100
    78/78 - 143s - loss: 0.1593 - acc: 0.9355 - val_loss: 0.2341 - val_acc: 0.9023
    Epoch 89/100
    78/78 - 141s - loss: 0.1557 - acc: 0.9346 - val_loss: 0.3245 - val_acc: 0.8935
    Epoch 90/100
    78/78 - 140s - loss: 0.1582 - acc: 0.9346 - val_loss: 0.2618 - val_acc: 0.9044
    Epoch 91/100
    78/78 - 139s - loss: 0.1514 - acc: 0.9388 - val_loss: 0.3941 - val_acc: 0.8302
    Epoch 92/100
    78/78 - 137s - loss: 0.1688 - acc: 0.9331 - val_loss: 0.1791 - val_acc: 0.9317
    Epoch 93/100
    78/78 - 138s - loss: 0.1533 - acc: 0.9365 - val_loss: 0.2477 - val_acc: 0.9169
    Epoch 94/100
    78/78 - 136s - loss: 0.1485 - acc: 0.9381 - val_loss: 0.2371 - val_acc: 0.9354
    Epoch 95/100
    78/78 - 136s - loss: 0.1656 - acc: 0.9321 - val_loss: 0.1838 - val_acc: 0.9221
    Epoch 96/100
    78/78 - 136s - loss: 0.1544 - acc: 0.9346 - val_loss: 0.1894 - val_acc: 0.9344
    Epoch 97/100
    78/78 - 138s - loss: 0.1529 - acc: 0.9378 - val_loss: 0.2735 - val_acc: 0.9192
    Epoch 98/100
    78/78 - 135s - loss: 0.1557 - acc: 0.9370 - val_loss: 0.1895 - val_acc: 0.9309
    Epoch 99/100
    78/78 - 137s - loss: 0.1609 - acc: 0.9349 - val_loss: 0.1683 - val_acc: 0.9375
    Epoch 100/100
    78/78 - 137s - loss: 0.1512 - acc: 0.9368 - val_loss: 0.5123 - val_acc: 0.8454
    2019-07-28 14:37:54,241 graeae.timers.timer end: Ended: 2019-07-28 14:37:54.241406
    I0728 14:37:54.241441 140643102242624 timer.py:77] Ended: 2019-07-28 14:37:54.241406
    2019-07-28 14:37:54,242 graeae.timers.timer end: Elapsed: 3:57:37.400465
    I0728 14:37:54.242489 140643102242624 timer.py:78] Elapsed: 3:57:37.400465
    
    data = pandas.DataFrame(network.model.history.history).rename(
        columns={
            "loss": "Training Loss",
            "acc": "Training Accuracy",
            "val_loss": "Validation Loss",
            "val_acc": "Validation Accuracy"
        })
    best_validation(data.rename(columns={
        "Validation Loss": "validation_loss", 
        "Validation Accuracy": "validation_accuracy"}))
    
    Best Accuracy: 0.94 (loss=0.16) Epoch: 85
    Best Loss: 0.16 (accuracy=0.94, Epoch: 85)
    
    line = holoviews.VLine(85)
    plot = data.hvplot(x="index", value_label="Epoch").opts(
        tools=["hover"],
        title="Accuracy and Loss For 100 Epochs",
        width=1000,
        height=800,
    ) * line
    Embed(plot=plot, file_name="five_layers_batch_size_256")()
    

    Figure Missing

    By re-training I managed to squeeze out another 1 percent. I might be able to get another percentage point improvement, but maybe at this point it's good enough.

Using the Model

test_path = Path("~/data/datasets/images/dogs-vs-cats/test1/").expanduser()
test_image = random.choice(list(test_path.iterdir()))
plot = holoviews.RGB.load_image(str(test_image)).opts(width=800, height=800)
Embed(plot=plot, file_name="test_image")()

Figure Missing

image = keras.preprocessing.image.load_img(test_image, target_size=(150, 150))
x = keras.preprocessing.image.img_to_array(image)
x = numpy.expand_dims(x, axis=0)
predictions = network.model.predict(x)
print(predictions[0])
classification = "dog" if predictions[0] else "cat"
print(f"{test_image.name} is a {classification}")
[1.]
8595.jpg is a dog

If you run this more than once you'll get different images, but it seems to have a bias towards predicting dogs.

Visualizing Intermediate Representations

Let's define a new Model that will take an image as input, and will output intermediate representations for all layers in the previous model after the first.

successive_outputs = [layer.output for layer in model.layers[1:]]
visualization_model = tensorflow.keras.models.Model(
    inputs = model.input, 
    outputs = successive_outputs)

Now prepare a random input image of a cat or dog from the training set.

image_path = random.choice(list(testing_path.iterdir()))
image = load_img(image_path, target_size=(150, 150))  # this is a PIL image

x = img_to_array(image) 
print(f"X ({type(x)}): {x.shape}")
x   = x.reshape((1,) + x.shape)
print(f"X re-shape: {x.shape}")
# Rescale by 1/255
x /= 255.0

successive_feature_maps = visualization_model.predict(x)

# These are the names of the layers, so can have them as part of our plot
layer_names = [layer.name for layer in model.layers]
X (<class 'numpy.ndarray'>): (150, 150, 3)
X re-shape: (1, 150, 150, 3)

Let's run our image through our network, thus obtaining all intermediate representations for this image.

# -----------------------------------------------------------------------
# Now let's display our representations
# -----------------------------------------------------------------------
for layer_name, feature_map in zip(layer_names, successive_feature_maps):

  if len(feature_map.shape) == 4:

    #-------------------------------------------
    # Just do this for the conv / maxpool layers, not the fully-connected layers
    #-------------------------------------------
    n_features = feature_map.shape[-1]  # number of features in the feature map
    size       = feature_map.shape[ 1]  # feature map shape (1, size, size, n_features)

    # We will tile our images in this matrix
    display_grid = numpy.zeros((size, size * n_features))

    #-------------------------------------------------
    # Postprocess the feature to be visually palatable
    #-------------------------------------------------
    for i in range(n_features):
      x  = feature_map[0, :, :, i]
      x -= x.mean()
      x /= x.std ()
      x *=  64
      x += 128
      x  = numpy.clip(x, 0, 255).astype('uint8')
      display_grid[:, i * size : (i + 1) * size] = x # Tile each filter into a horizontal grid

    #-----------------
    # Display the grid
    #-----------------

    scale = 40. / n_features
    pyplot.figure(figsize=(scale * n_features, scale))
    pyplot.title (layer_name)
    pyplot.grid (False )
    pyplot.imshow(display_grid, aspect='auto', cmap='viridis' ) 

layer_visualisation.png

End