<jupyter_start><jupyter_text>H-Transformer for Item Recommendation in MOBA Games<NAME>  Dependencies<jupyter_code>!pip install python-box
!wget https://gist.githubusercontent.com/vgaraujov/47ef44430fdbcc95dcb6c87233c3ef92/raw/97c4608ee2b62c77929784e0d07e05ff27b56ee4/drive_download.py
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials
# Authenticate and create the PyDrive client.
# This only needs to be done once per notebook.
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
import drive_download

idx = '19oln5xzNGI50KwO7kIP3HADQOeIXMW-R'
drive_download.drive_download(drive, idx)
!mv drive_download/* .
import time
import os
import logging
import yaml
from timeit import default_timer as timer

## Libraries
import numpy as np
from box import box_from_file
from pathlib import Path

## Torch
import torch
import torch.nn as nn
from torch.utils import data
import torch.optim as optim

## Custom Imports
from logger import setup_logs
from seed import set_seed
from train import train, snapshot
from validation import validation
from dataset import DotaDataset, DataCollatorForDota
from model_aux import HTransformer
import losses<jupyter_output><empty_output><jupyter_text>Training Model<jupyter_code>############ Control Center and Hyperparameter ###############
config = box_from_file(Path('config.yaml'), file_type='yaml')
config.training.logging_dir = '.'
config.dataset.train_data_path = '/content/training_all.pkl'
config.dataset.test_data_path = '/content/testing_all.pkl'
config.dataset.item_path = '/content/item_ids.csv'
config.dataset.champ_path = '/content/hero_names.csv'
run_name = config.model.model_type + time.strftime("-%Y-%m-%d_%H_%M_%S")
# setup logger    
global_timer = timer() # global timer
logger = setup_logs(config.training.logging_dir, run_name) # setup logs
logger.info('### Experiment {} ###'.format(run_name))
logger.info('### Hyperparameter summary below ###\n {}'.format(config))
    
# define if gpu or cpu
use_cuda = not config.training.no_cuda and torch.cuda.is_available()
device = torch.device("cuda" if use_cuda else "cpu")
logger.info('===> use_cuda is {}'.format(use_cuda))
# set seed for reproducibility
set_seed(config.training.seed, use_cuda)
## Loading the dataset
logger.info('===> loading train and validation dataset')
train_dataset = DotaDataset(config, 'train')
validation_dataset = DotaDataset(config, 'test')

data_collator = DataCollatorForDota(max_length = config.dataset.max_seq_length)

multiplier = torch.cuda.device_count() if not config.training.no_cuda else 1
batch_size = int(config.training.batch_size*multiplier)
train_loader = data.DataLoader(train_dataset,
                               batch_size=batch_size,
                               collate_fn=data_collator,
                               drop_last=True
                              )
validation_loader = data.DataLoader(validation_dataset, 
                                    batch_size=batch_size, # batch 1 for evaluate variable length
                                    collate_fn=data_collator,
                                    drop_last=True
                                   )

config.dataset.n_items = len(train_dataset.id2item)
config.dataset.n_champs = len(train_dataset.id2champ)
model = HTransformer(config=config)
# move to device
model.to(device)

# Adam optimizer
optimizer = optim.Adam(
        filter(lambda p: p.requires_grad, model.parameters()), 
        lr=2e-4, betas=(0.9, 0.98), eps=1e-09, weight_decay=1e-4, amsgrad=True)
if config.training.resume_name:
    optimizer.load_state_dict(checkpoint['optimizer'])

# create loss function
loss_fn = losses.LossFunction(loss_type=config.model.loss_fn)
    
model_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
logger.info('### Model summary below ###\n {}'.format(str(model)))
logger.info('===> Model total parameter: {}\n'.format(model_params))
best_acc = 0
best_loss = np.inf
best_epoch = -1 
step = 0
initial_epoch = 1
    
logger.info('### Training begins at epoch {} and step {} ###'.format(initial_epoch,step))
for epoch in range(initial_epoch, config.training.epochs + 1):
    epoch_timer = timer()
    # Train and validate
    tr_acc, tr_loss, step = train(
        step, 
        model, 
        train_loader, 
        loss_fn, 
        device, 
        optimizer, 
        epoch, 
        config.training.log_interval)
    
    if not epoch % 10:    
        val_acc, val_loss = validation(
            step, 
            model, 
            validation_loader, 
            loss_fn, 
            device)
        # Save
        if val_loss < best_loss: 
            best_loss = min(val_loss, best_loss)
            if torch.cuda.device_count() > 1 and not config.training.no_cuda:
                dict_to_save = model.module.state_dict()
            else:
                dict_to_save = model.state_dict()
            snapshot(config.training.logging_dir, run_name, {
                'epoch': epoch,
                'step_train': step,
                'validation_acc': val_acc,
                'validation_loss': val_loss,
                'state_dict': dict_to_save,
                'optimizer': optimizer.state_dict(),
            })
            best_epoch = epoch

    end_epoch_timer = timer()
    logger.info("#### End epoch {}/{}, elapsed time: {}".format(epoch, config.training.epochs, end_epoch_timer - epoch_timer))
    
## end 
end_global_timer = timer()
logger.info("################## Success #########################")
logger.info("Total elapsed time: %s" % (end_global_timer - global_timer))<jupyter_output><empty_output><jupyter_text>Visualization<jupyter_code>import numpy as np; np.random.seed(0)
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

def open_champs_info(champs_path):
    champs_df = pd.read_csv(champs_path)
    champs_df.drop([106, 111], inplace = True)
    champs_df.drop(['name'], axis = 1, inplace = True)
    champs_df.reset_index(drop=True, inplace=True)
    names = champs_df['localized_name'].tolist()
    dictionary = {names[i] : v for i, v in enumerate(champs_df['hero_id'].tolist())}
    dictionary[0] = 0
    reversed_dictionary = {value : key for (key, value) in dictionary.items()}
    return dictionary, reversed_dictionary

_, mapping = open_champs_info(config.dataset.champ_path)
run_name = 'HTransformerV3-2021-10-30_04_30_23'
logger.info('===> loading a checkpoint')
checkpoint = torch.load('{}/{}-{}'.format(config.training.logging_dir, run_name, 'model_best.pth'))
model.load_state_dict(checkpoint['state_dict'])
validation_loader = data.DataLoader(validation_dataset, 
                                    batch_size=1, # batch 1 for evaluate variable length
                                    collate_fn=data_collator,
                                    drop_last=True,
                                    shuffle=True
                                   )
champs, items, target, attn_mask = next(iter(validation_loader))
output, attn_1, attn_2 = model(champs.cuda(), items.cuda())
data_1=attn_1.detach().cpu().numpy()
data_2=attn_2.squeeze(0).detach().cpu().numpy()
heros = champs.detach().cpu().squeeze(0).tolist()
name_heros = []
for i in heros:
    name_heros.append(mapping[int(i)])
fig,axn = plt.subplots(5, 1, sharex=True, sharey=True, figsize=(10,6))

aux = 2
for i, ax in enumerate(axn.flat):
    df = pd.DataFrame(data_1[i+aux], index=name_heros, columns=name_heros)
    df.drop(labels=name_heros[1:], axis=0, inplace=True)
#     ax.set_title("Step "+str(i+aux))
    sns.heatmap(df, ax=ax, cmap="Blues", cbar=True)
plt.xlabel("Heros")
plt.figure(figsize=(8, 6))
ax = sns.heatmap(data_2, cmap="Blues")
plt.xlabel("Sequence Step")
plt.ylabel("Sequence Step")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12117379205666583, 'fraction_numerical': 0.015684290412345054, 'mean_word_length': 3.414852037967616, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 19, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '508014', 'license': 'MIT', 'n_tokens_mistral': 2631, 'n_tokens_neox': 2530, 'n_words': 534, 'path': 'practicos/HT4Rec.ipynb', 'repo_name': 'PUC-RecSys-Class/RecSysPUC-2021', 'size': '7915'}