text: from argparse import Namespace
  from collections import Counter
  import json
  import os
  import re
  import string
  from vocabulary import Vocabulary
  import numpy as np
  import pandas as pd
  import torch
  import torch.nn as nn
  import torch.nn.functional as F
  import torch.optim as optim
  from torch.utils.data import Dataset, DataLoader
  from tqdm import tqdm_notebook
  
  def make_train_state(args):
      return {'stop_early': False,
              'early_stopping_step': 0,
              'early_stopping_best_val': 1e8,
              'learning_rate': args.learning_rate,
              'epoch_index': 0,
              'train_loss': [],
              'train_acc': [],
              'val_loss': [],
              'val_acc': [],
              'test_loss': -1,
              'test_acc': -1,
              'model_filename': args.model_state_file}
  
  def update_train_state(args, model, train_state):
      """Handle the training state updates.
  
      Components:
       - Early Stopping: Prevent overfitting.
       - Model Checkpoint: Model is saved if the model is better
  
      :param args: main arguments
      :param model: model to train
      :param train_state: a dictionary representing the training state values
      :returns:
          a new train_state
      """
  
      # Save one model at least
      if train_state['epoch_index'] == 0:
          torch.save(model.state_dict(), train_state['model_filename'])
          train_state['stop_early'] = False
  
      # Save model if performance improved
      elif train_state['epoch_index'] >= 1:
          loss_tm1, loss_t = train_state['val_loss'][-2:]
  
          # If loss worsened
          if loss_t >= train_state['early_stopping_best_val']:
              # Update step
              train_state['early_stopping_step'] += 1
          # Loss decreased
          else:
              # Save the best model
              if loss_t < train_state['early_stopping_best_val']:
                  torch.save(model.state_dict(), train_state['model_filename'])
  
              # Reset early stopping step
              train_state['early_stopping_step'] = 0
  
          # Stop early ?
          train_state['stop_early'] = \
              train_state['early_stopping_step'] >= args.early_stopping_criteria
  
      return train_state
  
  def compute_accuracy(y_pred, y_target):
      y_target = y_target.cpu()
      y_pred_indices = (torch.sigmoid(y_pred)>0.5).cpu().long()#.max(dim=1)[1]
      n_correct = torch.eq(y_pred_indices, y_target).sum().item()
      return n_correct / len(y_pred_indices) * 100
  
  def set_seed_everywhere(seed, cuda):
      np.random.seed(seed)
      torch.manual_seed(seed)
      if cuda:
          torch.cuda.manual_seed_all(seed)
  
  def handle_dirs(dirpath):
      if not os.path.exists(dirpath):
          os.makedirs(dirpath)
  
  