Commit 9ef2a006 authored by Lukas Wolf's avatar Lukas Wolf
Browse files

xception and inception work

parent 4641d928
......@@ -40,8 +40,8 @@ config['root_dir'] = '.'
# Choose task and dataset
##################################################################
config['task'] = 'prosaccade-clf'
#config['task'] = 'gaze-reg'
#config['task'] = 'prosaccade-clf'
config['task'] = 'gaze-reg'
#config['task'] = 'angle-reg'
if config['task'] != 'prosaccade-clf':
......@@ -65,10 +65,10 @@ config['pretrained'] = False # We can use a model pretrained on processing speed
config['model'] = 'cnn'
#config['model'] = 'inception'
#config['model'] = 'eegnet'
#config['model'] = 'deepeye'
#config['model'] = 'deepeye-rnn'
#config['model'] = 'xception'
#config['model'] = 'pyramidal_cnn'
#config['model'] = 'deepeye'
#config['model'] = 'deepeye-rnn'
#config['model'] = 'siamese' # Note that you have to set data_mode to sacc_fix for this model
##################################################################
......@@ -76,7 +76,7 @@ config['model'] = 'cnn'
##################################################################
config['learning_rate'] = 1e-3 # fix only: 1e-2, sac only: 1e-3, sac_fix: 1e-3 , fix_sac_fix: 1e-4, for inception on angle 1e-5
config['regularization'] = 0 # fix only: 1e-3, sac only: 1e-2, sac_fix: 1, fix_sac_fix: 5, for inception on angle 0
config['epochs'] = 2
config['epochs'] = 5
config['batch_size'] = 64
##################################################################
......@@ -91,6 +91,7 @@ config['run'] = 'ensemble'
config['tensorboard_on'] = False
config['sanity_check'] = False
config['plot_model'] = True
config['save_models'] = False
##################################################################
# Options for prosaccade task, currently not used for regression
......
......@@ -9,9 +9,12 @@ import h5py
import logging
import time
from Trainer.Trainer import Trainer
import sys
def main():
# Do some logging
# Set recursion limit higher
#sys.setrecursionlimit(200000)
# Start logging
logging.basicConfig(filename=config['info_log'], level=logging.INFO)
logging.info('Started the Logging')
log_config()
......
......@@ -3,6 +3,7 @@ from torch import nn
import numpy as np
from config import config
import logging
from torch.utils.tensorboard import SummaryWriter
from torch_models.torch_utils.training import train_loop, test_loop
......@@ -85,17 +86,26 @@ class BaseNet(nn.Module):
# Create the optimizer
optimizer = torch.optim.Adam(list(self.parameters()), lr=config['learning_rate'])
# Create history and log
# Create a history to track ensemble performance
prediction_ensemble = Prediction_history(dataloader=test_dataloader)
# Create a summary writer for logging metrics
writer = SummaryWriter(log_dir=config['model_dir']+'/summary_writer')
# Train the model
epochs = config['epochs']
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train_loop(train_dataloader, self.float(), self.loss_fn, optimizer)
test_loop(test_dataloader, self.float(), self.loss_fn)
# Run through training and test set
train_loss = train_loop(train_dataloader, self.float(), self.loss_fn, optimizer)
test_loss, test_acc = test_loop(test_dataloader, self.float(), self.loss_fn)
# Add the predictions on the validation set
prediction_ensemble.on_epoch_end(model=self)
# Log metrics to the writer
writer.add_scalar('Loss/train', train_loss, t)
writer.add_scalar('Loss/test', test_loss, t)
if config['task'] == 'prosaccade-clf':
writer.add_scalar('Accuracy/test', test_acc, t)
print(f"Finished model number {self.model_number}")
# Save model
ckpt_dir = config['model_dir'] + '/best_models/' + config['model'] + '_nb_{}_'.format(self.model_number) + 'best_model.pth'
torch.save(self.state_dict(), ckpt_dir)
if config['save_model']:
ckpt_dir = config['model_dir'] + '/best_models/' + config['model'] + '_nb_{}_'.format(self.model_number) + 'best_model.pth'
torch.save(self.state_dict(), ckpt_dir)
return prediction_ensemble
\ No newline at end of file
......@@ -10,7 +10,7 @@ class CNN(ConvNet):
use_residual=True, depth=12, regularization=0.01, model_number=0):
self.regularization = regularization
self.nb_features = nb_filters # For CNN simply the number of filters inside the network
super().__init__(input_shape, kernel_size=kernel_size, epochs=epochs, nb_features=self.nb_features,
super().__init__(input_shape, kernel_size=kernel_size, epochs=epochs,
nb_filters=nb_filters, verbose=verbose, batch_size=batch_size,
use_residual=use_residual, depth=depth, model_number=model_number)
......
......@@ -14,7 +14,7 @@ class ConvNet(ABC, BaseNet):
This class defines all the common functionality for more complex convolutional nets
"""
def __init__(self, input_shape, nb_features, kernel_size=32, nb_filters=32, verbose=True, batch_size=64,
def __init__(self, input_shape, kernel_size=32, nb_filters=32, verbose=True, batch_size=64,
use_residual=False, depth=6, epochs=2, preprocessing = False, model_number=0):
"""
We define the layers of the network in the __init__ function
......@@ -35,15 +35,15 @@ class ConvNet(ABC, BaseNet):
self.gap_layer = nn.AvgPool1d(kernel_size=2, stride=1)
self.gap_layer_pad = Pad_Pool(left=0, right=1, value=0)
logging.info('Parameters of model number {}: '.format(self.model_number))
logging.info('--------------- use residual : ' + str(self.use_residual))
logging.info('--------------- depth : ' + str(self.depth))
logging.info('--------------- batch size : ' + str(self.batch_size))
logging.info('--------------- kernel size : ' + str(self.kernel_size))
logging.info('--------------- nb filters : ' + str(self.nb_filters))
logging.info('--------------- preprocessing: ' + str(self.preprocessing))
if self.verbose:
if self.verbose and model_number == 0:
logging.info(f"Number of model parameters: {sum(p.numel() for p in self.parameters())}")
logging.info(f"Number of trainable parameters: {sum(p.numel() for p in self.parameters() if p.requires_grad)}")
logging.info('--------------- use residual : ' + str(self.use_residual))
logging.info('--------------- depth : ' + str(self.depth))
logging.info('--------------- batch size : ' + str(self.batch_size))
logging.info('--------------- kernel size : ' + str(self.kernel_size))
logging.info('--------------- nb filters : ' + str(self.nb_filters))
logging.info('--------------- preprocessing: ' + str(self.preprocessing))
print(self)
......@@ -60,12 +60,9 @@ class ConvNet(ABC, BaseNet):
shortcut_cnt = 0
for d in range(self.depth):
x = self.conv_blocks[d](x)
#print(f"x after conv at depth {d} {x.size()}")
if self.use_residual and d % 3 == 2:
res = self.shortcuts[shortcut_cnt](input_res)
#print(f"input_res after shortcut at depth {d} {input_res.size()}")
shortcut_cnt += 1
#print(f" x shape {x.size()} res shape {res.size()}")
x = torch.add(x, res)
x = nn.functional.relu(x)
input_res = x
......@@ -73,11 +70,7 @@ class ConvNet(ABC, BaseNet):
x = self.gap_layer_pad(x) # Pad for the avgpool1d gap_layer
x = self.gap_layer(x)
#print(f"x size after gap layer: {x.size()}")
#print(f"x size before view: {x.size()}")
x = x.view(self.batch_size, -1)
#print(f"x size before output layer: {x.size()}")
output = self.output_layer(x) # Defined in BaseNet
return output
......@@ -86,6 +79,7 @@ class ConvNet(ABC, BaseNet):
"""
Implements a shortcut with a convolution and batch norm
This is the same for all our convolutional models
Padding before convolution for constant tensor shape, similar to Keras padding=same
"""
return nn.Sequential(
Pad_Conv(kernel_size=self.kernel_size, value=0),
......
......@@ -91,8 +91,6 @@ class Ensemble_torch:
if config['task'] == 'prosaccade-clf':
np.savetxt(X=accuracy, fname=config['model_dir']+'/'+'ensemble_acc_val.csv', delimiter=',')
plot_array(accuracy, config['model_dir'], 'accuracy')
# Save logs
#save_logs(hist, config['model_dir'], config['model'], pytorch = False)
def _build_ensemble_model(self):
"""
......@@ -124,15 +122,14 @@ def create_model(model_type, model_number):
Returns the specified torch model as nn.Module built on BaseNet
"""
if model_type == 'cnn':
model = CNN(input_shape=config['cnn']['input_shape'], kernel_size=64, epochs = config['epochs'],
nb_filters=16, verbose=True, batch_size=64, use_residual=True, depth=12,
model_number=model_number)
model = CNN(input_shape=config['cnn']['input_shape'], kernel_size=64, epochs = config['epochs'], nb_filters=16,
verbose=True, batch_size=64, use_residual=True, depth=12, model_number=model_number)
elif model_type == 'inception':
model = Inception(input_shape=config['inception']['input_shape'], use_residual=True, model_number=model_number,
kernel_size=64, nb_filters=16, depth=12, bottleneck_size=16, epochs=config['epochs'])
elif model_type == 'xception':
model = XCEPTION(input_shape=config['inception']['input_shape'], use_residual=True, model_number=model_number,
kernel_size=40, nb_filters=64, depth=18, epochs=config['epochs'])
kernel_size=40, nb_filters=64, depth=12, epochs=config['epochs'])
elif model_type == 'eegnet':
model = EEGNet(input_shape=(config['eegnet']['samples'], config['eegnet']['channels']),
model_number=model_number, epochs=config['epochs'])
......
......@@ -18,9 +18,9 @@ class Inception(ConvNet):
def __init__(self, input_shape, kernel_size=64, epochs = 50, nb_filters=16, verbose=True,
batch_size=64, use_residual=True, depth=12, bottleneck_size=16, model_number=0):
self.bottleneck_size = bottleneck_size
nb_features = 4 * self.nb_filters # these are the 4 concatenated parallel convolutions, width of the inner tensort passed through network
self.nb_features = 4 * nb_filters # these are the 4 concatenated parallel convolutions, width of the inner tensort passed through network
logging.info('--------------- bottleneck_size : ' + str(self.bottleneck_size))
super().__init__(input_shape, kernel_size=kernel_size, epochs=epochs, nb_features=nb_features,
super().__init__(input_shape, kernel_size=kernel_size, epochs=epochs,
nb_filters=nb_filters, verbose=verbose, batch_size=batch_size,
use_residual=use_residual, depth=depth, model_number=model_number)
......
......@@ -37,15 +37,19 @@ class TCSConv1d(nn.Module):
def __init__(self, mother, depth):
super(TCSConv1d, self).__init__()
self.pad_depthwise = Pad_Conv(mother.kernel_size)
self.depthwise = nn.Conv1d(in_channels=mother.nb_channels if depth==0 else mother.nb_filters,
out_channels=mother.nb_filters, kernel_size=mother.kernel_size, bias=False,
groups=mother.nb_channels if depth==0 else mother.nb_features) # groups=in_channels makes it separable
self.pad_pointwise = Pad_Conv(mother.kernel_size)
self.pointwise = nn.Conv1d(mother.nb_filters, mother.nb_filters, kernel_size=1)
# groups=in_channels makes it separable
self.depthwise = nn.Conv1d(in_channels=mother.nb_channels if depth==0 else mother.nb_features,
out_channels=mother.nb_channels if depth==0 else mother.nb_features,
groups=mother.nb_channels if depth==0 else mother.nb_features,
kernel_size=mother.kernel_size, bias=False)
self.pointwise = nn.Conv1d(in_channels=mother.nb_channels if depth==0 else mother.nb_features,
out_channels=mother.nb_features, kernel_size=1)
def forward(self, x):
x = self.pad_depthwise(x)
#print(f"tensor after pad depthwise: {x.size()}")
x = self.depthwise(x)
x = self.pad_pointwise(x)
#print(f"tensor after conv depthwise: {x.size()}")
x = self.pointwise(x)
#print(f"tensor after conv pointwise: {x.size()}")
return x
\ No newline at end of file
import torch
from torch import tensor
from torch.utils.data import DataLoader, TensorDataset
from config import config
import logging
def create_dataloader(X, y, batch_size):
"""
......@@ -10,8 +12,15 @@ def create_dataloader(X, y, batch_size):
# Transform np.array to torch tensor
tensor_x = torch.tensor(X)
tensor_y = torch.tensor(y)
# Unsqueeze channel direction for eegNet model
if config['model'] == 'eegnet' :
logging.info(f"Unsqueeze data for eegnet")
tensor_x = tensor_x.unsqueeze(1)
# Log the shapes
logging.info(f"Tensor x size: {tensor_x.size()}")
logging.info(f"Tensor y size: {tensor_y.size()}")
# Set device
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Create dataset and dataloader
dataset = TensorDataset(tensor_x, tensor_y)
return DataLoader(dataset, batch_size=batch_size, drop_last=True)
\ No newline at end of file
......@@ -6,6 +6,7 @@ def train_loop(dataloader, model, loss_fn, optimizer):
"""
Performs one epoch of training the model through the dataset stored in dataloader
Using the given loss_fn and optimizer
Returns training loss of the epoch to be tracked by the caller
"""
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
......@@ -19,9 +20,10 @@ def train_loop(dataloader, model, loss_fn, optimizer):
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch % 32 == 0:
if batch % 50 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
print(f"Avg training loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
return loss
def test_loop(dataloader, model, loss_fn):
"""
......@@ -46,4 +48,7 @@ def test_loop(dataloader, model, loss_fn):
if config['task'] == 'prosaccade_clf':
correct /= size
print(f"Avg accuracy {correct:>8f} \n")
\ No newline at end of file
print(f"Avg accuracy {correct:>8f} \n")
return test_loss, correct
# Otherwise return only loss
return test_loss, -1
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment