<jupyter_start><jupyter_text>Deep Neural Decision Forest This is the code for the Deep Learning Project (2019). Emotion recognition has been intesively exploited in the most recent years, due to the low-cost technologies involved and the interest derived from different fields of research, like psychology, psychiatry, neuroscience and computer science in general. Even if the interest in the topic had been constantly growing, the available datasets are still a small number. For this research we decided to test our network on the RAVDESS dataset, which contains audio and video data coming from 24 authors who emulate different emotions. Our problem is doing an audio emotion recognition using a particular kind of architecture: the deep random forest. This architecture has been tested on the MNIST dataset and on other image dataset while here we apply the network on audio data, which are converted in coefficient through an MFCC and then processed. This project follows the guide lines of the paper: [ Deep Neural Decision Forests](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/Kontschieder_Deep_Neural_Decision_ICCV_2015_paper.pdf).  Dataset Preparation<jupyter_code>import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import specgram
from sklearn.metrics import confusion_matrix
import os
from google.colab import drive
drive.mount('/content/gdrive')
!mkdir dataset
!cp "gdrive/My Drive/RAVDESS/RAVDESS_DEFINITIVE_EDITION.zip" dataset/
!unzip dataset/RAVDESS_DEFINITIVE_EDITION.zip
mylist= os.listdir('RAVDESS_DEFINITIVE_EDITION/')<jupyter_output><empty_output><jupyter_text>Creating Training + Test<jupyter_code>import librosa
from librosa import display
import time

path = 'RAVDESS_DEFINITIVE_EDITION/'
lst = []

start_time = time.time()

for subdir, dirs, files in os.walk(path):
  for file in files:
      try:
        print(file)
        #Load librosa array, obtain mfcss, store the file and the mcss information in a new array
        X, sample_rate = librosa.load(os.path.join(subdir,file), res_type='kaiser_fast')
        mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T,axis=0) 
        # The instruction below converts the labels (from 1 to 8) to a series from 0 to 7
        # This is because our predictor needs to start from 0 otherwise it will try to predict also 0.
        file = int(file[7:8]) - 1  
        arr = mfccs, file
        lst.append(arr)
      # If the file is not valid, skip it
      except ValueError:
        continue

print("--- Data loaded. Loading time: %s seconds ---" % (time.time() - start_time))
# Creating X and y: zip makes a list of all the first elements, and a list of all the second elements.
X, y = zip(*lst)

import numpy as np
X = np.asarray(X)
y = np.asarray(y)


X.shape, y.shape

import joblib

X_name = 'X.joblib'
y_name = 'y.joblib'
save_dir = '/content/drive/My Drive/Ravdess_model'
save_dir = 'gdrive/My Drive/RAVDESS/'

savedX = joblib.dump(X, os.path.join(save_dir, X_name))
savedy = joblib.dump(y, os.path.join(save_dir, y_name))<jupyter_output><empty_output><jupyter_text>Plotting the audio file's waveform and its spectrogram<jupyter_code>#Load libraries
import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import specgram
from sklearn.metrics import confusion_matrix
% pylab inline
import pandas as pd
import glob 
#file audio loading with librosa
data, sampling_rate = librosa.load('RawData/f11 (01).wav')

plt.figure(figsize=(15, 5))
librosa.display.waveplot(data, sr=sampling_rate)
import scipy.io.wavfile
import sys

sr,x = scipy.io.wavfile.read('RawData/f10 (01).wav')

## Parameters: 10ms step, 30ms window
nstep = int(sr * 0.01)
nwin  = int(sr * 0.03)
nfft = nwin

window = np.hamming(nwin)

## will take windows x[n1:n2].  generate
## and loop over n2 such that all frames
## fit within the waveform
nn = range(nwin, len(x), nstep)

X = np.zeros( (len(nn), nfft//2) )

for i,n in enumerate(nn):
    xseg = x[n-nwin:n]
    z = np.fft.fft(window * xseg, nfft)
    X[i,:] = np.log(np.abs(z[:nfft//2]))

plt.imshow(X.T, interpolation='nearest',
    origin='lower',
    aspect='auto')

plt.show()<jupyter_output><empty_output><jupyter_text>Getting Data from joblib filesJoblib is a powerful Python package for management of computation: parallel computing, caching, and primitives for out-of-core computing. It is handy when working on so called big data, that can consume more than the available RAM (several GB nowadays). In such situations, objects in the working space must be persisted to disk, for out-of-core computing, distribution of jobs, or caching.For data management, joblib provides transparent disk persistence that is very efficient with such objects. The internal mechanism relies on specializing pickle to handle better numpy arrays.On this project, we have decided to store our features and our output labels in two distinct joblib files. The main reason in doing this, is for the fact that with this file format we have reduced the loading time of the audio files.<jupyter_code>#PROVA NUOVO DATASET
import joblib
from sklearn.model_selection import train_test_split
import numpy as np
from tensorboardcolab import TensorBoardColab

# Loading saved models
X = joblib.load('X.joblib')
print(len(X))
y = joblib.load('y.joblib')
print(len(y))


#Add new dataset
'''X_Sentelli = joblib.load('X_Sentelli.joblib')
y_Sentelli = joblib.load('y_Sentelli.joblib')

print(len(y_Sentelli))# 4904 + 9237

X_new = np.append(X, X_Sentelli, axis=0)
print(len(X_new))
y_new = np.append (y, y_Sentelli, axis=0)'''

#Train 70 - Test 30 random splitting
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
'''#Expanding dimensions (for possible CNN)
X_train = np.expand_dims(X_train, axis=2)
X_test = np.expand_dims(X_test, axis=2)'''<jupyter_output><empty_output><jupyter_text>Simple Sklearn Random Forest ImplementationOur target is to beat the accuracy of this model with a deep neural network.<jupyter_code>import sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix

def random_forest_classifier(features, target):
    """
    To train the random forest classifier with features and target data
    :param features:
    :param target:
    :return: trained random forest classifier
    """
    clf = RandomForestClassifier()
    clf.fit(features, target)
    return clf<jupyter_output><empty_output><jupyter_text>Train and Test the random forest model:<jupyter_code># Create random forest classifier instance
trained_model = random_forest_classifier(X_train, y_train)
predictions = trained_model.predict(X_test)

print("Train Accuracy :: ", accuracy_score(y_train, trained_model.predict(X_train)))
print("Test Accuracy  :: ", accuracy_score(y_test, predictions))
print(" Confusion matrix \n", confusion_matrix(y_test, predictions))<jupyter_output>/usr/local/lib/python3.6/dist-packages/sklearn/ensemble/forest.py:245: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
  "10 in version 0.20 to 100 in 0.22.", FutureWarning)<jupyter_text>Target Results:*   Train Accuracy :  0.99*   Test Accuracy  :  0.87  Deep Random Forest<jupyter_code>from numpy import genfromtxt
import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.autograd import Variable
import torch.utils.data as Data
import os
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

from torch.nn.parameter import Parameter
import torch.nn.functional as F<jupyter_output><empty_output><jupyter_text>Network Model Definition<jupyter_code>class DeepNeuralDecisionForest(nn.Module):
    def __init__(self, p_keep_conv, p_keep_hidden, n_leaf, n_label, n_tree, n_depth, batch_size):
        super(DeepNeuralDecisionForest, self).__init__()

        #Case CNN as input to Deep Random Forest
        '''self.conv = nn.Sequential()
        self.conv.add_module('conv1', nn.Conv1d(in_channels = 40,out_channels = 64,kernel_size = 1,stride = 1))
        self.conv.add_module('relu1', nn.ReLU())
        self.conv.add_module('pool1', nn.MaxPool1d(kernel_size=5))
        self.conv.add_module('drop1', nn.Dropout(1-p_keep_conv))
        self.conv.add_module('conv2', nn.Conv1d(64, 128, kernel_size=1))
        self.conv.add_module('relu2', nn.ReLU())
        self.conv.add_module('pool2', nn.BatchNorm1d(128))
        self.conv.add_module('drop2', nn.Dropout(1-p_keep_conv))'''
        
        self.fc1 = nn.Sequential(
			   nn.Linear(40, 64),
			   nn.ReLU(),
         nn.BatchNorm1d(64),
         nn.Dropout(1-p_keep_conv))

        self._nleaf = n_leaf
        self._nlabel = n_label
        self._ntree = n_tree
        self._ndepth = n_depth
        self._batchsize = batch_size

        self.treelayers = nn.ModuleList()
        self.pi_e = nn.ParameterList()
        for i in range(self._ntree):
            treelayer = nn.Sequential()
            treelayer.add_module('sub_linear1', nn.Linear(64, 128))
            treelayer.add_module('sub_relu', nn.ReLU())
            treelayer.add_module('sub_drop1', nn.Dropout(1-p_keep_hidden))
            treelayer.add_module('sub_batchNorm', nn.BatchNorm1d(128))
            treelayer.add_module('sub_linear2', nn.Linear(128, self._nleaf))
            treelayer.add_module('sub_sigmoid', nn.Sigmoid())
            
            self.treelayers.append(treelayer)
            self.pi_e.append(Parameter(self.init_prob_weights([self._nleaf, self._nlabel], -2, 2)))

    def init_pi(self):
        return torch.ones(self._nleaf, self._nlabel)/float(self._nlabel)

    def init_weights(self, shape):
        return torch.randn(shape).uniform(-0.01,0.01)

    def init_prob_weights(self, shape, minval=-5, maxval=5):
        return torch.Tensor(shape[0], shape[1]).uniform_(minval, maxval)

    def compute_mu(self, flat_decision_p_e):
        n_batch = self._batchsize
        batch_0_indices = torch.range(0, n_batch * self._nleaf - 1, self._nleaf).unsqueeze(1).repeat(1, self._nleaf).long()

        in_repeat = self._nleaf // 2
        out_repeat = n_batch

        batch_complement_indices = torch.LongTensor(
            np.array([[0] * in_repeat, [n_batch * self._nleaf] * in_repeat] * out_repeat).reshape(n_batch, self._nleaf))

        # First define the routing probabilistics d for root nodes
        mu_e = []
        indices_var = Variable((batch_0_indices + batch_complement_indices).view(-1)) 
        indices_var = indices_var.cuda()
        # iterate over each tree
        for i, flat_decision_p in enumerate(flat_decision_p_e):
            mu = torch.gather(flat_decision_p, 0, indices_var).view(n_batch, self._nleaf)
            mu_e.append(mu)

        # from the scond layer to the last layer, we make the decison nodes
        for d in range(1, self._ndepth + 1):
            indices = torch.range(2 ** d, 2 ** (d + 1) - 1) - 1
            tile_indices = indices.unsqueeze(1).repeat(1, 2 ** (self._ndepth - d + 1)).view(1, -1)
            batch_indices = batch_0_indices + tile_indices.repeat(n_batch, 1).long()

            in_repeat = in_repeat // 2
            out_repeat = out_repeat * 2
            # Again define the indices that picks d and 1-d for the nodes
            batch_complement_indices = torch.LongTensor(
                np.array([[0] * in_repeat, [n_batch * self._nleaf] * in_repeat] * out_repeat).reshape(n_batch, self._nleaf))

            mu_e_update = []
            indices_var = Variable((batch_indices + batch_complement_indices).view(-1))
            indices_var = indices_var.cuda()
            for mu, flat_decision_p in zip(mu_e, flat_decision_p_e):
                mu = torch.mul(mu, torch.gather(flat_decision_p, 0, indices_var).view(
                    n_batch, self._nleaf))
                mu_e_update.append(mu)
            mu_e = mu_e_update
        return mu_e

    def compute_py_x(self, mu_e, leaf_p_e):
        py_x_e = []
        n_batch = self._batchsize

        for i in range(len(mu_e)):
            py_x_tree = mu_e[i].unsqueeze(2).repeat(1, 1, self._nlabel).mul(leaf_p_e[i].unsqueeze(0).repeat(n_batch, 1, 1)).mean(1)
            py_x_e.append(py_x_tree.squeeze().unsqueeze(0))

        py_x_e = torch.cat(py_x_e, 0)
        py_x = py_x_e.mean(0).squeeze()
        
        return py_x

    def forward(self, x):
        x = x.view(-1, 40)#DELETE
        feat = self.fc1.forward(x)#DELETE
        #feat = self.conv.forward(x)
        #print('out 8', feat.shape)
        
        feat = feat.view(-1, 64)
        self._batchsize = x.size(0)

        flat_decision_p_e = []
        leaf_p_e = []
        
        for i in range(len(self.treelayers)):
            decision_p = self.treelayers[i].forward(feat)
            decision_p_comp = 1 - decision_p
            decision_p_pack = torch.cat((decision_p, decision_p_comp))
            flat_decision_p = decision_p_pack.view(-1)
            flat_decision_p_e.append(flat_decision_p)
            leaf_p = F.softmax(self.pi_e[i])
            leaf_p_e.append(leaf_p)
        
        mu_e = self.compute_mu(flat_decision_p_e)
        
        py_x = self.compute_py_x(mu_e, leaf_p_e)
        return torch.log(py_x)
def train(net,data_loader,optimizer,cost_function, device='cuda'):
  samples = 0.
  cumulative_loss = 0.
  cumulative_accuracy = 0.
  
  # Set the network in train mode
  net.train()
  
  # Loop over the dataset
  for batch_idx, (inputs, targets) in enumerate(data_loader):
    # Load data into GPU
    inputs = inputs.to(device)
    
    targets = targets.to(device)
    
    # Forward pass
    outputs = net(inputs)

    # Apply the loss
    loss = cost_function(outputs, targets)
      
    # Backward pass
    loss.backward()
    
    # Update parameters
    optimizer.step()
    
    # Reset the optimizer
    optimizer.zero_grad()

    # Better print something, no?
    samples+=inputs.shape[0]
    cumulative_loss += loss.item()
    _, predicted = outputs.max(1)
    cumulative_accuracy += predicted.eq(targets).sum().item()

  return cumulative_loss/samples, cumulative_accuracy/samples*100


def test(net, data_loader, cost_function, device='cuda'):
  samples = 0.
  cumulative_loss = 0.
  cumulative_accuracy = 0.

  #Set the network in eval mode
  net.eval()
  with torch.no_grad(): # torch.no_grad() disables the autograd machinery, thus not saving the intermediate activations
    # Loop over the dataset
    for batch_idx, (inputs, targets) in enumerate(data_loader):
      # Load data into GPU
      inputs = inputs.to(device)

      targets = targets.to(device)

      # Forward pass
      outputs = net(inputs)

      # Apply the loss
      loss = cost_function(outputs, targets)

      # Better print something
      samples+=inputs.shape[0]
      cumulative_loss += loss.item() # Note: the .item() is needed to extract scalars from tensors
      _, predicted = outputs.max(1)
      cumulative_accuracy += predicted.eq(targets).sum().item()

  return cumulative_loss/samples, cumulative_accuracy/samples*100

def get_cost_function():
  cost_function = torch.nn.CrossEntropyLoss()
  return cost_function

def get_optimizer(net, lr, wd, momentum):
  optimizer = torch.optim.Adam(net.parameters(), lr=lr)#, betas=(0.9, 0.999), eps=1e-08, amsgrad=False)
  return optimizer

def get_data(batch_size, test_batch_size=128): 
  # Load data
  #X_train, X_test, y_train, y_test
  train_data = Data.TensorDataset(
    torch.from_numpy(X_train).float(), 
    torch.from_numpy(y_train).long())

  test_data = Data.TensorDataset(
    torch.from_numpy(X_test).float(), 
    torch.from_numpy(y_test).long())

  # Initialize dataloaders
  train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size, shuffle = True)
  test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch_size, shuffle = False)
  
  return train_loader, test_loader

# Instantiate visualizer
tb = TensorBoardColab(graph_path='./log')
visualization_name='Deep Random Forest'

device='cuda:0'
momentum = 0.95
learning_rate = 0.001 
num_epochs = 1000
weight_decay = 1e-5

DEPTH = 3  # Depth of a tree
N_LEAF = 2 ** (DEPTH + 1)  # Number of leaf node
N_LABEL = 8  # Number of classes
N_TREE = 3  # Number of trees
batch_size = 128

# Dropout Network hyperparameters
p_conv_keep = 0.9
p_full_keep = 0.6

    
#DataLoader creation
train_loader, test_loader = get_data(batch_size)

#Network initialization
net = DeepNeuralDecisionForest(p_keep_conv = p_conv_keep, p_keep_hidden = p_full_keep, n_leaf= N_LEAF, n_label= N_LABEL, n_tree= N_TREE, n_depth= DEPTH, batch_size=batch_size)
net.to(device)

optimizer = get_optimizer(net, learning_rate, weight_decay, momentum)
cost_function = get_cost_function()

train_accuracy_list = list()
test_accuracy_list = list()

train_loss_list = list()
test_loss_list = list()

print('Before training:')
train_loss, train_accuracy = test(net, train_loader, cost_function)
test_loss, test_accuracy = test(net, test_loader, cost_function)
train_accuracy_list.append(train_accuracy)
test_accuracy_list.append(test_accuracy)
train_loss_list.append(train_loss)
test_loss_list.append(test_loss)


print('\t Training loss {:.5f}, Training accuracy {:.2f}'.format(train_loss, train_accuracy))
print('\t Test loss {:.5f}, Test accuracy {:.2f}'.format(test_loss, test_accuracy))
print('-----------------------------------------------------')


# Add values to plots
tb.save_value('Loss/train_loss', visualization_name, 0, train_loss)
tb.save_value('Loss/test_loss', visualization_name, 0, test_loss)
tb.save_value('Accuracy/train_accuracy', visualization_name, 0, train_accuracy)
tb.save_value('Accuracy/test_accuracy', visualization_name, 0, test_accuracy)

# Update plots 
tb.flush_line(visualization_name)

for e in range(num_epochs):
  train_loss, train_accuracy = train(net, train_loader, optimizer, cost_function)
  val_loss, val_accuracy = test(net, test_loader, cost_function)
  print('Epoch: {:d}'.format(e+1))
  print('\t Training loss {:.5f}, Training accuracy {:.2f}'.format(train_loss, train_accuracy))
  print('\t Test loss {:.5f}, Test accuracy {:.2f}'.format(val_loss, val_accuracy))
  print('-----------------------------------------------------')
  
  train_accuracy_list.append(train_accuracy)
  test_accuracy_list.append(val_accuracy)
  train_loss_list.append(train_loss)
  test_loss_list.append(val_loss)
  
  # Add values to plots
  tb.save_value('Loss/train_loss', visualization_name, e + 1, train_loss)
  tb.save_value('Loss/test_loss', visualization_name, e + 1, val_loss)
  tb.save_value('Accuracy/train_accuracy', visualization_name, e + 1, train_accuracy)
  tb.save_value('Accuracy/test_accuracy', visualization_name, e + 1, val_accuracy)
  # Update plots 
  tb.flush_line(visualization_name)
  
print('After training:')
train_loss, train_accuracy = test(net, train_loader, cost_function)
test_loss, test_accuracy = test(net, test_loader, cost_function)

print('\t Training loss {:.5f}, Training accuracy {:.2f}'.format(train_loss, train_accuracy))
print('\t Test loss {:.5f}, Test accuracy {:.2f}'.format(test_loss, test_accuracy))
print('-----------------------------------------------------')<jupyter_output>Wait for 8 seconds...
TensorBoard link:
https://d1356e1d.ngrok.io
Before training:<jupyter_text>Accuracy plot<jupyter_code>import matplotlib.pyplot as plt
x = range(0,num_epochs +1)

fig, ax = plt.subplots()

plt.plot(x, train_accuracy_list, label='Train Accuracy')
plt.plot(x, test_accuracy_list, label='Test Accuracy')

plt.xlabel('N epochs')
plt.ylabel('Accuracy [%]')
plt.title("Accuracy Plot")
plt.legend()
plt.show()

#plt.savefig('accuracy.png', format='png', dpi=1000)

# Do the plot code
fig.savefig('accuracy.png', format='png', dpi=1000)<jupyter_output><empty_output><jupyter_text>Loss Plot<jupyter_code>fig, ax = plt.subplots()
plt.plot(x, train_loss_list, label='Train Loss')
plt.plot(x, test_loss_list, label='Test Loss')

plt.xlabel('N epochs')
plt.ylabel('Loss')
plt.title("Loss Plot")
plt.legend()
plt.show()

fig.savefig('loss.png', format='png', dpi=1000)<jupyter_output><empty_output><jupyter_text>Confusion Matrix<jupyter_code>'''test_loader_copy = test_loader
#val_loader_copy = val_loader
train_loader_copy = train_loader'''
net_copy = net
samples = 0.
cumulative_loss = 0.
cumulative_accuracy = 0.

net_copy.eval() # Strictly needed if network contains layers which has different behaviours between train and tes
predicted_label = list()
real_label = list()
#imgPath = list()
with torch.no_grad():
    for batch_idx, (inputs, targets) in enumerate(test_loader):
        # Load data into GPU
        inputs = inputs.to(device)
        targets = targets.to(device)

        # Forward pass
        outputs = net_copy(inputs)

        # Apply the loss
        loss = cost_function(outputs, targets)

        # Better print something
        samples+=inputs.shape[0]
        cumulative_loss += loss.item() # Note: the .item() is needed to extract scalars from tensors
        _, predicted = outputs.max(1)
        predicted_label.extend(predicted.tolist())
        real_label.extend(targets.tolist())
        cumulative_accuracy += predicted.eq(targets).sum().item()
        
print("Final Accuracy: ", cumulative_accuracy/samples*100, "%")

#print(__doc__)
from sklearn.utils.multiclass import unique_labels
from sklearn.metrics import confusion_matrix


#Classes to be predicted
class_names = ['neutral','calm','happy', 'sad','angry','fearful','disgust','surprised']

def plot_confusion_matrix(y_true, y_pred, classes,
                          normalize=False,
                          title=None,
                          cmap=plt.cm.Blues):
    """
    This function prints and plots the confusion matrix.
    Normalization can be applied by setting `normalize=True`.
    """
    if not title:
        if normalize:
            title = 'Normalized confusion matrix'
        else:
            title = 'Confusion matrix, without normalization'

    # Compute confusion matrix
    cm = confusion_matrix(y_true, y_pred)
    # Only use the labels that appear in the data

    fig, ax = plt.subplots()
    im = ax.imshow(cm, interpolation='nearest', cmap=cmap)
    ax.figure.colorbar(im, ax=ax)
    # We want to show all ticks...
    ax.set(xticks=np.arange(cm.shape[1]),
           yticks=np.arange(cm.shape[0]),
           # ... and label them with the respective list entries
           xticklabels=classes, yticklabels=classes,
           title=title,
           ylabel='True label',
           xlabel='Predicted label')

    # Rotate the tick labels and set their alignment.
    plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
             rotation_mode="anchor")

    # Loop over data dimensions and create text annotations.
    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            ax.text(j, i, format(cm[i, j], fmt),
                    ha="center", va="center",
                    color="white" if cm[i, j] > thresh else "black")
    fig.tight_layout()
    return ax


np.set_printoptions(precision=2)

print("Test items: ", len(predicted_label))

# Plot confusion matrix
plot_confusion_matrix(real_label,predicted_label, classes=class_names,
                      title='Confusion matrix, without normalization')
plt.show()<jupyter_output>Test items:  1619
{'fraction_non_alphanumeric': 0.1143914578636151, 'fraction_numerical': 0.014506317267197005, 'mean_word_length': 3.6430969780762394, 'pattern_counts': {'":': 0, '<': 42, '<?xml version=': 0, '>': 43, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '616708', 'license': 'MIT', 'n_tokens_mistral': 8057, 'n_tokens_neox': 7627, 'n_words': 1938, 'path': 'DEEP_RANDOM_FOREST.ipynb', 'repo_name': 'filippotessaro/deep-neural-decision-forest', 'size': '23507'}