<jupyter_start><jupyter_text>Classifying Names with character level RNN<jupyter_code>import numpy as np
import pandas as pd

import torch
import torch.nn as nn

import matplotlib.pyplot as plt

import os
import glob<jupyter_output><empty_output><jupyter_text>Building the input data<jupyter_code>ROOT_DIR = '../../Data/names_data/names/*.txt'
def find_files(path): return glob.glob(path)
import unicodedata
import string

all_ascii_letters = string.ascii_letters+" .,;'"
n_letters = len(all_ascii_letters)

print(f'All ASCII letters : {all_ascii_letters}')
print(f'Total number of letters : {n_letters}')
def convert_unicode2ascii(s):
    '''
        Converts a unicode character to ASCII format
    '''
    all_character = []
    for c in unicodedata.normalize('NFD',s):
        if unicodedata.category(c) != 'Mn' and c in all_ascii_letters:
            all_character.append(c)
            
    return ''.join(all_character)
        
convert_unicode2ascii('Ślusàrski')
## Building the dictionary with categories and names as list

category_lines = {}
category_labels = []


for files in find_files(ROOT_DIR):
    print(f'Reading Files : {files}')
    
    category = os.path.basename(files).split('.')[0]
    
    with open(files, mode='r', encoding='UTF-8') as f:
        content = f.read().strip().split('\n')
        ascii_content = [ convert_unicode2ascii(lines) for lines in content ]
        
    category_labels.append(category)
    category_lines[category] = ascii_content
## sample content

print(category_lines['Arabic'][:5])
print(category_lines['Dutch'][-5:])
n_categories = len(category_labels)

n_categories<jupyter_output><empty_output><jupyter_text>Converting to Tensor<jupyter_code>def letter_to_index(letter):
    '''
        Finds the index of the letter from the ascii vocab
    '''
    return all_ascii_letters.find(letter)
letter_to_index('A')
def letter_to_tensor(letter):
    tensor = torch.zeros(1, n_letters) ## a 1xn_letters tensor of zeros
    tensor[0][letter_to_index(letter)] = 1
    return tensor

letter_to_tensor('A')
def line_to_tensor(line):
    '''
        Converts a line into <line_length x 1 x n_letters> tensor
    '''
    
    tensor = torch.zeros(len(line), 1, n_letters)
    for li, letters in enumerate(line):
        tensor[li][0][letter_to_index(letters)] = 1
        
    return tensor
line_to_tensor('Rishu')
line_to_tensor('Rama').size()<jupyter_output><empty_output><jupyter_text>Model definition ![character_level]('/Users/rishushrivastava/Document/GitHub/MLPy/screenshots/charater_level_rnn.png')<jupyter_code>class RNNModel(nn.Module):
    
    def __init__(self, input_size=57, hidden_size=128, output_size=18):
        super().__init__()
        
        self.hidden_size = hidden_size
        self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
        self.i2o = nn.Linear(input_size + hidden_size, output_size)
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden):
        combined = torch.cat((input, hidden), 1)
        hidden = self.i2h(combined)
        output = self.i2o(combined)
        output = self.softmax(output)
        
        return output, hidden
    
    def initHidden(self):
        return torch.zeros(1, self.hidden_size)
    
n_hidden = 128

rnn = RNNModel(n_letters, n_hidden, n_categories)

rnn
## running the model once

input = line_to_tensor('Rishu')
hidden = torch.zeros(1, n_hidden)

output, next_hidden = rnn(input[0], hidden)
print(output)
def get_category_from_output(output):
    '''
        Returns the category from the output that the model generates
    '''
    value, indices = output.topk(1)
    category_index = indices[0]
    
    return category_labels[category_index], category_index
get_category_from_output(output)<jupyter_output><empty_output><jupyter_text>Training<jupyter_code>import random
def random_choice(r):
    return r[random.randint(0, len(r)-1)]
def random_training_sample():
    category = random_choice(category_labels)
    line = random_choice(category_lines[category])
    category_tensor = torch.tensor([category_labels.index(category)], dtype=torch.long)
    line_tensor = line_to_tensor(line)
    return category, line, category_tensor, line_tensor
for i in range(10):
    category, line, category_tensor, line_tensor = random_training_sample()
    print('category =', category, '/ line =', line)
## loss function
criterions = nn.NLLLoss()
learning_rate = 0.005

def train(category_tensor, line_tensor):
    hidden = rnn.initHidden()
    
    rnn.zero_grad()
    
    for i in range(line_tensor.size()[0]):
        output, hidden = rnn(line_tensor[i], hidden)
        
    loss = criterions(output, category_tensor)
    loss.backward()
    
    for p in rnn.parameters():
        p.data.add_(p.grad.data, alpha = -learning_rate)
        
    return output, loss.item()
import time
import math

n_iters = 100000
print_every = 5000
plot_every = 1000

current_loss = 0
all_losses = []

def timeSince(since):
    now = time.time()
    s = now - since
    m = math.floor(s / 60)
    s -= m * 60
    return '%dm %ds' % (m, s)

start = time.time()

for iter in range(1, n_iters + 1):
    category, line, category_tensor, line_tensor = random_training_sample()
    output, loss = train(category_tensor, line_tensor)
    
    current_loss += loss
    
    if iter % print_every == 0:
        guess, guess_i = get_category_from_output(output)
        correct = '✓' if guess == category else '✗ (%s)' % category
        print('%d %d%% (%s) %.4f %s / %s %s' % (iter, iter / n_iters * 100, timeSince(start), loss, line, guess, correct))
    
    if iter % plot_every == 0:
        all_losses.append(current_loss / plot_every)
        current_loss = 0
plt.plot(all_losses)
plt.title('Loss Plot')
plt.show()
torch.save(rnn.state_dict(),'classifying_names_clevel_rnn.pt')
# Just return an output given a line
def evaluate(line_tensor):
    hidden = rnn.initHidden()
    for i in range(line_tensor.size()[0]):
        output, hidden = rnn(line_tensor[i], hidden)

    return output

def predict(input_line, n_predictions=3):
    print('\n> %s' % input_line)
    with torch.no_grad():
        output = evaluate(line_to_tensor(input_line))

        # Get top N categories
        topv, topi = output.topk(n_predictions, 1, True)
        predictions = []

        for i in range(n_predictions):
            value = topv[0][i].item()
            category_index = topi[0][i].item()
            print('(%.2f) %s' % (value, category_labels[category_index]))
            predictions.append([value, category_labels[category_index]])

predict('Rishu')
predict('Rama')
predict('Peter')
predict('Anna')<jupyter_output>> Rishu
(-1.78) Scottish
(-1.84) Japanese
(-2.34) Korean

> Rama
(-1.02) Spanish
(-2.15) Portuguese
(-2.40) Italian

> Peter
(-0.98) German
(-1.79) Czech
(-1.95) Dutch

> Anna
(-1.17) Italian
(-1.30) Spanish
(-2.59) Czech
{'fraction_non_alphanumeric': 0.124745269286754, 'fraction_numerical': 0.016739446870451237, 'mean_word_length': 3.6331759946055295, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '416821', 'license': 'Apache-2.0', 'n_tokens_mistral': 2415, 'n_tokens_neox': 2305, 'n_words': 515, 'path': 'torch/14. Classifying Names with Character-Level RNN.ipynb', 'repo_name': 'rishuatgithub/MLPy', 'size': '6870'}