-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtrain_CNNLSTM_pooled.py
More file actions
210 lines (170 loc) · 7.51 KB
/
Copy pathtrain_CNNLSTM_pooled.py
File metadata and controls
210 lines (170 loc) · 7.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 20 2019
@author: berdakh
This script can be used to train CNNLSTM model on pooled data.
"""
import torch
import pandas as pd
import pickle
import itertools
from nu_data_loader import getTorch, EEGDataLoader
from nu_train_utils import train_model
from nu_models import CNN2DEncoder, CNNLSTM
get_data = getTorch.get_data
# device type
dev = torch.device("cpu")
if torch.cuda.is_available():
dev = torch.device("cuda")
torch.set_default_tensor_type('torch.cuda.FloatTensor')
# %% dataset information
'''
dname is a dictionary containing dataset names to be loaded from
the current directory
The following files represent the ERP datasets referred in the paper as:
NU data = 'data_allsubjects.pickle',
EPFL data = 'EPFLP300.pickle'
BNCI data ='TenHealthyData.pickle'
ALS data ='ALSdata.pickle'
'''
# Load ERP data
dname = dict(nu='data_allsubjects.pickle',
epfl='EPFLP300.pickle',
ten='TenHealthyData.pickle',
als='ALSdata.pickle')
# %% Hyperparameter settings
batch_size = 64
num_epochs = 100
verbose = 2
learning_rate = 1e-3
weight_decay = 1e-4
# %%
# one should run this script twice with ConvDown = True or False to have different convolutional layer patterns
# as defined below by params dictionary.
ConvDOWN = True # change this option
# %% The main loop starts here
# for each dataset in dname train and evaluate the model
for itemname, filename in dname.items():
print('working with', filename)
iname = itemname + '__'
# data loader
d = EEGDataLoader(filename)
# subject data indicies
s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
d1 = d.load_pooled(s)
# for saving the results
table = pd.DataFrame(columns=['Train_Loss', 'Val_Loss', 'Train_Acc',
'Val_Acc', 'Test_Acc', 'Epoch'])
# % identify input size (channel x timepoints)
timelength = d1['xtest'].shape[2]
chans = d1['xtest'].shape[1]
input_size = (batch_size, 1, chans, timelength)
# here we define different combination of hyperparameters with varying level of
# cnn and lstm layers, and kernel size.
if ConvDOWN:
params = {'conv_channels': [[1, 16, 8],
[1, 32, 16, 8],
[1, 64, 32, 16, 8],
[1, 128, 64, 32, 16, 8],
[1, 256, 128, 64, 32, 16, 8],
[1, 32, 16],
[1, 64, 32, 16],
[1, 128, 64, 32, 16],
[1, 256, 128, 64, 32, 16],
[1, 256, 256, 128, 64, 32, 16]],
'kernel_size': [[3, 3, 3, 3, 3, 3],
[7, 7, 5, 5, 3, 3],
[13, 11, 9, 7, 5, 3]],
'num_layers': [1, 2],
'hidden_size': [64, 128]}
else:
params = {'conv_channels': [[1, 8, 16],
[1, 8, 16, 32],
[1, 8, 16, 32, 64],
[1, 8, 16, 32, 64, 128],
[1, 8, 16, 32, 64, 128, 256],
[1, 16, 32],
[1, 16, 32, 64],
[1, 16, 32, 64, 128],
[1, 16, 32, 64, 128, 256],
[1, 16, 32, 64, 128, 256, 512]],
'kernel_size': [[3, 3, 3, 3, 3, 3],
[3, 3, 5, 5, 7, 7],
[3, 5, 7, 9, 11, 13]],
'num_layers': [1, 2],
'hidden_size': [64, 128]}
keys = list(params)
results = {}
ii = 0
# Train Loop starts here we try different combination of hyperparameters
for values in itertools.product(*map(params.get, keys)):
d = dict(zip(keys, values))
kernel_size = d['kernel_size'][:len(d['conv_channels'])-1]
description = '_L{}_H{}_C{}_K{}'.format(
d['num_layers'], d['hidden_size'], d['conv_channels'], kernel_size)
print('\n\n##### ' + description + ' #####')
ii += 1
# define the encoder model
encoder = CNN2DEncoder(kernel_size=kernel_size,
conv_channels=d['conv_channels'])
with torch.no_grad():
x = torch.randn(input_size)
outdim = encoder(x)
batch_size, chans, H, W = outdim.size()
# define the encoder-decoder model
model = CNNLSTM(input_size=H*W,
cnn=encoder,
hidden_size=d['hidden_size'],
num_layers=d['num_layers'],
batch_size=64,
dropout=0.2)
print('********** Model Architecture ****************')
print(model)
dat = get_data(d1, batch_size, image=True, lstm=False, raw=False)
dset_loaders = dat['dset_loaders']
dset_sizes = dat['dset_sizes']
results = {}
# optimizer and loss function
optimizer = torch.optim.Adam(
model.parameters(), lr=learning_rate, weight_decay=weight_decay)
criterion = torch.nn.CrossEntropyLoss()
# move the model to the GPU
model.to(dev)
criterion.to(dev)
# ******** Training loop *********
best_model, train_losses, val_losses, train_accs, val_accs, info = train_model(model, dset_loaders, dset_sizes,
criterion, optimizer,
dev, lr_scheduler=None,
num_epochs=num_epochs,
verbose=verbose)
# here train_model returns the best_model which is saved for a later use below
# we could immediately evaluate the best model on the test as
x_test = dat['test_data']['x_test']
y_test = dat['test_data']['y_test']
h = best_model.init_hidden(x_test.shape[0])
preds = best_model(x_test.to(dev), h)
preds_class = preds.data.max(1)[1]
# accuracy
corrects = torch.sum(preds_class == y_test.data.to(dev))
test_acc = corrects.cpu().numpy()/x_test.shape[0]
print("Test Accuracy :", test_acc)
# ------------------------------------------------
# save results
tab = dict(Train_Loss=train_losses[info['best_epoch']],
Val_Loss=val_losses[info['best_epoch']],
Train_Acc=train_accs[info['best_epoch']],
Val_Acc=val_accs[info['best_epoch']],
Test_Acc=test_acc,
Epoch=info['best_epoch'] + 1)
table.loc[description] = tab
results[description] = dict(train_accs=train_accs, val_accs=val_accs,
ytrain=info['ytrain'], yval=info['yval'])
fname = iname + 'CNNLSTMPOOLED' + description
torch.save(best_model.state_dict(), fname)
print(table)
# save all the results
result_cnnlstm = dict(table=table, results=results)
fname2 = iname + "__CNNLSTMPOOLED_RESULTS_ALL"
with open(fname2, 'wb') as fp:
pickle.dump(result_cnnlstm, fp)