Commit 40c0028c authored by Diogo Nunes Gonçalves's avatar Diogo Nunes Gonçalves
Browse files

Funcao cnn_keras e segnet_keras adicionadas

parent 1896c8e3
File mode changed from 100644 to 100755
......@@ -10,3 +10,4 @@ javabridge
python-weka-wrapper
cycler
cython
h5py
......@@ -18,9 +18,18 @@ except Exception as e:
CNNKeras = None
print e.message
try:
from .segnet_keras import SEGNETKeras
except Exception as e:
SEGNETKeras = None
print e.message
__all__ = ["classifier",
"cnn_caffe",
"cnn_keras",
"segnet_keras",
"weka_classifiers"
]
......@@ -33,7 +42,9 @@ _classifier_list = OrderedDict( [
["cnn_caffe", Config("Invalid" if CNNCaffe is None else CNNCaffe.__name__,
WekaClassifiers is None and CNNCaffe is not None, bool, meta=CNNCaffe, hidden=CNNCaffe is None)],
["cnn_keras", Config("Invalid" if CNNKeras is None else CNNKeras.__name__,
CNNKeras is not None, bool, meta=CNNKeras, hidden=CNNKeras is None)],
CNNKeras is not None, bool, meta=CNNKeras, hidden=CNNKeras is None)],
["segnet_keras", Config("Invalid" if SEGNETKeras is None else SEGNETKeras.__name__,
SEGNETKeras is not None, bool, meta=SEGNETKeras, hidden=SEGNETKeras is None)],
["weka_classifiers", Config("Invalid" if WekaClassifiers is None else WekaClassifiers.__name__,
WekaClassifiers is not None, bool, meta=WekaClassifiers, hidden=WekaClassifiers is None)]
] )
......@@ -44,4 +55,5 @@ def get_classifier_config():
def set_classifier_config(configs):
_classifier_list["cnn_caffe"] = Config.nvl_config(configs["cnn_caffe"], _classifier_list["cnn_caffe"])
_classifier_list["cnn_keras"] = Config.nvl_config(configs["cnn_keras"], _classifier_list["cnn_keras"])
_classifier_list["segnet_keras"] = Config.nvl_config(configs["segnet_keras"], _classifier_list["segnet_keras"])
_classifier_list["weka_classifiers"] = Config.nvl_config(configs["weka_classifiers"], _classifier_list["weka_classifiers"])
\ No newline at end of file
......@@ -90,7 +90,7 @@ class Classifier(object):
pass
@abstractmethod
def classify(self, dataset, test_dir = None, test_data = None):
def classify(self, dataset, test_dir = None, test_data = None, image = None):
"""Perform the classification.
Implement this method to extend this class with a new classifier algorithm.
"""
......
......@@ -116,7 +116,7 @@ class CNNCaffe(Classifier):
return summary
def classify(self, dataset, test_dir, test_data):
def classify(self, dataset, test_dir, test_data, image):
"""Perform the classification.
Parameters
......
......@@ -14,14 +14,15 @@ import os
import shutil
import random
import numpy as np
import json
from PIL import Image
from keras import applications
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.models import Model
from keras.models import Model, load_model
from keras.layers import Dropout, Flatten, Dense
from keras.callbacks import ModelCheckpoint
from sklearn.cross_validation import train_test_split
from keras.callbacks import ModelCheckpoint, TensorBoard
from keras import backend as K
from interface.interface import InterfaceException as IException
from classification.classifier import Classifier
......@@ -42,12 +43,12 @@ START_TIME = time.time()
IMG_WIDTH, IMG_HEIGHT = 256, 256
CLASS_NAMES = ['FolhasLargas', 'Gramineas',
'Soja', 'Solo']
weight_path = None
class CNNKeras(Classifier):
""" Class for CNN classifiers based on Keras applications """
def __init__(self, architecture="VGG16", learning_rate=0.0001, momentum=0.9, batch_size=16, epochs=1, fine_tuning_rate=100, transfer_learning=False, save_weights=True):
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):
"""
Constructor of CNNKeras
"""
......@@ -68,7 +69,12 @@ class CNNKeras(Classifier):
"Transfer Learning", transfer_learning, bool)
self.save_weights = Config(
"Save weights", save_weights, bool)
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)
self.file_name = "kerasCNN"
self.model = None
......@@ -93,7 +99,9 @@ class CNNKeras(Classifier):
keras_config["Fine Tuning rate"] = self.fine_tuning_rate
keras_config["Transfer Learning"] = self.transfer_learning
keras_config["Save weights"] = self.save_weights
keras_config["Perc Train"] = self.perc_train
keras_config["Perc Validation"] = self.perc_validation
keras_config["Recreate Dataset"] = self.recreate_dataset
return keras_config
def set_config(self, configs):
......@@ -104,31 +112,17 @@ class CNNKeras(Classifier):
configs : OrderedDict
New configs of classifier.
"""
keras_config = OrderedDict()
keras_config["Architecture"] = Config.nvl_config(
configs["Architecture"], self.architecture)
keras_config["Learning rate"] = Config.nvl_config(
configs["Learning rate"], self.learning_rate)
keras_config["Momentum"] = Config.nvl_config(
configs["Momentum"], self.momentum)
keras_config["Batch size"] = Config.nvl_config(
configs["Batch size"], self.batch_size)
keras_config["Epochs"] = Config.nvl_config(
configs["Epochs"], self.epochs)
keras_config["Fine Tuning rate"] = Config.nvl_config(
configs["Fine Tuning rate"], self.fine_tuning_rate)
keras_config["Transfer Learning"] = Config.nvl_config(
configs["Transfer Learning"], self.transfer_learning)
keras_config["Save weights"] = Config.nvl_config(
configs["Save weights"], self.save_weights)
self.architecture = Config.nvl_config(configs["Architecture"], self.architecture)
self.learning_rate = Config.nvl_config(configs["Learning rate"], self.learning_rate)
self.momentum = Config.nvl_config(configs["Momentum"], self.momentum)
self.batch_size = Config.nvl_config(configs["Batch size"], self.batch_size)
self.epochs = Config.nvl_config(configs["Epochs"], self.epochs)
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)
def get_summary_config(self):
"""Return fomatted summary of configuration.
......@@ -148,14 +142,16 @@ class CNNKeras(Classifier):
keras_config[self.fine_tuning_rate.label] = self.fine_tuning_rate.value
keras_config[self.transfer_learning.label] = self.transfer_learning.value
keras_config[self.save_weights.label] = self.save_weights.value
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
summary = ''
for config in keras_config:
summary += "%s: %s\n" % (config, str(keras_config[config]))
return summary
def classify(self, dataset, test_dir, test_data):
def classify(self, dataset, test_dir, test_data, image):
""""Perform the classification.
Parameters
......@@ -175,63 +171,43 @@ class CNNKeras(Classifier):
predict_directory = File.make_path(dataset, test_dir)
for root, dirs, files in os.walk(predict_directory, topdown=False):
for name in files:
print(os.path.join(root, name))
if os.path.splitext(os.path.join(root, name))[1].lower() == ".tif":
if os.path.isfile(os.path.splitext(os.path.join(root, name))[0] + ".png"):
print "A jpeg file already exists for %s" % name
# If a jpeg is *NOT* present, create one from the tiff.
else:
outfile = os.path.splitext(
os.path.join(root, name))[0] + ".png"
try:
im = Image.open(os.path.join(root, name))
print "Generating jpeg for %s" % name
im.thumbnail(im.size)
im.save(outfile, "PNG", quality=100)
except Exception, e:
print e
# Create a Keras class
if not os.path.exists(predict_directory + "/png"):
os.makedirs(predict_directory + "/png")
# move the .png images to inside the class
for _, _, files in os.walk(predict_directory, topdown=False):
for name in files:
if name.endswith('.png'):
shutil.move(os.path.join(predict_directory, name),
os.path.join(predict_directory, "png", name))
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":
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
else:
os.symlink(File.make_path(predict_directory, file), File.make_path(predict_directory, 'png', file))
classify_datagen = ImageDataGenerator()
classify_generator = classify_datagen.flow_from_directory(
predict_directory,
File.make_path(predict_directory, 'png'),
target_size=(IMG_HEIGHT, IMG_WIDTH),
batch_size=1,
shuffle=False,
class_mode=None)
validation_datagen = ImageDataGenerator()
validation_generator = validation_datagen.flow_from_directory(
dataset,
target_size=(IMG_HEIGHT, IMG_WIDTH),
batch_size=self.batch_size.value,
shuffle=False,
class_mode=None)
# TODO - A better solution to num_classes - 1
self.model = self.select_model_params(
validation_generator.num_classes - 1)
try:
self.model.load_weights(
"../models_checkpoints/" + self.file_name + ".h5")
#self.model.load_weights(
#"../models_checkpoints/" + self.file_name + ".h5")
K.clear_session()
if self.weight_path is not None:
self.model = load_model(self.weight_path)
path_classes = self.weight_path.replace("_model.h5", "_classes.npy")
CLASS_NAMES = np.load(path_classes).item().keys()
except Exception, e:
raise IException("Can't load the model in " +
"../models_checkpoints/" + self.file_name + ".h5" + str(e))
self.weight_path + str(e))
output_classification = self.model.predict_generator(
classify_generator, classify_generator.samples, verbose=2)
......@@ -259,51 +235,64 @@ class CNNKeras(Classifier):
"""
# select .h5 filename
if self.transfer_learning.value == 100:
file_name = str(self.architecture.value) + \
if self.fine_tuning_rate.value == 100:
self.file_name = str(self.architecture.value) + \
'_learning_rate' + str(self.learning_rate.value) + \
'_transfer_learning'
elif self.transfer_learning.value == -1:
file_name = str(self.architecture.value) + \
elif self.fine_tuning_rate.value == -1:
self.file_name = str(self.architecture.value) + \
'_learning_rate' + str(self.learning_rate.value) + \
'_without_transfer_learning'
else:
file_name = str(self.architecture.value) + \
self.file_name = str(self.architecture.value) + \
'_learning_rate' + str(self.learning_rate.value) + \
'_fine_tunning_' + str(self.fine_tuning_rate.value)
File.remove_dir(File.make_path(dataset, ".tmp"))
train_generator, validation_generator = self.make_dataset(dataset)
train_generator, validation_generator, test_generator = self.make_dataset(dataset)
# Save the model according to the conditions
if self.save_weights:
if not os.path.exists("../models_checkpoints/"):
os.makedirs("../models_checkpoints/")
checkpoint = ModelCheckpoint("../models_checkpoints/" + self.file_name + ".h5", monitor='val_acc',
verbose=1, save_best_only=True, save_weights_only=False,
mode='auto', period=1)
else:
checkpoint = None
self.model = self.select_model_params(train_generator.num_classes)
tensorboard = TensorBoard(log_dir="../models_checkpoints/logs_" + self.file_name, write_images=False)
#tensorboard.set_model(self.model)
# compile the model
self.model.compile(loss="categorical_crossentropy",
optimizer=optimizers.SGD(
lr=self.learning_rate.value, momentum=self.momentum.value),
metrics=["accuracy"])
# Save the model according to the conditions
if self.save_weights:
checkpoint = ModelCheckpoint("../models_checkpoints/" + self.file_name + ".h5", monitor='val_acc',
verbose=1, save_best_only=True, save_weights_only=False,
mode='auto', period=1)
else:
checkpoint = None
train_images, validation_images = train_test_split(
train_generator, test_size=0.4)
# Train the model
self.model.fit_generator(
train_generator,
steps_per_epoch=train_generator.samples // self.batch_size.value,
epochs=self.epochs.value,
callbacks=[checkpoint],
validation_data=train_generator,
validation_steps=train_generator.samples // self.batch_size.value)
callbacks=[checkpoint, tensorboard],
validation_data=validation_generator,
validation_steps=validation_generator.samples // self.batch_size.value)
if self.save_weights:
self.model.save_weights(
"../models_checkpoints/" + self.file_name + ".h5")
#self.model.save_weights(
# "../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
np.save("../models_checkpoints/" + self.file_name + "_classes.npy", dict_classes)
def must_train(self):
"""Return if classifier must be trained.
......@@ -344,7 +333,7 @@ class CNNKeras(Classifier):
model = applications.MobileNet(
weights="imagenet", include_top=False, input_shape=(IMG_WIDTH, IMG_HEIGHT, 3))
for layer in model.layers[:int(len(model.layers) * (self.fine_tuning_rate.value / 100))]:
for layer in model.layers[:int(len(model.layers) * (self.fine_tuning_rate.value / 100.0))]:
layer.trainable = False
else: # without transfer learning
......@@ -386,48 +375,95 @@ class CNNKeras(Classifier):
def make_dataset(self, dataset):
# create symbolic links to the dataset
KERAS_DATASET_DIR_NAME = "keras_dataset"
KERAS_DATASET_DIR_NAME = ".keras_dataset"
#KERAS_DATASET_DIR_NAME = File.make_path("..", os.path.split(dataset)[-1] + "_keras_dataset")
KERAS_DIR_TRAIN_NAME = "train"
KERAS_DIR_VALIDATION_NAME = "validation"
PERC_TRAIN = 60
KERAS_DIR_TEST_NAME = "test"
PERC_TRAIN = self.perc_train.value
PERC_VALIDATION = self.perc_validation.value
# create keras dir dataset
if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME)):
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))
os.makedirs(File.make_path(dataset, KERAS_DATASET_DIR_NAME))
# 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))
for root, dirs, files in os.walk(dataset, topdown=False):
# shuffle array
random.shuffle(files)
quant_files = len(files)
file_index = 0
if not KERAS_DATASET_DIR_NAME in root.split("/") and root.split("/")[-1] != dataset.split("/")[-1]:
if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME, root.split("/")[-1])):
os.makedirs(File.make_path(
dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME, root.split("/")[-1]))
# 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]
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))
for file in files_train:
dir_class_train = File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME, dir_class)
if not os.path.exists(dir_class_train):
os.makedirs(dir_class_train)
if os.path.splitext(file)[-1] == ".tif":
img = Image.open(File.make_path(root, file))
#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)
else:
os.symlink(File.make_path(root, file), File.make_path(dir_class_train, file))
for file in files_validation:
dir_class_validation = File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME, dir_class)
if not os.path.exists(dir_class_validation):
os.makedirs(dir_class_validation)
if not os.path.exists(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME, root.split("/")[-1])):
os.makedirs(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME, root.split("/")[-1]))
if os.path.splitext(file)[-1] == ".tif":
img = Image.open(File.make_path(root, file))
#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)
else:
os.symlink(File.make_path(root, file), File.make_path(dir_class_validation, file))
for file in files_test:
dir_class_test = File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TEST_NAME, dir_class)
if not os.path.exists(dir_class_test):
os.makedirs(dir_class_test)
if os.path.splitext(file)[-1] == ".tif":
img = Image.open(File.make_path(root, file))
#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)
else:
os.symlink(File.make_path(root, file), File.make_path(dir_class_test, file))
for file in files:
if file_index <= ((quant_files / 100) * PERC_TRAIN):
if not os.path.islink(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME, root.split("/")[-1], file)):
os.symlink(File.make_path(root, file), File.make_path(
dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TRAIN_NAME, root.split("/")[-1], file))
file_index += 1
else:
if not os.path.islink(File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME, root.split("/")[-1], file)):
os.symlink(File.make_path(root, file), File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_VALIDATION_NAME, root.split("/")[-1], file))
train_datagen = ImageDataGenerator()
......@@ -449,4 +485,16 @@ class CNNKeras(Classifier):
shuffle=True,
class_mode="categorical")
return train_generator, validation_generator
test_datagen = ImageDataGenerator()
test_generator = test_datagen.flow_from_directory(
File.make_path(dataset, KERAS_DATASET_DIR_NAME, KERAS_DIR_TEST_NAME),
target_size=(IMG_HEIGHT, IMG_WIDTH),
batch_size=self.batch_size.value,
shuffle=True,
class_mode="categorical")
return train_generator, validation_generator, test_generator
\ No newline at end of file
import time
import os
import shutil
import random
import numpy as np
import json
import itertools
from PIL import Image
from matplotlib import pyplot as plt
import keras
from keras import applications, models, optimizers
from keras import backend as K
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Model, load_model
from keras.layers import Dropout, Flatten, Dense, Input
from keras.layers.convolutional import Conv2D, MaxPooling2D, UpSampling2D
from keras.layers.normalization import BatchNormalization
from keras.layers.core import Activation, Reshape, Permute
from keras.callbacks import ModelCheckpoint, TensorBoard
from interface.interface import InterfaceException as IException
from classification.classifier import Classifier
from collections import OrderedDict
from util.config import Config
from util.file_utils import File
from util.utils import TimeUtils
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # Suppress warnings
START_TIME = time.time()
IMG_WIDTH, IMG_HEIGHT = 256, 256
class SEGNETKeras(Classifier):
def __init__(self, architecture="ResNet50", learning_rate=0.01, momentum=0.9, batch_size=16, epochs=150, fine_tuning_rate=0, transfer_learning=False, save_weights=True, perc_train=80, perc_validation=20, recreate_dataset=False, num_classes = 2):
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)
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)
self.num_classes = Config(
"Num Classes", num_classes, int)
self.file_name = "segnet_keras"
self.model = None
self.trained = False
def get_config(self):
"""Return configuration of classifier.
Returns
-------
config : OrderedDict
Current configs of classifier.