Stack expects each tensor to be equal size, but got [0] at entry 0 and [3] at entry 1

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.

The training epoch function


def train_epoch(

   model, 

   data_loader, 

   criterion, 

   optimizer, 

   device, 

   n_examples

 ):

     model = model.train()

 

     losses = []

     correct_predictions = 0

 

     print(f'Doing training on {n_examples} samples')

 

     for batch_idx , (b_x,b_y) in enumerate(data_loader):

 

         if batch_idx%10 == 0:

             print(f' Processing batch {batch_idx+1}/{len(data_loader)} ')

 

         b_x = b_x.to(device)

         b_y = b_y.to(device)

  

         outputs = model(b_x)

         _, b_preds = torch.max(outputs, 1)

         

         loss = criterion(outputs,b_y)

 

         correct_predictions += torch.sum(b_preds == b_y)

 

         losses.append(loss.item())

 

         loss.backward()

         optimizer.step()

         optimizer.zero_grad()

 

     accuracy = correct_predictions.double() / n_examples

     loss = round(np.mean(losses),2)

 

     return accuracy , loss

The training loop



def train_model(

     model,

     train_data_loader,

     train_dataset_size,

     optimizer,

     criterion,

     device, 

     n_epochs):

 

     history = defaultdict(list)

 

     criterion.to(device)

 

     for epoch in range(n_epochs):

 

         print(f'Epoch {epoch + 1}/{n_epochs}')

         print('-' * 10)

 

         train_acc, train_loss = train_epoch(

                                     model, 

                                     train_data_loader, 

                                     criterion, 

                                     optimizer, 

                                     device, 

                                     train_dataset_size

                                 )

 

         print("Train loss {:.2f} accuracy {:.2f}".format(train_loss,train_acc))

       
         history['train_acc'].append(train_acc)

         history['train_loss'].append(train_loss)

      
     return model, history

This code is general and should work for any x,y pairs , for ur case u can change the

outputs = model(b_x)
according to ur case as told earlier. in ur case outputs will be a two membered tuple so pass ur logits accordingly to the loss function. Hope this helps.

1 Like

@nikhil6041 Thanks a lot for your time, I will definitely try, but what is train_dataset_size is it X_train.shape[0] in my case number of samples, is it same as n_examples.?

at last should I run this line

model, history=train_model(model,tr_loader,X_train.shape[0],optimizer,criterion,device, 50)

for this its throwing error

ValueError: not enough values to unpack (expected 3, got 2) at line

train_acc, train_loss = train_epoch(

train_dataset_size is len(train_loader)*batch_size . yes it is same as num_examples . for the error i m not sure why its coming like that try first this once. let me know if it helps

from collections import defaultdict
def train_epoch(model,  data_loader, criterion, optimizer, device, n_examples ):
     model = model.train()
     losses = []
     correct_predictions = 0
     print(f'Doing training on {n_examples} samples')
     
     for X,y in enumerate(tr_loader):

         

         X = X.to(device)

         y = y.to(device)

  

         logits,outputs = model(X)

         b_preds = torch.max(outputs, 1)

         

         loss = criterion(logits,y)

 

         correct_predictions += torch.sum(b_preds == y)

 

         losses.append(loss.item())

 

         loss.backward()

         optimizer.step()

         optimizer.zero_grad()

 

     accuracy = correct_predictions.double() / n_examples

     loss = round(np.mean(losses),2)

 

     return accuracy , loss
 
#%%
def train_model(model,tr_loader,train_dataset_size,optimizer,criterion,device, 

     n_epochs):
     history = defaultdict(list)
     criterion.to(device)
     for epoch in range(n_epochs):
         print(f'Epoch {epoch + 1}/{n_epochs}')

         print('-' * 50)

 

         train_acc, train_loss = train_epoch(

                                     model, 

                                     tr_loader, 

                                     criterion, 

                                     optimizer, 

                                     device, 

                                     train_dataset_size

                                 )

 

         print("Train loss {:.2f} accuracy {:.2f}".format(train_loss,train_acc))

       
         history['train_acc'].append(train_acc)

         history['train_loss'].append(train_loss)

      
     return model, history
    





model, history=train_model(model,tr_loader,X_train.shape[0],optimizer,criterion,device, 50)

I am not sure what to enumerate in tr_loader X and y as in Dataset??
For above code I am getting this error:

AttributeError: ‘int’ object has no attribute 'to’

traceback:
File “…py”, line 530, in
model, history=train_model(model,tr_loader,X_train.shape[0],optimizer,criterion,device, 50)

File “…py”, line 497, in train_model
train_acc, train_loss = train_epoch(

File “…py”, line 444, in train_epoch
X = X.to(device)

Actually this X is integer values, not the features in X_train, I think there is some mistake in class Dataset
I m using this for tr_loader

train_set = Dataset(X=X_train, y=Y_train,mode="train")
tr_loader = DL(train_set, batch_size=8, num_workers=0,shuffle=True)

what needs to be change here?

@krishna511 you dont need to create your own custom dataset class for it. you can use the TensorDataset provided by pytorch just covert ur X_train,y_train to tensors and pass it to the TensorDataset and you are good to go.

1 Like

@nikhil6041 I am doing this:

from torch.utils.data import TensorDataset
type(X_train)=torch.Tensor

train_set = TensorDataset(X_train, Y_train)
tr_loader = DL(train_set, batch_size=8, num_workers=0,shuffle=True)

test_set  = TensorDataset(X_test, Y_test)
ts_loader = DL(test_set, batch_size=8,num_workers=0,shuffle=False)

Still getting same error:

X = X.to(device,dtype=torch.float)

AttributeError: ‘int’ object has no attribute 'to’

@krishna511 type(X_train) = torch.Tensor is wrong . u need to do it like X_train = torch.Tensor(X_train)

1 Like

@nikhil6041 ,No I have already convert it into tensor , I am just showing its type for you here. These are the functions as suggested by you

from collections import defaultdict
def train_epoch(model,  data_loader, criterion, optimizer, device, n_examples ):
     model = model.train()
     losses = []
     correct_predictions = 0
     print(f'Doing training on {n_examples} samples')
     
     for batch_idx, (x,y) in enumerate(tr_loader):
         #print(X)
         # if X%10 == 0:

         #     print(f' Processing batch {X+1}/{len(tr_loader)} ')

         x = x.to(device,dtype=torch.float)

         y = y.to(device)

  

         logits,outputs = model(x)

         b_preds = torch.max(outputs, 1)

         print(type(b_preds))

         loss = criterion(logits,y)

 

         correct_predictions += torch.sum(b_preds == y)

 

         losses.append(loss.item())

 

         loss.backward()

         optimizer.step()

         optimizer.zero_grad()

 

     accuracy = correct_predictions.double() / n_examples

     loss = round(np.mean(losses),2)

 

     return accuracy , loss
 
#%%
def train_model(model,tr_loader,train_dataset_size,optimizer,criterion,device, 

     n_epochs):
     history = defaultdict(list)
     criterion.to(device)
     for epoch in range(n_epochs):
         print(f'Epoch {epoch + 1}/{n_epochs}')

         print('-' * 50)

 

         train_acc, train_loss = train_epoch(

                                     model, 

                                     tr_loader, 

                                     criterion, 

                                     optimizer, 

                                     device, 

                                     train_dataset_size

                                 )

 

         print("Train loss {:.2f} accuracy {:.2f}".format(train_loss,train_acc))

       
         history['train_acc'].append(train_acc)

         history['train_loss'].append(train_loss)

      
     return model, history
    





model, history=train_model(model,tr_loader,X_train.shape[0],optimizer,criterion,device, 50)


The error is :frowning:
correct_predictions += torch.sum(b_preds == y)
TypeError: sum(): argument ‘input’ (position 1) must be Tensor, not bool

here b_pred is a <class ‘torch.return_types.max’>

It is working now, training is started, How to validate and test the model ?
I am trying this code:

def make_validate_fnc(model,criterion):
    def validate(X,Y):
        with torch.no_grad():
            model.eval()
            for batch_idx, (X,Y) in enumerate(ts_loader):
                X= X.to(device,dtype=torch.float)
                Y = Y.to(device)
                output_logits, output_softmax = model(X)
                predictions = torch.argmax(output_softmax,dim=1)
                accuracy = torch.sum(Y==predictions)/float(len(Y))
                loss = criterion(output_logits,Y)
            return loss.item(), accuracy*100
    return validate

is it okay sir @nikhil6041 How to use this function correctly, plz guide if its okay.
also similar to training I need to note down loss and acc to finally plot both the graphs.

def train_epoch(model,  data_loader, criterion, optimizer, device, n_examples ):
     model = model.train()
     losses = []
     correct_predictions = 0
     print(f'Doing training on {n_examples} samples')
     
     for batch_idx, (x,y) in enumerate(tr_loader):
         #print(X)
         # if X%10 == 0:

         #     print(f' Processing batch {X+1}/{len(tr_loader)} ')

         x = x.to(device,dtype=torch.float)

         y = y.to(device)

  

         logits,outputs = model(x)

         b_preds = torch.max(outputs, 1)

         print(type(b_preds))

         loss = criterion(logits,y)

 

         correct_predictions += torch.sum(b_preds == y)

 

         losses.append(loss.item())

 

         loss.backward()

         optimizer.step()

         optimizer.zero_grad()

 

     accuracy = correct_predictions.double() / n_examples

     loss = round(np.mean(losses),2)

 

     return accuracy , loss
def eval_model(model,  data_loader, criterion, device, n_examples ):
     model = model.eval()
     losses = []
     correct_predictions = 0
     print(f'Doing training on {n_examples} samples')
     
     for batch_idx, (x,y) in enumerate(data_loader):
         #print(X)
         # if X%10 == 0:

         #     print(f' Processing batch {X+1}/{len(data_loader)} ')

         x = x.to(device,dtype=torch.float)

         y = y.to(device)

  

         logits,outputs = model(x)

         b_preds = torch.max(outputs, 1)

         print(type(b_preds))

         loss = criterion(logits,y)

 

         correct_predictions += torch.sum(b_preds == y)

 

         losses.append(loss.item())

 
     accuracy = correct_predictions.double() / n_examples

     loss = round(np.mean(losses),2)

 

     return accuracy , loss

def train_model(
    model,
    train_data_loader,
    val_data_loader, 
    train_dataset_size,
    val_dataset_size,
    optimizer,
    criterion,
    scheduler,
    device, 
    n_epochs=3):

    history = defaultdict(list)

    best_accuracy = 0
    criterion.to(device)

    for epoch in range(n_epochs):

        print(f'Epoch {epoch + 1}/{n_epochs}')
        print('-' * 10)

        train_acc, train_loss = train_epoch(
                                    model, 
                                    train_data_loader, 
                                    criterion, 
                                    optimizer, 
                                    device, 
                                    train_dataset_size
                                )

        print("Train loss {:.2f} accuracy {:.2f}".format(train_loss,train_acc))

        val_acc, val_loss = eval_model(
                                    model, 
                                    val_data_loader, 
                                    criterion, 
                                    device, 
                                    val_dataset_size

                            )

        print("Validation  loss {:.2f} accuracy {:.2f}".format(val_loss,val_acc))
        
        print()

        scheduler.step(val_loss)

        history['train_acc'].append(train_acc)
        history['train_loss'].append(train_loss)
        history['val_acc'].append(val_acc)
        history['val_loss'].append(val_loss)

        if val_acc > best_accuracy:
            torch.save(model.state_dict(), 'best_model_state.bin')
            best_accuracy = val_acc

    print(f'Best val accuracy: {best_accuracy}')

    model.load_state_dict(torch.load('best_model_state.bin'))

    return model, history

Here i have added the validation function with the train function . You can create separate dataloaders for train,val and test . Use the train and val dataloaders in train_model function and for evaluating the model its just a simple call to eval_model by passing your trained model with test_loader. I hope this answers your queries.

model,history = train_model(
    model,
    train_data_loader,
    val_data_loader, 
    train_dataset_size,
    val_dataset_size,
    optimizer,
    criterion,
    scheduler,
    device, 
    n_epochs)

@nikhil6041 Thanks a lot, for your help , But its not working actually I was trying to replicate a code on github, But its not working , after 50 epochs the test accuracy is 45% and train in only 25% something is weird here.

Can I plot these two graphs using sklearn ? to get a better idea of model ?

Well @krishna511 the performance depends upon a lot of factors for example the quality of the dataset, the selection of hyperparameters, the sampling strategy used during training ,etc. its not possible to list all of them you can explore them on your own . Graphs are always a good way to understand and debug our models, there are various tools available which you can integrate in your training loops to get logs like tensorboard,wandb and others,check them out I hope these helps you. Best of luck!

As per that code it should give validation acc of 95% and my training goes like

Epoch 1/53
----------

Train loss 2.06 accuracy 0.14
Validation  loss 2.04 accuracy 0.16

Epoch 2/53
----------

Train loss 2.05 accuracy 0.16
Validation  loss 2.02 accuracy 0.32

Epoch 3/53
----------

Train loss 2.04 accuracy 0.18
Validation  loss 1.97 accuracy 0.29

Epoch 4/53
----------

Train loss 2.03 accuracy 0.18
Validation  loss 1.92 accuracy 0.30

Epoch 5/53
----------

Train loss 2.01 accuracy 0.19
Validation  loss 1.88 accuracy 0.33

Epoch 6/53
----------

Train loss 2.00 accuracy 0.20
Validation  loss 1.78 accuracy 0.33

Epoch 7/53
----------

Train loss 1.98 accuracy 0.22
Validation  loss 1.74 accuracy 0.43

Epoch 8/53
----------

Train loss 1.96 accuracy 0.22
Validation  loss 1.77 accuracy 0.38

Epoch 9/53
----------

Train loss 1.95 accuracy 0.23
Validation  loss 1.63 accuracy 0.45

Epoch 10/53
----------


Train loss 1.94 accuracy 0.23
Validation  loss 1.62 accuracy 0.48

Epoch 11/53
----------

Train loss 1.93 accuracy 0.23
Validation  loss 1.66 accuracy 0.41

Epoch 12/53
----------

Train loss 1.92 accuracy 0.23
Validation  loss 1.56 accuracy 0.42

Epoch 13/53
----------
 
Train loss 1.90 accuracy 0.25
Validation  loss 1.55 accuracy 0.41

Epoch 14/53
----------

Train loss 1.90 accuracy 0.24
Validation  loss 1.53 accuracy 0.47

Epoch 15/53
----------

Train loss 1.88 accuracy 0.26
Validation  loss 1.60 accuracy 0.46

Epoch 16/53
----------

Train loss 1.87 accuracy 0.26
Validation  loss 1.48 accuracy 0.49

Epoch 17/53
----------

Train loss 1.86 accuracy 0.27
Validation  loss 1.45 accuracy 0.45

Epoch 18/53
----------

Train loss 1.85 accuracy 0.26

Validation  loss 1.48 accuracy 0.49

Epoch 19/53
----------

Train loss 1.84 accuracy 0.27
Validation  loss 1.42 accuracy 0.50

Epoch 20/53
----------

Train loss 1.83 accuracy 0.27
Validation  loss 1.41 accuracy 0.53

Epoch 21/53
----------

Train loss 1.83 accuracy 0.29
Validation  loss 1.41 accuracy 0.45

Epoch 22/53
----------

Train loss 1.81 accuracy 0.30
Validation  loss 1.36 accuracy 0.50

Epoch 23/53
----------
 
Train loss 1.80 accuracy 0.29
Validation  loss 1.38 accuracy 0.49

Epoch 24/53
----------

Train loss 1.79 accuracy 0.31
Validation  loss 1.34 accuracy 0.55

Epoch 25/53
----------

Train loss 1.77 accuracy 0.31
Validation  loss 1.32 accuracy 0.55

Epoch 26/53
----------

Train loss 1.75 accuracy 0.33 
Validation  loss 1.30 accuracy 0.52

Epoch 27/53
----------

Train loss 1.74 accuracy 0.32
Validation  loss 1.28 accuracy 0.52

Epoch 28/53
----------
Train loss 1.73 accuracy 0.34
Validation  loss 1.28 accuracy 0.54

Epoch 29/53
----------
Train loss 1.72 accuracy 0.34
Validation  loss 1.33 accuracy 0.48

Epoch 30/53
----------
Train loss 1.70 accuracy 0.35
Validation  loss 1.32 accuracy 0.53

Epoch 31/53
----------

Train loss 1.68 accuracy 0.35
Validation  loss 1.29 accuracy 0.54

Epoch 32/53
----------

Train loss 1.66 accuracy 0.37
Validation  loss 1.35 accuracy 0.48

Epoch 33/53
----------

Train loss 1.66 accuracy 0.37
Validation  loss 1.34 accuracy 0.48

Epoch    33: reducing learning rate of group 0 to 1.0000e-03.
Epoch 34/53
----------

Train loss 1.57 accuracy 0.42
Validation  loss 1.25 accuracy 0.57

Epoch 35/53
----------
Train loss 1.53 accuracy 0.43
Validation  loss 1.23 accuracy 0.59

Epoch 36/53
----------

Train loss 1.52 accuracy 0.43
Validation  loss 1.24 accuracy 0.56

Epoch 37/53
----------
Train loss 1.50 accuracy 0.44
Validation  loss 1.23 accuracy 0.58