Skip to content
Snippets Groups Projects
Commit bc460d80 authored by Olegs NIKISINS's avatar Olegs NIKISINS
Browse files

Added initial version of the config for MLP training

parent 9ecfc286
No related branches found
No related tags found
1 merge request!14MLP class and config to train it
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
@author: Olegs Nikisins
"""
#==============================================================================
# Import here:
from bob.pad.face.database import BatlPadDatabase
from torch import nn
import torch.nn.functional as F
import numpy as np
import torch
#==============================================================================
# Define parameters here:
"""
Note: do not change names of the below constants.
"""
NUM_EPOCHS = 100 # Maximum number of epochs
BATCH_SIZE = 64 # Size of the batch
LEARNING_RATE = 1e-4 # Learning rate
NUM_WORKERS = 8 # The number of workers for the DataLoader
"""
Set the kwargs of the "dataset" instance of the DataFolder class.
Note: do not change the name ``kwargs``.
"""
# Initialize HLDI for data folder:
ORIGINAL_DIRECTORY = "" # this arguments is not important in this case
ORIGINAL_EXTENSION = ".h5" # extension of the data files
ANNOTATIONS_TEMP_DIR = "" # this argument is not used here
PROTOCOL = 'grandtest-color*infrared*depth-10' # 3 channels are used here, 10 frames
bob_hldi_instance = BatlPadDatabase(protocol=PROTOCOL,
original_directory=ORIGINAL_DIRECTORY,
original_extension=ORIGINAL_EXTENSION,
annotations_temp_dir=ANNOTATIONS_TEMP_DIR, # annotations computed here will not be saved because ANNOTATIONS_TEMP_DIR is empty string
landmark_detect_method="mtcnn", # detect annotations using mtcnn
exclude_attacks_list=['makeup'],
exclude_pai_all_sets=True, # exclude makeup from all the sets, which is the default behavior for grandtest protocol
append_color_face_roi_annot=False) # annotations defining ROI in the cropped face image are not important here
kwargs = {}
kwargs["data_folder"] = "NO NEED TO SET HERE, WILL BE SET IN THE TRAINING SCRIPT"
# NOTE: ``kwargs["transform"] = transform`` is re-defined below, after ``transform()`` method is defined
kwargs["transform"] = None # keep None for now, re-define below
kwargs["extension"] = '.hdf5'
kwargs["bob_hldi_instance"] = bob_hldi_instance
kwargs["hldi_type"] = "pad"
kwargs["groups"] = ['train']
kwargs["protocol"] = 'grandtest'
kwargs["purposes"] = ['real', 'attack']
kwargs["allow_missing_files"] = True
"""
Transformations to be applied to the input data sample.
Note: the variable or function name ``transform`` must be the same in
all configuration files. This transformation is handled in DataFolder.
"""
import os
from bob.pad.face.utils.pytorch.data_utils import compute_mean_std_bf_class, save_mean_std_to_hdf5, load_mean_std_from_hdf5
from bob.pad.base.utils.helper_functions import mean_std_normalize
# name of the file containing mean-std normalization parameters:
file_path = "/idiap/temp/onikisins/project/ODIN/experiment_data/pad_experiments_bob4/batl_db/autoencoder_face_features_128x128/batl_train_mlp_10_relu_algo_celeba_and_partial_3_layers_batl_features/mean_std_params.hdf5"
def transform(x):
"""
In this case transformation is mean-std normalization of the 1D feature
vector / numpy array.
**Parameters:**
``x`` : 1D :py:class:`numpy.ndarray`
Feature vector to be normalizaed.
"""
if not os.path.isfile(file_path): # if no file with normalization parameters available:
print ("Computing mean-std normalization parameters using real samples of the training set")
# compute the normalization parameters on the fly:
features_mean, features_std = compute_mean_std_bf_class(kwargs)
# save normalization parameters:
print ("Saving normalization parameters to the file: \n{}".format(file_path))
save_mean_std_to_hdf5(features_mean, features_std, file_path)
else:
# load the normalization parameters:
features_mean, features_std = load_mean_std_from_hdf5(file_path)
# normalize the sample
x_norm, _, _ = mean_std_normalize(features = np.expand_dims(x, axis=0),
features_mean = features_mean,
features_std = features_std)
return x_norm.squeeze()
"""
Set the kwargs of the "dataset" instance of the DataFolder class.
Note: do not change the name ``kwargs``.
"""
# NOTE: re-define ``transform`` parameter, after we defined the ``transform()`` method
# In this case transformation is mean-std normalization, given mean-std for each feature:
kwargs["transform"] = transform
"""
Define the network to be trained as a class, named ``Network``.
Note: Do not change the name of the below class.
"""
class Network(nn.Module):
"""
MLP for two-class classification.
"""
def __init__(self):
super(Network, self).__init__()
self.fc1 = nn.Linear(in_features = 1296, out_features = 10, bias=True)
self.fc2 = nn.Linear(in_features = 10, out_features = 1, bias=True)
def forward(self, x):
# input is a batch of the size: [batch_size, 1, 1296],
# convert it to the size [batch_size, 1296] as expected by FC layer:
x = x.squeeze()
# first fully connected activated by ReLu:
x = self.fc1(x)
x = F.relu(x)
# second fully connected activated by sigmoid:
x = self.fc2(x)
x = F.sigmoid(x)
return x
"""
Define the loss to be used for training.
Note: do not change the name of the below variable.
"""
loss_type = nn.BCELoss()
def comp_loss_weights(target):
"""
This function is used in ``loss_function()``.
Compute the weights for the BCE loss function.
``target`` : Tensor
Tensor containing class labels for each sample in ``img``.
Tensor of the size: ``[num_patches]``
"""
weights = np.copy(target.cpu().numpy())
pos_weight = 1-np.sum(weights)/len(weights)
neg_weight = 1-pos_weight
weights[weights==1]=pos_weight
weights[weights==0]=neg_weight
# weights = weights/np.sum(weights)
weights = torch.Tensor(weights)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
weights = weights.to(device)
return weights
"""
OPTIONAL: if not defined loss will be computed in the training script.
See training script for details
Define the function to compute the loss. Don't change the signature of this
function.
"""
def loss_function(output, img, target):
"""
Returns a loss defined by a global variable loss_type in this config file.
**Parameters:**
``output`` : Tensor
Tensor of the size: ``[num_patches, 1]``
``img`` : Tensor
Tensor containing input training patches. Input for the above Network()
class. The dimensions are: ``[num_patches, 4, 8, 8]``.
Note: this argument is not used in current loss function.
``target`` : Tensor
Tensor containing class labels for each sample in ``img``.
Tensor of the size: ``[num_patches]``
**Returns:**
``loss`` : Tensor
Tensor containing loss value.
"""
target = target.float() # make sure the target is float, not int
# convert "target" tensor from size [num_patches] to [num_patches, 1], to match "output" dimensions:
target = target.view(-1, 1)
weight = comp_loss_weights(target)
loss_type.weight = weight
loss = loss_type(output, target)
return loss
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment