dl_seq2seq/fin-to-en-seq2seq-v3.ipynb

1301 lines
119 KiB
Plaintext

{
"metadata": {
"kernelspec": {
"language": "python",
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.10.13",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
},
"kaggle": {
"accelerator": "nvidiaTeslaT4",
"dataSources": [
{
"sourceId": 8513800,
"sourceType": "datasetVersion",
"datasetId": 5082663
}
],
"dockerImageVersionId": 30699,
"isInternetEnabled": true,
"language": "python",
"sourceType": "notebook",
"isGpuEnabled": true
}
},
"nbformat_minor": 4,
"nbformat": 4,
"cells": [
{
"cell_type": "markdown",
"source": [
"# Seq2Seq Fiński --> Angielski\n",
"https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"from __future__ import unicode_literals, print_function, division\n",
"from io import open\n",
"import unicodedata\n",
"import re\n",
"import random\n",
"\n",
"import torch\n",
"import torch.nn as nn\n",
"from torch import optim\n",
"import torch.nn.functional as F\n",
"\n",
"import numpy as np\n",
"from torch.utils.data import TensorDataset, DataLoader, RandomSampler\n",
"\n",
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")"
],
"metadata": {
"_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5",
"_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
"execution": {
"iopub.status.busy": "2024-05-25T14:03:55.886451Z",
"iopub.execute_input": "2024-05-25T14:03:55.887266Z",
"iopub.status.idle": "2024-05-25T14:04:02.514594Z",
"shell.execute_reply.started": "2024-05-25T14:03:55.887232Z",
"shell.execute_reply": "2024-05-25T14:04:02.513697Z"
},
"trusted": true
},
"execution_count": 1,
"outputs": []
},
{
"cell_type": "code",
"source": [
"torch.cuda.device_count()"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:04:09.403445Z",
"iopub.execute_input": "2024-05-25T14:04:09.403926Z",
"iopub.status.idle": "2024-05-25T14:04:09.434533Z",
"shell.execute_reply.started": "2024-05-25T14:04:09.403898Z",
"shell.execute_reply": "2024-05-25T14:04:09.433678Z"
},
"trusted": true
},
"execution_count": 2,
"outputs": [
{
"execution_count": 2,
"output_type": "execute_result",
"data": {
"text/plain": "2"
},
"metadata": {}
}
]
},
{
"cell_type": "markdown",
"source": [
"### Konwersja słów na index"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"SOS_token = 0\n",
"EOS_token = 1\n",
"\n",
"class Lang:\n",
" def __init__(self, name):\n",
" self.name = name\n",
" self.word2index = {}\n",
" self.word2count = {}\n",
" self.index2word = {0: \"SOS\", 1: \"EOS\"}\n",
" self.n_words = 2 # Count SOS and EOS\n",
"\n",
" def addSentence(self, sentence):\n",
" for word in sentence.split(' '):\n",
" self.addWord(word)\n",
"\n",
" def addWord(self, word):\n",
" if word not in self.word2index:\n",
" self.word2index[word] = self.n_words\n",
" self.word2count[word] = 1\n",
" self.index2word[self.n_words] = word\n",
" self.n_words += 1\n",
" else:\n",
" self.word2count[word] += 1"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:04:14.014114Z",
"iopub.execute_input": "2024-05-25T14:04:14.014490Z",
"iopub.status.idle": "2024-05-25T14:04:14.024526Z",
"shell.execute_reply.started": "2024-05-25T14:04:14.014461Z",
"shell.execute_reply": "2024-05-25T14:04:14.023673Z"
},
"trusted": true
},
"execution_count": 3,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Normalizacja tekstu"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"# Turn a Unicode string to plain ASCII, thanks to\n",
"# https://stackoverflow.com/a/518232/2809427\n",
"def unicodeToAscii(s):\n",
" return ''.join(\n",
" c for c in unicodedata.normalize('NFD', s)\n",
" if unicodedata.category(c) != 'Mn'\n",
" )\n",
"\n",
"# Lowercase, trim, and remove non-letter characters\n",
"def normalizeString(s):\n",
" s = unicodeToAscii(s.lower().strip())\n",
" s = re.sub(r\"([.!?])\", r\" \\1\", s)\n",
" s = re.sub(r\"[^a-zA-Z!?]+\", r\" \", s)\n",
" return s.strip()"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:04:23.431898Z",
"iopub.execute_input": "2024-05-25T14:04:23.432285Z",
"iopub.status.idle": "2024-05-25T14:04:23.438688Z",
"shell.execute_reply.started": "2024-05-25T14:04:23.432256Z",
"shell.execute_reply": "2024-05-25T14:04:23.437569Z"
},
"trusted": true
},
"execution_count": 4,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Wczytywanie danych (zmodyfikowane ze względu na ścieżkę w kaggle)"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"# Zmodyfikowana wersja ze względu na użycie pojedynczego pliku przesłanego na Kaggle\n",
"def readLangs(reverse=False):\n",
" print(\"Reading lines...\")\n",
" lang1=\"en\"\n",
" lang2=\"fin\"\n",
" # Read the file and split into lines\n",
" lines = open('/kaggle/input/anki-en-fin/fin.txt', encoding='utf-8').\\\n",
" read().strip().split('\\n')\n",
"\n",
" # Split every line into pairs and normalize\n",
" pairs = [[normalizeString(s) for s in l.split('\\t')[:-1]] for l in lines] # +Usuwanie licencji CC z linii\n",
"\n",
" # Reverse pairs, make Lang instances\n",
" if reverse:\n",
" pairs = [list(reversed(p)) for p in pairs]\n",
" input_lang = Lang(lang2)\n",
" output_lang = Lang(lang1)\n",
" else:\n",
" input_lang = Lang(lang1)\n",
" output_lang = Lang(lang2)\n",
"\n",
" return input_lang, output_lang, pairs"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:12:25.385674Z",
"iopub.execute_input": "2024-05-25T14:12:25.386029Z",
"iopub.status.idle": "2024-05-25T14:12:25.394103Z",
"shell.execute_reply.started": "2024-05-25T14:12:25.386002Z",
"shell.execute_reply": "2024-05-25T14:12:25.392925Z"
},
"trusted": true
},
"execution_count": 14,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"#### Ograniczenie do zdań max 10 słów, formy I am / You are / He is etc. bez interpunkcji"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"MAX_LENGTH = 10\n",
"\n",
"eng_prefixes = (\n",
" \"i am \", \"i m \",\n",
" \"he is\", \"he s \",\n",
" \"she is\", \"she s \",\n",
" \"you are\", \"you re \",\n",
" \"we are\", \"we re \",\n",
" \"they are\", \"they re \"\n",
")\n",
"\n",
"def filterPair(p):\n",
" return len(p[0].split(' ')) < MAX_LENGTH and \\\n",
" len(p[1].split(' ')) < MAX_LENGTH and \\\n",
" p[1].startswith(eng_prefixes)\n",
"\n",
"\n",
"def filterPairs(pairs):\n",
" return [pair for pair in pairs if filterPair(pair)]"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:12:29.729786Z",
"iopub.execute_input": "2024-05-25T14:12:29.730147Z",
"iopub.status.idle": "2024-05-25T14:12:29.737013Z",
"shell.execute_reply.started": "2024-05-25T14:12:29.730121Z",
"shell.execute_reply": "2024-05-25T14:12:29.735886Z"
},
"trusted": true
},
"execution_count": 15,
"outputs": []
},
{
"cell_type": "code",
"source": [
"def prepareData(reverse=False):\n",
" input_lang, output_lang, pairs = readLangs(reverse)\n",
" print(\"Read %s sentence pairs\" % len(pairs))\n",
" pairs = filterPairs(pairs)\n",
" print(\"Trimmed to %s sentence pairs\" % len(pairs))\n",
" print(\"Counting words...\")\n",
" for pair in pairs:\n",
" input_lang.addSentence(pair[0])\n",
" output_lang.addSentence(pair[1])\n",
" print(\"Counted words:\")\n",
" print(input_lang.name, input_lang.n_words)\n",
" print(output_lang.name, output_lang.n_words)\n",
" return input_lang, output_lang, pairs\n",
"\n",
"input_lang, output_lang, pairs = prepareData(True)\n",
"print(random.choice(pairs))"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:12:33.204103Z",
"iopub.execute_input": "2024-05-25T14:12:33.204776Z",
"iopub.status.idle": "2024-05-25T14:12:36.889693Z",
"shell.execute_reply.started": "2024-05-25T14:12:33.204744Z",
"shell.execute_reply": "2024-05-25T14:12:36.888700Z"
},
"trusted": true
},
"execution_count": 16,
"outputs": [
{
"name": "stdout",
"text": "Reading lines...\nRead 72258 sentence pairs\nTrimmed to 5005 sentence pairs\nCounting words...\nCounted words:\nfin 3686\nen 1971\n['mina odotan joulua innolla', 'i am looking forward to christmas']\n",
"output_type": "stream"
}
]
},
{
"cell_type": "markdown",
"source": [
"### Definicja modelu"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"class EncoderRNN(nn.Module):\n",
" def __init__(self, input_size, hidden_size, dropout_p=0.1):\n",
" super(EncoderRNN, self).__init__()\n",
" self.hidden_size = hidden_size\n",
"\n",
" self.embedding = nn.Embedding(input_size, hidden_size)\n",
" self.gru = nn.GRU(hidden_size, hidden_size, batch_first=True)\n",
" self.dropout = nn.Dropout(dropout_p)\n",
"\n",
" def forward(self, input):\n",
" embedded = self.dropout(self.embedding(input))\n",
" output, hidden = self.gru(embedded)\n",
" return output, hidden"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:12:52.383787Z",
"iopub.execute_input": "2024-05-25T14:12:52.384131Z",
"iopub.status.idle": "2024-05-25T14:12:52.391196Z",
"shell.execute_reply.started": "2024-05-25T14:12:52.384104Z",
"shell.execute_reply": "2024-05-25T14:12:52.390316Z"
},
"trusted": true
},
"execution_count": 17,
"outputs": []
},
{
"cell_type": "code",
"source": [
"class DecoderRNN(nn.Module):\n",
" def __init__(self, hidden_size, output_size):\n",
" super(DecoderRNN, self).__init__()\n",
" self.embedding = nn.Embedding(output_size, hidden_size)\n",
" self.gru = nn.GRU(hidden_size, hidden_size, batch_first=True)\n",
" self.out = nn.Linear(hidden_size, output_size)\n",
"\n",
" def forward(self, encoder_outputs, encoder_hidden, target_tensor=None):\n",
" batch_size = encoder_outputs.size(0)\n",
" decoder_input = torch.empty(batch_size, 1, dtype=torch.long, device=device).fill_(SOS_token)\n",
" decoder_hidden = encoder_hidden\n",
" decoder_outputs = []\n",
"\n",
" for i in range(MAX_LENGTH):\n",
" decoder_output, decoder_hidden = self.forward_step(decoder_input, decoder_hidden)\n",
" decoder_outputs.append(decoder_output)\n",
"\n",
" if target_tensor is not None:\n",
" # Teacher forcing: Feed the target as the next input\n",
" decoder_input = target_tensor[:, i].unsqueeze(1) # Teacher forcing\n",
" else:\n",
" # Without teacher forcing: use its own predictions as the next input\n",
" _, topi = decoder_output.topk(1)\n",
" decoder_input = topi.squeeze(-1).detach() # detach from history as input\n",
"\n",
" decoder_outputs = torch.cat(decoder_outputs, dim=1)\n",
" decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)\n",
" return decoder_outputs, decoder_hidden, None # We return `None` for consistency in the training loop\n",
"\n",
" def forward_step(self, input, hidden):\n",
" output = self.embedding(input)\n",
" output = F.relu(output)\n",
" output, hidden = self.gru(output, hidden)\n",
" output = self.out(output)\n",
" return output, hidden"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:12:54.393953Z",
"iopub.execute_input": "2024-05-25T14:12:54.394808Z",
"iopub.status.idle": "2024-05-25T14:12:54.409000Z",
"shell.execute_reply.started": "2024-05-25T14:12:54.394765Z",
"shell.execute_reply": "2024-05-25T14:12:54.407827Z"
},
"trusted": true
},
"execution_count": 18,
"outputs": []
},
{
"cell_type": "code",
"source": [
"class BahdanauAttention(nn.Module):\n",
" def __init__(self, hidden_size):\n",
" super(BahdanauAttention, self).__init__()\n",
" self.Wa = nn.Linear(hidden_size, hidden_size)\n",
" self.Ua = nn.Linear(hidden_size, hidden_size)\n",
" self.Va = nn.Linear(hidden_size, 1)\n",
"\n",
" def forward(self, query, keys):\n",
" scores = self.Va(torch.tanh(self.Wa(query) + self.Ua(keys)))\n",
" scores = scores.squeeze(2).unsqueeze(1)\n",
"\n",
" weights = F.softmax(scores, dim=-1)\n",
" context = torch.bmm(weights, keys)\n",
"\n",
" return context, weights\n",
"\n",
"class AttnDecoderRNN(nn.Module):\n",
" def __init__(self, hidden_size, output_size, dropout_p=0.1):\n",
" super(AttnDecoderRNN, self).__init__()\n",
" self.embedding = nn.Embedding(output_size, hidden_size)\n",
" self.attention = BahdanauAttention(hidden_size)\n",
" self.gru = nn.GRU(2 * hidden_size, hidden_size, batch_first=True)\n",
" self.out = nn.Linear(hidden_size, output_size)\n",
" self.dropout = nn.Dropout(dropout_p)\n",
"\n",
" def forward(self, encoder_outputs, encoder_hidden, target_tensor=None):\n",
" batch_size = encoder_outputs.size(0)\n",
" decoder_input = torch.empty(batch_size, 1, dtype=torch.long, device=device).fill_(SOS_token)\n",
" decoder_hidden = encoder_hidden\n",
" decoder_outputs = []\n",
" attentions = []\n",
"\n",
" for i in range(MAX_LENGTH):\n",
" decoder_output, decoder_hidden, attn_weights = self.forward_step(\n",
" decoder_input, decoder_hidden, encoder_outputs\n",
" )\n",
" decoder_outputs.append(decoder_output)\n",
" attentions.append(attn_weights)\n",
"\n",
" if target_tensor is not None:\n",
" # Teacher forcing: Feed the target as the next input\n",
" decoder_input = target_tensor[:, i].unsqueeze(1) # Teacher forcing\n",
" else:\n",
" # Without teacher forcing: use its own predictions as the next input\n",
" _, topi = decoder_output.topk(1)\n",
" decoder_input = topi.squeeze(-1).detach() # detach from history as input\n",
"\n",
" decoder_outputs = torch.cat(decoder_outputs, dim=1)\n",
" decoder_outputs = F.log_softmax(decoder_outputs, dim=-1)\n",
" attentions = torch.cat(attentions, dim=1)\n",
"\n",
" return decoder_outputs, decoder_hidden, attentions\n",
"\n",
"\n",
" def forward_step(self, input, hidden, encoder_outputs):\n",
" embedded = self.dropout(self.embedding(input))\n",
"\n",
" query = hidden.permute(1, 0, 2)\n",
" context, attn_weights = self.attention(query, encoder_outputs)\n",
" input_gru = torch.cat((embedded, context), dim=2)\n",
"\n",
" output, hidden = self.gru(input_gru, hidden)\n",
" output = self.out(output)\n",
"\n",
" return output, hidden, attn_weights"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:13:00.670299Z",
"iopub.execute_input": "2024-05-25T14:13:00.670758Z",
"iopub.status.idle": "2024-05-25T14:13:00.687695Z",
"shell.execute_reply.started": "2024-05-25T14:13:00.670720Z",
"shell.execute_reply": "2024-05-25T14:13:00.686610Z"
},
"trusted": true
},
"execution_count": 19,
"outputs": []
},
{
"cell_type": "code",
"source": [
"def indexesFromSentence(lang, sentence):\n",
" return [lang.word2index[word] for word in sentence.split(' ')]\n",
"\n",
"def tensorFromSentence(lang, sentence):\n",
" indexes = indexesFromSentence(lang, sentence)\n",
" indexes.append(EOS_token)\n",
" return torch.tensor(indexes, dtype=torch.long, device=device).view(1, -1)\n",
"\n",
"def tensorsFromPair(pair):\n",
" input_tensor = tensorFromSentence(input_lang, pair[0])\n",
" target_tensor = tensorFromSentence(output_lang, pair[1])\n",
" return (input_tensor, target_tensor)\n",
"\n",
"def get_dataloader(batch_size):\n",
" input_lang, output_lang, pairs = prepareData(True)\n",
"\n",
" n = len(pairs)\n",
" input_ids = np.zeros((n, MAX_LENGTH), dtype=np.int32)\n",
" target_ids = np.zeros((n, MAX_LENGTH), dtype=np.int32)\n",
"\n",
" for idx, (inp, tgt) in enumerate(pairs):\n",
" inp_ids = indexesFromSentence(input_lang, inp)\n",
" tgt_ids = indexesFromSentence(output_lang, tgt)\n",
" inp_ids.append(EOS_token)\n",
" tgt_ids.append(EOS_token)\n",
" input_ids[idx, :len(inp_ids)] = inp_ids\n",
" target_ids[idx, :len(tgt_ids)] = tgt_ids\n",
"\n",
" train_data = TensorDataset(torch.LongTensor(input_ids).to(device),\n",
" torch.LongTensor(target_ids).to(device))\n",
"\n",
" train_sampler = RandomSampler(train_data)\n",
" train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=batch_size)\n",
" return input_lang, output_lang, train_dataloader"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:22:08.183866Z",
"iopub.execute_input": "2024-05-25T14:22:08.184711Z",
"iopub.status.idle": "2024-05-25T14:22:08.194870Z",
"shell.execute_reply.started": "2024-05-25T14:22:08.184675Z",
"shell.execute_reply": "2024-05-25T14:22:08.193965Z"
},
"trusted": true
},
"execution_count": 31,
"outputs": []
},
{
"cell_type": "code",
"source": [
"def train_epoch(dataloader, encoder, decoder, encoder_optimizer,\n",
" decoder_optimizer, criterion):\n",
"\n",
" total_loss = 0\n",
" for data in dataloader:\n",
" input_tensor, target_tensor = data\n",
"\n",
" encoder_optimizer.zero_grad()\n",
" decoder_optimizer.zero_grad()\n",
"\n",
" encoder_outputs, encoder_hidden = encoder(input_tensor)\n",
" decoder_outputs, _, _ = decoder(encoder_outputs, encoder_hidden, target_tensor)\n",
"\n",
" loss = criterion(\n",
" decoder_outputs.view(-1, decoder_outputs.size(-1)),\n",
" target_tensor.view(-1)\n",
" )\n",
" loss.backward()\n",
"\n",
" encoder_optimizer.step()\n",
" decoder_optimizer.step()\n",
"\n",
" total_loss += loss.item()\n",
"\n",
" return total_loss / len(dataloader)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:16:38.894580Z",
"iopub.execute_input": "2024-05-25T14:16:38.895410Z",
"iopub.status.idle": "2024-05-25T14:16:38.902142Z",
"shell.execute_reply.started": "2024-05-25T14:16:38.895382Z",
"shell.execute_reply": "2024-05-25T14:16:38.900953Z"
},
"trusted": true
},
"execution_count": 22,
"outputs": []
},
{
"cell_type": "code",
"source": [
"import time\n",
"import math\n",
"\n",
"def asMinutes(s):\n",
" m = math.floor(s / 60)\n",
" s -= m * 60\n",
" return '%dm %ds' % (m, s)\n",
"\n",
"def timeSince(since, percent):\n",
" now = time.time()\n",
" s = now - since\n",
" es = s / (percent)\n",
" rs = es - s\n",
" return '%s (- %s)' % (asMinutes(s), asMinutes(rs))"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:16:43.069584Z",
"iopub.execute_input": "2024-05-25T14:16:43.069953Z",
"iopub.status.idle": "2024-05-25T14:16:43.075972Z",
"shell.execute_reply.started": "2024-05-25T14:16:43.069926Z",
"shell.execute_reply": "2024-05-25T14:16:43.075033Z"
},
"trusted": true
},
"execution_count": 23,
"outputs": []
},
{
"cell_type": "code",
"source": [
"def train(train_dataloader, encoder, decoder, n_epochs, learning_rate=0.001,\n",
" print_every=100, plot_every=100):\n",
" start = time.time()\n",
" plot_losses = []\n",
" print_loss_total = 0 # Reset every print_every\n",
" plot_loss_total = 0 # Reset every plot_every\n",
"\n",
" encoder_optimizer = optim.Adam(encoder.parameters(), lr=learning_rate)\n",
" decoder_optimizer = optim.Adam(decoder.parameters(), lr=learning_rate)\n",
" criterion = nn.NLLLoss()\n",
"\n",
" for epoch in range(1, n_epochs + 1):\n",
" loss = train_epoch(train_dataloader, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion)\n",
" print_loss_total += loss\n",
" plot_loss_total += loss\n",
"\n",
" if epoch % print_every == 0:\n",
" print_loss_avg = print_loss_total / print_every\n",
" print_loss_total = 0\n",
" print('%s (%d %d%%) %.4f' % (timeSince(start, epoch / n_epochs),\n",
" epoch, epoch / n_epochs * 100, print_loss_avg))\n",
"\n",
" if epoch % plot_every == 0:\n",
" plot_loss_avg = plot_loss_total / plot_every\n",
" plot_losses.append(plot_loss_avg)\n",
" plot_loss_total = 0\n",
"\n",
" showPlot(plot_losses)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:20:58.574148Z",
"iopub.execute_input": "2024-05-25T14:20:58.574520Z",
"iopub.status.idle": "2024-05-25T14:20:58.583203Z",
"shell.execute_reply.started": "2024-05-25T14:20:58.574492Z",
"shell.execute_reply": "2024-05-25T14:20:58.582230Z"
},
"trusted": true
},
"execution_count": 24,
"outputs": []
},
{
"cell_type": "code",
"source": [
"import matplotlib.pyplot as plt\n",
"plt.switch_backend('agg')\n",
"import matplotlib.ticker as ticker\n",
"import numpy as np\n",
"%matplotlib inline\n",
"\n",
"def showPlot(points):\n",
" plt.figure()\n",
" fig, ax = plt.subplots()\n",
" # this locator puts ticks at regular intervals\n",
" loc = ticker.MultipleLocator(base=0.2)\n",
" ax.yaxis.set_major_locator(loc)\n",
" plt.plot(points)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:21:00.586018Z",
"iopub.execute_input": "2024-05-25T14:21:00.586719Z",
"iopub.status.idle": "2024-05-25T14:21:00.592633Z",
"shell.execute_reply.started": "2024-05-25T14:21:00.586683Z",
"shell.execute_reply": "2024-05-25T14:21:00.591636Z"
},
"trusted": true
},
"execution_count": 25,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"### Ewaluacja"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"def evaluate(encoder, decoder, sentence, input_lang, output_lang):\n",
" with torch.no_grad():\n",
" input_tensor = tensorFromSentence(input_lang, sentence)\n",
"\n",
" encoder_outputs, encoder_hidden = encoder(input_tensor)\n",
" decoder_outputs, decoder_hidden, decoder_attn = decoder(encoder_outputs, encoder_hidden)\n",
"\n",
" _, topi = decoder_outputs.topk(1)\n",
" decoded_ids = topi.squeeze()\n",
"\n",
" decoded_words = []\n",
" for idx in decoded_ids:\n",
" if idx.item() == EOS_token:\n",
" decoded_words.append('<EOS>')\n",
" break\n",
" decoded_words.append(output_lang.index2word[idx.item()])\n",
" return decoded_words, decoder_attn"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:21:01.858691Z",
"iopub.execute_input": "2024-05-25T14:21:01.859612Z",
"iopub.status.idle": "2024-05-25T14:21:01.866857Z",
"shell.execute_reply.started": "2024-05-25T14:21:01.859574Z",
"shell.execute_reply": "2024-05-25T14:21:01.865732Z"
},
"trusted": true
},
"execution_count": 26,
"outputs": []
},
{
"cell_type": "code",
"source": [
"def evaluateRandomly(encoder, decoder, n=10):\n",
" for i in range(n):\n",
" pair = random.choice(pairs)\n",
" print('Input sentence: ', pair[0])\n",
" print('Target (true) translation:' , pair[1])\n",
" output_words, _ = evaluate(encoder, decoder, pair[0], input_lang, output_lang)\n",
" output_sentence = ' '.join(output_words)\n",
" print('Output sentence: ', output_sentence)\n",
" print('')"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:39:52.474985Z",
"iopub.execute_input": "2024-05-25T14:39:52.475327Z",
"iopub.status.idle": "2024-05-25T14:39:52.481801Z",
"shell.execute_reply.started": "2024-05-25T14:39:52.475304Z",
"shell.execute_reply": "2024-05-25T14:39:52.480957Z"
},
"trusted": true
},
"execution_count": 36,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"# Wykorzystanie zdefiniowanych wyżej funkcji"
],
"metadata": {}
},
{
"cell_type": "markdown",
"source": [
"### Trenowanie modelu"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"hidden_size = 128\n",
"batch_size = 32\n",
"\n",
"input_lang, output_lang, train_dataloader = get_dataloader(batch_size)\n",
"\n",
"encoder = EncoderRNN(input_lang.n_words, hidden_size).to(device)\n",
"decoder = AttnDecoderRNN(hidden_size, output_lang.n_words).to(device)\n",
"\n",
"train(train_dataloader, encoder, decoder, 80, print_every=5, plot_every=5)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:22:39.754370Z",
"iopub.execute_input": "2024-05-25T14:22:39.754740Z",
"iopub.status.idle": "2024-05-25T14:26:53.707012Z",
"shell.execute_reply.started": "2024-05-25T14:22:39.754714Z",
"shell.execute_reply": "2024-05-25T14:26:53.705969Z"
},
"trusted": true
},
"execution_count": 32,
"outputs": [
{
"name": "stdout",
"text": "Reading lines...\nRead 72258 sentence pairs\nTrimmed to 5005 sentence pairs\nCounting words...\nCounted words:\nfin 3686\nen 1971\n0m 21s (- 5m 21s) (5 6%) 1.9364\n0m 36s (- 4m 17s) (10 12%) 1.0355\n0m 51s (- 3m 45s) (15 18%) 0.6313\n1m 7s (- 3m 21s) (20 25%) 0.3787\n1m 22s (- 3m 1s) (25 31%) 0.2243\n1m 37s (- 2m 42s) (30 37%) 0.1371\n1m 52s (- 2m 25s) (35 43%) 0.0903\n2m 7s (- 2m 7s) (40 50%) 0.0668\n2m 23s (- 1m 51s) (45 56%) 0.0538\n2m 38s (- 1m 34s) (50 62%) 0.0471\n2m 53s (- 1m 18s) (55 68%) 0.0410\n3m 8s (- 1m 2s) (60 75%) 0.0381\n3m 23s (- 0m 47s) (65 81%) 0.0343\n3m 38s (- 0m 31s) (70 87%) 0.0342\n3m 54s (- 0m 15s) (75 93%) 0.0322\n4m 9s (- 0m 0s) (80 100%) 0.0307\n",
"output_type": "stream"
}
]
},
{
"cell_type": "code",
"source": [
"evaluateRandomly(encoder, decoder)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:48:23.131435Z",
"iopub.execute_input": "2024-05-25T15:48:23.131948Z",
"iopub.status.idle": "2024-05-25T15:48:23.213007Z",
"shell.execute_reply.started": "2024-05-25T15:48:23.131911Z",
"shell.execute_reply": "2024-05-25T15:48:23.211856Z"
},
"trusted": true
},
"execution_count": 121,
"outputs": [
{
"name": "stdout",
"text": "Input sentence: olen hyvin hyvin vihainen\nTarget (true) translation: i m very very angry\nOutput sentence: i am very angry today <EOS>\n\nInput sentence: han valehtelee\nTarget (true) translation: he s lying\nOutput sentence: he is telling a lie <EOS>\n\nInput sentence: olen myohassa\nTarget (true) translation: i m late\nOutput sentence: i m late <EOS>\n\nInput sentence: han on linja autonkuljettaja\nTarget (true) translation: he is a bus driver\nOutput sentence: he is a bus driver <EOS>\n\nInput sentence: mukava tavata sinut taas\nTarget (true) translation: i m glad to see you again\nOutput sentence: i m glad to see you again <EOS>\n\nInput sentence: olet kuumeessa\nTarget (true) translation: you re running a fever\nOutput sentence: you re so predictable <EOS>\n\nInput sentence: anteeksi mutta unohdin tehda laksyt\nTarget (true) translation: i m sorry i forgot to do my homework\nOutput sentence: i m sorry i forgot to do my homework <EOS>\n\nInput sentence: mina olen tyoton\nTarget (true) translation: i m unemployed\nOutput sentence: i m unemployed <EOS>\n\nInput sentence: olen taynna\nTarget (true) translation: i am full\nOutput sentence: i am full of french <EOS>\n\nInput sentence: ma kuolen nalkaan !\nTarget (true) translation: i m dying of hunger\nOutput sentence: i m dying of hunger <EOS>\n\n",
"output_type": "stream"
}
]
},
{
"cell_type": "code",
"source": [
"def showAttention(input_sentence, output_words, attentions):\n",
" fig = plt.figure()\n",
" ax = fig.add_subplot(111)\n",
" cax = ax.matshow(attentions.cpu().numpy(), cmap='bone')\n",
" fig.colorbar(cax)\n",
"\n",
" # Set up axes\n",
" ax.set_xticklabels([''] + input_sentence.split(' ') +\n",
" ['<EOS>'], rotation=90)\n",
" ax.set_yticklabels([''] + output_words)\n",
"\n",
" # Show label at every tick\n",
" ax.xaxis.set_major_locator(ticker.MultipleLocator(1))\n",
" ax.yaxis.set_major_locator(ticker.MultipleLocator(1))\n",
"\n",
" plt.show()\n",
"\n",
"\n",
"def evaluateAndShowAttention(input_sentence):\n",
" input_sentence = normalizeString(input_sentence)\n",
" output_words, attentions = evaluate(encoder, decoder, input_sentence, input_lang, output_lang)\n",
" print('input =', input_sentence)\n",
" print('output =', ' '.join(output_words))\n",
" showAttention(input_sentence, output_words, attentions[0, :len(output_words), :])\n",
"\n",
"def translate(input_sentence, tokenized=False):\n",
" input_sentence = normalizeString(input_sentence)\n",
" output_words, attentions = evaluate(encoder, decoder, input_sentence, input_lang, output_lang)\n",
" if tokenized:\n",
" if \"<EOS>\" in output_words:\n",
" output_words.remove(\"<EOS>\")\n",
" return output_words\n",
" return ' '.join(output_words)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:30:41.253325Z",
"iopub.execute_input": "2024-05-25T15:30:41.253734Z",
"iopub.status.idle": "2024-05-25T15:30:41.264515Z",
"shell.execute_reply.started": "2024-05-25T15:30:41.253703Z",
"shell.execute_reply": "2024-05-25T15:30:41.263376Z"
},
"trusted": true
},
"execution_count": 99,
"outputs": []
},
{
"cell_type": "code",
"source": [
"translate(\"Meillä on nälkä\", tokenized=True)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:58:53.639252Z",
"iopub.execute_input": "2024-05-25T14:58:53.639963Z",
"iopub.status.idle": "2024-05-25T14:58:53.654186Z",
"shell.execute_reply.started": "2024-05-25T14:58:53.639932Z",
"shell.execute_reply": "2024-05-25T14:58:53.653028Z"
},
"trusted": true
},
"execution_count": 76,
"outputs": [
{
"execution_count": 76,
"output_type": "execute_result",
"data": {
"text/plain": "['we', 'are', 'hungry']"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"evaluateAndShowAttention('Olet liian naivi')"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:46:05.023218Z",
"iopub.execute_input": "2024-05-25T14:46:05.024277Z",
"iopub.status.idle": "2024-05-25T14:46:05.426793Z",
"shell.execute_reply.started": "2024-05-25T14:46:05.024227Z",
"shell.execute_reply": "2024-05-25T14:46:05.424993Z"
},
"trusted": true
},
"execution_count": 44,
"outputs": [
{
"name": "stdout",
"text": "input = olet liian naivi\noutput = you re too naive <EOS>\n",
"output_type": "stream"
},
{
"name": "stderr",
"text": "/tmp/ipykernel_34/2052950992.py:8: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_xticklabels([''] + input_sentence.split(' ') +\n/tmp/ipykernel_34/2052950992.py:10: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_yticklabels([''] + output_words)\n",
"output_type": "stream"
},
{
"output_type": "display_data",
"data": {
"text/plain": "<Figure size 640x480 with 2 Axes>",
"image/png": "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N/nIaIO0cOFC5eTkuH/+7bffPO5rPXfunF5//XUzQoOfUSEGuJo1ayotLU1//etfVb58eW3atEm1atXSrl271Lx58z99eoFV5ObmauLEiVq4cKH279/v8QtNko4fP25SZOabN2+eunfvrrCwMHenwUi/fv2KKarA9cd7f+12uzZu3KhatWpJkg4dOqSqVatyi0oJxGBUgDty5MhV9yBKl1dmYZHm/xo9erRmzZqlZ555RiNGjNCLL76offv26R//+IdGjhxpdnimujLJkfD+3B9rBGoG66BlGuASEhK0ZMkS9895SXDWrFlKTEw0K6yA8+GHH2rmzJl65plnVLp0afXo0UOzZs3SyJEjWXfSwIULF+RwODw2wMqoEAPcmDFj1LFjR23dulWXLl3S5MmTtXXrVq1evVrffvut2eEFjKysLPdSWxERETp16pQk6W9/+5teeuklM0MLKGfPntXzzz+vhQsX6tixY1e9ThsQVkaFGOBuvfVWbdy4UZcuXVLjxo319ddfKyoqSmvWrFGLFi3MDi9gVK9eXQcPHpQk1a5dW19//bUkad26dQoLCzMztIAydOhQrVixQtOnT1dYWJhmzZql0aNHq2rVqpo/f77Z4QWMZcuWafHixVq8eLGcTqfS09PdPy9btszs8OAnTKpBiTBs2DDZ7Xa98MILSktLU+/evRUXF6f9+/fr6aef1rhx48wOMSDUqFFD8+fPV9u2bWW327VhwwbVqVNH77//vj766COe4CAV6IZ7m81GNV0CkRADUGHGcux2ux8jCV5r1qzRmjVrVLduXR7meoWIiAht3bpVNWrUUPXq1fXZZ5+pZcuW2rt3rxo3bqwzZ86YHSJgGsYQA1CFChX+dAapy+Xib6leJCYmMukoH7Vq1dLevXtVo0YNxcfHa+HChWrZsqW++OILVahQwezwAsa5c+e0e/fufB8BtWXLFtWsWZO1X0sgEmIAWrlypdkhBIXFixerY8eOKlOmjBYvXuz12HvvvbeYogpsycnJ2rRpk26//XYNGzZMnTp10tSpU3Xx4kVNmDDB7PACRk5Ojlq1aqWMjAy1bNnSvX/r1q1q1qyZ9u/fT0IsgWiZBoGTJ09q9uzZ2rZtmySpYcOGevjhhxUZGWlyZOa68lmR3sZ9qKSN/frrr1q/fr3q1KmjJk2amB1OQOnatauioqI0depU977hw4dr48aN+uqrr0yMDP5CQgxwP/74o+6++26Fh4e7/6a6bt06nT9/Xl9//bWaN29ucoQINunp6UpPT9fhw4c9liSTpDlz5pgUVeBZsmSJHnzwQR08eFClS5eWy+VSzZo1NX78eHXt2tXs8OAHJMQA16ZNG9WpU0czZ850P+Xi0qVL6t+/v/bs2aPvvvvO5AgRTEaPHq2XX35ZCQkJqlKlylVj1Z9//rlJkQWe3NxcVa9eXTNmzNDf//53rVy5Uvfdd5+ysrIUGhpqdnjwAxJigCtbtqz+7//+T/Hx8R77t27dqoSEBJ07d86kyMw3ZcoUPfLIIwoPD9eUKVO8Hvvkk08WU1SBrUqVKnr99dfVp08fs0MJCs8++6z27t2rRYsW6aGHHlJYWJimT59udljwEybVBDi73a79+/dflRAzMzNVvnx5k6IKDBMnTlSvXr0UHh6uiRMnGh5ns9lIiP+Rk5OjW265xewwgka/fv3UsmVLHThwQIsWLeKm/BKOCjHAPfnkk/r88881fvx49y+yVatW6bnnntN9992nSZMmmRsggsrzzz+viIgIlrMrhBYtWqh8+fLKysrS9u3bzQ4HfkSFGODGjx8vm82mvn376tKlS5KkMmXKaODAgZZffSUlJaVAx9lsNr355pt+jiY4XLhwQe+++66WL1+uJk2aqEyZMh6vc+vF1fr27aunn35ar776qtmhwM+oEINE3o3C0uW1Oq+77jqTIzLfHXfcUaDjbDabVqxY4edogoO374zvKX/Hjx/XW2+9pUcffVQxMTFmhwM/IiECACCedgEAgCQSIgAAkkiIQSU7O1ujRo1Sdna22aEENL6nguF7Khi+J+tgDDGIOBwORUZG6tSpUzz2yQu+p4LheyoYvifroEIEAEAkRAAAJHFjviGn06nff/9d5cuX/9OH9RYXh8Ph8b/IH99TwfA9FUwgfk8ul0unT59W1apVvT76zFcXLlxQTk6Oz+8TGhqq8PDwIojIvxhDNPDbb78pNjbW7DAAwFBmZqaqV6/ul/e+cOGCbrzxRmVlZfn8XjExMdq7d2/AJ0UqRANWXzgb/hAYnYZAd/zEcbNDCHgOh0NxNWv69fdUTk6OsrKytH//fp8mEzkcDtWoUUM5OTkkxGAVKG1SlBz8O1UwzOQsuOL4dyqifHlF+JB4nUHUhGRSDQAAokIEAHjhcrnky1STYJqmQkIEABhy/eePL+cHC1qmAACIChEA4IXTdXnz5fxgQUIEABiy0hgiLVMAAESFCADwwuly+XQvYTDdh0hCBAAYomUKAIDFUCECAAxZqUIkIQIADDGGCACArFUhMoYIAICoEAEAXlhpLVMSIgDAkJWWbqNlCgCAqBABAN74OKlGQTSphoQIADBkpdsuaJkCACAqRACAF1a6D5GECAAwZKWESMsUAABRIQIAvLDSpBoSIgDAkJVapiREAIAhKy3dxhgiAACiQgQAeGGltUxJiAAAQy75Ng4YRPmQlikAABIVIgDAC2aZAgAga92HGJAt0/nz5+v6669Xdna2x/7OnTurT58+kqTp06erdu3aCg0NVf369fX++++7j9u3b59sNps2btzo3nfy5EnZbDZlZGTke83s7Gw5HA6PDQBgHQGZEB944AHl5uZq8eLF7n2HDx/WkiVL9NBDD+nzzz/XU089pWeeeUabN2/Wo48+quTkZK1cufKarzl27FhFRka6t9jY2KL4KAAQ1PJapr5swSIgE2LZsmXVs2dPvffee+59H3zwgWrUqKG2bdtq/PjxevDBB/X444+rXr16SklJUZcuXTR+/Phrvubw4cN16tQp95aZmVkUHwUAglpey9SXLVgEZEKUpAEDBujrr7/WgQMHJElz587Vgw8+KJvNpm3btql169Yex7du3Vrbtm275uuFhYXJbrd7bAAA6wjYSTXNmjVT06ZNNX/+fLVv315btmzRkiVLCnRuSMjlPH9lqX7x4kW/xAkAJZqvbU8qxKLRv39/zZ07V++9956SkpLc43oNGjTQqlWrPI5dtWqVGjZsKEm64YYbJEkHDx50v37lBBsAQMG4iuBPsAjYClGSevbsqWeffVYzZ87U/Pnz3fufe+45de3aVc2aNVNSUpK++OILffbZZ1q+fLmky2OQf/3rXzVu3DjdeOONOnz4sEaMGGHWxwCAoGWlpdsCukKMjIzUfffdp4iICHXu3Nm9v3Pnzpo8ebLGjx+vv/zlL3rnnXf03nvvqW3btu5j5syZo0uXLqlFixYaMmSIXn311eL/AACAoBHQFaIkHThwQL169VJYWJjH/oEDB2rgwIGG5zVo0ECrV6/22BdM038BIBCwUk0AOHHihDIyMpSRkaG3337b7HAAwJJIiAGgWbNmOnHihF577TXVr1/f7HAA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ChEA4IWV7kMkIQIADFlplikJEQBgyEoJkTFEAABEhQgA8MJKFSIJEQBgyEoJkZYpAACiQgQAeHG5Qrz2WyeCqUIkIQIAjFlo6Ta/tkxtNlu+28cff+w+Jjc3VxMnTlTjxo0VHh6uihUrqmPHjlq1apXHe+Xm5mrcuHGKj49X2bJlValSJbVq1UqzZs3y50cAAFhEkVeIJ06cUJkyZRQRESFJeu+993T33Xd7HFOhQgVJl0vp7t27a/ny5XrjjTd05513yuFwaNq0aWrbtq0++eQTde7cWZI0evRovfPOO5o6daoSEhLkcDj0448/6sSJE+73/f333xUVFaXSpSl8AaAoWGkt0yLJHJcuXdKyZcs0d+5cffHFF/rhhx/UtGlTSZeTX0xMTL7nLVy4UJ9++qkWL16sTp06ufe/++67OnbsmPr376+77rpL5cqV0+LFi/X444/rgQcecB+Xd408M2fO1PTp09W7d2/169dPjRs3LoqPBwCWxSzTAvr555/1zDPPqHr16urbt69uuOEGrVy58qpEZWTBggWqV6+eRzLM88wzz+jYsWP65ptvJEkxMTFasWKFjhw5Yvh+zz//vCZPnqxt27apefPmat68uaZMmeL1nDzZ2dlyOBweGwDAOgqdEI8dO6bJkyerefPmSkhI0J49e/T222/r4MGDevvtt5WYmOhxfI8ePRQREeGx7d+/X5K0Y8cONWjQIN/r5O3fsWOHJGnChAk6cuSIYmJi1KRJEz322GP66quvPM4JDw9Xt27dtGTJEh04cEB9+/bV3LlzVa1aNXXu3Fmff/65Ll26lO/1xo4dq8jISPcWGxtb2K8GAEqcy4t7+7YFi0InxLfeektDhgxRRESEdu3apc8//1xdunRRaGhovsdPnDhRGzdu9NiqVq3qfr2g5XTDhg21efNmff/993rooYd0+PBhderUSf3798/3+KioKA0ZMkQbNmzQP//5T61Zs0ZdunTR5s2b8z1++PDhOnXqlHvLzMwsUFwAUJLltUx92YJFoccQH3nkEZUuXVrz58/XX/7yF913333q06eP2rZtq5CQq/NrTEyM6tSpk+971atXT9u2bcv3tbz99erVc+8LCQnRzTffrJtvvllDhgzRBx98oD59+ujFF1/UjTfe6HH+6dOn9emnn+r999/Xd999p9tvv139+vVTw4YN871eWFiYwsLCCvQdAIBVMIboRdWqVTVixAjt2LFDS5cuVWhoqLp06aKaNWtq2LBh2rJlS4Hfq3v37tq5c6e++OKLq1578803df311+uuu+4yPD8vuZ09e1bS5VszvvrqK/Xs2VPR0dEaN26c7rzzTu3Zs0fp6enq27evYSULALA2nybV3HLLLXrnnXeUlZWlN954Qxs3blTTpk31888/u485efKksrKyPLa8BNa9e3f9z//8j/r166fZs2dr3759+umnn/Too49q8eLFmjVrlsqVKydJuv/++zVx4kT98MMP+vXXX5WRkaFBgwapXr16io+PlySNGTNGPXr0UPny5bV8+XL98ssvevHFF1WjRg1fPiYAWJaVWqY2VxFH+/vvvysiIkJ2u102W/5PWR47dqyGDRsm6fItG5MmTdLcuXO1c+dOhYeHKzExUS+99JJat27tPmfmzJn66KOPtHnzZp06dUoxMTFq166dRo0apZo1a0qS9u3bp5iYGIWHh/v8ORwOhyIjI31+HwCFE0y/QM2S9/vp1KlTstvtfr1GxYoxstmuvXZyuZw6cSLLr7EWlSJPiCUFCREwB7+S/hwJ0T9Y0gUAYMzX2yaC6LYLEiIAwNDlpdessXQbz0MEAEBUiAAALy6P6VrjPkQSIgDAkJUSIi1TAABEhQgA8MLXxbmDaXFvEiIAwNDljqcvLdMiC8XvSIgAAEO+jgEyhggAQJChQgQAGLJShUhCBAAY8zWhBVFCpGUKAICoEAEAXrjklJT/o/wKdn7wVIgkRACAISuNIdIyBQBAVIgAAC+sVCGSEAEAhqyUEGmZAgAgKkQAgBdWqhBJiAAAQ5efVuHDbRckRABASWClCpExRAAARIUIAPDGQmuZkhABAIZ8XXotmJZuo2UKAICoEAEAXjDLFAAAMcsUAADLoUI0EEx/qwFKEofDYXYIAS/vOyqu31NW+X1IQjRw+vRps0MALCkyMtLsEILG6dOn/fZ9hYaGKiYmRllZWT6/V0xMjEJDQ4sgKv+yuayS+gvJ6XTq999/V/ny5WWzXfuAclFyOByKjY1VZmam7Ha72eEELL6nguF7KphA/J5cLpdOnz6tqlWrKiTEfyNfFy5cUE5Ojs/vExoaqvDw8CKIyL+oEA2EhISoevXqZoeRL7vdHjD/YQYyvqeC4XsqmED7noqjkg4PDw+KRFZUmFQDAIBIiAAASCIhBpWwsDClpqYqLCzM7FACGt9TwfA9FQzfk3UwqQYAAFEhAgAgiYQIAIAkEiIAAJJIiAAASCIhAgAgiYQIAIAkEiIAAJJIiAAASJL+H5bvJJHifT/eAAAAAElFTkSuQmCC"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"evaluateAndShowAttention('Olen todella pahoillani')"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:46:10.394969Z",
"iopub.execute_input": "2024-05-25T14:46:10.395671Z",
"iopub.status.idle": "2024-05-25T14:46:10.793392Z",
"shell.execute_reply.started": "2024-05-25T14:46:10.395630Z",
"shell.execute_reply": "2024-05-25T14:46:10.791940Z"
},
"trusted": true
},
"execution_count": 45,
"outputs": [
{
"name": "stdout",
"text": "input = olen todella pahoillani\noutput = i am truly sorry <EOS>\n",
"output_type": "stream"
},
{
"name": "stderr",
"text": "/tmp/ipykernel_34/2052950992.py:8: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_xticklabels([''] + input_sentence.split(' ') +\n/tmp/ipykernel_34/2052950992.py:10: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_yticklabels([''] + output_words)\n",
"output_type": "stream"
},
{
"output_type": "display_data",
"data": {
"text/plain": "<Figure size 640x480 with 2 Axes>",
"image/png": "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3367lixZogceeMDgCI339NNP6/z58/rwww8VGRmp9957z+n1jRs3asCAAQZFh/LEoBpUGIcPH9bixYt1+PBhpaSkKCIiQp9++qkaNGigG264wejwvEJ0dLQeffRRjRo1ymn/rFmzlJqa6qgaATMiIaJC2LBhg3r06KFOnTrpq6++Unp6uho3bqxp06Zp69atjhGCZhcUFKS9e/fq+uuvd9r//fffq0WLFrpw4YJBkXmfX3/9VV988YUOHjwoSWratKnuuOMOVa5c2eDIUF5oMvUBhw4d0rp163Ty5EnZbDan1yZOnGhQVN5l7NixeuGFF5SUlKRq1ao59t92222aO3eugZF5l6ioKKWlpV2WEL/88ksmmv/OqlWrNHjwYJ06dcppf82aNbVw4UL17NnToMhQnkiIXi41NVWPP/64atasqcjISKdRlRaLhYT4m927d2vZsmWX7Y+IiLjsS83MRo8erSeffFI7d+5Ux44dJRX2iS1ZskQpKSkGR+cdNm3apL59+6pXr14aPXq0oqOjJUn79u3TzJkz1bdvX23YsEE333yzwZGirNFk6uUaNmyooUOH6plnnjE6FK9Wv359vfvuu+rYsaOqVaum//f//p8aN26slStXasyYMTp8+LDRIXqNlStXaubMmY7+wujoaD311FP629/+ZnBk3uHuu+9WVFSUXn/99WJff+yxx5SZmalPPvnkKkeG8kZC9HKhoaHauXOnGjdubHQoXm3MmDHasmWL3nvvPTVt2lTbt2/XiRMnFB8fr/j4eCUnJxsdInxEjRo1tGHDBsdKNX+0a9cudenSRWfOnLnKkaG8sVKNl7vvvvv0+eefGx2G15syZYqaN2+uqKgo/fLLL4qJidEtt9yijh07avz48UaH53Xy8/P13//+VxkZGU4bLl+p5o/CwsIYfFRB0Yfo5a6//npNmDBB33zzjVq2bKmAgACn14vmkpldYGCgUlNTNWHCBO3Zs0e//PKL2rZtqyZNmhgdmlc5dOiQBg0apE2bNjntt9vtrGX6myZNmmjt2rVKTEws9vW0tDT+XlVQNJl6uWuvvdblaxaLRUeOHLmK0cDXderUSZUqVdLYsWNVp06dy5a+a926tUGReY/Zs2frhRde0FtvvaW7777b6bXVq1crISFBzz77rNPjoVAxkBDhs0rzhTRr1qxyjMR3VK1aVdu2bVPz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2fT888+rfv36CgoKUps2bbRmzRrHeUePHpXFYtGKFSvUpUsXBQcH61//+pcGDhyo3r1768UXX1TdunXVrFkzPf/882rRosVl927Tpo0mTJhQbFx5eXmyWq1OGwCYXVGF6MnmK65qQjx+/LgGDBigQYMGKT09XevXr1efPn1kt9uVkpKimTNnasaMGdq1a5e6d++uXr166dChQ07XGDt2rEaMGKH09HR1795dkpSWlqYDBw7oiy++0P/+7/86rv/dd985ztuxY4d27dqlxMTEYmObOnWqwsLCHFtUVFT5fRAA4CuK1jL1ZPMRFvtVTN/bt29Xu3btdPToUTVs2NDptXr16mnYsGF69tlnHfvat2+vm266SfPmzdPRo0d17bXXas6cORoxYoTjmIEDB2rNmjXKyMhQYGCgY//dd9+tRo0a6dVXX5UkPfnkk9q9e7fWrVtXbGx5eXnKy8tz/Gy1WkmKKGMWowPwCb40TN8oVqtVYWFhOnfunEJDQ8v1Hrfccr8qVQq44utcunRRX331brnGWlauaoXYunVr3X777WrZsqXuu+8+paam6syZM7JarTp27Jg6derkdHynTp2Unp7utC82Nvay67Zs2dIpGUrSkCFD9M477+jChQvKz8/XsmXLNGjQIJexBQUFKTQ01GkDAJjHVU2I/v7++uKLL/Tpp58qJiZGr7zyipo1a6YffvihxNeoWrVqifb17NlTQUFBWrlypT7++GNdvHhRffv29Sh+ADAb+hDLkcViUadOnTR58mTt2LFDgYGBSktLU926dbVx40anYzdu3KiYmJgruk+lSpWUkJCgxYsXa/Hixerfv78qV65cFm8BAEzDTAnxqs5D3LJli9LS0nTnnXcqIiJCW7ZsUXZ2tqKjo/XUU08pOTlZ1113ndq0aaPFixdr586d+te//nXF9xs8eLCio6Ml6bJkCwDA713VhBgaGqqvvvpKc+bMkdVqVcOGDTVz5kz16NFD3bt317lz5zR69GidPHlSMTExWrVqlZo0aXLF92vSpIk6duyo06dPKy4urgzfCQCYg5km5l/VUaZXm91uV5MmTTR06FAlJSWV6tyiEVZA2WGUaUkwyvTPXc1Rph073uPxKNNNm1b6xCjTCrt0W3Z2tpYvX66srCyXcw8BAChSYRNiRESEatasqQULFig8PNzocADAJ5mpybTCJkRf+kMAAG9lpoTo04t7AwBQVipshQgAKAOerkfqQxUiCREA4JL9t1+enO8rSIgAAJfsdptHU2F8aRoNfYgAAIgKEQDghplGmZIQAQAumSkh0mQKAICoEAEAbpipQiQhAgDc8GyUqcQoUwAAfAoVIgDAJZpMAQCQTLV0G02mAACIChEA4IZdnq1H6jv1IQkRAOAGfYgAAIjFvQEAMB0qRACASzSZAgAgcyVEmkwBABAVIgDADSpEAAD0fwnRk+1KzJs3T40aNVJwcLDi4uL07bffujw2NTVVnTt3Vnh4uMLDw9WtWze3x7tCQgQAeJUVK1YoKSlJycnJ2r59u1q3bq3u3bvr5MmTxR6/fv16DRgwQOvWrdPmzZsVFRWlO++8Uz/99FOp7mux+1I9exVZrVaFhYUZHQYqFIvRAfgEX5q3ZpSi76dz584pNDS0XO9xQ0wn+ftfee9aQcEl7d23sVSxxsXF6aabbtLcuXMlSTabTVFRURo+fLjGjh1bgnsWKDw8XHPnzlV8fHyJY6VCBAC4ZC+DX1Jhgv39lpeXV+z98vPztW3bNnXr1s2xz8/PT926ddPmzZtLFPP58+d18eJF1ahRo1TvlYQIXDV2thJtqIiioqIUFhbm2KZOnVrscadOnVJBQYFq167ttL927drKysoq0b2eeeYZ1a1b1ymplgSjTAEALpXVKNPMzEynJtOgoCCPYyvOtGnTtHz5cq1fv17BwcGlOpeECABwqawSYmhoaIn6EGvWrCl/f3+dOHHCaf+JEycUGRnp9twZM2Zo2rRp+vLLL9WqVatSx0qTKQDApaLFvT3ZSiMwMFDt2rVTWlqaY5/NZlNaWpo6dOjg8ryXXnpJ//jHP7RmzRrFxsZe0XulQgQAeJWkpCQlJCQoNjZW7du315w5c5Sbm6vExERJUnx8vOrVq+foh/znP/+piRMnatmyZWrUqJGjrzEkJEQhISElvi8JEQDgkhEr1fTr10/Z2dmaOHGisrKy1KZNG61Zs8Yx0CYjI0N+fv/XwPnaa68pPz9fffv2dbpOcnKyJk2aVOL7Mg/RBeYhAsbgK+nPXc15iE2axHo8D/HQoa3lGmtZoQ8RAADRZAoAcMNMi3uTEAEArtkleZLUfCcf0mQKAIBEhQgAcMMum+weLExvl+8s1k5CBAC4ZKY+RJpMAQAQFSIAwC3PKkRfGlVDQgQAuGSmJlMSIgDApcIFuj0YVFPKxb2NRB8iAACiQgQAuEGTKQAAMldCpMkUAABRIQIA3LHbPVzL1HcqRBIiAMAl+2+/PDnfV9BkCgCAqBABAG6YaR4iCREA4JKZRpmSEAEALpkpIdKHCACAqBABAG6YqUIkIQIAXDJTQqTJFAAAUSECANworBCvfOqEL1WIJEQAgGsmWrqtXJtMLRZLsdvy5csdxxQUFGj27Nlq2bKlgoODFR4erh49emjjxo1O1yooKNC0adPUvHlzVa5cWTVq1FBcXJzeeOON8nwLAACTKPMK8cyZMwoICFBISIgkafHixbrrrrucjqlevbqkwlK6f//++vLLLzV9+nTdfvvtslqtmjdvnrp27ar33ntPvXv3liRNnjxZr7/+uubOnavY2FhZrVZt3bpVZ86ccVz32LFjioiIUKVKFL4AUBbMtJZpmWSOS5cu6bPPPtOSJUv08ccfa8uWLWrdurWkwuQXGRlZ7Hnvvvuu3n//fa1atUo9e/Z07F+wYIF+/vlnDR48WHfccYeqVq2qVatWaejQobrvvvscxxXdo0hqaqpee+01PfTQQ0pISFDLli3L4u0BgGkxyrSEdu/erdGjR6t+/fqKj49XrVq1tG7dussSlSvLli1T06ZNnZJhkdGjR+vnn3/WF198IUmKjIzU2rVrlZ2d7fJ6zzzzjFJSUpSenq4bb7xRN954o15++WW35xTJy8uT1Wp12gAA5lHqhPjzzz8rJSVFN954o2JjY3XkyBG9+uqrOn78uF599VV16NDB6fgBAwYoJCTEacvIyJAkHTx4UNHR0cXep2j/wYMHJUmzZs1Sdna2IiMj1apVK/3973/Xp59+6nROcHCw+vXrp9WrV+unn35SfHy8lixZonr16ql3795auXKlLl26VOz9pk6dqrCwMMcWFRVV2o8GACqcwsW9Pdt8RakT4iuvvKKRI0cqJCRE33//vVauXKk+ffooMDCw2ONnz56tnTt3Om1169Z1vF7ScjomJkZ79uzRN998o0GDBunkyZPq2bOnBg8eXOzxERERGjlypLZv365///vf2rx5s/r06aM9e/YUe/y4ceN07tw5x5aZmVmiuACgIitqMvVk8xWl7kN89NFHValSJb355pu64YYbdO+99+rhhx9W165d5ed3eX6NjIzU9ddfX+y1mjZtqvT09GJfK9rftGlTxz4/Pz/ddNNNuummmzRy5Ei9/fbbevjhh/Xcc8/p2muvdTo/JydH77//vt566y199dVX6tKlixISEhQTE1Ps/YKCghQUFFSizwAAzII+RDfq1q2r8ePH6+DBg1qzZo0CAwPVp08fNWzYUGPHjtXevXtLfK3+/fvr0KFD+vjjjy97bebMmbrmmmt0xx13uDy/KLnl5uZKKpya8emnn+qBBx5Q7dq1NW3aNN1+++06cuSI0tLSFB8f77KSBQCYm0eDajp27KjXX39dWVlZmj59unbu3KnWrVtr9+7djmPOnj2rrKwsp60ogfXv31/33HOPEhIStHDhQh09elS7du3SY489plWrVumNN95Q1apVJUl9+/bV7NmztWXLFv34449av369hg0bpqZNm6p58+aSpClTpmjAgAGqVq2avvzySx04cEDPPfecGjRo4MnbBADTMlOTqcVextEeO3ZMISEhCg0NlcVS/FOWp06dqrFjx0oqnLIxZ84cLVmyRIcOHVJwcLA6dOigCRMmqFOnTo5zUlNT9c4772jPnj06d+6cIiMjddttt2nSpElq2LChJOno0aOKjIxUcHCwx+/DarUqLCzM4+sAKB1f+gI1StH307lz5xQaGlqu9wgPj5TFcuW1k91u05kzWeUaa1kp84RYUZAQAWPwlfTnSIjlgyVdAACueTptwoemXZAQAQAuFS69Zo6l23geIgAAokIEALhR2KdrjnmIJEQAgEtmSog0mQIAICpEAIAbni7O7UuLe5MQAQAuFbZ4etJkWmahlDsSIgDAJU/7AOlDBADAx1AhAgBcMlOFSEIEALjmaULzoYRIkykAAKJCBAC4YZdNUvGP8ivZ+b5TIZIQAQAumakPkSZTAABEhQgAcMNMFSIJEQDgkpkSIk2mAACIChEA4IaZKkQSIgDApcKnVXgw7YKECACoCMxUIdKHCACAqBABAO6YaC1TEiIAwCVPl17zpaXbaDIFAEBUiAAANxhlCgCAGGUKAIDpUCG64Ev/qgEqEqvVanQIXq/oM7pa31Nm+T4kIbqQk5NjdAiAKYWFhRkdgs/Iyckpt88rMDBQkZGRysrK8vhakZGRCgwMLIOoypfFbpbUX0o2m03Hjh1TtWrVZLFceYdyWbJarYqKilJmZqZCQ0ONDsdr8TmVDJ9TyXjj52S325WTk6O6devKz6/8er4uXLig/Px8j68TGBio4ODgMoiofFEhuuDn56f69esbHUaxQkNDveZ/TG/G51QyfE4l422f09WopIODg30ikZUVBtUAACASIgAAkkiIPiUoKEjJyckKCgoyOhSvxudUMnxOJcPnZB4MqgEAQFSIAABIIiECACCJhAgAgCQSIgAAkkiIAABIIiECACCJhAgAgCQSIgAAkqT/Dz82QwJ9FeKgAAAAAElFTkSuQmCC"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"evaluateAndShowAttention('Olet minun isäni')"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:46:13.190403Z",
"iopub.execute_input": "2024-05-25T14:46:13.191025Z",
"iopub.status.idle": "2024-05-25T14:46:13.613486Z",
"shell.execute_reply.started": "2024-05-25T14:46:13.190997Z",
"shell.execute_reply": "2024-05-25T14:46:13.612143Z"
},
"trusted": true
},
"execution_count": 46,
"outputs": [
{
"name": "stdout",
"text": "input = olet minun isani\noutput = you re my father <EOS>\n",
"output_type": "stream"
},
{
"name": "stderr",
"text": "/tmp/ipykernel_34/2052950992.py:8: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_xticklabels([''] + input_sentence.split(' ') +\n/tmp/ipykernel_34/2052950992.py:10: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_yticklabels([''] + output_words)\n",
"output_type": "stream"
},
{
"output_type": "display_data",
"data": {
"text/plain": "<Figure size 640x480 with 2 Axes>",
"image/png": "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QDabTfv379ehQ4c0duxYvfXWW/LzYyno5oaE6CUqKir0+eefq1evXsyYrEF0dLT+/Oc/KzY21t2heLSafsRNJpNsNhuTan4kKytLb775psON+RMmTNCECRPcHBkaCwnRw50/f15paWlavXq1JOngwYPq2bOn7r33XnXr1k0zZ850c4Se4YMPPtDzzz+vpUuXKioqyt3heKzjx487fb9Hjx5NFAngeaj5PdzMmTP12WefKTc3V0FBQfb9iYmJysrKcmNkniUpKUm5ubnq1auX2rZtqw4dOjhsqNSjRw+nG6S//OUvqqiosL/+4osvHO7XPHfunJ599ll3hIZGRoXo4Xr06KGsrCxdfvnlatu2rT777DP17NlThw8f1mWXXSaz2ezuED1CVQVtJCUlpYki8Q779u1TQUGBww+/JN10001uishz/Pje35CQEO3cuVM9e/aUVDmjuWvXrnQvN0MMRnm40tLSajflS1JZWRkzKX+AhFc7R48e1S233KLdu3fbxw4l2f8u8SNf/d5fagbfQZeph6u6ibpK1Q/X8uXLNWzYMHeF5RF+WB2bzWanGyrdf//9uvTSS1VSUqLWrVtr79692rJli+Lj45Wbm+vu8AC3okL0cPPmzdOvfvUr7du3TxcvXtSLL76offv2adu2bfrHP/7h7vDcqn379vaurXbt2tVYMTN70lFeXp42bdqksLAw+fn5yc/PT1deeaUyMjJ033336dNPP3V3iIDbkBA93JVXXqmdO3dq/vz5GjRokD744ANddtllysvLM1xr0Vds2rTJPmFm8+bNbo7GO1gsFvujoMLCwvTll1+qX79+6tGjhw4cOODm6DzHxo0bFRoaKqnyvsScnBzt2bNHknTmzBk3RobGxKQaNBvfffeddu3aVeNTHJgsUmnEiBF68MEHNXbsWE2cOFGnT5/WY489pldffVX5+fn2H31fVpsb7ul1aJ5IiB6oLmNezhYh9iXZ2dlKTk6u9kBXiR+vH9q4caPKysr061//WocPH9aNN96ogwcPqmPHjsrKytI111zj7hABtyEheiA/P7+fnEHK2JijPn36aNSoUZozZ47Cw8PdHY5X+frrr9W+fXtmLf/AuXPndOTIkRqHJfbu3asePXo4LLiP5oGE6IHqMlnm6quvbsRIvEdISIg+/fRT9erVy92heBWz2axNmzapf//+PD3l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"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"evaluateAndShowAttention('Hän on opettaja')"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:46:15.840433Z",
"iopub.execute_input": "2024-05-25T14:46:15.841005Z",
"iopub.status.idle": "2024-05-25T14:46:16.232003Z",
"shell.execute_reply.started": "2024-05-25T14:46:15.840973Z",
"shell.execute_reply": "2024-05-25T14:46:16.230365Z"
},
"trusted": true
},
"execution_count": 47,
"outputs": [
{
"name": "stdout",
"text": "input = han on opettaja\noutput = he is a teacher <EOS>\n",
"output_type": "stream"
},
{
"name": "stderr",
"text": "/tmp/ipykernel_34/2052950992.py:8: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_xticklabels([''] + input_sentence.split(' ') +\n/tmp/ipykernel_34/2052950992.py:10: UserWarning: FixedFormatter should only be used together with FixedLocator\n ax.set_yticklabels([''] + output_words)\n",
"output_type": "stream"
},
{
"output_type": "display_data",
"data": {
"text/plain": "<Figure size 640x480 with 2 Axes>",
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAcUAAAHOCAYAAADpBhJHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/xnp5ZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAx5klEQVR4nO3deVxU9f7H8feAAioMriwqgpZL7lsalmmFWT2ybDUqF8qysl8p9TC95VqJWZlZloqa2i21bLmWSwuKXdMs8Wq5pOYGWihKikJCMvP7g2Fuc8UjBnhmOK8nj/O4zpmzfObE5TOf7/l+v8fmdDqdAgAA8jM7AAAAvAVJEQAAF5IiAAAuJEUAAFxIigAAuJAUAQBwISkCAOBCUgQAwIWkCACAC0kRAAAXkiIAAC4kRQAAXKqYHQAAcyxZskQffPCB0tPTVVBQ4PHepk2bTIoKMBeVImBB06ZNU0JCgsLDw/Wf//xHXbp0UZ06dbR3717deOONZocHmMbGo6MA62nRooXGjh2r+Ph4hYSEaMuWLWrSpInGjBmj7Oxsvfnmm2aHCJiCShGwoPT0dHXr1k2SVK1aNZ08eVKS1L9/fy1cuNDM0ABTkRQBC4qIiFB2drYkqVGjRvruu+8kSfv27RONR7AykiJgQddee62WLl0qSUpISNDw4cPVq1cv9evXT7fddpvJ0QHm4Z4iYEEOh0MOh0NVqhR1QF+0aJHWrVunpk2basiQIQoICDA5QsAcJEUAOI/CwkJt27ZNLVu2dH+RQOXEf13AIn788Ue1bt1afn5++vHHHw23DQ4OVlRUlKpWrXqRovNun332me644w4tWLBA9913n9nhoAJRKQIW4efnp8zMTIWFhcnPz082m82wU01oaKhmzJihfv36XcQovdNtt92m9evXq02bNvrqq6/MDgcViKQIWMSBAwfUqFEj2Ww2HThwwHDb/Px8ffjhh0pOTtb+/fsvToBe6ujRo2rYsKE+/fRT3XLLLdq7d68aNmxodlioIDSfAhYRHR1d4r/P5bHHHlNaWlpFhuQTFi5cqNatW+uGG25Q9+7d9e6772rUqFFmh4UKQqUIWFheXl6Jc5+2bdvWpIi8T6dOnTRw4EA98cQTeueddzR58mTt2LHD7LBQQUiKgAVlZWUpISFBK1asKPH9wsLCixyRd9q6das6deqkQ4cOqW7dujp16pTCw8O1atUqde3a1ezwUAEYvA9Y0LBhw3T8+HFt2LBB1apV08qVKzV//nw1bdrUPagf0vz583X99derbt26kop65fbt21fz5s0zNzBUGCpFwIIiIyP1r3/9S126dJHdbtfGjRvVrFkzLV26VJMnT9batWvNDtF0hYWFatiwoaZNm6a77rrLvX7FihW67777lJmZySQHlRCVImBBubm5CgsLkyTVqlVLWVlZkqQ2bdrwLEWXI0eO6NFHH9Wtt97qsb53795KTExUZmamSZGhIlEpAhZ0+eWX64UXXlDv3r11yy23qGbNmkpKStK0adO0ZMkS7dmzx+wQAVOQFAEL+uc//6kzZ85o0KBBSktL0w033KDs7GwFBARo3rx5DNg/hwMHDig3N1ctWrSQnx8NbZURSRGA8vLy9PPPP6tRo0buTiVWNnfuXB0/flyJiYnudQ8//LDmzJkjSWrevLm++OILRUVFmRUiKghfdQALmjBhgvLy8tyvq1evro4dO6pGjRqaMGGCiZF5h1mzZqlWrVru1ytXrtQ777yjBQsW6IcfflDNmjU1fvx4EyNERaFSBCzI399fv/32m7uzTbFjx44pLCzM8uMU69Spo9TUVLVp00aS9OijjyorK0tLliyRJKWmpiohIUH79u0zM0xUACpFwIKcTqdsNttZ67ds2aLatWubEJF3+eOPP2S3292v161bp6uvvtr9ukmTJvQ+raSY+xSwkFq1aslms8lms6lZs2YeibGwsFCnTp3SI488YmKE3iE6OlppaWmKjo7W0aNHtW3bNl155ZXu9zMzMxUaGmpihKgoJEXAQqZOnSqn06kHHnhA48eP9/jDHhAQoJiYGMXGxpoYoXcYOHCghg4dqm3btmnVqlVq0aKFOnXq5H5/3bp1at26tYkRoqKQFAELGThwoCSpcePGuvLKK3mK/DmMGDFCeXl5+vjjjxUREaEPP/zQ4/1vv/1W8fHxJkWHikRHG8CC6GgDlIyviYAFneu7cH5+PvN5/sUff/yhr776Srt27ZIkNWvWTL169VK1atVMjgwVhaQIWMi0adMkSTabTbNnz1ZwcLD7vcLCQn3zzTdq0aKFWeF5laVLl2rw4ME6evSox/q6detqzpw56tOnj0mRoSLRfApYSOPGjSUVTVfWsGFD+fv7u98r7mgzYcIEyz8rcN26derZs6duueUW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AAALolIEABjieYoAALhYKSnSfAoAgAuVIgDAkJUqRZIiAMCYU1JZk5pv5ESaTwEAKEalCAAw5JRDTpVt8hKnfGOcIkkRAGDISvcUaT4FAMCFShEAcB5lrxR9pacNSREAYMhKzackRQCAoaIJwcvY0YYJwQEA8C1UigAAQzSfAgDgYqWkSPMpAAAuVIoAAGNOZznMfeoblSJJEQBgyOn6KesxfAHNpwAAuFApAgAMWWmcIkkRAGDISr1PSYoAAENWSorcUwQAwIVKEQBgyEqVIkkRAGDISkmR5lMAAFyoFAEAhooqxbINqfCVSpGkCAAwZqFp3iq8+dRms5W4LFq0yL1NYWGhXnvtNbVp00ZBQUGqVauWbrzxRn377bcexyosLNSkSZPUokULVatWTbVr11bXrl01e/bsiv4YAAALqJBK8ffff1fVqlUVHBwsSXrnnXd0ww03eGxTs2ZNSUUl9T333KOvv/5aL7/8sq677jrl5ORo+vTp6tmzpz788EP17dtXkjR+/HjNnDlTb775pjp37qycnBxt3LhRv//+u/u4v/76q8LCwlSlCkUwAJQHK819Wm6Z48yZM/riiy80b948ffbZZ9qwYYPatWsnqSgBRkRElLjfBx98oCVLlmjp0qXq06ePe/2sWbN07NgxDR48WL169VKNGjW0dOlSPfbYY7rrrrvc2xWfo1hycrLefvtt3X///Ro4cKDatGlTXh8RACyJ3qcX4KefftJTTz2lhg0basCAAapXr55Wr159VrI6l/fff1/NmjXzSIjFnnrqKR07dkxfffWVJCkiIkKrVq1SVlbWOY/3zDPP6PXXX9eOHTvUsWNHdezYUdOmTTPc56/y8/OVk5PjsQAArOFvJcVjx47p9ddfV8eOHdW5c2ft3btXb731ln777Te99dZbio2N9dg+Pj5ewcHBHkt6erokadeuXbrssstKPE/x+l27dkmSpkyZoqysLEVERKht27Z65JFHtGLFCo99goKC1K9fPy1btkyHDh3SgAEDNG/ePDVo0EB9+/bVJ598ojNnzpzzsyUlJSk0NNS9REVF/Z1LBACVRtGE4GVffMHfSopvvPGGhg0bpuDgYP3yyy/65JNPdPvttysgIKDE7V977TVt3rzZY6lfv777/dKW1S1bttTWrVv13Xff6YEHHtCRI0fUp08fDR48uMTtw8LCNGzYMG3atEn/+te/tH79et1+++3aunXrOc8xatQonThxwr1kZGSUKjYAqKyKm0/LuviCv3VP8eGHH1aVKlW0YMECtWrVSnfccYf69++vnj17ys/v7DwbERGhSy+9tMRjNWvWTDt27CjxveL1zZo1c6/z8/PT5Zdfrssvv1zDhg3TP//5T/Xv31/PPvusGjdu7LH/yZMntWTJEr377rv65ptv1KNHDw0cOFAtW7Y852cLDAxUYGDgea8BAFgF9xTPo379+nruuee0a9curVy5UgEBAbr99tsVHR2tkSNHatu2baU+1j333KPdu3frs88+O+u9V199VXXq1FGvXr3OuX9xgsvNzZVUNGxjxYoVuvfeexUeHq5Jkybpuuuu0969e5WSkqIBAwacs6IFAFhbmTvadOvWTTNnzlRmZqZefvllbd68We3atdNPP/3k3ub48ePKzMz0WIqT2D333KPbbrtNAwcO1Jw5c7R//379+OOPGjJkiJYuXarZs2erRo0akqQ777xTr732mjZs2KADBw4oNTVVQ4cOVbNmzdSiRQtJ0sSJExUfH6+QkBB9/fXX2rlzp5599lk1atSorB8VACzJSs2nNmcFRPrrr78qODhYdrtdNlvJT2tOSkrSyJEjJRUN55g6darmzZun3bt3KygoSLGxsRo9erSuvPJK9z7JyclauHChtm7dqhMnTigiIkLXXnutxo0bp+joaEnS/v37FRERoaCgoHL5LDk5OQoNDZVkO+dnQRFfuZFutmrVQswOwSfk5dHz+3yK/z6dOHFCdru9wo5fq1aEbLay1VBOp0O//55ZYbGWlwpJipUJSbH0SIqlQ1IsHZLi+ZEUyx/TvgAAjJXHF14f+dJMUgQAGCqaos0a07zxPEUAAFyoFAEAhoq6nlhjnCJJEQBgyEpJkeZTAABcqBQBAIbKY7iVrwzZIikCAAwVtXyWtfm0XEKpcCRFAICh8rgfyD1FAAB8DJUiAMCQlSpFkiIAwFh5JDQfSYo0nwIA4EKlCAAw5JRDUtmeEuQrc5+SFAEAhqx0T5HmUwAAXKgUAQCGrFQpkhQBAIaslBRpPgUAwIVKEQBgyEqVIkkRAGCo6AkXZRySQVIEAFQGVqoUuacIAIALlSIAwJiF5j4lKQIADJXHFG2+Ms0bzacAALhQKQIADNH7FAAAF3qfAgBgQVSK5/HfbzdOX+k8BS/nK9+YzZaTk2N2CF6v+BpdjN8pq/zekhTP4+TJk395ZY1fClSs06dPmR2CTwgNDTU7BJ9x8uTJCrleAQEBioiIUGZmZrkcLyIiQgEBAeVyrIpic1ol/f9NDodDv/76q0JCQmSzle1Gc3nJyclRVFSUMjIyZLfbzQ7Ha3GdSofrVDreeJ2cTqdOnjyp+vXry8+vYu6GnT59WgUFBeVyrICAAAUFBZXLsSoKleJ5+Pn5qWHDhmaHUSK73e41/+f0Zlyn0uE6lY63XaeKrqiDgoK8PpGVJzraAADgQlIEAMCFpOiDAgMDNXbsWAUGBpodilfjOpUO16l0uE7WQEcbAABcqBQBAHAhKQIA4EJSBADAhaQIAIALSREAABeSIgAALiRFAABcSIoAALj8P/bLSA8+8gedAAAAAElFTkSuQmCC"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"torch.save(encoder.state_dict(), \"encoder.pt\")\n",
"torch.save(decoder.state_dict(), \"decoder.pt\")"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T14:50:24.773506Z",
"iopub.execute_input": "2024-05-25T14:50:24.774464Z",
"iopub.status.idle": "2024-05-25T14:50:24.795895Z",
"shell.execute_reply.started": "2024-05-25T14:50:24.774430Z",
"shell.execute_reply": "2024-05-25T14:50:24.794979Z"
},
"trusted": true
},
"execution_count": 48,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"# BLEU score"
],
"metadata": {}
},
{
"cell_type": "markdown",
"source": [
"Jako że korzystaliśmy z okrojonej wersji zbioru danych, słownik nie zawiera wszystkich słów pojawiających się w przykładach więc do ewaluacji wykorzystujemy część przykładów z treningu"
],
"metadata": {}
},
{
"cell_type": "code",
"source": [
"import pandas as pd\n",
"\n",
"\n",
"def filter_rows(row):\n",
" return len(row[\"English\"].split(' '))<MAX_LENGTH and \\\n",
" len(row[\"Finnish\"].split(' '))<MAX_LENGTH and \\\n",
" row[\"English\"].startswith(eng_prefixes)\n",
"data_file = pd.read_csv(\"/kaggle/input/anki-en-fin/fin.txt\", sep='\\t', names=[\"English\",\"Finnish\",\"attribution\"])\n",
"data_file[\"English\"] = data_file[\"English\"].apply(normalizeString)\n",
"data_file[\"Finnish\"] = data_file[\"Finnish\"].apply(normalizeString)\n",
"\n",
"filter_list = data_file.apply(filter_rows, axis=1)\n",
"\n",
"test_section = data_file[filter_list]\n",
"test_section = test_section.sample(frac=1).head(500)\n",
"test_section.head()"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:28:54.296348Z",
"iopub.execute_input": "2024-05-25T15:28:54.297253Z",
"iopub.status.idle": "2024-05-25T15:28:59.041172Z",
"shell.execute_reply.started": "2024-05-25T15:28:54.297211Z",
"shell.execute_reply": "2024-05-25T15:28:59.040201Z"
},
"trusted": true
},
"execution_count": 95,
"outputs": [
{
"execution_count": 95,
"output_type": "execute_result",
"data": {
"text/plain": " English ... attribution\n38027 i m very serious about this ... CC-BY 2.0 (France) Attribution: tatoeba.org #2...\n3803 i m not tired ... CC-BY 2.0 (France) Attribution: tatoeba.org #1...\n26924 i m not married either ... CC-BY 2.0 (France) Attribution: tatoeba.org #6...\n32009 he s sleeping like a baby ... CC-BY 2.0 (France) Attribution: tatoeba.org #2...\n21339 i m joking of course ... CC-BY 2.0 (France) Attribution: tatoeba.org #2...\n\n[5 rows x 3 columns]",
"text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th>English</th>\n <th>Finnish</th>\n <th>attribution</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>38027</th>\n <td>i m very serious about this</td>\n <td>olen hyvin tosissani tasta</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #2...</td>\n </tr>\n <tr>\n <th>3803</th>\n <td>i m not tired</td>\n <td>en ole vasynyt</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #1...</td>\n </tr>\n <tr>\n <th>26924</th>\n <td>i m not married either</td>\n <td>minakaan en ole naimisissa</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #6...</td>\n </tr>\n <tr>\n <th>32009</th>\n <td>he s sleeping like a baby</td>\n <td>han nukkuu kuin pikkuvauva</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #2...</td>\n </tr>\n <tr>\n <th>21339</th>\n <td>i m joking of course</td>\n <td>se oli vitsi tietenkin</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #2...</td>\n </tr>\n </tbody>\n</table>\n</div>"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"test_section[\"English_tokenized\"] = test_section[\"English\"].apply(lambda x: x.split())"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:29:07.110416Z",
"iopub.execute_input": "2024-05-25T15:29:07.110816Z",
"iopub.status.idle": "2024-05-25T15:29:07.117378Z",
"shell.execute_reply.started": "2024-05-25T15:29:07.110786Z",
"shell.execute_reply": "2024-05-25T15:29:07.116136Z"
},
"trusted": true
},
"execution_count": 96,
"outputs": []
},
{
"cell_type": "code",
"source": [
"test_section.head()[\"English_tokenized\"]"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:29:10.203170Z",
"iopub.execute_input": "2024-05-25T15:29:10.203540Z",
"iopub.status.idle": "2024-05-25T15:29:10.212993Z",
"shell.execute_reply.started": "2024-05-25T15:29:10.203511Z",
"shell.execute_reply": "2024-05-25T15:29:10.211937Z"
},
"trusted": true
},
"execution_count": 97,
"outputs": [
{
"execution_count": 97,
"output_type": "execute_result",
"data": {
"text/plain": "38027 [i, m, very, serious, about, this]\n3803 [i, m, not, tired]\n26924 [i, m, not, married, either]\n32009 [he, s, sleeping, like, a, baby]\n21339 [i, m, joking, of, course]\nName: English_tokenized, dtype: object"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"test_section[\"English_translated\"] = test_section[\"Finnish\"].apply(lambda x: translate(x, tokenized=True))"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:30:53.183117Z",
"iopub.execute_input": "2024-05-25T15:30:53.183937Z",
"iopub.status.idle": "2024-05-25T15:30:56.313012Z",
"shell.execute_reply.started": "2024-05-25T15:30:53.183902Z",
"shell.execute_reply": "2024-05-25T15:30:56.312202Z"
},
"trusted": true
},
"execution_count": 100,
"outputs": []
},
{
"cell_type": "code",
"source": [
"test_section.head()"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:31:06.745381Z",
"iopub.execute_input": "2024-05-25T15:31:06.746471Z",
"iopub.status.idle": "2024-05-25T15:31:06.771839Z",
"shell.execute_reply.started": "2024-05-25T15:31:06.746417Z",
"shell.execute_reply": "2024-05-25T15:31:06.770679Z"
},
"trusted": true
},
"execution_count": 101,
"outputs": [
{
"execution_count": 101,
"output_type": "execute_result",
"data": {
"text/plain": " English ... English_translated\n38027 i m very serious about this ... [i, m, in, french]\n3803 i m not tired ... [i, not, tired]\n26924 i m not married either ... [i, m, not, married, either]\n32009 he s sleeping like a baby ... [he, is, as, a, pianist]\n21339 i m joking of course ... [i, m, joking, of, course]\n\n[5 rows x 5 columns]",
"text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th>English</th>\n <th>Finnish</th>\n <th>attribution</th>\n <th>English_tokenized</th>\n <th>English_translated</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>38027</th>\n <td>i m very serious about this</td>\n <td>olen hyvin tosissani tasta</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #2...</td>\n <td>[i, m, very, serious, about, this]</td>\n <td>[i, m, in, french]</td>\n </tr>\n <tr>\n <th>3803</th>\n <td>i m not tired</td>\n <td>en ole vasynyt</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #1...</td>\n <td>[i, m, not, tired]</td>\n <td>[i, not, tired]</td>\n </tr>\n <tr>\n <th>26924</th>\n <td>i m not married either</td>\n <td>minakaan en ole naimisissa</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #6...</td>\n <td>[i, m, not, married, either]</td>\n <td>[i, m, not, married, either]</td>\n </tr>\n <tr>\n <th>32009</th>\n <td>he s sleeping like a baby</td>\n <td>han nukkuu kuin pikkuvauva</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #2...</td>\n <td>[he, s, sleeping, like, a, baby]</td>\n <td>[he, is, as, a, pianist]</td>\n </tr>\n <tr>\n <th>21339</th>\n <td>i m joking of course</td>\n <td>se oli vitsi tietenkin</td>\n <td>CC-BY 2.0 (France) Attribution: tatoeba.org #2...</td>\n <td>[i, m, joking, of, course]</td>\n <td>[i, m, joking, of, course]</td>\n </tr>\n </tbody>\n</table>\n</div>"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"candidate_corpus = test_section[\"English_translated\"].values\n",
"references_corpus = test_section[\"English_tokenized\"].values.tolist()\n",
"x = candidate_corpus.tolist()\n",
"y = [[el] for el in references_corpus]\n",
"#print(references_corpus[:5])\n",
"#print(candidate_corpus[:5])"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:43:29.441911Z",
"iopub.execute_input": "2024-05-25T15:43:29.442752Z",
"iopub.status.idle": "2024-05-25T15:43:29.447799Z",
"shell.execute_reply.started": "2024-05-25T15:43:29.442721Z",
"shell.execute_reply": "2024-05-25T15:43:29.446877Z"
},
"trusted": true
},
"execution_count": 118,
"outputs": []
},
{
"cell_type": "code",
"source": [
"y[:5]"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:43:30.474463Z",
"iopub.execute_input": "2024-05-25T15:43:30.475080Z",
"iopub.status.idle": "2024-05-25T15:43:30.482690Z",
"shell.execute_reply.started": "2024-05-25T15:43:30.475039Z",
"shell.execute_reply": "2024-05-25T15:43:30.481686Z"
},
"trusted": true
},
"execution_count": 119,
"outputs": [
{
"execution_count": 119,
"output_type": "execute_result",
"data": {
"text/plain": "[[['i', 'm', 'very', 'serious', 'about', 'this']],\n [['i', 'm', 'not', 'tired']],\n [['i', 'm', 'not', 'married', 'either']],\n [['he', 's', 'sleeping', 'like', 'a', 'baby']],\n [['i', 'm', 'joking', 'of', 'course']]]"
},
"metadata": {}
}
]
},
{
"cell_type": "code",
"source": [
"from torchtext.data.metrics import bleu_score\n",
"\n",
"bleu_score(x, y)"
],
"metadata": {
"execution": {
"iopub.status.busy": "2024-05-25T15:43:36.654035Z",
"iopub.execute_input": "2024-05-25T15:43:36.654953Z",
"iopub.status.idle": "2024-05-25T15:43:36.916617Z",
"shell.execute_reply.started": "2024-05-25T15:43:36.654906Z",
"shell.execute_reply": "2024-05-25T15:43:36.915429Z"
},
"trusted": true
},
"execution_count": 120,
"outputs": [
{
"execution_count": 120,
"output_type": "execute_result",
"data": {
"text/plain": "0.5885258316993713"
},
"metadata": {}
}
]
}
]
}