In [1]:
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Cascade (HD-CNN Model Deriative)

Objective

This notebook demonstrates building a hierachical image classifer based on a HD-CNN deriative which uses cascading classifers to predict the class of a label from a coarse to finer classes.

In this demonstration, we have two classes in the heirarchy: fruits and varieties of fruit. The model will first predict the coarse class (type of fruit) and then within that class of fruit, the variety. For example, if given an image of Apple Granny Smith, it would first predict 'Apple' (fruit) and then predict the 'Apple Granny Smith'.

This deriative of the HD-CNN is designed to demonstrate both the methodology of heirarchical classification, as well as design improvements not available at the time (2014) when the model was first published Zhicheng Yan.

General Approach

Our HD-CNN deriative archirecture consists of:

1. An stem convolutional block.
    - The output from the stem convolutional head is shared with the coarse and finer classifiers 
    (referred to as the shared layers in the paper).
2. A coarse classifier.
    - A Convolution and Dense layers for classifying the coarse level class. 
3. A set of finer classifiers, one per coarse level class.
    - A Convolution and Dense layers per coarse level class for classifying the corresponding finer 
    level class.
4. A conditional execution step for predicting a specific finer classifier based on the output of the 
   coarse classifier.
    - The coarse level classifier is predicted.
    - The index of the prediction is used to select a finer classifier.
    - An im-memory copy of the shared bottleneck layer (i.e., last convolution layer in stem) is passed as the
      input to the finer level classifier.


Our HD-CNN deriative is trained as follows:

1. Train the coarse level classifier using the coarse level labels in the dataset.

2. Train the finer level classifier per coarse level class, using the corresponding subset (with finer
   labels) from the dataset.


Dataset

We will be using the Fruits-360 dataset, which was formerly a Kaggle competition. It consists of images of fruit labeled by fruit type and the variety.

1. There are a total of 47 types of fruit (e.g., Apple, Orange, Pear, etc) and 81 varieties.
2. On average, there are 656 images per variety.
3. Each image is 128x128 RGB.

Objective

The objective is to train a hierarchical image classifier (coarse and then finer label) using a cascading layer architecture. First, the shared layers and coarse classifier are trained. Then the cascading finer classifiers are trained.

For prediction, the outcome (softmax) of the coarse classifier will conditionally execute the corresponding finer classifier and reuse the feature maps from the shared layers.

Costs

This notebook requires 17GB of memory. It will not run on a Standard TF JaaS instance (15GB). You will need to select an instance with memory > 17GB.

Prerequisites

Download the Fruits 360 dataset from GCS public bucket into this JaaS instance.

Some of the cells in the notebook display images. The images will not appear until the cell for copying the training data/misc from GCS into the JaaS instance is executed.


In [1]:
!gsutil cp gs://cloud-samples-data/air/fruits360/fruits360-combined.zip .
!ls
!unzip -qn fruits360-combined.zip


Copying gs://cloud-samples-data/air/fruits360/fruits360-combined.zip...
==> NOTE: You are downloading one or more large file(s), which would            
run significantly faster if you enabled sliced object downloads. This
feature is enabled by default but requires that compiled crcmod be
installed (see "gsutil help crcmod").

/ [1 files][230.9 MiB/230.9 MiB]                                                
Operation completed over 1 objects/230.9 MiB.                                    
arch-1.png		model-coarse.h5    model-finer-1.h5  model-finer-8.h5
arch-2.png		model-finer-0.h5   model-finer-2.h5  model-finer-9.h5
cascade-gap.ipynb	model-finer-10.h5  model-finer-3.h5  model.h5
cascade.ipynb		model-finer-11.h5  model-finer-4.h5  Save
fruits360-Cascade.zip	model-finer-12.h5  model-finer-5.h5  Training
fruits360-combined.zip	model-finer-13.h5  model-finer-6.h5
fruits.h5.h5		model-finer-14.h5  model-finer-7.h5

Getting Started

We will be using the fully frameworks and Python modules:

1. Keras framework for building and training models.
2. Keras builtin models (resnet50).
3. Keras preprocessing for feeding and augmenting the dataset during training.
4. Gap data engineering framework for preprocessing the image data.
5. Numpy for general image/matrix manipulation.

In [2]:
import os
from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image
from keras.applications.resnet50 import preprocess_input, decode_predictions
from keras.preprocessing.image import ImageDataGenerator
from keras.layers import GlobalAveragePooling2D, Dense
from keras import Sequential, Model, Input
from keras.layers import Conv2D, Flatten, MaxPooling2D, Dense, Dropout, BatchNormalization, ReLU
from keras import Model, optimizers
from keras.models import load_model
from keras.utils import to_categorical
import keras.layers as layers
from sklearn.model_selection import train_test_split
import tensorflow as tf
import numpy as np
import cv2


Using TensorFlow backend.

Make Datasets

Make Coarse Category Dataset

This makes the by fruit type dataset.


In [3]:
def Fruits(root):
    n_label = 0
    images = []
    labels = []
    classes = {}
    
    os.chdir(root)
    classes_ = os.scandir('./')
    for class_ in classes_:
        print(class_.name)
        os.chdir(class_.name)
        classes[class_.name] = n_label

        # Finer Level Subdirectories per Coarse Level
        subclasses = os.scandir('./')
        for subclass in subclasses:
            os.chdir(subclass.name)
            files = os.listdir('./')
            for file in files:
                image = cv2.imread(file)
                images.append(image)
                labels.append(n_label)
                
            os.chdir('../')

        os.chdir('../')
        n_label += 1
    os.chdir('../')
    images = np.asarray(images)
    images = (images / 255.0).astype(np.float32)
    labels = to_categorical(labels, n_label)
    print("Images", images.shape, "Labels", labels.shape, "Classes", classes)

    # Split the processed image dataset into training and test data
    x_train, x_test, y_train, y_test = train_test_split(images, labels, test_size=0.20, shuffle=True)
    return x_train, x_test, y_train, y_test, classes

Make Finer Category Datasets

This makes the by Fruit Variety datasets


In [4]:
def Varieties(root):
    ''' Generate Cascade (Finer) Level Dataset for Fruit Varieties'''

    datasets = {}
    
    os.chdir(root)
    fruits = os.scandir('./')
    for fruit in fruits:
        n_label = 0
        images = []
        labels = []
        classes = {}
        print('FRUIT', fruit.name)
        os.chdir(fruit.name)
        varieties = os.scandir('./')
        for variety in varieties:
            print('VARIETY', variety.name)
            classes[variety.name] = n_label
            os.chdir(variety.name)
            files = os.listdir('./')
            for file in files:
                image = cv2.imread(file)
                images.append(image)
                labels.append(n_label)
            os.chdir('../')
            n_label += 1
        images = np.asarray(images)
        images = (images / 255.0).astype(np.float32)
        labels = to_categorical(labels, n_label)
        x_train, x_test, y_train, y_test = train_test_split(images, labels, test_size=0.20, shuffle=True)
        datasets[fruit.name] = (x_train, x_test, y_train, y_test, classes)
        os.chdir('../')
        print("IMAGES", x_train.shape, y_train.shape, "CLASSES", classes)
    os.chdir('../')
    return datasets

Generate the preprocessed Coarse Dataset


In [5]:
!free -m
x_train, x_test, y_train, y_test, fruits_classes = Fruits('Training')
!free -m


              total        used        free      shared  buff/cache   available
Mem:          64146        8888       45049         101       10208       54503
Swap:         65187        5628       59559
Avocado
Rambutan
Pineapple
Kiwi
Cantaloupe
Apple
Tamarillo
Physalis
Plum
Pitahaya
Guava
Limes
Grapefruit
Peach
Pomegranate
Nectarine
Apricot
Banana
Cherry
Mulberry
Raspberry
Cactus Fruit
Grape
Mandarine
Granadilla
Carambula
Passion Fruit
Lychee
Quince
Maracuja
Strawberry
Tangelo
Huckleberry
Orange
Dates
Melon
Pepino
Clementine
Papaya
Mango
Tomato
Salak
Kaki
Pear
Cocos
Lemon
Kumquats
Images (51258, 100, 100, 3) Labels (51258, 47) Classes {'Avocado': 0, 'Rambutan': 1, 'Pineapple': 2, 'Kiwi': 3, 'Cantaloupe': 4, 'Apple': 5, 'Tamarillo': 6, 'Physalis': 7, 'Plum': 8, 'Pitahaya': 9, 'Guava': 10, 'Limes': 11, 'Grapefruit': 12, 'Peach': 13, 'Pomegranate': 14, 'Nectarine': 15, 'Apricot': 16, 'Banana': 17, 'Cherry': 18, 'Mulberry': 19, 'Raspberry': 20, 'Cactus Fruit': 21, 'Grape': 22, 'Mandarine': 23, 'Granadilla': 24, 'Carambula': 25, 'Passion Fruit': 26, 'Lychee': 27, 'Quince': 28, 'Maracuja': 29, 'Strawberry': 30, 'Tangelo': 31, 'Huckleberry': 32, 'Orange': 33, 'Dates': 34, 'Melon': 35, 'Pepino': 36, 'Clementine': 37, 'Papaya': 38, 'Mango': 39, 'Tomato': 40, 'Salak': 41, 'Kaki': 42, 'Pear': 43, 'Cocos': 44, 'Lemon': 45, 'Kumquats': 46}
              total        used        free      shared  buff/cache   available
Mem:          64146       16224       37722          93       10199       47175
Swap:         65187        5628       59559

Split Coarse Dataset (by Fruit) into Train, Validation and Test

First split into train and test. Then split out 10% of train to use for validation during training.

- Train: 80%
    - Train: 90%
    - Validation: 10%
- Test : 20%

In [6]:
# Split out 10% of Train to use for Validation
pivot = int(len(x_train) * 0.9)
x_val = x_train[pivot:]
y_val = y_train[pivot:]
x_train = x_train[:pivot]
y_train = y_train[:pivot]

print("train", x_train.shape, y_train.shape)
print("val  ", x_val.shape, y_val.shape)
print("test ", x_test.shape, y_test.shape)
!free -m


train (36905, 100, 100, 3) (36905, 47)
val   (4101, 100, 100, 3) (4101, 47)
test  (10252, 100, 100, 3) (10252, 47)
              total        used        free      shared  buff/cache   available
Mem:          64146       16255       37683         101       10207       47136
Swap:         65187        5628       59559

Make Trainers

Create the routines we will use for training.

Make Feeder

Prepare the Feeder mechanism for training the neural networkm using ImageDataGenerator.

Add image augmentation for:

1. Horizontal Flip
2. Verticial  Flip
3. Random Rotation +/- 30 degrees

In [7]:
def Feeder():
    datagen = ImageDataGenerator(horizontal_flip=True, vertical_flip=True, rotation_range=30)
    return datagen

Make Trainer

Prepare a training session:

1. Epochs defaults to 10
2. Batch size defaults to 32
3. Train with validation data
4. Final evaluation with test data (holdout set).

In [8]:
def Train(model, datagen, x_train, y_train, x_test, y_test, epochs=10, batch_size=32):
    model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size, shuffle=True),
                    steps_per_epoch=len(x_train) / batch_size, epochs=epochs, verbose=1, validation_data=(x_test, y_test))
    scores = model.evaluate(x_train, y_train, verbose=1)
    print("Train", scores)

Make Model

Stem Convolutional Block (Base Model)

We will use this base model as the stem convolutional block of cascading model:

1. The output of this model are a set of pooled feature maps.
2. The last layer that produces this set of pooled feature maps is referred to as the bottleneck layer.

Coarse Classifier

The coarse classifier is an independent block layer for classifying the coarse level label:

1. Input is the bottleneck layer from the stem convolutional block.
2. Layer consists of a convolution layer and a dense layer, where the dense layer is the classifier.

Finer Classifier

The finer classifiers are a set of independent block layers for classifying the finer label. There is one finer classifier per unique coarse level label.

1. Input is the bottleneck layer from the stem convolutional block.
2. Layer consists of a convolution layer and a dense layer, where the dense layer is the classifier.
3. The finer classifer is conditionally executed based on the softmax output from the coarse classifier.

ResNet for Transfer Learning

Use a prebuilt Keras model (ResNet 50). Either as:

1. Transfer Learning: The layers are pretrained with imagenet weights.
2. Full Training: layers are not pretrained (weights = None)

In [9]:
def ResNet(shape=(128, 128, 3), nclasses=47, optimizer='adam', weights=None):
    base_model = ResNet50(weights=weights, include_top=False, input_shape=shape)

    for i, layer in enumerate(base_model.layers):
        # first: train only the top layers (which were randomly initialized) for Transfer Learning
        if weights is not None:
            layer.trainable = False
       
    # label the last convolutional layer in the base model as the bottleneck
    layer.name = 'bottleneck'
    
    # Get the last convolutional layer of the ResNet base model
    x = base_model.output
    
    # add a global spatial average pooling layer
    x = GlobalAveragePooling2D()(x)
    # let's add a fully-connected layer
    #x = Dense(1024, activation='relu')(x)
    # and a logistic layer 
    predictions = Dense(nclasses, activation='softmax')(x)
    # this is the model we will train
    model = Model(inputs=base_model.input, outputs=predictions)

    # compile the model (should be done *after* setting layers to non-trainable)
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    model.summary()
    return model

Simple ConvNet

The stem convolutional block consists of a mini-VGG, which consists of:

1. A convolutional input (stem)
2. Three convolutional groups, each doubling the number of filers.
3. Each convolutional group consists of one convolutional block.
4. A dropout of 50% is added to the first convolutional group.

The coarse classifier consists of:

1. A 1024 none dense layer
2. A 47 node dense layer for classification.

In [10]:
def ConvNet(shape=(128, 128, 3), nclasses=47, optimizer='adam'):
    model = Sequential()
    # stem convolutional group
    model.add(Conv2D(16, (3,3), padding='same', activation='relu', input_shape=shape))

    # conv block - double filters
    model.add(Conv2D(32, (3,3), padding='same'))
    model.add(ReLU())    
    model.add(Dropout(0.50)) 
    model.add(MaxPooling2D((2,2)))
    
    # conv block - double filters
    model.add(Conv2D(64, (3,3), padding='same'))
    model.add(ReLU())
    model.add(MaxPooling2D((2,2)))
    
    # conv block - double filters + bottleneck layer
    model.add(Conv2D(128, (3,3), padding='same', activation='relu'))
    model.add(MaxPooling2D((2,2), name="bottleneck"))
    
    # dense block
    model.add(Flatten())
    model.add(Dense(1024, activation='relu'))
    model.add(Dropout(0.25))
    
    # classifier
    model.add(Dense(nclasses, activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    model.summary()
    return model

Start Training

1. Train the Coarse Classifier
2. Add Finer Classifiers
4. Train the Finer Classifiers

Generate Coarse Model

Choose between:

1. A untrained simple VGG CovNet as Stem Convolution Group, or
2. Pre-trained ResNet50 (imagenet weights) for Transfer Learning

In [11]:
# Select the model for the stem convolutional group (shared layers)
stem = 'ConvNet'
if stem == 'ConvNet':
    model = ConvNet(shape=(100, 100, 3))
elif stem == 'ResNet-imagenet':
    model = ResNet(weights='imagenet', optimizer='adagrad')
elif stem == 'ResNet':
    model = ResNet()
# load previously stored model
else:
    model = load_model('model.h5')


WARNING:tensorflow:From /usr/local/google/home/aferlitsch/.local/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
WARNING:tensorflow:From /usr/local/google/home/aferlitsch/.local/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3445: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and will be removed in a future version.
Instructions for updating:
Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
dropout_2 (Dropout)          (None, 1024)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 47)                48175     
=================================================================
Total params: 19,021,007
Trainable params: 19,021,007
Non-trainable params: 0
_________________________________________________________________

Train the Coarse Model


In [12]:
datagen = Feeder()
Train(model, datagen, x_train, y_train, x_val, y_val, 5)

scores = model.evaluate(x_test, y_test, verbose=1)
print("Test", scores)


WARNING:tensorflow:From /usr/local/google/home/aferlitsch/.local/lib/python3.6/site-packages/tensorflow/python/ops/math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
Epoch 1/5
1154/1153 [==============================] - 492s 427ms/step - loss: 0.7688 - acc: 0.7665 - val_loss: 0.4038 - val_acc: 0.8800
Epoch 2/5
1154/1153 [==============================] - 489s 424ms/step - loss: 0.1687 - acc: 0.9431 - val_loss: 0.1588 - val_acc: 0.9537
Epoch 3/5
1154/1153 [==============================] - 487s 422ms/step - loss: 0.1329 - acc: 0.9529 - val_loss: 0.1037 - val_acc: 0.9659
Epoch 4/5
1154/1153 [==============================] - 489s 424ms/step - loss: 0.1239 - acc: 0.9589 - val_loss: 0.2824 - val_acc: 0.9056
Epoch 5/5
1154/1153 [==============================] - 488s 423ms/step - loss: 0.0854 - acc: 0.9683 - val_loss: 0.1708 - val_acc: 0.9361
36905/36905 [==============================] - 90s 2ms/step
Train [0.1527849808228305, 0.9426364991209756]
10252/10252 [==============================] - 26s 3ms/step
Test [0.17052910335498586, 0.935914943425673]

Save the Coarse Model


In [13]:
# Save the model and weights
model.save("model-coarse.h5")

Prepare Coarse CNN for cascade training

1. Freeze all layers
2. Find bottleneck layer

In [14]:
def Bottleneck(model):
    for layer in model.layers:
        layer.trainable = False
        if layer.name == 'bottleneck':
            bottleneck = layer

    print("BOTTLENECK", bottleneck.output.shape)
    return bottleneck

Generate the preprocessed Finer Datasets

Split Finer (by Variety) Datasets into Train, Validation and Test

1. For each fruit type, split the corresponding variety images into train, validation and test.
2. Save each split dataset in a dictionary, using the fruit name as the key.

In [15]:
# Converse memory by releasing training data for coarse model
import gc
x_train = y_train = x_val = y_val = x_test = y_test = None
gc.collect()


Out[15]:
5

In [16]:
varieties_datasets = Varieties('Training')
for key, dataset in varieties_datasets.items():
    
    _x_train, _x_test, _y_train, _y_test, classes = dataset
            
    # Separate out 10% of train for validation
    pivot = int(len(_x_train) * 0.9)
    _x_val = _x_train[pivot:]
    _y_val = _y_train[pivot:]
    _x_train = _x_train[:pivot]
    _y_train = _y_train[:pivot]
    
    # save the dataset for this fruit (key)
    varieties_datasets[key] = { 'classes': classes, 'train': (_x_train, _y_train), 'val': (_x_val, _y_val), 'test': (_x_test, _y_test) }
    
!free -m


FRUIT Avocado
VARIETY Avocado
VARIETY Avocado ripe
IMAGES (981, 100, 100, 3) (981, 2) CLASSES {'Avocado': 0, 'Avocado ripe': 1}
FRUIT Rambutan
VARIETY Rambutan
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Rambutan': 0}
FRUIT Pineapple
VARIETY Pineapple
VARIETY Pineapple Mini
IMAGES (1048, 100, 100, 3) (1048, 2) CLASSES {'Pineapple': 0, 'Pineapple Mini': 1}
FRUIT Kiwi
VARIETY Kiwi
IMAGES (497, 100, 100, 3) (497, 1) CLASSES {'Kiwi': 0}
FRUIT Cantaloupe
VARIETY Cantaloupe 1
VARIETY Cantaloupe 2
IMAGES (1049, 100, 100, 3) (1049, 2) CLASSES {'Cantaloupe 1': 0, 'Cantaloupe 2': 1}
FRUIT Apple
VARIETY Apple Golden 2
VARIETY Apple Red 3
VARIETY Apple Red Yellow
VARIETY Apple Granny Smith
VARIETY Apple Red 2
VARIETY Apple Braeburn
VARIETY Apple Golden 3
VARIETY Apple Red Delicious
VARIETY Apple Red 1
VARIETY Apple Golden 1
IMAGES (5170, 100, 100, 3) (5170, 10) CLASSES {'Apple Golden 2': 0, 'Apple Red 3': 1, 'Apple Red Yellow': 2, 'Apple Granny Smith': 3, 'Apple Red 2': 4, 'Apple Braeburn': 5, 'Apple Golden 3': 6, 'Apple Red Delicious': 7, 'Apple Red 1': 8, 'Apple Golden 1': 9}
FRUIT Tamarillo
VARIETY Tamarillo
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Tamarillo': 0}
FRUIT Physalis
VARIETY Physalis
VARIETY Physalis with Husk
IMAGES (1049, 100, 100, 3) (1049, 2) CLASSES {'Physalis': 0, 'Physalis with Husk': 1}
FRUIT Plum
VARIETY Plum
IMAGES (478, 100, 100, 3) (478, 1) CLASSES {'Plum': 0}
FRUIT Pitahaya
VARIETY Pitahaya Red
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Pitahaya Red': 0}
FRUIT Guava
VARIETY Guava
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Guava': 0}
FRUIT Limes
VARIETY Limes
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Limes': 0}
FRUIT Grapefruit
VARIETY Grapefruit White
VARIETY Grapefruit Pink
IMAGES (1049, 100, 100, 3) (1049, 2) CLASSES {'Grapefruit White': 0, 'Grapefruit Pink': 1}
FRUIT Peach
VARIETY Peach
VARIETY Peach Flat
IMAGES (1049, 100, 100, 3) (1049, 2) CLASSES {'Peach': 0, 'Peach Flat': 1}
FRUIT Pomegranate
VARIETY Pomegranate
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Pomegranate': 0}
FRUIT Nectarine
VARIETY Nectarine
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Nectarine': 0}
FRUIT Apricot
VARIETY Apricot
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Apricot': 0}
FRUIT Banana
VARIETY Banana
VARIETY Banana Red
IMAGES (1049, 100, 100, 3) (1049, 2) CLASSES {'Banana': 0, 'Banana Red': 1}
FRUIT Cherry
VARIETY Cherry Rainier
VARIETY Cherry 2
VARIETY Carambula
VARIETY Cherry Wax Yellow
VARIETY Cherry Wax Black
VARIETY Cherry 1
VARIETY Cherry Wax Red
IMAGES (1310, 100, 100, 3) (1310, 7) CLASSES {'Cherry Rainier': 0, 'Cherry 2': 1, 'Carambula': 2, 'Cherry Wax Yellow': 3, 'Cherry Wax Black': 4, 'Cherry 1': 5, 'Cherry Wax Red': 6}
FRUIT Mulberry
VARIETY Mulberry
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Mulberry': 0}
FRUIT Raspberry
VARIETY Rambutan
VARIETY Raspberry
IMAGES (523, 100, 100, 3) (523, 2) CLASSES {'Rambutan': 0, 'Raspberry': 1}
FRUIT Cactus Fruit
VARIETY Cactus fruit
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Cactus fruit': 0}
FRUIT Grape
VARIETY Grape White
VARIETY Grape Pink
VARIETY Grape White 2
IMAGES (1574, 100, 100, 3) (1574, 3) CLASSES {'Grape White': 0, 'Grape Pink': 1, 'Grape White 2': 2}
FRUIT Mandarine
VARIETY Mandarine
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Mandarine': 0}
FRUIT Granadilla
VARIETY Granadilla
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Granadilla': 0}
FRUIT Carambula
VARIETY Carambula
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Carambula': 0}
FRUIT Passion Fruit
VARIETY Passion Fruit
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Passion Fruit': 0}
FRUIT Lychee
VARIETY Lychee
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Lychee': 0}
FRUIT Quince
VARIETY Quince
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Quince': 0}
FRUIT Maracuja
VARIETY Maracuja
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Maracuja': 0}
FRUIT Strawberry
VARIETY Strawberry Wedge
VARIETY Strawberry
IMAGES (1312, 100, 100, 3) (1312, 2) CLASSES {'Strawberry Wedge': 0, 'Strawberry': 1}
FRUIT Tangelo
VARIETY Tangelo
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Tangelo': 0}
FRUIT Huckleberry
VARIETY Huckleberry
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Huckleberry': 0}
FRUIT Orange
VARIETY Orange
IMAGES (511, 100, 100, 3) (511, 1) CLASSES {'Orange': 0}
FRUIT Dates
VARIETY Dates
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Dates': 0}
FRUIT Melon
VARIETY Melon Piel de Sapo
IMAGES (787, 100, 100, 3) (787, 1) CLASSES {'Melon Piel de Sapo': 0}
FRUIT Pepino
VARIETY Pepino
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Pepino': 0}
FRUIT Clementine
VARIETY Clementine
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Clementine': 0}
FRUIT Papaya
VARIETY Papaya
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Papaya': 0}
FRUIT Mango
VARIETY Mango
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Mango': 0}
FRUIT Tomato
VARIETY Tomato 2
VARIETY Tomato Cherry Red
VARIETY Tomato Maroon
VARIETY Tomato 1
VARIETY Tomato 3
VARIETY Tomato 4
IMAGES (3723, 100, 100, 3) (3723, 6) CLASSES {'Tomato 2': 0, 'Tomato Cherry Red': 1, 'Tomato Maroon': 2, 'Tomato 1': 3, 'Tomato 3': 4, 'Tomato 4': 5}
FRUIT Salak
VARIETY Salak
IMAGES (521, 100, 100, 3) (521, 1) CLASSES {'Salak': 0}
FRUIT Kaki
VARIETY Kaki
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Kaki': 0}
FRUIT Pear
VARIETY Pear Williams
VARIETY Pear Monster
VARIETY Pear Abate
VARIETY Pear
IMAGES (2099, 100, 100, 3) (2099, 4) CLASSES {'Pear Williams': 0, 'Pear Monster': 1, 'Pear Abate': 2, 'Pear': 3}
FRUIT Cocos
VARIETY Cocos
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Cocos': 0}
FRUIT Lemon
VARIETY Lemon Meyer
VARIETY Lemon
IMAGES (1049, 100, 100, 3) (1049, 2) CLASSES {'Lemon Meyer': 0, 'Lemon': 1}
FRUIT Kumquats
VARIETY Kumquats
IMAGES (524, 100, 100, 3) (524, 1) CLASSES {'Kumquats': 0}
              total        used        free      shared  buff/cache   available
Mem:          64146       20753       33471          95        9921       42644
Swap:         65187        5624       59563

Add Each Cascade (Finer) Classifier

1. Get the bottleneck layer for the coarse CNN
2. Add an independent finer classifier per fruit from the bottleneck layer

In [17]:
bottleneck = Bottleneck(model)
cascades = []
for key, val in varieties_datasets.items():
    classes = val['classes']
    print("KEY", key, classes)
    # if only one subclassifier, then skip (i.e., coarse == finer)
    if len(classes) == 1:
        continue
    x = layers.Conv2D(128, (3,3), padding='same', activation='relu')(bottleneck.output)
    x = BatchNormalization()(x)
    x = MaxPooling2D((2,2))(x)
    
    x = layers.Flatten()(bottleneck.output)
    x = layers.Dense(1024, activation='relu')(x)
    x = layers.Dense(len(classes), activation='softmax', name=key.replace(' ', ''))(x)
    cascades.append(x)


BOTTLENECK (?, 12, 12, 128)
KEY Avocado {'Avocado': 0, 'Avocado ripe': 1}
KEY Rambutan {'Rambutan': 0}
KEY Pineapple {'Pineapple': 0, 'Pineapple Mini': 1}
KEY Kiwi {'Kiwi': 0}
KEY Cantaloupe {'Cantaloupe 1': 0, 'Cantaloupe 2': 1}
KEY Apple {'Apple Golden 2': 0, 'Apple Red 3': 1, 'Apple Red Yellow': 2, 'Apple Granny Smith': 3, 'Apple Red 2': 4, 'Apple Braeburn': 5, 'Apple Golden 3': 6, 'Apple Red Delicious': 7, 'Apple Red 1': 8, 'Apple Golden 1': 9}
KEY Tamarillo {'Tamarillo': 0}
KEY Physalis {'Physalis': 0, 'Physalis with Husk': 1}
KEY Plum {'Plum': 0}
KEY Pitahaya {'Pitahaya Red': 0}
KEY Guava {'Guava': 0}
KEY Limes {'Limes': 0}
KEY Grapefruit {'Grapefruit White': 0, 'Grapefruit Pink': 1}
KEY Peach {'Peach': 0, 'Peach Flat': 1}
KEY Pomegranate {'Pomegranate': 0}
KEY Nectarine {'Nectarine': 0}
KEY Apricot {'Apricot': 0}
KEY Banana {'Banana': 0, 'Banana Red': 1}
KEY Cherry {'Cherry Rainier': 0, 'Cherry 2': 1, 'Carambula': 2, 'Cherry Wax Yellow': 3, 'Cherry Wax Black': 4, 'Cherry 1': 5, 'Cherry Wax Red': 6}
KEY Mulberry {'Mulberry': 0}
KEY Raspberry {'Rambutan': 0, 'Raspberry': 1}
KEY Cactus Fruit {'Cactus fruit': 0}
KEY Grape {'Grape White': 0, 'Grape Pink': 1, 'Grape White 2': 2}
KEY Mandarine {'Mandarine': 0}
KEY Granadilla {'Granadilla': 0}
KEY Carambula {'Carambula': 0}
KEY Passion Fruit {'Passion Fruit': 0}
KEY Lychee {'Lychee': 0}
KEY Quince {'Quince': 0}
KEY Maracuja {'Maracuja': 0}
KEY Strawberry {'Strawberry Wedge': 0, 'Strawberry': 1}
KEY Tangelo {'Tangelo': 0}
KEY Huckleberry {'Huckleberry': 0}
KEY Orange {'Orange': 0}
KEY Dates {'Dates': 0}
KEY Melon {'Melon Piel de Sapo': 0}
KEY Pepino {'Pepino': 0}
KEY Clementine {'Clementine': 0}
KEY Papaya {'Papaya': 0}
KEY Mango {'Mango': 0}
KEY Tomato {'Tomato 2': 0, 'Tomato Cherry Red': 1, 'Tomato Maroon': 2, 'Tomato 1': 3, 'Tomato 3': 4, 'Tomato 4': 5}
KEY Salak {'Salak': 0}
KEY Kaki {'Kaki': 0}
KEY Pear {'Pear Williams': 0, 'Pear Monster': 1, 'Pear Abate': 2, 'Pear': 3}
KEY Cocos {'Cocos': 0}
KEY Lemon {'Lemon Meyer': 0, 'Lemon': 1}
KEY Kumquats {'Kumquats': 0}

Compile each finer classifier


In [18]:
classifiers = []
for cascade in cascades:
    _model = Model(model.input, cascade)
    _model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    _model.summary()
    classifiers.append(_model)


_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_3 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Avocado (Dense)              (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_3 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_4 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Pineapple (Dense)            (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_4 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_5 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Cantaloupe (Dense)           (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_5 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_6 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Apple (Dense)                (None, 10)                10250     
=================================================================
Total params: 18,983,082
Trainable params: 18,885,642
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_6 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_7 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Physalis (Dense)             (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_7 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_8 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Grapefruit (Dense)           (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_8 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_9 (Dense)              (None, 1024)              18875392  
_________________________________________________________________
Peach (Dense)                (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_9 (Flatten)          (None, 18432)             0         
_________________________________________________________________
dense_10 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Banana (Dense)               (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_10 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_11 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Cherry (Dense)               (None, 7)                 7175      
=================================================================
Total params: 18,980,007
Trainable params: 18,882,567
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_11 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_12 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Raspberry (Dense)            (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_12 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_13 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Grape (Dense)                (None, 3)                 3075      
=================================================================
Total params: 18,975,907
Trainable params: 18,878,467
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_13 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_14 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Strawberry (Dense)           (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_14 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_15 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Tomato (Dense)               (None, 6)                 6150      
=================================================================
Total params: 18,978,982
Trainable params: 18,881,542
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_15 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_16 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Pear (Dense)                 (None, 4)                 4100      
=================================================================
Total params: 18,976,932
Trainable params: 18,879,492
Non-trainable params: 97,440
_________________________________________________________________
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1_input (InputLayer)  (None, 100, 100, 3)       0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 100, 100, 16)      448       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 100, 100, 32)      4640      
_________________________________________________________________
re_lu_1 (ReLU)               (None, 100, 100, 32)      0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 100, 100, 32)      0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 50, 50, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 50, 50, 64)        18496     
_________________________________________________________________
re_lu_2 (ReLU)               (None, 50, 50, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 25, 25, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 25, 128)       73856     
_________________________________________________________________
bottleneck (MaxPooling2D)    (None, 12, 12, 128)       0         
_________________________________________________________________
flatten_16 (Flatten)         (None, 18432)             0         
_________________________________________________________________
dense_17 (Dense)             (None, 1024)              18875392  
_________________________________________________________________
Lemon (Dense)                (None, 2)                 2050      
=================================================================
Total params: 18,974,882
Trainable params: 18,877,442
Non-trainable params: 97,440
_________________________________________________________________

Train the finer classifiers


In [19]:
for classifier in classifiers:
    # get the output layer for this subclassifier
    last = classifier.layers[len(classifier.layers)-1]
    print(last, last.name)
    
    # find the corresponding variety dataset
    for key, dataset in varieties_datasets.items():
        if key == last.name:
            x_train, y_train = dataset['train']
            x_val, y_val     = dataset['val']

            datagen = Feeder()
            Train(classifier, datagen, x_train, y_train, x_val, y_val, 5)


<keras.layers.core.Dense object at 0x7f622995a9b0> Avocado
Epoch 1/5
28/27 [==============================] - 8s 274ms/step - loss: 0.0588 - acc: 0.9620 - val_loss: 1.1626e-04 - val_acc: 1.0000
Epoch 2/5
28/27 [==============================] - 5s 196ms/step - loss: 3.6445e-06 - acc: 1.0000 - val_loss: 4.3129e-05 - val_acc: 1.0000
Epoch 3/5
28/27 [==============================] - 5s 194ms/step - loss: 8.5374e-07 - acc: 1.0000 - val_loss: 4.0188e-05 - val_acc: 1.0000
Epoch 4/5
28/27 [==============================] - 5s 190ms/step - loss: 8.1645e-07 - acc: 1.0000 - val_loss: 3.9653e-05 - val_acc: 1.0000
Epoch 5/5
28/27 [==============================] - 5s 182ms/step - loss: 6.9528e-07 - acc: 1.0000 - val_loss: 3.9208e-05 - val_acc: 1.0000
882/882 [==============================] - 2s 2ms/step
Train [3.1851555930955815e-05, 1.0]
<keras.layers.core.Dense object at 0x7f62297766a0> Pineapple
Epoch 1/5
30/29 [==============================] - 6s 216ms/step - loss: 0.0656 - acc: 0.9666 - val_loss: 8.1402e-04 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 5s 181ms/step - loss: 1.3917e-05 - acc: 1.0000 - val_loss: 0.0022 - val_acc: 1.0000
Epoch 3/5
30/29 [==============================] - 6s 185ms/step - loss: 5.6931e-06 - acc: 1.0000 - val_loss: 0.0031 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 6s 185ms/step - loss: 3.4368e-06 - acc: 1.0000 - val_loss: 0.0033 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 6s 185ms/step - loss: 4.9285e-06 - acc: 1.0000 - val_loss: 0.0029 - val_acc: 1.0000
943/943 [==============================] - 2s 2ms/step
Train [0.0017961749410965852, 1.0]
<keras.layers.core.Dense object at 0x7f62296131d0> Cantaloupe
Epoch 1/5
30/29 [==============================] - 6s 215ms/step - loss: 0.0263 - acc: 0.9719 - val_loss: 1.9471e-07 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 6s 186ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.5270e-07 - val_acc: 1.0000
Epoch 3/5
30/29 [==============================] - 6s 191ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.5100e-07 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 6s 192ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.5043e-07 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 6s 191ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.5043e-07 - val_acc: 1.0000
944/944 [==============================] - 2s 3ms/step
Train [1.5387344834087314e-07, 1.0]
<keras.layers.core.Dense object at 0x7f6229493ac8> Apple
Epoch 1/5
146/145 [==============================] - 28s 195ms/step - loss: 0.2106 - acc: 0.9238 - val_loss: 0.2795 - val_acc: 0.8762
Epoch 2/5
146/145 [==============================] - 27s 186ms/step - loss: 0.0223 - acc: 0.9940 - val_loss: 0.2492 - val_acc: 0.8878
Epoch 3/5
146/145 [==============================] - 27s 184ms/step - loss: 0.0170 - acc: 0.9955 - val_loss: 0.2986 - val_acc: 0.8607
Epoch 4/5
146/145 [==============================] - 27s 186ms/step - loss: 0.0125 - acc: 0.9955 - val_loss: 0.4114 - val_acc: 0.8162
Epoch 5/5
146/145 [==============================] - 27s 184ms/step - loss: 0.0033 - acc: 0.9994 - val_loss: 0.4460 - val_acc: 0.8240
4653/4653 [==============================] - 11s 2ms/step
Train [0.517334802097437, 0.7986245433438242]
<keras.layers.core.Dense object at 0x7f62292ad828> Physalis
Epoch 1/5
30/29 [==============================] - 7s 218ms/step - loss: 0.0232 - acc: 0.9844 - val_loss: 5.0205e-06 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 5s 183ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 3.2874e-06 - val_acc: 1.0000
Epoch 3/5
30/29 [==============================] - 6s 186ms/step - loss: 1.2008e-07 - acc: 1.0000 - val_loss: 3.2096e-06 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 6s 186ms/step - loss: 1.1958e-07 - acc: 1.0000 - val_loss: 3.2028e-06 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 6s 186ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 3.2022e-06 - val_acc: 1.0000
944/944 [==============================] - 2s 2ms/step
Train [2.059461342284167e-05, 1.0]
<keras.layers.core.Dense object at 0x7f60ae144358> Grapefruit
Epoch 1/5
30/29 [==============================] - 6s 216ms/step - loss: 0.0242 - acc: 0.9812 - val_loss: 2.2119e-05 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 5s 182ms/step - loss: 1.2871e-07 - acc: 1.0000 - val_loss: 1.5222e-05 - val_acc: 1.0000
Epoch 3/5
30/29 [==============================] - 6s 189ms/step - loss: 1.2629e-07 - acc: 1.0000 - val_loss: 1.4822e-05 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 5s 183ms/step - loss: 1.3039e-07 - acc: 1.0000 - val_loss: 1.4711e-05 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 6s 186ms/step - loss: 1.2753e-07 - acc: 1.0000 - val_loss: 1.4579e-05 - val_acc: 1.0000
944/944 [==============================] - 2s 3ms/step
Train [2.3263756424890065e-05, 1.0]
<keras.layers.core.Dense object at 0x7f60adfcbfd0> Peach
Epoch 1/5
30/29 [==============================] - 7s 222ms/step - loss: 0.0416 - acc: 0.9812 - val_loss: 0.0040 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 6s 189ms/step - loss: 0.0012 - acc: 0.9990 - val_loss: 0.0535 - val_acc: 0.9810
Epoch 3/5
30/29 [==============================] - 6s 185ms/step - loss: 2.2926e-04 - acc: 1.0000 - val_loss: 0.0015 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 6s 188ms/step - loss: 6.4975e-07 - acc: 1.0000 - val_loss: 0.0011 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 6s 188ms/step - loss: 4.1982e-07 - acc: 1.0000 - val_loss: 0.0011 - val_acc: 1.0000
944/944 [==============================] - 2s 2ms/step
Train [0.0010120372087424013, 1.0]
<keras.layers.core.Dense object at 0x7f60adde6f28> Banana
Epoch 1/5
30/29 [==============================] - 7s 219ms/step - loss: 0.0470 - acc: 0.9719 - val_loss: 0.0018 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 6s 185ms/step - loss: 8.4761e-06 - acc: 1.0000 - val_loss: 7.3545e-04 - val_acc: 1.0000
Epoch 3/5
30/29 [==============================] - 5s 181ms/step - loss: 1.0674e-05 - acc: 1.0000 - val_loss: 6.4712e-04 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 6s 185ms/step - loss: 5.5472e-06 - acc: 1.0000 - val_loss: 6.1552e-04 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 6s 187ms/step - loss: 4.6980e-06 - acc: 1.0000 - val_loss: 5.8839e-04 - val_acc: 1.0000
944/944 [==============================] - 2s 2ms/step
Train [0.0003026937695922551, 1.0]
<keras.layers.core.Dense object at 0x7f60adc7aa20> Cherry
Epoch 1/5
37/36 [==============================] - 8s 216ms/step - loss: 0.2950 - acc: 0.8860 - val_loss: 0.1023 - val_acc: 0.9618
Epoch 2/5
37/36 [==============================] - 7s 184ms/step - loss: 0.1187 - acc: 0.9568 - val_loss: 0.0552 - val_acc: 0.9847
Epoch 3/5
37/36 [==============================] - 7s 188ms/step - loss: 0.1273 - acc: 0.9489 - val_loss: 0.0889 - val_acc: 0.9695
Epoch 4/5
37/36 [==============================] - 7s 188ms/step - loss: 0.0855 - acc: 0.9634 - val_loss: 0.0581 - val_acc: 0.9924
Epoch 5/5
37/36 [==============================] - 7s 192ms/step - loss: 0.0918 - acc: 0.9583 - val_loss: 0.0609 - val_acc: 0.9847
1179/1179 [==============================] - 3s 3ms/step
Train [0.09612723731888463, 0.9609838851535594]
<keras.layers.core.Dense object at 0x7f60a9e78550> Raspberry
Epoch 1/5
15/14 [==============================] - 4s 257ms/step - loss: 0.0347 - acc: 0.9937 - val_loss: 6.7927e-07 - val_acc: 1.0000
Epoch 2/5
15/14 [==============================] - 3s 187ms/step - loss: 1.2070e-07 - acc: 1.0000 - val_loss: 1.3833e-07 - val_acc: 1.0000
Epoch 3/5
15/14 [==============================] - 3s 182ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.2483e-07 - val_acc: 1.0000
Epoch 4/5
15/14 [==============================] - 3s 187ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.2146e-07 - val_acc: 1.0000
Epoch 5/5
15/14 [==============================] - 3s 180ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.2146e-07 - val_acc: 1.0000
470/470 [==============================] - 1s 2ms/step
Train [1.2440884366948555e-07, 1.0]
<keras.layers.core.Dense object at 0x7f60a9cf3b70> Grape
Epoch 1/5
45/44 [==============================] - 10s 212ms/step - loss: 0.0321 - acc: 0.9847 - val_loss: 0.4649 - val_acc: 0.7658
Epoch 2/5
45/44 [==============================] - 8s 184ms/step - loss: 1.2833e-05 - acc: 1.0000 - val_loss: 0.6064 - val_acc: 0.7278
Epoch 3/5
45/44 [==============================] - 9s 193ms/step - loss: 7.4392e-06 - acc: 1.0000 - val_loss: 0.7033 - val_acc: 0.6962
Epoch 4/5
45/44 [==============================] - 8s 189ms/step - loss: 6.0521e-06 - acc: 1.0000 - val_loss: 0.6891 - val_acc: 0.7025
Epoch 5/5
45/44 [==============================] - 8s 185ms/step - loss: 5.5889e-06 - acc: 1.0000 - val_loss: 0.7612 - val_acc: 0.6835
1416/1416 [==============================] - 3s 2ms/step
Train [0.7892591367333622, 0.702683615819209]
<keras.layers.core.Dense object at 0x7f60a9b935c0> Strawberry
Epoch 1/5
37/36 [==============================] - 8s 218ms/step - loss: 0.0207 - acc: 0.9890 - val_loss: 2.8583e-07 - val_acc: 1.0000
Epoch 2/5
37/36 [==============================] - 7s 191ms/step - loss: 1.9574e-07 - acc: 1.0000 - val_loss: 2.3029e-07 - val_acc: 1.0000
Epoch 3/5
37/36 [==============================] - 7s 185ms/step - loss: 2.5435e-07 - acc: 1.0000 - val_loss: 2.3029e-07 - val_acc: 1.0000
Epoch 4/5
37/36 [==============================] - 7s 185ms/step - loss: 7.2514e-07 - acc: 1.0000 - val_loss: 2.3661e-07 - val_acc: 1.0000
Epoch 5/5
37/36 [==============================] - 7s 186ms/step - loss: 3.0224e-07 - acc: 1.0000 - val_loss: 2.3977e-07 - val_acc: 1.0000
1180/1180 [==============================] - 3s 2ms/step
Train [1.0047292608140011e-06, 1.0]
<keras.layers.core.Dense object at 0x7f60a99b9550> Tomato
Epoch 1/5
105/104 [==============================] - 21s 197ms/step - loss: 0.1086 - acc: 0.9554 - val_loss: 0.0535 - val_acc: 0.9973
Epoch 2/5
105/104 [==============================] - 20s 186ms/step - loss: 0.0180 - acc: 0.9946 - val_loss: 0.0643 - val_acc: 0.9946
Epoch 3/5
105/104 [==============================] - 20s 186ms/step - loss: 0.0029 - acc: 0.9988 - val_loss: 0.0451 - val_acc: 0.9946
Epoch 4/5
105/104 [==============================] - 20s 186ms/step - loss: 0.0150 - acc: 0.9955 - val_loss: 0.0517 - val_acc: 0.9812
Epoch 5/5
105/104 [==============================] - 20s 188ms/step - loss: 0.0070 - acc: 0.9976 - val_loss: 0.0168 - val_acc: 1.0000
3350/3350 [==============================] - 8s 2ms/step
Train [0.014588202945888043, 0.9988059701492538]
<keras.layers.core.Dense object at 0x7f60a9830390> Pear
Epoch 1/5
60/59 [==============================] - 14s 236ms/step - loss: 0.0529 - acc: 0.9755 - val_loss: 0.0268 - val_acc: 1.0000
Epoch 2/5
60/59 [==============================] - 13s 212ms/step - loss: 7.2313e-05 - acc: 1.0000 - val_loss: 0.0057 - val_acc: 1.0000
Epoch 3/5
60/59 [==============================] - 13s 212ms/step - loss: 3.2620e-05 - acc: 1.0000 - val_loss: 0.0061 - val_acc: 1.0000
Epoch 4/5
60/59 [==============================] - 13s 213ms/step - loss: 1.8335e-05 - acc: 1.0000 - val_loss: 0.0059 - val_acc: 1.0000
Epoch 5/5
60/59 [==============================] - 13s 211ms/step - loss: 2.7962e-05 - acc: 1.0000 - val_loss: 0.0064 - val_acc: 1.0000
1889/1889 [==============================] - 4s 2ms/step
Train [0.00811844131755981, 1.0]
<keras.layers.core.Dense object at 0x7f60a96ccb00> Lemon
Epoch 1/5
30/29 [==============================] - 7s 224ms/step - loss: 0.0224 - acc: 0.9865 - val_loss: 2.0606e-07 - val_acc: 1.0000
Epoch 2/5
30/29 [==============================] - 5s 182ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.6576e-07 - val_acc: 1.0000
Epoch 3/5
30/29 [==============================] - 5s 182ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.6462e-07 - val_acc: 1.0000
Epoch 4/5
30/29 [==============================] - 5s 182ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.6462e-07 - val_acc: 1.0000
Epoch 5/5
30/29 [==============================] - 5s 183ms/step - loss: 1.1921e-07 - acc: 1.0000 - val_loss: 1.6462e-07 - val_acc: 1.0000
944/944 [==============================] - 2s 2ms/step
Train [1.9251557413384544e-07, 1.0]

Evaluate the Model

1. Evaluate the Model for each finer classifier.

In [20]:
for classifier in classifiers:
    # get the output layer for this subclassifier
    last = classifier.layers[len(classifier.layers)-1]
    print(last, last.name)
    
    # find the corresponding variety dataset
    for key, dataset in varieties_datasets.items():
        if key == last.name:
            x_test, y_test = dataset['test']
            scores = classifier.evaluate(x_test, y_test, verbose=1)
            print("Test", scores)


<keras.layers.core.Dense object at 0x7f622995a9b0> Avocado
246/246 [==============================] - 1s 3ms/step
Test [3.334964506992525e-05, 1.0]
<keras.layers.core.Dense object at 0x7f62297766a0> Pineapple
263/263 [==============================] - 1s 2ms/step
Test [0.0016150613485378684, 1.0]
<keras.layers.core.Dense object at 0x7f62296131d0> Cantaloupe
263/263 [==============================] - 1s 3ms/step
Test [1.6362951567596597e-07, 1.0]
<keras.layers.core.Dense object at 0x7f6229493ac8> Apple
1293/1293 [==============================] - 3s 2ms/step
Test [0.5182560322848015, 0.7973704563492688]
<keras.layers.core.Dense object at 0x7f62292ad828> Physalis
263/263 [==============================] - 1s 2ms/step
Test [2.5120300804652986e-06, 1.0]
<keras.layers.core.Dense object at 0x7f60ae144358> Grapefruit
263/263 [==============================] - 1s 2ms/step
Test [2.3878306024448906e-05, 1.0]
<keras.layers.core.Dense object at 0x7f60adfcbfd0> Peach
263/263 [==============================] - 1s 3ms/step
Test [0.0013185769895856542, 1.0]
<keras.layers.core.Dense object at 0x7f60adde6f28> Banana
263/263 [==============================] - 1s 2ms/step
Test [0.0003372718393437462, 1.0]
<keras.layers.core.Dense object at 0x7f60adc7aa20> Cherry
328/328 [==============================] - 1s 3ms/step
Test [0.09346718377456432, 0.9512195121951219]
<keras.layers.core.Dense object at 0x7f60a9e78550> Raspberry
131/131 [==============================] - 0s 2ms/step
Test [1.1966428716458243e-07, 1.0]
<keras.layers.core.Dense object at 0x7f60a9cf3b70> Grape
394/394 [==============================] - 1s 2ms/step
Test [0.7861503450398518, 0.710659898779719]
<keras.layers.core.Dense object at 0x7f60a9b935c0> Strawberry
328/328 [==============================] - 1s 2ms/step
Test [0.001072080738674131, 1.0]
<keras.layers.core.Dense object at 0x7f60a99b9550> Tomato
931/931 [==============================] - 2s 2ms/step
Test [0.017835404435782888, 0.9967776584317938]
<keras.layers.core.Dense object at 0x7f60a9830390> Pear
525/525 [==============================] - 1s 2ms/step
Test [0.008367355272528671, 1.0]
<keras.layers.core.Dense object at 0x7f60a96ccb00> Lemon
263/263 [==============================] - 1s 3ms/step
Test [1.5025812138251395e-07, 1.0]

Save the Finer Models


In [21]:
n = 0
for classifier in classifiers:
    classifier.save('model-finer-' + str(n) + '.h5')
    n += 1

Let's do some cascading predictions

We will take one random selected image per type of fruit, and:

1. Run the image through the coarse classifier (by fruit).
2. Based on the predicted output, select the corresponding finer classifier (by variety).
3. Run the image through the corresponding finer classifier.

In [22]:
import random

# Let's make a prediction for each type of fruit
for key, dataset in varieties_datasets.items():
    
    # Get the variety test data for this type of fruit
    x_test, y_test = dataset['test']
    
    # pick a random image in the variety datast
    index = random.randint(0, len(x_test))
    
    # use the coarse model to predict the type of fruit
    yhat = np.argmax( model.predict(x_test[index:index+1]) )
    
    # let's find the class name (type of fruit) for this predicted label
    for fruit, label in fruits_classes.items():
        if label == yhat:
            break
    
    print("Yhat", yhat, "Coarse Prediction", key, "=", fruit)
    
    # Prediction was correct
    if key == fruit:
        if len(dataset['classes']) == 1:
            print("No Finer Classifier")
            continue
            
        # find the corresponding finer classifier for this type of fruit
        for classifier in classifiers:
            # get the output layer for this subclassifier
            last = classifier.layers[len(classifier.layers)-1]
            if last.name == fruit:
                # use the finer model to predict the variety of this type of fruit
                yhat = np.argmax(classifier.predict(x_test[index:index+1]))
                for variety, value in dataset['classes'].items():
                    if value == np.argmax(y_test[index]):
                        break
                for yhat_variety, value in dataset['classes'].items():
                    if value == yhat:
                        break
                print("Yhat", yhat, "Finer  Prediction", variety, "=", yhat_variety)
                break


Yhat 0 Coarse Prediction Avocado = Avocado
Yhat 1 Finer  Prediction Avocado ripe = Avocado ripe
Yhat 20 Coarse Prediction Rambutan = Raspberry
Yhat 2 Coarse Prediction Pineapple = Pineapple
Yhat 0 Finer  Prediction Pineapple = Pineapple
Yhat 3 Coarse Prediction Kiwi = Kiwi
No Finer Classifier
Yhat 4 Coarse Prediction Cantaloupe = Cantaloupe
Yhat 1 Finer  Prediction Cantaloupe 2 = Cantaloupe 2
Yhat 5 Coarse Prediction Apple = Apple
Yhat 4 Finer  Prediction Apple Red 2 = Apple Red 2
Yhat 6 Coarse Prediction Tamarillo = Tamarillo
No Finer Classifier
Yhat 7 Coarse Prediction Physalis = Physalis
Yhat 1 Finer  Prediction Physalis with Husk = Physalis with Husk
Yhat 8 Coarse Prediction Plum = Plum
No Finer Classifier
Yhat 9 Coarse Prediction Pitahaya = Pitahaya
No Finer Classifier
Yhat 10 Coarse Prediction Guava = Guava
No Finer Classifier
Yhat 11 Coarse Prediction Limes = Limes
No Finer Classifier
Yhat 12 Coarse Prediction Grapefruit = Grapefruit
Yhat 1 Finer  Prediction Grapefruit Pink = Grapefruit Pink
Yhat 13 Coarse Prediction Peach = Peach
Yhat 0 Finer  Prediction Peach = Peach
Yhat 14 Coarse Prediction Pomegranate = Pomegranate
No Finer Classifier
Yhat 15 Coarse Prediction Nectarine = Nectarine
No Finer Classifier
Yhat 16 Coarse Prediction Apricot = Apricot
No Finer Classifier
Yhat 17 Coarse Prediction Banana = Banana
Yhat 0 Finer  Prediction Banana = Banana
Yhat 18 Coarse Prediction Cherry = Cherry
Yhat 2 Finer  Prediction Carambula = Carambula
Yhat 19 Coarse Prediction Mulberry = Mulberry
No Finer Classifier
Yhat 20 Coarse Prediction Raspberry = Raspberry
Yhat 1 Finer  Prediction Raspberry = Raspberry
Yhat 35 Coarse Prediction Cactus Fruit = Melon
Yhat 22 Coarse Prediction Grape = Grape
Yhat 2 Finer  Prediction Grape White 2 = Grape White 2
Yhat 23 Coarse Prediction Mandarine = Mandarine
No Finer Classifier
Yhat 24 Coarse Prediction Granadilla = Granadilla
No Finer Classifier
Yhat 18 Coarse Prediction Carambula = Cherry
Yhat 26 Coarse Prediction Passion Fruit = Passion Fruit
No Finer Classifier
Yhat 27 Coarse Prediction Lychee = Lychee
No Finer Classifier
Yhat 28 Coarse Prediction Quince = Quince
No Finer Classifier
Yhat 29 Coarse Prediction Maracuja = Maracuja
No Finer Classifier
Yhat 30 Coarse Prediction Strawberry = Strawberry
Yhat 0 Finer  Prediction Strawberry Wedge = Strawberry Wedge
Yhat 31 Coarse Prediction Tangelo = Tangelo
No Finer Classifier
Yhat 32 Coarse Prediction Huckleberry = Huckleberry
No Finer Classifier
Yhat 33 Coarse Prediction Orange = Orange
No Finer Classifier
Yhat 34 Coarse Prediction Dates = Dates
No Finer Classifier
Yhat 35 Coarse Prediction Melon = Melon
No Finer Classifier
Yhat 36 Coarse Prediction Pepino = Pepino
No Finer Classifier
Yhat 37 Coarse Prediction Clementine = Clementine
No Finer Classifier
Yhat 38 Coarse Prediction Papaya = Papaya
No Finer Classifier
Yhat 39 Coarse Prediction Mango = Mango
No Finer Classifier
Yhat 40 Coarse Prediction Tomato = Tomato
Yhat 1 Finer  Prediction Tomato Cherry Red = Tomato Cherry Red
Yhat 41 Coarse Prediction Salak = Salak
No Finer Classifier
Yhat 42 Coarse Prediction Kaki = Kaki
No Finer Classifier
Yhat 43 Coarse Prediction Pear = Pear
Yhat 0 Finer  Prediction Pear Williams = Pear Williams
Yhat 44 Coarse Prediction Cocos = Cocos
No Finer Classifier
Yhat 45 Coarse Prediction Lemon = Lemon
Yhat 0 Finer  Prediction Lemon Meyer = Lemon Meyer
Yhat 46 Coarse Prediction Kumquats = Kumquats
No Finer Classifier

End of Notebook


In [ ]:
#     extractfeatures = Model(input=model.input, output=model.get_layer('bottleneck').output)