Okay I will post is again, although I have posted it above. First I will post the previous code with the loc of error and then the second code with the same data preprocessing but with data loaders.
So the whole code goes:
Shape of X_train: (1147, 7, 1, 128, 128)
Shape of X_val: (143, 7, 1, 128, 128)
Shape of X_test: (150, 7, 1, 128, 128)
b,t,c,h,w = X_train.shape
X_train = np.reshape(X_train, newshape=(b,-1))
X_train = scaler.fit_transform(X_train)
X_train = np.reshape(X_train, newshape=(b,t,c,h,w))
b,t,c,h,w = X_test.shape
X_test = np.reshape(X_test, newshape=(b,-1))
X_test = scaler.transform(X_test)
X_test = np.reshape(X_test, newshape=(b,t,c,h,w))
b,t,c,h,w = X_val.shape
X_val = np.reshape(X_val, newshape=(b,-1))
X_val = scaler.transform(X_val)
X_val = np.reshape(X_val, newshape=(b,t,c,h,w))
The model is
import torch
import torch.nn as nn
# BATCH FIRST TimeDistributed layer
class TimeDistributed(nn.Module):
def __init__(self, module):
super(TimeDistributed, self).__init__()
self.module = module
def forward(self, x):
if len(x.size()) <= 2:
return self.module(x)
# squash samples and timesteps into a single axis
elif len(x.size()) == 3: # (samples, timesteps, inp1)
x_reshape = x.contiguous().view(-1, x.size(2)) # (samples * timesteps, inp1)
elif len(x.size()) == 4: # (samples,timesteps,inp1,inp2)
x_reshape = x.contiguous().view(-1, x.size(2), x.size(3)) # (samples*timesteps,inp1,inp2)
else: # (samples,timesteps,inp1,inp2,inp3)
x_reshape = x.contiguous().view(-1, x.size(2), x.size(3),x.size(4)) # (samples*timesteps,inp1,inp2,inp3)
y = self.module(x_reshape)
# we have to reshape Y
if len(x.size()) == 3:
y = y.contiguous().view(x.size(0), -1, y.size(1)) # (samples, timesteps, out1)
elif len(x.size()) == 4:
y = y.contiguous().view(x.size(0), -1, y.size(1), y.size(2)) # (samples, timesteps, out1,out2)
else:
y = y.contiguous().view(x.size(0), -1, y.size(1), y.size(2),y.size(3)) # (samples, timesteps, out1,out2, out3)
return y
class HybridModel(nn.Module):
def __init__(self,num_emotions):
super().__init__()
# conv block
self.conv2Dblock = nn.Sequential(
# 1. conv block
TimeDistributed(nn.Conv2d(in_channels=1,
out_channels=16,
kernel_size=3,
stride=1,
padding=1
)),
TimeDistributed(nn.BatchNorm2d(16)),
TimeDistributed(nn.ReLU()),
TimeDistributed(nn.MaxPool2d(kernel_size=2, stride=2)),
TimeDistributed(nn.Dropout(p=0.4)),
# 2. conv block
TimeDistributed(nn.Conv2d(in_channels=16,
out_channels=32,
kernel_size=3,
stride=1,
padding=1
)),
TimeDistributed(nn.BatchNorm2d(32)),
TimeDistributed(nn.ReLU()),
TimeDistributed(nn.MaxPool2d(kernel_size=4, stride=4)),
TimeDistributed(nn.Dropout(p=0.4)),
# 3. conv block
TimeDistributed(nn.Conv2d(in_channels=32,
out_channels=64,
kernel_size=3,
stride=1,
padding=1
)),
TimeDistributed(nn.BatchNorm2d(64)),
TimeDistributed(nn.ReLU()),
TimeDistributed(nn.MaxPool2d(kernel_size=4, stride=4)),
TimeDistributed(nn.Dropout(p=0.4)),
# 4. conv block
TimeDistributed(nn.Conv2d(in_channels=64,
out_channels=128,
kernel_size=3,
stride=1,
padding=1
)),
TimeDistributed(nn.BatchNorm2d(128)),
TimeDistributed(nn.ReLU()),
TimeDistributed(nn.MaxPool2d(kernel_size=4, stride=4)),
TimeDistributed(nn.Dropout(p=0.4))
)
# LSTM block
hidden_size = 64
self.lstm = nn.LSTM(input_size=128,hidden_size=hidden_size,bidirectional=False, batch_first=True)
self.dropout_lstm = nn.Dropout(p=0.3)
# Linear softmax layer
self.out_linear = nn.Linear(hidden_size,num_emotions)
def forward(self,x):
conv_embedding = self.conv2Dblock(x)
conv_embedding = torch.flatten(conv_embedding, start_dim=2) # do not flatten batch dimension and time
lstm_embedding, (h,c) = self.lstm(conv_embedding)
lstm_embedding = self.dropout_lstm(lstm_embedding)
# lstm_embedding (batch, time, hidden_size)
lstm_output = lstm_embedding[:,-1,:]
output_logits = self.out_linear(lstm_output)
output_softmax = nn.functional.softmax(output_logits,dim=1)
return output_logits, output_softmax
def loss_fnc(predictions, targets):
return nn.CrossEntropyLoss()(input=predictions,target=targets)
def make_train_step(model, loss_fnc, optimizer):
def train_step(X,Y):
# set model to train mode
model.train()
# forward pass
output_logits, output_softmax = model(X)
predictions = torch.argmax(output_softmax,dim=1)
accuracy = torch.sum(Y==predictions)/float(len(Y))
# compute loss
loss = loss_fnc(output_logits, Y)
# compute gradients
loss.backward()
# update parameters and zero gradients
optimizer.step()
optimizer.zero_grad()
return loss.item(), accuracy*100
return train_step
def make_validate_fnc(model,loss_fnc):
def validate(X,Y):
with torch.no_grad():
model.eval()
output_logits, output_softmax = model(X)
predictions = torch.argmax(output_softmax,dim=1)
accuracy = torch.sum(Y==predictions)/float(len(Y))
loss = loss_fnc(output_logits,Y)
return loss.item(), accuracy*100, predictions
return validate
up till here both the codes are the same: Now previously the training was
EPOCHS=700
DATASET_SIZE = X_train.shape[0]
BATCH_SIZE = 32
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Selected device is {}'.format(device))
model = HybridModel(num_emotions=len(EMOTIONS)).to(device)
print('Number of trainable params: ',sum(p.numel() for p in model.parameters()) )
OPTIMIZER = torch.optim.SGD(model.parameters(),lr=0.01, weight_decay=1e-3, momentum=0.8)
train_step = make_train_step(model, loss_fnc, optimizer=OPTIMIZER)
validate = make_validate_fnc(model,loss_fnc)
losses=[]
val_losses = []
for epoch in range(EPOCHS):
# schuffle data
ind = np.random.permutation(DATASET_SIZE)
X_train = X_train[ind,:,:,:,:]
Y_train = Y_train[ind]
epoch_acc = 0
epoch_loss = 0
iters = int(DATASET_SIZE / BATCH_SIZE)
for i in range(iters):
batch_start = i * BATCH_SIZE
batch_end = min(batch_start + BATCH_SIZE, DATASET_SIZE)
actual_batch_size = batch_end-batch_start
X = X_train[batch_start:batch_end,:,:,:,:]
Y = Y_train[batch_start:batch_end]
X_tensor = torch.tensor(X,device=device).float()
Y_tensor = torch.tensor(Y, dtype=torch.long,device=device)
loss, acc = train_step(X_tensor,Y_tensor)
epoch_acc += acc*actual_batch_size/DATASET_SIZE
epoch_loss += loss*actual_batch_size/DATASET_SIZE
print(f"\r Epoch {epoch}: iteration {i}/{iters}",end='')
X_val_tensor = torch.tensor(X_val,device=device).float()
Y_val_tensor = torch.tensor(Y_val,dtype=torch.long,device=device)
val_loss, val_acc, _ = validate(X_val_tensor,Y_val_tensor)
losses.append(epoch_loss)
val_losses.append(val_loss)
print('')
print(f"Epoch {epoch} --> loss:{epoch_loss:.4f}, acc:{epoch_acc:.2f}%, val_loss:{val_loss:.4f}, val_acc:{val_acc:.2f}%")
This last part is not executable in my machine, and thows error : Cuda out of memory @nikhil6041 you can run it now.
Now this training part is changed by loading the data through pytorch loader. For this class Dataset
is created as
import torch
from torch.utils.data import Dataset
class Dataset(Dataset):
def __init__(this, X=None, y=None, mode="train"):
this.mode = mode
this.X = X
if mode == "train":
this.y = y
def __len__(this):
return this.X.shape[0]
def __getitem__(this, idx):
if this.mode == "train":
rec= torch.tensor(this.X[idx],dtype=torch.float), torch.tensor(this.y[idx],dtype=torch.long)
#print(rec)
return rec
else:
return torch.tensor(this.X[idx],dtype=torch.float)
and the training part I need to code. I hope you get it now. Plz instruct me if anything else needed to explain here.