-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #99 from Paeti/Adjustments_Code
Adjustments code(model, trainer, test), Docs written
- Loading branch information
Showing
14 changed files
with
390 additions
and
419 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
The OurModel class builds and compiles the convolutional networks for gender or age estimation. | ||
Depending on the identifier in the construcor either a gender or a age estimation network will be build. | ||
|
||
The model from the OurModel class consists of a vgg16 base model with the pre-trained weights from 'imagenet' and 5 additional layers. | ||
|
||
So the structure is as follows: | ||
|
||
16 Layer from the vgg16 base model | ||
1 GlobalAveragePooling2D layer | ||
2 Dense layer | ||
|
||
1 Dense layer with sigmoid for age estimation | ||
or | ||
1 Dense layer with softmax for gender estimation | ||
|
||
The structure of this model is inspired by the following paper. | ||
https://www.vision.ee.ethz.ch/en/publications/papers/proceedings/eth_biwi_01229.pdf | ||
|
||
As optimizer the GradientDescentOptimizer from tf.train is use. | ||
This optimizer makes it possible to load and save the trained model as saved_model file effortlessly. | ||
https://www.tensorflow.org/api_docs/python/tf/train/GradientDescentOptimizer | ||
|
||
|
||
The load_model method offers the possibility to load a saved_model file and compile it allready. | ||
So after the model is loaded with this method, it's ready for training. | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
This is the main method of the training. Here the training will be started, models can be loaded and/or evaluated. | ||
|
||
Requirement for training: | ||
Make sure to have the dataset be available in subfolders sorted by their use. So the structure is as follows: | ||
../dataset/Train | ||
../dataset/Valid | ||
../dataset/Test | ||
|
||
https://medium.com/@vijayabhaskar96/tutorial-image-classification-with-keras-flow-from-directory-and-generators-95f75ebe5720 | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
The Trainer class does the training for gender or age estimation depending on the identifier given in the constructor of this class. | ||
|
||
Loading and preprocessing of the dataset will be done by the ImageDataGenerator from keras. | ||
All the preprocessing parameters are adjusted by the preprocess_input from keras. These are the parameters which were used for the imagent weights. | ||
|
||
The Trainer class takes use of the Cback class, which consits of the callbacks for the training. | ||
These callbacks are in use: | ||
EarlyStopping | ||
batch_print_callback | ||
json_logging_callback | ||
cleanup_callback | ||
|
||
For further reading: | ||
https://keras.io/callbacks/ | ||
|
||
The train method returns the trained model and saves the model in the Trainer instance. | ||
The trained model will be saved per default. This will be default directory for the saved model: | ||
|
||
/IPNeuronaleNetze/models/GenderWeights for gender | ||
or | ||
/IPNeuronaleNetze/models/AgeWeights" for age | ||
|
||
A .csv file will be created by the evaluate method. Use this .csv file in combination with the parser scripts to interpret the results of the training. | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
The files parse_age.py and parse_gender.py are for evualtion of the .csv file created in training. | ||
parse_age: returns the average difference in years from test dataset | ||
parse_gender: returns the correct predictions in percent from test dataset | ||
|
||
Requirement: | ||
python 3 | ||
|
||
How to: | ||
python3 parse_age csv.file_name | ||
python3 parse_gender csv.file_name | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
The modelTest class offers a few methods to confirm the proper functionality of the convolutional network you want to train. | ||
It is advisable to take a small dataset with just a couple of hundreds of pictures. Due to the test environment each single step | ||
of training will take more ressources of your computer as well as time than it would normally do. | ||
|
||
This testclass tests the correct structure of the OurModel class, which will be used for training. | ||
Also it tests the training itself, to confirm the right functionality within the training. | ||
|
||
Test cases: | ||
1. Test whether saved model file will be created after training | ||
test_model_get_saved | ||
|
||
2. Test whether model will be saved and loaded properly | ||
test_model_get_saved_and_loaded_correctly | ||
|
||
3. Test whether the weigts are changed after one step of training | ||
test_one_training_step | ||
|
||
4. Test whether all of the layers of a model are trainable, except the input layers | ||
test_model_layers_allTrainable | ||
|
||
5. Test whether Gendermodel is in expected shape | ||
test_Gendermodel_layerLength | ||
|
||
6. Test whether Agemodel is in expected shape | ||
test_Agemodel_layerLength | ||
|
||
Recommendation: | ||
Use the test.py before the actual training. | ||
|
||
Note: | ||
Test case 1 and 2 will create a folder with a saved_model file. | ||
You might want to delete these folders before the actual training. | ||
|
||
Inspiration for the test cases: | ||
https://medium.com/@keeper6928/how-to-unit-test-machine-learning-code-57cf6fd81765 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,57 @@ | ||
import sys, os | ||
parent_dir = os.getcwd() | ||
sys.path.append("/home/ip/IPNeuronaleNetze") | ||
sys.path.append("/home/ip/IPNeuronaleNetze/trainers") | ||
import sys | ||
sys.path.append("/IPNeuronaleNetze") | ||
sys.path.append("/IPNeuronaleNetze/trainers") | ||
import tensorflow as tf | ||
|
||
from tensorflow.python.keras.models import Sequential | ||
from tensorflow.python.keras.applications.vgg16 import VGG16 | ||
from tensorflow.python.keras.models import Model | ||
from tensorflow.python.keras import models | ||
from tensorflow.python.keras.layers import Flatten, Dense, Dropout, GlobalAveragePooling2D, Input | ||
from tensorflow.python.keras.layers import Flatten, Dense, GlobalAveragePooling2D, Input | ||
from tensorflow.python.keras.optimizers import SGD | ||
import numpy as np | ||
from models.optimizer.LR_SGD import LR_SGD | ||
|
||
from keras.utils import plot_model | ||
|
||
|
||
class OurModel: | ||
def __init__(self, identifier): | ||
self.model = self.buildModel(identifier) | ||
|
||
self.model = self.build_model(identifier) | ||
|
||
def build_model(self, identifier): | ||
# Load VGG16 | ||
base_model = VGG16(weights='imagenet', include_top=False) | ||
fyipg = base_model.output | ||
|
||
def buildModel(self, identifier): | ||
# LOAD VGG16 | ||
base_model = VGG16(weights='imagenet', include_top=False) | ||
fyipg = base_model.output | ||
|
||
# add a global spatial average pooling layer | ||
fyipg = GlobalAveragePooling2D()(fyipg) | ||
# let's add a fully-connected layer | ||
fyipg = Flatten(name ='Flatten1')(fyipg) | ||
# Add a global spatial average pooling layer | ||
fyipg = GlobalAveragePooling2D()(fyipg) | ||
# Let's add a fully-connected layer | ||
fyipg = Flatten(name ='Flatten1')(fyipg) | ||
fyipg = Dense(4096, activation='relu', name='AdditianlLayer1')(fyipg) | ||
fyipg = Dense(4096, activation='relu', name='AdditianlLayer2')(fyipg) | ||
if identifier == 1: | ||
fyipg = Dense(1, activation='sigmoid', name='Predictions')(fyipg) | ||
else: | ||
fyipg = Dense(101, activation='softmax', name='Predictions')(fyipg) | ||
|
||
# this is the model we will train | ||
model = Model(inputs = base_model.input , outputs = fyipg) | ||
|
||
# Setting the Learning rate multipliers | ||
LR_mult_dict = {} | ||
LR_mult_dict['Flatten1'] = 100 | ||
LR_mult_dict['AdditianLayer1'] = 100 | ||
LR_mult_dict['AdditianLayer2'] = 100 | ||
LR_mult_dict['Predictions'] = 100 | ||
|
||
# Setting optimizer for model | ||
optimizer = LR_SGD(lr=0.0001, momentum=0.9, decay=0.0005, nesterov=True, multipliers = LR_mult_dict) | ||
|
||
# This is the model we will train | ||
model = Model(inputs = base_model.input , outputs = fyipg) | ||
# Setting optimizer for model | ||
optimizer =tf.train.GradientDescentOptimizer(learning_rate = 0.0001) | ||
# Optimize model for gender- and agemodel | ||
if identifier == 1: | ||
model.compile(optimizer=optimizer, | ||
loss='binary_crossentropy', metrics=['mae']) | ||
loss='binary_crossentropy', metrics=['mae','acc']) | ||
else: | ||
model.compile(optimizer= optimizer, | ||
loss='categorical_crossentropy', metrics=['mae']) | ||
|
||
return model | ||
|
||
|
||
def loadModel(self, filepath): | ||
self.model = tf.contrib.saved_model.load_keras_model(filepath) | ||
return self.model | ||
|
||
|
||
loss='categorical_crossentropy', metrics=['mae', 'acc']) | ||
return model | ||
|
||
def load_model(self, filepath, identifier): | ||
# Load the save_model file | ||
self.model = tf.contrib.saved_model.load_keras_model(filepath) | ||
# Setting optimizer for model | ||
optimizer =tf.train.GradientDescentOptimizer(learning_rate = 0.0001) | ||
# Optimize model for gender- and agemodel | ||
if identifier == 1: | ||
self.model.compile(optimizer=optimizer, | ||
loss='binary_crossentropy', metrics=['mae','acc']) | ||
else: | ||
self.model.compile(optimizer= optimizer, | ||
loss='categorical_crossentropy', metrics=['mae', 'acc']) | ||
return self.model |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.