<jupyter_start><jupyter_text>**Βήμα10:**Παρακάτω έχουμε υλοποιήσει τα μοντέλα που ζητήθηκαν για το βημα 10 (3 για κάθε κατηγορία - valence,energy,danceability)<jupyter_code># This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load in 

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the "../input/" directory.
# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory

import os
print(os.listdir("../input"))

# Any results you write to the current directory are saved as output.
import numpy as np
import gzip
import copy
from sklearn.preprocessing import LabelEncoder
from torch.utils.data import Dataset
from torch.utils.data import SubsetRandomSampler, DataLoader
import os


class_mapping = {
    'Rock': 'Rock',
    'Psych-Rock': 'Rock',
    'Indie-Rock': None,
    'Post-Rock': 'Rock',
    'Psych-Folk': 'Folk',
    'Folk': 'Folk',
    'Metal': 'Metal',
    'Punk': 'Metal',
    'Post-Punk': None,
    'Trip-Hop': 'Trip-Hop',
    'Pop': 'Pop',
    'Electronic': 'Electronic',
    'Hip-Hop': 'Hip-Hop',
    'Classical': 'Classical',
    'Blues': 'Blues',
    'Chiptune': 'Electronic',
    'Jazz': 'Jazz',
    'Soundtrack': None,
    'International': None,
    'Old-Time': None
}


def torch_train_val_split(
        dataset, batch_train, batch_eval,
        val_size=.2, shuffle=True, seed=42):
    # Creating data indices for training and validation splits:
    dataset_size = len(dataset)
    indices = list(range(dataset_size))
    val_split = int(np.floor(val_size * dataset_size))
    if shuffle:
        np.random.seed(seed)
        np.random.shuffle(indices)
    train_indices = indices[val_split:]
    val_indices = indices[:val_split]

    # Creating PT data samplers and loaders:
    train_sampler = SubsetRandomSampler(train_indices)
    val_sampler = SubsetRandomSampler(val_indices)

    train_loader = DataLoader(dataset,
                              batch_size=batch_train,
                              sampler=train_sampler)
    val_loader = DataLoader(dataset,
                            batch_size=batch_eval,
                            sampler=val_sampler)
    return train_loader, val_loader


def read_spectrogram(spectrogram_file, chroma=True):
    with gzip.GzipFile(spectrogram_file, 'r') as f:
        spectrograms = np.load(f)
    # spectrograms contains a fused mel spectrogram and chromagram
    # Decompose as follows
    return spectrograms.T


class LabelTransformer(LabelEncoder):
    def inverse(self, y):
        try:
            return super(LabelTransformer, self).inverse_transform(y)
        except:
            return super(LabelTransformer, self).inverse_transform([y])

    def transform(self, y):
        try:
            return super(LabelTransformer, self).transform(y)
        except:
            return super(LabelTransformer, self).transform([y])

        
class PaddingTransform(object):
    def __init__(self, max_length, padding_value=0):
        self.max_length = max_length
        self.padding_value = padding_value

    def __call__(self, s):
        if len(s) == self.max_length:
            return s

        if len(s) > self.max_length:
            return s[:self.max_length]

        if len(s) < self.max_length:
            s1 = copy.deepcopy(s)
            pad = np.zeros((self.max_length - s.shape[0], s.shape[1]), dtype=np.float32)
            s1 = np.vstack((s1, pad))
            return s1

        
class SpectrogramDataset(Dataset):
    def __init__(self, path, class_mapping=None, train=True, max_length=-1):
        t = 'train' if train else 'test'
        p = os.path.join(path, t)
        self.index = os.path.join(path, "{}_labels.txt".format(t))
        self.files, labels = self.get_files_labels(self.index, class_mapping)
        #print(self.files)
        
        self.feats = [read_spectrogram(os.path.join(p, f+".fused.full.npy.gz")) for f in self.files]
        self.feat_dim = self.feats[0].shape[1]
        self.lengths = [len(i) for i in self.feats]
        self.max_length = max(self.lengths) if max_length <= 0 else max_length
        self.zero_pad_and_stack = PaddingTransform(self.max_length)
        #self.label_transformer = LabelTransformer()
        #if isinstance(labels, (list, tuple)):
            #self.labels = np.array(self.label_transformer.fit_transform(labels)).astype('int64')
        self.labels=labels
    def get_files_labels(self, txt, class_mapping):
        with open(txt, 'r') as fd:
            lines = [l.rstrip().split('\t') for l in fd.readlines()[1:]]
            
        files, labels = [], []
        for l in lines:
            l=l[0].split(",")
            b=l[1:]
            b = list(map(float,b))
            files.append(l[0])
            
            labels.append(b)
        return files, labels

    def __getitem__(self, item):
        l = min(self.lengths[item], self.max_length)
        return self.zero_pad_and_stack(self.feats[item]), self.labels[item], l

    def __len__(self):
        return len(self.labels)

BATCH_SZ=32

specs = SpectrogramDataset('../input/data/data/multitask_dataset/', train=True, class_mapping=class_mapping, max_length=-1)
train_loader, val_loader = torch_train_val_split(specs, BATCH_SZ ,BATCH_SZ, val_size=.33)
#test_loader = DataLoader(SpectrogramDataset('../input/data/data/multitask_dataset/', train=False, class_mapping=class_mapping, max_length=-1))<jupyter_output><empty_output><jupyter_text>**REGRESSION FOR VALENCE** 1. LSTM for regression<jupyter_code>import numpy as np
import torch
from torch.utils.data import Dataset
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from scipy import stats

class BasicLSTM(nn.Module):
    def __init__(self, input_dim,rnn_size, output_dim, num_layers,dropout_type=None,dropout=0, bidirectional=False):
        super(BasicLSTM, self).__init__()
        self.bidirectional = bidirectional
        self.feature_size = rnn_size * 2 if self.bidirectional else rnn_size
        self.dropout=dropout
        '''
        if dropout_type is not None:
            if dropout_type = 'Variational_Locked_Dropout'
            self.dropout = Variational_LockedDropout(dropout=dropout_prob)
        '''
            
        # --------------- Insert your code here ---------------- #
        # Initialize the LSTM, Dropout, Output layers
        
        
        #for non-bidirectional:
        #we assume that rnn-size is the number of lstm-units...
        #input_dim is the vector that each unit will receive as input..
        #hidden_dim at basic lstm is the same as hidden_dim...
        #so we have...
        self.num_layers=num_layers
        self.hidden_dim = rnn_size # OR self.hidden_dim = self.feature_size
        if self.bidirectional:
            self.lstm = nn.LSTM(input_dim,self.hidden_dim//2,num_layers=num_layers,bidirectional=bidirectional,
                                dropout=self.dropout,batch_first=True)
        else:
            self.lstm = nn.LSTM(input_dim,self.hidden_dim,num_layers=num_layers,bidirectional=bidirectional,
                                dropout=self.dropout,batch_first=True)

        #using batch_first=True affects only the input!
        # if the input is at form seq_len,batch,features batch_first=True is not needed
        
        #self.hidden = self.init_hidden() #initialize hidden state(and cell state)
       
        self.output_set_size = output_dim
        self.hidden2output = nn.Linear(self.hidden_dim,self.output_set_size)

    def forward(self, x, lengths):
        """ 
            x : 3D numpy array of dimension N x L x D
                N: batch index
                L: sequence index
                D: feature index

            lengths: N x 1
         """
        
        # --------------- Insert your code here ---------------- #
        
        # You must have all of the outputs of the LSTM, but you need only the last one (that does not exceed the sequence length)
        # To get it use the last_timestep method
        # Then pass it through the remaining network 
        lstm_out,_ = self.lstm(x)
        last_lstm_out = self.last_timestep(lstm_out,lengths)   
        out_space = self.hidden2output(last_lstm_out)
        return out_space

    def last_timestep(self, outputs, lengths, bidirectional=False):
        """
            Returns the last output of the LSTM taking into account the zero padding
        """
        if self.bidirectional:
            forward, backward = self.split_directions(outputs)
            last_forward = self.last_by_index(forward, lengths)
            last_backward = backward[:, 0, :]
            # Concatenate and return - maybe add more functionalities like average
            return torch.cat((last_forward, last_backward), dim=-1)

        else:
            return self.last_by_index(outputs, lengths)

    @staticmethod
    def split_directions(outputs):
        direction_size = int(outputs.size(-1) / 2)
        forward = outputs[:, :, :direction_size]
        backward = outputs[:, :, direction_size:]
        return forward, backward

    @staticmethod
    def last_by_index(outputs, lengths):
        # Index of the last output for each sequence.
        idx = (lengths - 1).view(-1, 1).expand(outputs.size(0),
                                               outputs.size(2)).unsqueeze(1)
        return outputs.gather(1, idx).squeeze()
INPUT_SZ=140
NUM_CLASSES=1
NUM_LAYERS=1
HIDDEN_SIZE=20
DROPOUT=0

num_epochs=30

device=torch.device("cuda")
model_lstm_regr_val = BasicLSTM(INPUT_SZ,HIDDEN_SIZE,NUM_CLASSES,NUM_LAYERS,dropout=DROPOUT,bidirectional=False)
model_lstm_regr_val.to(device)

# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model_lstm_regr_val.parameters(),lr=0.01)



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_lstm_regr_val.train()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        #print(instance)
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_lstm_regr_val(features,lengths)
        prediction_vec.to(device)
        #print(prediction_vec.shape)
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        valence_labels=valence_labels.unsqueeze(1)
        loss = criterion(prediction_vec,valence_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_lstm_regr_val.eval()

n_samples = 0
SE = 0
spearman=[]
running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        out = model_lstm_regr_val(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        valence_labels = valence_labels.unsqueeze(1)
        E = valence_labels-out
        SE = pow(E,2).sum().item() + SE
        #print(SE)
        n_samples+=features.shape[0]
        
        spearman.append(stats.spearmanr(valence_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for LSTM in validation set (predicting valence): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for LSTM in validation set (predicting valence):  0.03340419179081181<jupyter_text>2. CNN Regression<jupyter_code>import numpy as np
import torch
from torch.utils.data import Dataset
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class ConvNet(nn.Module):
    def __init__(self,input_channels,out_channels,kernel_sz,stride,padding, num_classes):
        super(ConvNet, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(input_channels, 4, kernel_size=(3,3), stride=1, padding=1),
            nn.ReLU(),
            nn.BatchNorm2d(4),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(4, 16, kernel_size=(3,3), stride=1, padding=1),
            nn.ReLU(),
            nn.BatchNorm2d(16),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )
        self.layer3 = nn.Sequential(
            nn.Conv2d(16 , 32 , kernel_size=(3,3), stride=1, padding=1),
            nn.ReLU(),
            nn.BatchNorm2d(32),
            nn.MaxPool2d(kernel_size=3, stride=3)
        )
        self.layer4 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=(3,3), stride=1, padding=1),
            nn.ReLU(),
            nn.BatchNorm2d(64),
            nn.MaxPool2d(kernel_size=3, stride=3)
        )
        
        self.dense1= nn.Linear(6720,500) 
        self.dense2 = nn.Linear(500,1)

        
    def forward(self, x,lengths):
        #print(x.shape)
        x = x.transpose(1, 2)
        #print(x.shape)
        x.unsqueeze_(1)
        #print(x.shape)
        out1 = self.layer1(x)
        #print(out1.shape)
        out2= self.layer2(out1)
        #print(out2.shape)
        out3= self.layer3(out2)
        #print(out3.shape)
        out4= self.layer4(out3)
        #print(out4.shape)
        
    
        out_flat=out4.reshape(-1,out4.size(1)*out4.size(2)*out4.size(3))
        #print(out_flat.shape)
        
        
        #implementing fully connected layers
        
        hidden_out = self.dense1(out_flat)
        final_out = self.dense2(hidden_out)
        
        return final_out
        

num_epochs=35
kernel_sz=3
input_channels=1
out_channels=1
stride=2
padding=2
num_classes=1


device=torch.device("cuda")

model_cnn_regr_val = ConvNet(input_channels,out_channels,kernel_sz,stride,padding ,num_classes)
model_cnn_regr_val.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model_cnn_regr_val.parameters())



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_cnn_regr_val.train()
    #scheduler.step()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_cnn_regr_val(features,lengths)
        prediction_vec.to(device)
        
        
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        valence_labels = valence_labels.unsqueeze(1)
        
        loss = criterion(prediction_vec,valence_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_cnn_regr_val.eval()

n_samples = 0
SE = 0
spearman=[]
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_cnn_regr_val(features,lengths)
        out = out.to(device)
        
        valence_labels = valence_labels.unsqueeze(1)
        E = valence_labels-out
        SE = pow(E,2).sum().item() + SE
        #print(SE)
        n_samples+=features.shape[0]
        
        
        spearman.append(stats.spearmanr(valence_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN-2D in validation set (predicting valence): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN-2D in validation set (predicting valence):  0.4285448002238674<jupyter_text>3. CNN-LSTM regression<jupyter_code>import numpy as np
import torch
from torch.utils.data import Dataset
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class ConvLSTM(nn.Module):
    def __init__(self,input_channels,out_channels,kernel_sz,stride,padding, num_classes,input_dim,rnn_size, output_dim, num_layers,dropout_type=None,dropout=0, bidirectional=False):
        super(ConvLSTM, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv1d(input_channels, 256, kernel_size=kernel_sz, stride=stride, padding=padding),
            nn.ReLU(),
            nn.BatchNorm1d(256),
            nn.MaxPool1d(kernel_size=2, stride=2)
        )
        self.layer2 = nn.Sequential(
            nn.Conv1d(256, 512, kernel_size=kernel_sz, stride=stride, padding=padding),
            nn.ReLU(),
            nn.BatchNorm1d(512),
            nn.MaxPool1d(kernel_size=2, stride=2)
        )
        
        
        self.bidirectional = bidirectional
        self.feature_size = rnn_size * 2 if self.bidirectional else rnn_size
        self.dropout=dropout
        '''
        if dropout_type is not None:
            if dropout_type = 'Variational_Locked_Dropout'
            self.dropout = Variational_LockedDropout(dropout=dropout_prob)
        '''
            
        # --------------- Insert your code here ---------------- #
        # Initialize the LSTM, Dropout, Output layers
        
        
        #for non-bidirectional:
        #we assume that rnn-size is the number of lstm-units...
        #input_dim is the vector that each unit will receive as input..
        #hidden_dim at basic lstm is the same as hidden_dim...
        #so we have...
        self.num_layers=num_layers
        self.hidden_dim = rnn_size # OR self.hidden_dim = self.feature_size
        if self.bidirectional:
            self.lstm = nn.LSTM(input_dim,self.hidden_dim//2,num_layers=num_layers,bidirectional=bidirectional,
                                dropout=self.dropout,batch_first=True)
        else:
            self.lstm = nn.LSTM(input_dim,self.hidden_dim,num_layers=num_layers,bidirectional=bidirectional,
                                dropout=self.dropout,batch_first=True)

        #using batch_first=True affects only the input! 
        # if the input is at form seq_len,batch,features batch_first=True is not needed
        
        #self.hidden = self.init_hidden() #initialize hidden state(and cell state)
        
        #use a linear transformation from lstm hidden_state space to ouput space..
        #for digit classification we want to classify a sequence to 0-9 digits. So we will use as output dim the number 10.
        self.output_set_size = output_dim
        self.hidden2output = nn.Linear(self.hidden_dim,self.output_set_size)
        
    def forward(self, x,lengths):
  
        #print(x.shape)
        x = x.transpose(1, 2)
        #print(x.shape)
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.transpose(1, 2)
        #print(out.shape)
        #newlengths = torch.ones(out.shape[0])
        #newlengths=newlengths * (out.shape[1])
        newlengths = lengths//4-1
        #print(newlengths)
        newlengths = newlengths.type(torch.LongTensor).to(device)
        
       
        #print(out.shape)
        lstm_out,_ = self.lstm(out)
        #print(lstm_out.shape)
        last_lstm_out = self.last_timestep(lstm_out,newlengths)   
        out_space = self.hidden2output(last_lstm_out)
        
        #print(out_space.shape)
        #out_space = self.hidden2output(lstm_out)
        
        return out_space
        
    def last_timestep(self, outputs, lengths):
        """
            Returns the last output of the LSTM taking into account the zero padding
        """
        if self.bidirectional:
            forward, backward = self.split_directions(outputs)
            last_forward = self.last_by_index(forward, lengths)
            last_backward = backward[:, 0, :]
            # Concatenate and return - maybe add more functionalities like average
            return torch.cat((last_forward, last_backward), dim=-1)

        else:
            return self.last_by_index(outputs, lengths)

    @staticmethod
    def split_directions(outputs):
        direction_size = int(outputs.size(-1) / 2)
        forward = outputs[:, :, :direction_size]
        backward = outputs[:, :, direction_size:]
        return forward, backward

    @staticmethod
    def last_by_index(outputs, lengths):
        # Index of the last output for each sequence.
        idx = (lengths - 1).view(-1, 1).expand(outputs.size(0),
                                               outputs.size(2)).unsqueeze(1)
        return outputs.gather(1, idx).squeeze()
    


num_epochs=35
kernel_sz=3
input_channels=140
out_channels=140
stride=1
padding=1
num_classes=1

INPUT_SZ=512
NUM_CLASSES=1
NUM_LAYERS=1
HIDDEN_SIZE=20
DROPOUT=0

device=torch.device("cuda")
model_cnn_lstm_regr_val = ConvLSTM(input_channels,out_channels,kernel_sz,stride,padding ,num_classes,INPUT_SZ,HIDDEN_SIZE,NUM_CLASSES,NUM_LAYERS,dropout=DROPOUT,bidirectional=False)
model_cnn_lstm_regr_val.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model_cnn_lstm_regr_val.parameters())



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_cnn_lstm_regr_val.train()
    #scheduler.step()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        
        features = instance[:][0]
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_cnn_lstm_regr_val(features,lengths)
        prediction_vec.to(device)
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        valence_labels = valence_labels.unsqueeze(1)
        
        loss = criterion(prediction_vec,valence_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_cnn_lstm_regr_val.eval()

n_samples = 0
SE = 0
spearman=[]
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_cnn_lstm_regr_val(features,lengths)
        out = out.to(device)
        
        valence_labels = valence_labels.unsqueeze(1)
        E = valence_labels-out
        SE = pow(E,2).sum().item() + SE
        #print(SE)
        n_samples+=features.shape[0]

        spearman.append(stats.spearmanr(valence_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN-LSTM in validation set (predicting valence): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN-LSTM in validation set (predicting valence):  0.24241181466361428<jupyter_text>**REGRESSION FOR ENERGY** 1. LSTM Regression<jupyter_code>INPUT_SZ=140
NUM_CLASSES=1
NUM_LAYERS=1
HIDDEN_SIZE=40
DROPOUT=0

num_epochs=30

device=torch.device("cuda")
model_lstm_regr_energy = BasicLSTM(INPUT_SZ,HIDDEN_SIZE,NUM_CLASSES,NUM_LAYERS,dropout=DROPOUT,bidirectional=False)
model_lstm_regr_energy.to(device)


# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model_lstm_regr_energy.parameters(),lr=0.001)



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_lstm_regr_energy.train()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        #print(instance)
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_lstm_regr_energy(features,lengths)
        prediction_vec.to(device)
        #print(prediction_vec.shape)
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        energy_labels=energy_labels.unsqueeze(1)
        loss = criterion(prediction_vec,energy_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_lstm_regr_energy.eval()

n_samples = 0
SE = 0
spearman=[]
running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_lstm_regr_energy(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        energy_labels = energy_labels.unsqueeze(1)
        E = energy_labels-out
        SE = pow(E,2).sum().item() + SE
        
        n_samples+=features.shape[0]
        
        
        spearman.append(stats.spearmanr(energy_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN-LSTM in validation set (predicting energy): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN-LSTM in validation set (predicting energy):  0.17821239577610523<jupyter_text>2.CNN regression<jupyter_code>num_epochs=35
kernel_sz=3
input_channels=1
out_channels=1
stride=2
padding=2
num_classes=10


device=torch.device("cuda")

model_cnn_regr_energy = ConvNet(input_channels,out_channels,kernel_sz,stride,padding ,num_classes)
model_cnn_regr_energy.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model_cnn_regr_energy.parameters())



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_cnn_regr_energy.train()
    #scheduler.step()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_cnn_regr_energy(features,lengths)
        prediction_vec.to(device)
        
        
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        energy_labels = energy_labels.unsqueeze(1)
        
        loss = criterion(prediction_vec,energy_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_cnn_regr_energy.eval()

n_samples = 0
SE = 0
spearman=[]
running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_cnn_regr_energy(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        energy_labels = energy_labels.unsqueeze(1)
        E = energy_labels-out
        SE = pow(E,2).sum().item() + SE
        
        n_samples+=features.shape[0]
        
        spearman.append(stats.spearmanr(energy_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN-2d in validation set (predicting energy): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN-2d in validation set (predicting energy):  0.5819362912855087<jupyter_text>3.CNN-LSTM Regression<jupyter_code>num_epochs=35
kernel_sz=3
input_channels=140
out_channels=140
stride=1
padding=1
num_classes=1

INPUT_SZ=512
NUM_CLASSES=1
NUM_LAYERS=1
HIDDEN_SIZE=20
DROPOUT=0

device=torch.device("cuda")
model_cnn_lstm_regr_energy = ConvLSTM(input_channels,out_channels,kernel_sz,stride,padding ,num_classes,INPUT_SZ,HIDDEN_SIZE,NUM_CLASSES,NUM_LAYERS,dropout=DROPOUT,bidirectional=False)
model_cnn_lstm_regr_energy.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model_cnn_regr_energy.parameters())



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_cnn_lstm_regr_energy.train()
    #scheduler.step()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_cnn_lstm_regr_energy(features,lengths)
        prediction_vec.to(device)
        
        
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        energy_labels = energy_labels.unsqueeze(1)
        
        loss = criterion(prediction_vec,energy_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_cnn_lstm_regr_energy.eval()

n_samples = 0
SE = 0
spearman=[]
running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_cnn_lstm_regr_energy(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        energy_labels = energy_labels.unsqueeze(1)
        E = energy_labels-out
        SE = pow(E,2).sum().item() + SE
        
        n_samples+=features.shape[0]
        
        spearman.append(stats.spearmanr(energy_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN-LSTM in validation set (predicting energy): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN-LSTM in validation set (predicting energy):  0.2440124449706023<jupyter_text>**REGRESSION FOR DANCEABILITY** 1.LSTM Regression<jupyter_code>INPUT_SZ=140
NUM_CLASSES=1
NUM_LAYERS=1
HIDDEN_SIZE=40
DROPOUT=0

num_epochs=30

device=torch.device("cuda")
model_lstm_regr_dance = BasicLSTM(INPUT_SZ,HIDDEN_SIZE,NUM_CLASSES,NUM_LAYERS,dropout=DROPOUT,bidirectional=False)
model_lstm_regr_dance.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model_lstm_regr_dance.parameters(),lr=0.001)



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_lstm_regr_dance.train()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        #print(instance)
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_lstm_regr_dance(features,lengths)
        prediction_vec.to(device)
        #print(prediction_vec.shape)
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        dance_labels=dance_labels.unsqueeze(1)
        loss = criterion(prediction_vec,dance_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_lstm_regr_dance.eval()

n_samples = 0
SE = 0
spearman=[]
running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_lstm_regr_dance(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        dance_labels = dance_labels.unsqueeze(1)
        E = dance_labels-out
        SE = pow(E,2).sum().item() + SE
        #print(SE)
        n_samples+=features.shape[0]
        
        
        spearman.append(stats.spearmanr(dance_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for LSTM in validation set (predicting dance): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for LSTM in validation set (predicting dance):  0.09592557532326672<jupyter_text>CNN regression<jupyter_code>num_epochs=35
kernel_sz=3
input_channels=1
out_channels=1
stride=2
padding=2
num_classes=10


device=torch.device("cuda")

model_cnn_regr_dance = ConvNet(input_channels,out_channels,kernel_sz,stride,padding ,num_classes)
model_cnn_regr_dance.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model_cnn_regr_dance.parameters())



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_cnn_regr_dance.train()
    #scheduler.step()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_cnn_regr_dance(features,lengths)
        prediction_vec.to(device)
        
        
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        dance_labels = dance_labels.unsqueeze(1)
        
        loss = criterion(prediction_vec,dance_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_cnn_regr_dance.eval()

n_samples = 0
SE = 0
spearman=[]
running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_cnn_regr_dance(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        dance_labels = dance_labels.unsqueeze(1)
        E = dance_labels-out
        SE = pow(E,2).sum().item() + SE
        
        n_samples+=features.shape[0]
        
        
        spearman.append(stats.spearmanr(dance_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN in validation set (predicting dance): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN in validation set (predicting dance):  0.5619338200866792<jupyter_text>3. CNN-LSTM regression<jupyter_code>num_epochs=35
kernel_sz=3
input_channels=140
out_channels=140
stride=1
padding=1
num_classes=1

INPUT_SZ=512
NUM_CLASSES=1
NUM_LAYERS=1
HIDDEN_SIZE=20
DROPOUT=0

device=torch.device("cuda")
model_cnn_lstm_regr_dance = ConvLSTM(input_channels,out_channels,kernel_sz,stride,padding ,num_classes,INPUT_SZ,HIDDEN_SIZE,NUM_CLASSES,NUM_LAYERS,dropout=DROPOUT,bidirectional=False)
model_cnn_lstm_regr_dance.to(device)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model_cnn_regr_dance.parameters())



for epoch in range(num_epochs):
    #no need to set requires_grad=True for parameters(weights) as it done by default. Also for input requires_grad is not
    #always necessary. So we comment the following line.
    #with torch.autograd(): 
    model_cnn_lstm_regr_dance.train()
    #scheduler.step()
    running_average_loss = 0

    #train model in each epoch
    for index,instance in enumerate(train_loader):
        # Step 1. Remember that Pytorch accumulates gradients.
        # We need to clear them out before each instance
        #features,labels,lengths=instance
        
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)

        optimizer.zero_grad()
        
        # Step 3. Run our forward pass.
        prediction_vec = model_cnn_lstm_regr_dance(features,lengths)
        prediction_vec.to(device)
        
        
        # Step 4. Compute the loss, gradients, and update the parameters by
        #  calling optimizer.step()
        dance_labels = dance_labels.unsqueeze(1)
        
        loss = criterion(prediction_vec,dance_labels)
        loss.backward(retain_graph=True)
        optimizer.step()

        running_average_loss += loss.detach().item()
    print("Epoch: {} \t \t Training Loss {}".format(epoch, float(running_average_loss) / (index + 1)))
model_cnn_lstm_regr_dance.eval()

n_samples = 0
SE = 0
spearman = []

running_average_loss=0
with torch.no_grad():
    for index, instance in enumerate(val_loader):
        features = instance[:][0].to(device)
        labels = instance[:][1]
        valence_labels = labels[0].type(torch.FloatTensor).to(device)
        energy_labels = labels[1].type(torch.FloatTensor).to(device)
        dance_labels = labels[2].type(torch.FloatTensor).to(device)
        lengths = instance[:][2].to(device)
        features = features.type(torch.FloatTensor).to(device)
        
        
    
        out = model_cnn_lstm_regr_dance(features,lengths)
        out = out.to(device)
        #print(out)
        #print(valence_labels)

        dance_labels = dance_labels.unsqueeze(1)
        #E = dance_labels-out
        #SE = pow(E,2).sum().item() + SE
        #n_samples+=features.shape[0]
        
        spearman.append(stats.spearmanr(dance_labels.cpu().squeeze(),out.cpu().squeeze(),axis=0)[0])

print("Spearnman's correlation for CNN-LSTM in validation set (predicting danceability): " , np.mean(spearman) )<jupyter_output>Spearnman's correlation for CNN-LSTM in validation set (predicting danceability):  -0.03544197194074701
{'fraction_non_alphanumeric': 0.11103120641562064, 'fraction_numerical': 0.016104428172942817, 'mean_word_length': 2.956289335287525, 'pattern_counts': {'":': 0, '<': 34, '<?xml version=': 0, '>': 33, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '506442', 'license': 'MIT', 'n_tokens_mistral': 15147, 'n_tokens_neox': 14568, 'n_words': 2953, 'path': 'lab3/step_10_regression.ipynb', 'repo_name': 'manzar96/pat_rec_ntua', 'size': '45888'}