|
|
|
|
|
import gradio as gr |
|
|
|
import os |
|
from pathlib import Path |
|
|
|
|
|
import torch |
|
import torch.nn as nn |
|
|
|
import pandas as pd |
|
from nlpia2.init import SRC_DATA_DIR, maybe_download |
|
|
|
from nlpia2.string_normalizers import Asciifier, ASCII_NAME_CHARS |
|
|
|
name_char_vocab_size = len(ASCII_NAME_CHARS) + 1 |
|
|
|
|
|
asciify = Asciifier(include=ASCII_NAME_CHARS) |
|
|
|
|
|
def find_files(path, pattern): |
|
return Path(path).glob(pattern) |
|
|
|
|
|
|
|
char2i = {c: i for i, c in enumerate(ASCII_NAME_CHARS)} |
|
|
|
|
|
|
|
print(f'asciify("O’Néàl") => {asciify("O’Néàl")}') |
|
|
|
|
|
category_lines = {} |
|
all_categories = [] |
|
labeled_lines = [] |
|
categories = [] |
|
for filepath in find_files(SRC_DATA_DIR / 'names', '*.txt'): |
|
filename = Path(filepath).name |
|
filepath = maybe_download(filename=Path('names') / filename) |
|
with filepath.open() as fin: |
|
lines = [asciify(line.rstrip()) for line in fin] |
|
category = Path(filename).with_suffix('') |
|
categories.append(category) |
|
labeled_lines += list(zip(lines, [category] * len(lines))) |
|
|
|
n_categories = len(categories) |
|
|
|
df = pd.DataFrame(labeled_lines, columns=('name', 'category')) |
|
|
|
|
|
def readLines(filename): |
|
lines = open(filename, encoding='utf-8').read().strip().split('\n') |
|
return [asciify(line) for line in lines] |
|
|
|
|
|
for filename in find_files(path='data/names', pattern='*.txt'): |
|
category = os.path.splitext(os.path.basename(filename))[0] |
|
all_categories.append(category) |
|
lines = readLines(filename) |
|
category_lines[category] = lines |
|
|
|
n_categories = len(all_categories) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print(category_lines['Italian'][:5]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def letterToIndex(c): |
|
return char2i[c] |
|
|
|
|
|
|
|
|
|
def encode_one_hot_vec(letter): |
|
tensor = torch.zeros(1, len(ASCII_NAME_CHARS)) |
|
tensor[0][letterToIndex(letter)] = 1 |
|
return tensor |
|
|
|
|
|
|
|
|
|
|
|
def encode_one_hot_seq(line): |
|
tensor = torch.zeros(len(line), 1, len(ASCII_NAME_CHARS)) |
|
for li, letter in enumerate(line): |
|
tensor[li][0][letterToIndex(letter)] = 1 |
|
return tensor |
|
|
|
|
|
print(encode_one_hot_vec('A')) |
|
|
|
print(encode_one_hot_seq('Abe').size()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RNN(nn.Module): |
|
def __init__(self, input_size, hidden_size, output_size): |
|
super(RNN, self).__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, char_tens, hidden): |
|
combined = torch.cat((char_tens, 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 = RNN(len(ASCII_NAME_CHARS), n_hidden, n_categories) |
|
|
|
|
|
input = encode_one_hot_vec('A') |
|
hidden = torch.zeros(1, n_hidden) |
|
|
|
output, next_hidden = rnn(input, hidden) |
|
|
|
|
|
def categoryFromOutput(output): |
|
top_n, top_i = output.topk(1) |
|
category_i = top_i[0].item() |
|
return all_categories[category_i], category_i |
|
|
|
|
|
def output_from_str(s): |
|
global rnn |
|
|
|
input = encode_one_hot_seq(s) |
|
hidden = torch.zeros(1, n_hidden) |
|
|
|
output, next_hidden = rnn(input[0], hidden) |
|
print(output) |
|
|
|
return categoryFromOutput(output) |
|
|
|
|
|
|
|
|
|
|
|
|
|
state_dict = torch.load('rnn_from_scratch_name_nationality.state_dict.pickle') |
|
rnn.load_state_dict(state_dict) |
|
|
|
|
|
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(encode_one_hot_seq(input_line)) |
|
|
|
|
|
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, all_categories[category_index])) |
|
predictions.append([value, all_categories[category_index]]) |
|
|
|
|
|
predict('Dovesky') |
|
predict('Jackson') |
|
predict('Satoshi') |
|
|
|
|
|
|
|
|
|
|
|
def greet_nationality(name): |
|
nationality = predict(name) |
|
return f"Hello {name}!!\n Your name seems to be from {nationality}. Am I right?" |
|
|
|
|
|
iface = gr.Interface(fn=greet_nationality, inputs="text", outputs="text") |
|
iface.launch() |
|
|