cnn_keras.py 23.3 KB
Newer Older
1 2 3 4 5 6
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
"""
    Generic classifier with multiple models
    Models -> (Xception, VGG16, VGG19, ResNet50, InceptionV3, MobileNet)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
7

8 9 10 11 12 13
    Name: cnn_keras.py
    Author: Gabriel Kirsten Menezes (gabriel.kirsten@hotmail.com)

"""
import time
import os
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
14 15
import shutil
import random
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
16
import numpy as np
17
import json
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
18 19 20
import logging
import sys

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
21
from PIL import Image
22 23 24
from keras import applications
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
25
from keras.models import Model, load_model
26
from keras.layers import Dropout, Flatten, Dense
27 28
from keras.callbacks import ModelCheckpoint, TensorBoard
from keras import backend as K
29 30 31
from numpy import resize, expand_dims
from keras.preprocessing.image import load_img, img_to_array
        
32

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
33
from interface.interface import InterfaceException as IException
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
34
from classification.classifier import Classifier
35 36 37 38 39 40

from collections import OrderedDict

from util.config import Config
from util.file_utils import File
from util.utils import TimeUtils
41
        
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
42 43 44 45

logger = logging.getLogger('PIL')
logger.setLevel(logging.WARNING)

46 47 48 49 50 51 52
START_TIME = time.time()

# =========================================================
# Constants
# =========================================================

IMG_WIDTH, IMG_HEIGHT = 256, 256
53
weight_path = None
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
54

55 56 57 58 59 60 61
dict_preprocessing = {}
dict_preprocessing[0] = applications.xception.preprocess_input, applications.xception.decode_predictions
dict_preprocessing[1] = applications.vgg16.preprocess_input, applications.vgg16.decode_predictions
dict_preprocessing[2] = applications.vgg19.preprocess_input, applications.vgg19.decode_predictions
dict_preprocessing[3] = applications.resnet50.preprocess_input, applications.resnet50.decode_predictions
dict_preprocessing[4] = applications.inception_v3.preprocess_input, applications.inception_v3.decode_predictions
dict_preprocessing[5] = applications.mobilenet.preprocess_input, applications.mobilenet.decode_predictions
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
62

63
class CNNKeras(Classifier):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
64 65
    """ Class for CNN classifiers based on Keras applications """

66
    def __init__(self, architecture="ResNet50", learning_rate=0.001, momentum=0.9, batch_size=32, epochs=50, fine_tuning_rate=100, transfer_learning=False, save_weights=True, perc_train=80, perc_validation=20, recreate_dataset=False):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
67 68 69 70
        """
            Constructor of CNNKeras
        """

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
        self.architecture = Config(
            "Architecture", architecture, str)
        self.learning_rate = Config(
            "Learning rate", learning_rate, float)
        self.momentum = Config(
            "Momentum", momentum, float)
        self.batch_size = Config(
            "Batch size", batch_size, int)
        self.epochs = Config(
            "Epochs", epochs, int)
        self.fine_tuning_rate = Config(
            "Fine Tuning Rate", fine_tuning_rate, int)
        self.transfer_learning = Config(
            "Transfer Learning", transfer_learning, bool)
        self.save_weights = Config(
            "Save weights", save_weights, bool)
87 88 89 90 91 92
        self.perc_train = Config(
            "Perc Train", perc_train, float)
        self.perc_validation = Config(
            "Perc Validation", perc_validation, float)
        self.recreate_dataset = Config(
            "Recreate Dataset", recreate_dataset, bool)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
93
        self.file_name = "kerasCNN"
94

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
95
        self.model = None
96

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
97
        self.trained = False
98 99

    def get_config(self):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
100
        """Return configuration of classifier.
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
101

102 103 104 105 106
        Returns
        -------
        config : OrderedDict
            Current configs of classifier.
        """
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
107 108
        keras_config = OrderedDict()

109 110 111 112 113 114 115 116
        keras_config["Architecture"] = self.architecture
        keras_config["Learning rate"] = self.learning_rate
        keras_config["Momentum"] = self.momentum
        keras_config["Batch size"] = self.batch_size
        keras_config["Epochs"] = self.epochs
        keras_config["Fine Tuning rate"] = self.fine_tuning_rate
        keras_config["Transfer Learning"] = self.transfer_learning
        keras_config["Save weights"] = self.save_weights
117 118 119
        keras_config["Perc Train"] = self.perc_train
        keras_config["Perc Validation"] = self.perc_validation
        keras_config["Recreate Dataset"] = self.recreate_dataset
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
120
        return keras_config
121 122

    def set_config(self, configs):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
123
        """Update configuration of classifier.
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
124

125 126 127 128 129
        Parameters
        ----------
        configs : OrderedDict
            New configs of classifier.
        """
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
130 131 132 133
        self.architecture = Config.nvl_config(
            configs["Architecture"], self.architecture)
        self.learning_rate = Config.nvl_config(
            configs["Learning rate"], self.learning_rate)
134
        self.momentum = Config.nvl_config(configs["Momentum"], self.momentum)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
135 136
        self.batch_size = Config.nvl_config(
            configs["Batch size"], self.batch_size)
137
        self.epochs = Config.nvl_config(configs["Epochs"], self.epochs)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
138 139 140 141 142 143 144 145 146 147 148 149
        self.fine_tuning_rate = Config.nvl_config(
            configs["Fine Tuning rate"], self.fine_tuning_rate)
        self.transfer_learning = Config.nvl_config(
            configs["Transfer Learning"], self.transfer_learning)
        self.save_weights = Config.nvl_config(
            configs["Save weights"], self.save_weights)
        self.perc_train = Config.nvl_config(
            configs["Perc Train"], self.perc_train)
        self.perc_validation = Config.nvl_config(
            configs["Perc Validation"], self.perc_validation)
        self.recreate_dataset = Config.nvl_config(
            configs["Recreate Dataset"], self.recreate_dataset)
150 151

    def get_summary_config(self):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
152
        """Return fomatted summary of configuration.
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
153

154 155 156 157 158
        Returns
        -------
        summary : string
            Formatted string with summary of configuration.
        """
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
159
        keras_config = OrderedDict()
160

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
161
        keras_config[self.architecture.label] = self.architecture.value
162 163 164 165
        keras_config[self.learning_rate.label] = self.learning_rate.value
        keras_config[self.momentum.label] = self.momentum.value
        keras_config[self.batch_size.label] = self.batch_size.value
        keras_config[self.epochs.label] = self.epochs.value
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
166
        keras_config[self.fine_tuning_rate.label] = self.fine_tuning_rate.value
167 168
        keras_config[self.transfer_learning.label] = self.transfer_learning.value
        keras_config[self.save_weights.label] = self.save_weights.value
169 170 171
        keras_config[self.perc_train.label] = self.perc_train.value
        keras_config[self.perc_validation.label] = self.perc_validation.value
        keras_config[self.recreate_dataset.label] = self.recreate_dataset.value
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
172 173 174
        summary = ''
        for config in keras_config:
            summary += "%s: %s\n" % (config, str(keras_config[config]))
175

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
176
        return summary
177

178
    def classify(self, dataset, test_dir, test_data, image):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
179
        """"Perform the classification.
180

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
181 182 183 184 185 186 187 188
        Parameters
        ----------
        dataset : string
            Path to image dataset.
        test_dir : string
            Not used.
        test_data : string
            Name of test data file.
189

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
190 191 192 193 194 195 196 197
        Returns
        -------
        summary : list of string
            List of predicted classes for each instance in test data in ordered way.
        """

        predict_directory = File.make_path(dataset, test_dir)

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
198
        # Create a Keras class
199 200 201 202 203 204
        if not os.path.exists(File.make_path(predict_directory, "png")):
            os.makedirs(File.make_path(predict_directory, "png"))

        for file in os.listdir(predict_directory):
            print(File.make_path(predict_directory, file))
            if os.path.splitext(file)[-1] == ".tif":
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
205 206 207 208 209 210 211 212
                try:
                    img = Image.open(File.make_path(predict_directory, file))
                    # img.thumbnail(img.size)
                    new_file = os.path.splitext(file)[0] + ".png"
                    img.save(File.make_path(predict_directory,
                                            'png', new_file), "PNG", quality=100)
                except Exception, e:
                    print e
213
            else:
214
                print File.make_path(predict_directory, file)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
215 216
                os.symlink(File.make_path(predict_directory, file),
                           File.make_path(predict_directory, 'png', file))
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
217

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
218 219 220
        classify_datagen = ImageDataGenerator()

        classify_generator = classify_datagen.flow_from_directory(
221
            File.make_path(predict_directory, 'png'),
222
            taet_size=(IMG_HEIGHT, IMG_WIDTH),
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
223 224 225 226 227
            batch_size=1,
            shuffle=False,
            class_mode=None)

        try:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
228 229
            # self.model.load_weights(
            #"../models_checkpoints/" + self.file_name + ".h5")
230 231 232
            K.clear_session()
            if self.weight_path is not None:
                self.model = load_model(self.weight_path)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
233 234
                path_classes = self.weight_path.replace(
                    "_model.h5", "_classes.npy")
235
                CLASS_NAMES = np.load(path_classes).item().keys()
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
236 237
        except Exception, e:
            raise IException("Can't load the model in " +
238
                             self.weight_path + str(e))
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
239

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
240
        output_classification = self.model.predict_generator(
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
241
            classify_generator, classify_generator.samples, verbose=2)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
242 243 244

        one_hot_output = np.argmax(output_classification, axis=1)

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
245 246
        one_hot_output = one_hot_output.tolist()

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
        for index in range(0, len(one_hot_output)):
            one_hot_output[index] = CLASS_NAMES[one_hot_output[index]]

        return one_hot_output

    def train(self, dataset, training_data, force=False):
        """Perform the training of classifier.

        Parameters
        ----------
        dataset : string
            Path to image dataset.
        training_data : string
            Name of ARFF training file.
        force : boolean, optional, default = False
            If False don't perform new training if there is trained data.
        """
264

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
265
        # select .h5 filename
266 267 268
        if self.fine_tuning_rate.value == 100:
            self.file_name = str(self.architecture.value) + \
                '_learning_rate' + str(self.learning_rate.value) + \
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
269
                '_transfer_learning'
270 271 272
        elif self.fine_tuning_rate.value == -1:
            self.file_name = str(self.architecture.value) + \
                '_learning_rate' + str(self.learning_rate.value) + \
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
273 274
                '_without_transfer_learning'
        else:
275 276
            self.file_name = str(self.architecture.value) + \
                '_learning_rate' + str(self.learning_rate.value) + \
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
277
                '_fine_tunning_' + str(self.fine_tuning_rate.value)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
278

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
279 280
        File.remove_dir(File.make_path(dataset, ".tmp"))

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
281 282
        train_generator, validation_generator, test_generator = self.make_dataset(
            dataset)
283 284 285 286 287

        # Save the model according to the conditions
        if self.save_weights:
            if not os.path.exists("../models_checkpoints/"):
                os.makedirs("../models_checkpoints/")
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
288

289
            checkpoint = ModelCheckpoint("../models_checkpoints/" + self.file_name + ".h5", monitor='val_acc',
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
290 291
                                         verbose=1, save_best_only=True, save_weights_only=False,
                                         mode='auto', period=1)
292 293 294
        else:
            checkpoint = None

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
295 296
        self.model = self.select_model_params(train_generator.num_classes)

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
297 298 299
        tensorboard = TensorBoard(
            log_dir="../models_checkpoints/logs_" + self.file_name, write_images=False)
        # tensorboard.set_model(self.model)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
300 301 302 303 304
        # compile the model
        self.model.compile(loss="categorical_crossentropy",
                           optimizer=optimizers.SGD(
                               lr=self.learning_rate.value, momentum=self.momentum.value),
                           metrics=["accuracy"])
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
305

306
        # Train the model
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
307
        self.model.fit_generator(
308
            train_generator,
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
309 310
            steps_per_epoch=train_generator.samples // self.batch_size.value,
            epochs=self.epochs.value,
311 312 313
            callbacks=[checkpoint, tensorboard],
            validation_data=validation_generator,
            validation_steps=validation_generator.samples // self.batch_size.value)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
314 315

        if self.save_weights:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
316
            # self.model.save_weights(
317 318 319 320 321 322
            #    "../models_checkpoints/" + self.file_name + ".h5")
            self.model.save(
                "../models_checkpoints/" + self.file_name + "_model.h5")
            self.weight_path = "../models_checkpoints/" + self.file_name + "_model.h5"

            dict_classes = validation_generator.class_indices
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
323 324
            np.save("../models_checkpoints/" + self.file_name +
                    "_classes.npy", dict_classes)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
325 326

    def must_train(self):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
327
        """Return if classifier must be trained.
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
328 329 330 331 332

        Returns
        -------
        True
        """
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
333
        return not self.trained
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
334 335

    def must_extract_features(self):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
336
        """Return if classifier must be extracted features.
337

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
338 339 340 341 342
        Returns
        -------
        False
        """
        return False
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
343 344 345 346

    def select_model_params(self, num_classes):
        if self.fine_tuning_rate.value != -1:
            if self.architecture.value == "Xception":
347
                self.app = 0
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
348 349 350
                model = applications.Xception(
                    weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "VGG16":
351
                self.app = 1
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
352 353 354
                model = applications.VGG16(
                    weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "VGG19":
355
                self.app = 2
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
356 357 358
                model = applications.VGG19(
                    weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "ResNet50":
359
                self.app = 3
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
360 361 362
                model = applications.ResNet50(
                    weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "InceptionV3":
363
                self.app = 4
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
364 365 366
                model = applications.InceptionV3(
                    weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "MobileNet":
367
                self.app = 5
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
368 369 370
                model = applications.MobileNet(
                    weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))

371
            for layer in model.layers[:int(len(model.layers) * (self.fine_tuning_rate.value / 100.0))]:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
372 373 374 375
                layer.trainable = False

        else:  # without transfer learning
            if self.architecture.value == "Xception":
376
                self.app = 0
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
377 378 379
                model = applications.Xception(
                    weights=None, include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "VGG16":
380
                self.app = 1
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
381 382 383
                model = applications.VGG16(
                    weights=None, include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "VGG19":
384
                self.app = 2
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
385 386 387
                model = applications.VGG19(
                    weights=None, include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "ResNet50":
388
                self.app = 3
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
389 390 391
                model = applications.ResNet50(
                    weights=None, include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "InceptionV3":
392
                self.app = 4
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
393 394 395
                model = applications.InceptionV3(
                    weights=None, include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            elif self.architecture.value == "MobileNet":
396
                self.app = 5
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
                model = applications.MobileNet(
                    weights=None, include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
            for layer in model.layers:
                layer.trainable = True

        # Adding custom Layers
        new_custom_layers = model.output
        new_custom_layers = Flatten()(new_custom_layers)
        new_custom_layers = Dense(1024, activation="relu")(new_custom_layers)
        new_custom_layers = Dropout(0.5)(new_custom_layers)
        new_custom_layers = Dense(1024, activation="relu")(new_custom_layers)
        predictions = Dense(num_classes,
                            activation="softmax")(new_custom_layers)

        # creating the final model
        model = Model(inputs=model.input, outputs=predictions)

        return model

    def make_dataset(self, dataset):

        # create symbolic links to the dataset
419 420
        KERAS_DATASET_DIR_NAME = ".keras_dataset"
        #KERAS_DATASET_DIR_NAME = File.make_path("..", os.path.split(dataset)[-1] + "_keras_dataset")
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
421 422
        KERAS_DIR_TRAIN_NAME = "train"
        KERAS_DIR_VALIDATION_NAME = "validation"
423 424 425 426
        KERAS_DIR_TEST_NAME = "test"
        PERC_TRAIN = self.perc_train.value
        PERC_VALIDATION = self.perc_validation.value

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
427
        # create keras dir dataset
428 429 430 431
        if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME)) or self.recreate_dataset.value:
            if os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME)):
                shutil.rmtree(File.make_path(dataset, KERAS_DATASET_DIR_NAME))

Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
432 433
            os.makedirs(File.make_path(dataset, KERAS_DATASET_DIR_NAME))

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
            # create keras dir train
            if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME)):
                os.makedirs(File.make_path(
                    dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME))

            # create keras dir validation
            if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME)):
                os.makedirs(File.make_path(
                    dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME))

            # create keras dir test
            if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TEST_NAME)):
                os.makedirs(File.make_path(
                    dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TEST_NAME))

            dir_classes = sorted(File.list_dirs(dataset))

            if KERAS_DATASET_DIR_NAME in dir_classes:
                dir_classes.remove(KERAS_DATASET_DIR_NAME)

            for dir_class in dir_classes:
                root = File.make_path(dataset, dir_class)
                files = os.listdir(root)
                random.shuffle(files)
                quant_files = len(files)
                quant_train = int((quant_files / 100.0) * PERC_TRAIN)
                quant_validation = int((quant_files / 100.0) * PERC_VALIDATION)

                files_train = files[0:quant_train]
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
463 464 465 466 467
                files_validation = files[quant_train:quant_train +
                                         quant_validation]
                files_test = files[quant_train + quant_validation:quant_files]
                print("Processing class %s - %d itens - %d train items - %d validation items" %
                      (dir_class, quant_files, quant_train, quant_validation))
468 469

                for file in files_train:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
470 471
                    dir_class_train = File.make_path(
                        dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME, dir_class)
472 473
                    if not os.path.exists(dir_class_train):
                        os.makedirs(dir_class_train)
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
474

475 476
                    if os.path.splitext(file)[-1] == ".tif":
                        img = Image.open(File.make_path(root, file))
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
477 478 479 480
                        # img.thumbnail(img.size)
                        new_file = os.path.splitext(file)[0] + ".png"
                        img.save(File.make_path(dir_class_train,
                                                new_file), "PNG", quality=100)
481
                    else:
482 483 484
                        print 100*'-'
                        print File.make_path(root, file)
                        print 100*'-'
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
485 486
                        os.symlink(File.make_path(root, file),
                                   File.make_path(dir_class_train, file))
487 488

                for file in files_validation:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
489 490
                    dir_class_validation = File.make_path(
                        dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME, dir_class)
491
                    if not os.path.exists(dir_class_validation):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
492 493
                        os.makedirs(dir_class_validation)

494 495
                    if os.path.splitext(file)[-1] == ".tif":
                        img = Image.open(File.make_path(root, file))
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
496 497 498 499
                        # img.thumbnail(img.size)
                        new_file = os.path.splitext(file)[0] + ".png"
                        img.save(File.make_path(dir_class_validation,
                                                new_file), "PNG", quality=100)
500
                    else:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
501 502
                        os.symlink(File.make_path(root, file),
                                   File.make_path(dir_class_validation, file))
503 504

                for file in files_test:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
505 506
                    dir_class_test = File.make_path(
                        dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TEST_NAME, dir_class)
507
                    if not os.path.exists(dir_class_test):
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
508 509
                        os.makedirs(dir_class_test)

510 511
                    if os.path.splitext(file)[-1] == ".tif":
                        img = Image.open(File.make_path(root, file))
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
512 513 514 515
                        # img.thumbnail(img.size)
                        new_file = os.path.splitext(file)[0] + ".png"
                        img.save(File.make_path(dir_class_test,
                                                new_file), "PNG", quality=100)
516
                    else:
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
517 518
                        os.symlink(File.make_path(root, file),
                                   File.make_path(dir_class_test, file))
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
519 520 521 522

        train_datagen = ImageDataGenerator()

        train_generator = train_datagen.flow_from_directory(
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
523 524
            File.make_path(dataset, KERAS_DATASET_DIR_NAME,
                           KERAS_DIR_TRAIN_NAME),
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
525 526 527 528 529 530 531 532
            target_size=(IMG_HEIGHT, IMG_WIDTH),
            batch_size=self.batch_size.value,
            shuffle=True,
            class_mode="categorical")

        validation_datagen = ImageDataGenerator()

        validation_generator = validation_datagen.flow_from_directory(
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
533 534
            File.make_path(dataset, KERAS_DATASET_DIR_NAME,
                           KERAS_DIR_VALIDATION_NAME),
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
535 536 537 538 539
            target_size=(IMG_HEIGHT, IMG_WIDTH),
            batch_size=self.batch_size.value,
            shuffle=True,
            class_mode="categorical")

540 541 542
        test_datagen = ImageDataGenerator()

        test_generator = test_datagen.flow_from_directory(
Gabriel Kirsten's avatar
 
Gabriel Kirsten committed
543 544
            File.make_path(dataset, KERAS_DATASET_DIR_NAME,
                           KERAS_DIR_TEST_NAME),
545 546 547 548 549 550
            target_size=(IMG_HEIGHT, IMG_WIDTH),
            batch_size=self.batch_size.value,
            shuffle=True,
            class_mode="categorical")

        return train_generator, validation_generator, test_generator
551 552

    def single_classify(self, image_path, directory, extractors, dict_classes):
553 554 555 556 557 558 559 560 561
        preprocess_input, decode_predictions = dict_preprocessing[self.app]
        pil_image = load_img(image_path)
        np_image = img_to_array(pil_image)
        res_image = resize(np_image, (IMG_HEIGHT, IMG_WIDTH, 3))
        tensor = expand_dims(res_image, axis=0)
        tensor = preprocess_input(tensor)
        predict = self.model.predict(tensor)
        predict = np.argmax(predict, axis=1)
        return dict_classes[predict[0]]