{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "8NIm_0b_sjJc", "outputId": "615bda96-593f-4851-b6e6-6acb84376b93" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: sacrebleu in /usr/local/lib/python3.10/dist-packages (2.4.3)\n", "Requirement already satisfied: portalocker in /usr/local/lib/python3.10/dist-packages (from sacrebleu) (2.10.1)\n", "Requirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from sacrebleu) (2024.9.11)\n", "Requirement already satisfied: tabulate>=0.8.9 in /usr/local/lib/python3.10/dist-packages (from sacrebleu) (0.9.0)\n", "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.10/dist-packages (from sacrebleu) (1.26.4)\n", "Requirement already satisfied: colorama in /usr/local/lib/python3.10/dist-packages (from sacrebleu) (0.4.6)\n", "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from sacrebleu) (5.3.0)\n" ] } ], "source": [ "!pip install sacrebleu\n", "\n", "import torch\n", "import torch.nn as nn\n", "import torch.optim as optim\n", "from torch.utils.data import DataLoader, Dataset\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import sacrebleu\n", "import json\n", "import csv\n", "from collections import Counter" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "XAapN08evSpV", "outputId": "61281ff6-7979-48a5-9da9-a92d17f17210" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "EN to IC\n", "\n", " give three tips for staying healthy \n", " gefðu þrjú ráð til að halda heilsu \n", "\n", "IC to EN\n", "\n", " gefðu þrjú ráð til að halda heilsu \n", " give three tips for staying healthy \n", "\n", "\n", "EN to IC\n", "\n", " 1 eat a balanced and nutritious diet make sure your meals are inclusive of a variety of fruits and vegetables lean protein whole grains and healthy fats this helps to provide your body with the essential nutrients to function at its best and can help prevent chronic diseases 2 engage in regular physical activity exercise is crucial for maintaining strong bones muscles and cardiovascular health aim for at least 150 minutes of moderate aerobic exercise or 75 minutes of vigorous exercise each week 3 get enough sleep getting enough quality sleep is crucial for physical and mental wellbeing it helps to regulate mood improve cognitive function and supports healthy growth and immune function aim for 79 hours of sleep each night \n", " 1 borðaðu hollt og næringarríkt mataræði gakktu úr skugga um að máltíðirnar þínar innihaldi margs konar ávexti og grænmeti magurt prótein heilkorn og holla fitu þetta hjálpar til við að veita líkamanum nauðsynleg næringarefni til að virka sem best og getur hjálpað til við að koma í veg fyrir langvinna sjúkdóma 2 taktu þátt í reglulegri hreyfingu hreyfing er mikilvæg til að viðhalda sterkum beinum vöðvum og hjarta og æðaheilbrigði miðaðu við að minnsta kosti 150 mínútur af hóflegri þolþjálfun eða 75 mínútur af öflugri hreyfingu í hverri viku 3 fáðu nægan svefn að fá nægan gæðasvefn skiptir sköpum fyrir líkamlega og andlega vellíðan það hjálpar til við að stjórna skapi bæta vitræna virkni og styðja við heilbrigðan vöxt og ónæmisvirkni miðaðu við 79 tíma svefn á hverri nóttu \n", "\n", "IC to EN\n", "\n", " 1 borðaðu hollt og næringarríkt mataræði gakktu úr skugga um að máltíðirnar þínar innihaldi margs konar ávexti og grænmeti magurt prótein heilkorn og holla fitu þetta hjálpar til við að veita líkamanum nauðsynleg næringarefni til að virka sem best og getur hjálpað til við að koma í veg fyrir langvinna sjúkdóma 2 taktu þátt í reglulegri hreyfingu hreyfing er mikilvæg til að viðhalda sterkum beinum vöðvum og hjarta og æðaheilbrigði miðaðu við að minnsta kosti 150 mínútur af hóflegri þolþjálfun eða 75 mínútur af öflugri hreyfingu í hverri viku 3 fáðu nægan svefn að fá nægan gæðasvefn skiptir sköpum fyrir líkamlega og andlega vellíðan það hjálpar til við að stjórna skapi bæta vitræna virkni og styðja við heilbrigðan vöxt og ónæmisvirkni miðaðu við 79 tíma svefn á hverri nóttu \n", " 1 eat a balanced and nutritious diet make sure your meals are inclusive of a variety of fruits and vegetables lean protein whole grains and healthy fats this helps to provide your body with the essential nutrients to function at its best and can help prevent chronic diseases 2 engage in regular physical activity exercise is crucial for maintaining strong bones muscles and cardiovascular health aim for at least 150 minutes of moderate aerobic exercise or 75 minutes of vigorous exercise each week 3 get enough sleep getting enough quality sleep is crucial for physical and mental wellbeing it helps to regulate mood improve cognitive function and supports healthy growth and immune function aim for 79 hours of sleep each night \n", "\n", "\n", "EN to IC\n", "\n", " what are the three primary colors \n", " hverjir eru þrír aðallitirnir \n", "\n", "IC to EN\n", "\n", " hverjir eru þrír aðallitirnir \n", " what are the three primary colors \n", "\n", "\n", "EN to IC\n", "\n", " the three primary colors are red blue and yellow these colors are called primary because they cannot be created by mixing other colors and all other colors can be made by combining them in various proportions in the additive color system used for light the primary colors are red green and blue rgb \n", " aðallitirnir þrír eru rauður blár og gulur þessir litir eru kallaðir frumefni vegna þess að ekki er hægt að búa þá til með því að blanda öðrum litum og alla aðra liti er hægt að búa til með því að sameina þá í ýmsum hlutföllum í auklitakerfinu notað fyrir ljós eru aðallitirnir rauður grænn og blár rgb \n", "\n", "IC to EN\n", "\n", " aðallitirnir þrír eru rauður blár og gulur þessir litir eru kallaðir frumefni vegna þess að ekki er hægt að búa þá til með því að blanda öðrum litum og alla aðra liti er hægt að búa til með því að sameina þá í ýmsum hlutföllum í auklitakerfinu notað fyrir ljós eru aðallitirnir rauður grænn og blár rgb \n", " the three primary colors are red blue and yellow these colors are called primary because they cannot be created by mixing other colors and all other colors can be made by combining them in various proportions in the additive color system used for light the primary colors are red green and blue rgb \n", "\n", "\n", "EN to IC\n", "\n", " describe the structure of an atom \n", " lýstu byggingu atóms \n", "\n", "IC to EN\n", "\n", " lýstu byggingu atóms \n", " describe the structure of an atom \n", "\n", "\n" ] } ], "source": [ "DEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", "\n", "\n", "# Load the Icelandic_cleaned.json dataset\n", "with open('/content/Icelandic_cleaned.json', 'r', encoding='utf-8') as f:\n", " data = json.load(f)\n", "\n", "# Extract the first 1,000 English and Icelandic sentences for BLEU and CHRF calculation\n", "en_sentences = [entry['input'] for entry in data[:1000]]\n", "ic_sentences = [entry['output'] for entry in data[:1000]]\n", "\n", "# Tokenizer and Vectorization\n", "tokenizer = lambda x: x.split()\n", "\n", "def build_vocab(sentences):\n", " counter = Counter()\n", " for sentence in sentences:\n", " counter.update(tokenizer(sentence))\n", " return counter\n", "\n", "en_vocab = build_vocab(en_sentences)\n", "ic_vocab = build_vocab(ic_sentences)\n", "\n", "# Adding special tokens\n", "en_vocab = {'': 1, '': 2, '': 0, '': 3, **en_vocab}\n", "ic_vocab = {'': 1, '': 2, '': 0, '': 3, **ic_vocab}\n", "\n", "def sentence_to_tensor(sentence, vocab, max_len=MAX_LEN):\n", " tokens = tokenizer(sentence)\n", " indices = [vocab.get(token, vocab['']) for token in tokens]\n", " indices = [vocab['']] + indices + [vocab['']]\n", " if len(indices) < max_len:\n", " indices += [vocab['']] * (max_len - len(indices))\n", " else:\n", " indices = indices[:max_len]\n", " return torch.tensor(indices)\n", "\n", "\n", "VOCAB_SIZE = 10000\n", "EMBEDDING_DIM = 256\n", "HIDDEN_DIM = 512\n", "BATCH_SIZE = 32\n", "NUM_EPOCHS = 10\n", "MAX_LEN = 50\n", "\n", "# Prepare dataset and dataloaders\n", "en_tensor_sentences = [sentence_to_tensor(s, en_vocab) for s in en_sentences]\n", "ic_tensor_sentences = [sentence_to_tensor(s, ic_vocab) for s in ic_sentences]\n", "\n", "# Split data into training and validation sets (80% train, 20% validation)\n", "train_size = int(0.8 * len(en_tensor_sentences))\n", "train_en, val_en = en_tensor_sentences[:train_size], en_tensor_sentences[train_size:]\n", "train_ic, val_ic = ic_tensor_sentences[:train_size], ic_tensor_sentences[train_size:]\n", "\n", "# Sample Data Printing in Specified Format\n", "def print_sample_data(en_sentences, ic_sentences):\n", " for i in range(5):\n", " en_sample = en_sentences[i]\n", " ic_sample = ic_sentences[i]\n", "\n", " print(\"EN to IC\")\n", " print(\"\")\n", " print(f\" {en_sample} \")\n", " print(f\" {ic_sample} \")\n", " print(\"\")\n", "\n", " print(\"IC to EN\")\n", " print(\"\")\n", " print(f\" {ic_sample} \")\n", " print(f\" {en_sample} \")\n", " print(\"\")\n", " print()\n", "\n", "print_sample_data(en_sentences, ic_sentences)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "id": "nzbNHJI1vSlg" }, "outputs": [], "source": [ "# Custom Dataset\n", "class TranslationDataset(Dataset):\n", " def __init__(self, en_sentences, ic_sentences):\n", " self.en_sentences = en_sentences\n", " self.ic_sentences = ic_sentences\n", "\n", " def __len__(self):\n", " return len(self.en_sentences)\n", "\n", " def __getitem__(self, idx):\n", " return self.en_sentences[idx], self.ic_sentences[idx]\n", "\n", "# Prepare dataloader\n", "train_dataset = TranslationDataset(train_en, train_ic)\n", "val_dataset = TranslationDataset(val_en, val_ic)\n", "\n", "# Define a collate_fn to pad sequences dynamically\n", "def collate_fn(batch):\n", " en_batch, ic_batch = zip(*batch)\n", " en_batch = torch.stack(en_batch, dim=0)\n", " ic_batch = torch.stack(ic_batch, dim=0)\n", " return en_batch, ic_batch\n", "\n", "train_dataloader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, collate_fn=collate_fn)\n", "val_dataloader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, collate_fn=collate_fn)\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "id": "3tVw3ao4vSiX" }, "outputs": [], "source": [ "\n", "# Seq2Seq Model\n", "class Seq2SeqModel(nn.Module):\n", " def __init__(self, input_dim, output_dim, embedding_dim, hidden_dim, num_layers=1):\n", " super(Seq2SeqModel, self).__init__()\n", "\n", " self.encoder_embedding = nn.Embedding(input_dim, embedding_dim)\n", " self.encoder_lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers, batch_first=True)\n", "\n", " self.decoder_embedding = nn.Embedding(output_dim, embedding_dim)\n", " self.decoder_lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers, batch_first=True)\n", " self.fc_out = nn.Linear(hidden_dim, output_dim)\n", "\n", " def forward(self, src, trg):\n", " embedded_src = self.encoder_embedding(src)\n", " encoder_output, (hidden, cell) = self.encoder_lstm(embedded_src)\n", "\n", " embedded_trg = self.decoder_embedding(trg)\n", " decoder_output, _ = self.decoder_lstm(embedded_trg, (hidden, cell))\n", "\n", " output = self.fc_out(decoder_output)\n", " return output\n", "\n", "# Initialize the Seq2Seq model\n", "model = Seq2SeqModel(len(en_vocab), len(ic_vocab), EMBEDDING_DIM, HIDDEN_DIM, num_layers=1).to(DEVICE)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "caqExHCzvSgZ", "outputId": "e03cd84e-4e07-4cae-f804-406b98cfa0dd" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10, Training Loss: 4.162079634666443, Validation Loss: 1.783459918839591\n", "Epoch 2/10, Training Loss: 1.0344110178947448, Validation Loss: 0.4918278966631208\n", "Epoch 3/10, Training Loss: 0.2632215261459351, Validation Loss: 0.12271245462553841\n", "Epoch 4/10, Training Loss: 0.07123038023710251, Validation Loss: 0.04314851335116795\n", "Epoch 5/10, Training Loss: 0.030836958587169647, Validation Loss: 0.02404651258672987\n", "Epoch 6/10, Training Loss: 0.01885295122861862, Validation Loss: 0.01633326443178313\n", "Epoch 7/10, Training Loss: 0.013474887125194073, Validation Loss: 0.012323189526796341\n", "Epoch 8/10, Training Loss: 0.010358258336782455, Validation Loss: 0.009776035456785135\n", "Epoch 9/10, Training Loss: 0.00829771364107728, Validation Loss: 0.008006346212433917\n", "Epoch 10/10, Training Loss: 0.006895635910332203, Validation Loss: 0.006732985709926912\n" ] } ], "source": [ "# Define the loss function and optimizer\n", "criterion = nn.CrossEntropyLoss(ignore_index=ic_vocab[''])\n", "optimizer = optim.Adam(model.parameters(), lr=0.001)\n", "\n", "# Function to train the model\n", "def train_model(model, train_dataloader, val_dataloader, optimizer, criterion, num_epochs=10):\n", " model.to(DEVICE)\n", " train_losses, val_losses = [], []\n", "\n", " for epoch in range(num_epochs):\n", " model.train()\n", " epoch_train_loss = 0\n", " for en_batch, ic_batch in train_dataloader:\n", " en_batch, ic_batch = en_batch.to(DEVICE), ic_batch.to(DEVICE)\n", " ic_batch = ic_batch.long()\n", "\n", " optimizer.zero_grad()\n", " output = model(en_batch, ic_batch)\n", "\n", " output_dim = output.shape[-1]\n", " output = output.reshape(-1, output_dim)\n", " ic_batch = ic_batch.reshape(-1)\n", " loss = criterion(output, ic_batch)\n", "\n", " loss.backward()\n", " optimizer.step()\n", "\n", " epoch_train_loss += loss.item()\n", "\n", " train_losses.append(epoch_train_loss / len(train_dataloader))\n", "\n", " model.eval()\n", " epoch_val_loss = 0\n", " with torch.no_grad():\n", " for en_batch, ic_batch in val_dataloader:\n", " en_batch, ic_batch = en_batch.to(DEVICE), ic_batch.to(DEVICE)\n", " ic_batch = ic_batch.long()\n", "\n", " output = model(en_batch, ic_batch)\n", " output_dim = output.shape[-1]\n", " output = output.reshape(-1, output_dim)\n", " ic_batch = ic_batch.reshape(-1)\n", "\n", " loss = criterion(output, ic_batch)\n", " epoch_val_loss += loss.item()\n", "\n", " val_losses.append(epoch_val_loss / len(val_dataloader))\n", "\n", " print(f'Epoch {epoch+1}/{num_epochs}, Training Loss: {train_losses[-1]}, Validation Loss: {val_losses[-1]}')\n", "\n", " return train_losses, val_losses\n", "\n", "train_losses, val_losses = train_model(model, train_dataloader, val_dataloader, optimizer, criterion, num_epochs=NUM_EPOCHS)\n", "\n", "# Save the trained model\n", "torch.save(model.state_dict(), 'seq2seq_translation_model.pth')\n", "\n", "\n", "def translate_new_sentence(model, sentence, src_vocab, tgt_vocab, max_len=MAX_LEN):\n", " # Prepare input tensor for the source sentence (English)\n", " model.eval() # Set model to evaluation mode\n", " en_indices = [src_vocab.get(word, src_vocab['']) for word in sentence.split()] # Handle unknown words\n", " en_tensor = torch.tensor(en_indices).unsqueeze(0).to(DEVICE)\n", "\n", " # Initialize target sentence for translation (Croatian) with start token\n", " tgt_tensor = torch.tensor([tgt_vocab['']]).unsqueeze(0).to(DEVICE)\n", "\n", " translated_sentence = []\n", "\n", " for _ in range(max_len):\n", " with torch.no_grad():\n", " output = model(en_tensor, tgt_tensor)\n", "\n", " # Get the last output token's prediction (the next word)\n", " output_token = output.argmax(dim=-1)[:, -1]\n", "\n", " # Get the predicted word from the target vocabulary\n", " output_token_item = output_token.item()\n", "\n", " # Check if the token is within the target vocabulary range\n", " if output_token_item not in tgt_vocab.values():\n", " translated_word = '' # Map to if not found\n", " else:\n", " translated_word = list(tgt_vocab.keys())[list(tgt_vocab.values()).index(output_token_item)]\n", "\n", " # Append predicted word to the translated sentence\n", " translated_sentence.append(translated_word)\n", "\n", " # If we encounter an end token, stop the translation\n", " if translated_word == '':\n", " break\n", "\n", " # Update tgt_tensor for next prediction\n", " tgt_tensor = torch.cat((tgt_tensor, output_token.unsqueeze(0)), dim=-1)\n", "\n", " return ' '.join(translated_sentence)\n", "\n", "# BLEU and CHRF Scores Calculation\n", "def calculate_bleu_chrf(en_sentences, ic_sentences, model, en_vocab, ic_vocab, max_len=MAX_LEN):\n", " bleu_scores = []\n", " chrf_scores = []\n", "\n", " for en_sentence, ic_sentence in zip(en_sentences, ic_sentences):\n", " translated_sentence = translate_new_sentence(model, en_sentence, en_vocab, ic_vocab, max_len)\n", "\n", " bleu_score = sacrebleu.corpus_bleu([translated_sentence], [[ic_sentence]]).score\n", " bleu_scores.append(bleu_score)\n", "\n", " chrf_score = sacrebleu.corpus_chrf([translated_sentence], [[ic_sentence]]).score\n", " chrf_scores.append(chrf_score)\n", "\n", " return bleu_scores, chrf_scores\n", "\n", "lstm_bleu_scores, lstm_chrf_scores = calculate_bleu_chrf(en_sentences, ic_sentences, model, en_vocab, ic_vocab)\n", "\n", "# Save BLEU and CHRF scores to CSV\n", "with open('Seq2Seq_BLEU_CHRF_scores.csv', mode='w', newline='', encoding='utf-8') as file:\n", " writer = csv.writer(file)\n", " writer.writerow([\"BLEU Score\", \"CHRF Score\"])\n", " for bleu, chrf in zip(lstm_bleu_scores, lstm_chrf_scores):\n", " writer.writerow([bleu, chrf])\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 487 }, "id": "pllSNt5vK-AX", "outputId": "ba288b64-8026-4194-94fb-83cf9a54f7c2" }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0EAAAHWCAYAAACxAYILAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAABsR0lEQVR4nO3dd3xT9eLG8eck3ZNCSwEpexUERJbsUZShKMONCi4coOIWvSLiwHWvXuGKOC5OXEx/XhDZAqIiG9mrbMpqS1u6kvP7IzS0tEApbU/afN6vV15NTs54GlLt03O+3ximaZoCAAAAAC9hszoAAAAAAJQmShAAAAAAr0IJAgAAAOBVKEEAAAAAvAolCAAAAIBXoQQBAAAA8CqUIAAAAABehRIEAAAAwKtQggAAAAB4FUoQAI80ZMgQ1apVq0jbjh49WoZhFG8gD7N7924ZhqHPPvus1I9tGIZGjx7tfvzZZ5/JMAzt3r37gtvWqlVLQ4YMKdY8l/Je8Rbbtm3TNddco/DwcBmGoRkzZlgdCQAsRQkCcFEMwyjUbdGiRVZH9XqPPvqoDMPQ9u3bz7nOCy+8IMMwtG7dulJMdvEOHDig0aNHa82aNVZHccspou+8847VUS5o8ODBWr9+vV577TV9+eWXatWqldWRit20adN0yy23qE6dOgoKClLDhg315JNPKjEx0epoADyQj9UBAJQtX375ZZ7HX3zxhebOnZtveWxs7CUd5+OPP5bT6SzStv/4xz/03HPPXdLxy4NBgwZp3Lhxmjx5skaNGlXgOt98842aNm2qZs2aFfk4d955p2699Vb5+/sXeR8XcuDAAb388suqVauWrrjiijzPXcp7xRucOnVKy5cv1wsvvKDhw4dbHafEDB06VNWqVdMdd9yhGjVqaP369Ro/frxmzZqlVatWKTAw0OqIADwIJQjARbnjjjvyPP799981d+7cfMvPlpaWpqCgoEIfx9fXt0j5JMnHx0c+PvznrW3btqpXr56++eabAkvQ8uXLtWvXLr3xxhuXdBy73S673X5J+7gUl/Je8QZHjhyRJFWoUKHY9pmamqrg4OBi219xmDJlirp27ZpnWcuWLTV48GB9/fXXuu+++6wJBsAjcTkcgGLXtWtXXX755Vq5cqU6d+6soKAgPf/885KkmTNn6tprr1W1atXk7++vunXr6pVXXpHD4cizj7PHeeS+9Oijjz5S3bp15e/vr9atW2vFihV5ti1oTJBhGBo+fLhmzJihyy+/XP7+/mrSpIl+/vnnfPkXLVqkVq1aKSAgQHXr1tXEiRMLPc5oyZIluummm1SjRg35+/srJiZGjz/+uE6dOpXv+wsJCdH+/fvVr18/hYSEKCoqSk899VS+1yIxMVFDhgxReHi4KlSooMGDBxf6Ep9BgwZp8+bNWrVqVb7nJk+eLMMwdNtttykzM1OjRo1Sy5YtFR4eruDgYHXq1EkLFy684DEKGhNkmqZeffVVVa9eXUFBQerWrZv+/vvvfNseP35cTz31lJo2baqQkBCFhYWpd+/eWrt2rXudRYsWqXXr1pKku+++233JZc54qILGBKWmpurJJ59UTEyM/P391bBhQ73zzjsyTTPPehfzviiqhIQE3XvvvYqOjlZAQICaN2+uzz//PN963377rVq2bKnQ0FCFhYWpadOm+ve//+1+PisrSy+//LLq16+vgIAAVapUSR07dtTcuXPPeezRo0erZs2akqSnn35ahmHkea1Wr16t3r17KywsTCEhIYqLi9Pvv/+eZx85/76LFy/Www8/rMqVK6t69ern/Z7HjRunJk2aKCgoSBEREWrVqpUmT56cZ539+/frnnvuUXR0tPt1/+9//5tvX/v27VO/fv0UHBysypUr6/HHH9ecOXPyXXZ7dgGSpP79+0uSNm3alGf5hV5ryfVzN2LECPd7qF69enrzzTfznXUs6OdzzZo1lo3ZA1A4/KkUQIk4duyYevfurVtvvVV33HGHoqOjJbl+oQoJCdETTzyhkJAQLViwQKNGjVJycrLefvvtC+538uTJOnnypB544AEZhqG33npLAwYM0M6dOy94RmDp0qWaNm2aHn74YYWGhur999/XwIEDtWfPHlWqVEmS65fCXr16qWrVqnr55ZflcDg0ZswYRUVFFer7/uGHH5SWlqaHHnpIlSpV0p9//qlx48Zp3759+uGHH/Ks63A41LNnT7Vt21bvvPOO5s2bp3/+85+qW7euHnroIUmuMnHDDTdo6dKlevDBBxUbG6vp06dr8ODBhcozaNAgvfzyy5o8ebKuvPLKPMf+/vvv1alTJ9WoUUNHjx7VJ598ottuu03333+/Tp48qU8//VQ9e/bUn3/+me8StAsZNWqUXn31VfXp00d9+vTRqlWrdM011ygzMzPPejt37tSMGTN00003qXbt2jp8+LAmTpyoLl26aOPGjapWrZpiY2M1ZswYjRo1SkOHDlWnTp0kSe3bty/w2KZp6vrrr9fChQt177336oorrtCcOXP09NNPa//+/Xr33XfzrF+Y90VRnTp1Sl27dtX27ds1fPhw1a5dWz/88IOGDBmixMREPfbYY5KkuXPn6rbbblNcXJzefPNNSa5f3JctW+ZeZ/To0Ro7dqzuu+8+tWnTRsnJyfrrr7+0atUqXX311QUef8CAAapQoYIef/xx3XbbberTp49CQkIkSX///bc6deqksLAwPfPMM/L19dXEiRPVtWtXLV68WG3bts2zr4cfflhRUVEaNWqUUlNTz/k9f/zxx3r00Ud144036rHHHlN6errWrVunP/74Q7fffrsk6fDhw7rqqqvcJTQqKkqzZ8/Wvffeq+TkZI0YMcL9+sXFxWnPnj169NFHVa1aNX355ZdasGBBoV7/Q4cOSZIiIyPdywrzWqelpalLly7av3+/HnjgAdWoUUO//fabRo4cqYMHD+q9996TdOk/nwAsZALAJRg2bJh59n9KunTpYkoyP/zww3zrp6Wl5Vv2wAMPmEFBQWZ6erp72eDBg82aNWu6H+/atcuUZFaqVMk8fvy4e/nMmTNNSeb//d//uZe99NJL+TJJMv38/Mzt27e7l61du9aUZI4bN869rG/fvmZQUJC5f/9+97Jt27aZPj4++fZZkIK+v7Fjx5qGYZjx8fF5vj9J5pgxY/Ks26JFC7Nly5buxzNmzDAlmW+99ZZ7WXZ2ttmpUydTkjlp0qQLZmrdurVZvXp10+FwuJf9/PPPpiRz4sSJ7n1mZGTk2e7EiRNmdHS0ec899+RZLsl86aWX3I8nTZpkSjJ37dplmqZpJiQkmH5+fua1115rOp1O93rPP/+8KckcPHiwe1l6enqeXKbp+rf29/fP89qsWLHinN/v2e+VnNfs1VdfzbPejTfeaBqGkec9UNj3RUFy3pNvv/32Odd57733TEnmV1995V6WmZlptmvXzgwJCTGTk5NN0zTNxx57zAwLCzOzs7PPua/mzZub11577XkzXUzOfv36mX5+fuaOHTvcyw4cOGCGhoaanTt3di/L+fft2LHjefPluOGGG8wmTZqcd517773XrFq1qnn06NE8y2+99VYzPDzc/XOU8/p9//337nVSU1PNevXqmZLMhQsXXvA4drvd3Lp1q3tZYV7rV155xQwODs6znWma5nPPPWfa7XZzz549pmkWz88nAGtwORyAEuHv76+777473/Lcg5NPnjypo0ePqlOnTkpLS9PmzZsvuN9bbrlFERER7sc5ZwV27tx5wW179OihunXruh83a9ZMYWFh7m0dDofmzZunfv36qVq1au716tWrp969e19w/1Le7y81NVVHjx5V+/btZZqmVq9enW/9Bx98MM/jTp065fleZs2aJR8fH/eZIck1BueRRx4pVB7JNY5r3759+vXXX93LJk+eLD8/P910003uffr5+UmSnE6njh8/ruzsbLVq1arAS+nOZ968ecrMzNQjjzyS5xLCnL/u5+bv7y+bzfW/IofDoWPHjikkJEQNGza86OPmmDVrlux2ux599NE8y5988kmZpqnZs2fnWX6h98WlmDVrlqpUqaLbbrvNvczX11ePPvqoUlJStHjxYkmu8TqpqannvbStQoUK+vvvv7Vt27ZLzuVwOPTLL7+oX79+qlOnjnt51apVdfvtt2vp0qVKTk7Os839999fqLFfFSpU0L59+/JdpprDNE1NnTpVffv2lWmaOnr0qPvWs2dPJSUluf/tZ82apapVq+rGG290bx8UFKShQ4deMMfkyZP16aef6sknn1T9+vXz5LvQa/3DDz+oU6dOioiIyJOvR48ecjgc7p+l4vj5BGANShCAEnHZZZe5f6nO7e+//1b//v0VHh6usLAwRUVFuSdVSEpKuuB+a9SokedxTiE6ceLERW+bs33OtgkJCTp16pTq1auXb72ClhVkz549GjJkiCpWrOge59OlSxdJ+b+/gICAfJfZ5c4jSfHx8apatar7EqYcDRs2LFQeSbr11ltlt9vdYzLS09M1ffp09e7dO0+h/Pzzz9WsWTP3eJOoqCj973//K9S/S27x8fGSlOcXT0mKiorKczzJVbjeffdd1a9fX/7+/oqMjFRUVJTWrVt30cfNffxq1aopNDQ0z/KcGQtz8uW40PviUsTHx6t+/fruoneuLA8//LAaNGig3r17q3r16rrnnnvyjUsaM2aMEhMT1aBBAzVt2lRPP/10kac2P3LkiNLS0gp8H8XGxsrpdGrv3r15lteuXbtQ+3722WcVEhKiNm3aqH79+ho2bJiWLVuW59iJiYn66KOPFBUVleeW84eThIQESa7Xp169evnG413o/b9kyRLde++96tmzp1577bU8zxXmtd62bZt+/vnnfPl69OiRL9+l/nwCsAZjggCUiIKmo01MTFSXLl0UFhamMWPGqG7dugoICNCqVav07LPPFmqa43P9Jdo8a8B7cW9bGA6HQ1dffbWOHz+uZ599Vo0aNVJwcLD279+vIUOG5Pv+SmtGtcqVK+vqq6/W1KlT9Z///Ef/93//p5MnT2rQoEHudb766isNGTJE/fr109NPP63KlSvLbrdr7Nix2rFjR4lle/311/Xiiy/qnnvu0SuvvKKKFSvKZrNpxIgRpTbtdUm/LwqjcuXKWrNmjebMmaPZs2dr9uzZmjRpku666y73JAqdO3fWjh07NHPmTP3yyy/65JNP9O677+rDDz8slZnPCjvFdGxsrLZs2aKffvpJP//8s6ZOnaoPPvhAo0aN0ssvv+z+d73jjjvOOXbmUqZsX7t2ra6//npdfvnlmjJlSr6ZIgvzWjudTl199dV65plnCjxGgwYNipwPgGegBAEoNYsWLdKxY8c0bdo0de7c2b18165dFqY6o3LlygoICCjww0XP94GjOdavX6+tW7fq888/11133eVefr7Lbi6kZs2amj9/vlJSUvL8tXnLli0XtZ9Bgwbp559/1uzZszV58mSFhYWpb9++7uenTJmiOnXqaNq0aXn+6v7SSy8VKbPk+mt67kutjhw5ku/sypQpU9StWzd9+umneZYnJibmGcxemJn5ch9/3rx5OnnyZJ6zQTmXW+bkKw01a9bUunXr5HQ685wNKiiLn5+f+vbtq759+8rpdOrhhx/WxIkT9eKLL7rPRFasWFF333237r77bqWkpKhz584aPXr0RZegqKgoBQUFFfg+2rx5s2w2m2JiYoryLUuSgoODdcstt+iWW25RZmamBgwYoNdee00jR45UVFSUQkND5XA43GdWzqVmzZrasGGDTNPM8x441/t/x44d6tWrlypXrqxZs2blO0OT40Kvdd26dZWSklKofMXx8wmg9HE5HIBSk/MX99x/Yc/MzNQHH3xgVaQ87Ha7evTooRkzZujAgQPu5du3b883juRc20t5vz/TNPNNvXsx+vTpo+zsbE2YMMG9zOFwaNy4cRe1n379+ikoKEgffPCBZs+erQEDBiggIOC82f/44w8tX778ojP36NFDvr6+GjduXJ795cyolZvdbs93xuWHH37Q/v378yzL+UyawkwN3qdPHzkcDo0fPz7P8nfffVeGYRR6fFdx6NOnjw4dOqTvvvvOvSw7O1vjxo1TSEiI+1LJY8eO5dnOZrO5z4ZkZGQUuE5ISIjq1avnfv5i2O12XXPNNZo5c2aeqc0PHz6syZMnq2PHjgoLC7vo/RaU08/PT40bN5ZpmsrKypLdbtfAgQM1depUbdiwId/2OZ9rJLlevwMHDmjKlCnuZWlpafroo4/ybXfo0CFdc801stlsmjNnzjlndCzMa33zzTdr+fLlmjNnTr7tExMTlZ2d7c5XHD+fAEofZ4IAlJr27dsrIiJCgwcP1qOPPirDMPTll1+W6mVHFzJ69Gj98ssv6tChgx566CH3L9OXX3651qxZc95tGzVqpLp16+qpp57S/v37FRYWpqlTp17S2JK+ffuqQ4cOeu6557R79241btxY06ZNu+jxMiEhIerXr597XFDuS+Ek6brrrtO0adPUv39/XXvttdq1a5c+/PBDNW7cWCkpKRd1rJzPOxo7dqyuu+469enTR6tXr9bs2bPznN3JOe6YMWN09913q3379lq/fr2+/vrrPGeQJKlu3bqqUKGCPvzwQ4WGhio4OFht27YtcJxK37591a1bN73wwgvavXu3mjdvrl9++UUzZ87UiBEj8kyCUBzmz5+v9PT0fMv79eunoUOHauLEiRoyZIhWrlypWrVqacqUKVq2bJnee+8995mq++67T8ePH1f37t1VvXp1xcfHa9y4cbriiivc44caN26srl27qmXLlqpYsaL++usvTZkyRcOHDy9S7ldffVVz585Vx44d9fDDD8vHx0cTJ05URkaG3nrrrSK/Htdcc42qVKmiDh06KDo6Wps2bdL48eN17bXXur/fN954QwsXLlTbtm11//33q3Hjxjp+/LhWrVqlefPm6fjx45JckzGMHz9ed911l1auXKmqVavqyy+/LPCDl3v16qWdO3fqmWee0dKlS7V06VL3c9HR0e5pxAvzWj/99NP68ccfdd1112nIkCFq2bKlUlNTtX79ek2ZMkW7d+9WZGRksf18ArBA6U9IB6A8OdcU2eeaInfZsmXmVVddZQYGBprVqlUzn3nmGXPOnDn5prs91xTZBU1HrLOmbD7XFNnDhg3Lt23NmjXzTNlsmqY5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X1RWVpYk15mYl19+WWvXrpVhGDIMw5357Mvh1q9fr+7duyswMFCVKlXS0KFDlZKS4n5+yJAh6tevn9555x1VrVpVlSpV0rBhw9zHKoo9e/bohhtuUEhIiMLCwnTzzTfr8OEzsySvXbtW3bp1U2hoqMLCwtSyZUv99ddfkqT4+Hj17dtXERERCg4OVpMmTTRr1qwiZykMnxLdO9QjNlq/bDysBZsP67Ee9a2OAwAAUHqy0qTXq1lz7OcPSH7BF1zNx8dHd911lz777DO98MILMgxDkvTDDz/I4XDotttuU0pKilq2bKlnn31WYWFh+t///qc777xTdevWVZs2bS54DKfTqQEDBig6Olp//PGHkpKS8owfyhEaGqrPPvtM1apV0/r163X//fcrNDRUzzzzjG655RZt2LBBP//8s+bNmydJCg8Pz7eP1NRU9ezZU+3atdOKFSuUkJCg++67T8OHD89T9BYuXKiqVatq4cKF2r59u2655RZdccUVuv/++y/4/RT0/eUUoMWLFys7O1vDhg3TLbfcokWLFkmSBg0apBYtWmjChAmy2+1as2aNfH19Jbk+NzQzM1O//vqrgoODtXHjRoWEhFx0jotBCSphXRtFSZLW7ktSwsl0VQ4t3HTgAAAAKB333HOP3n77bS1evFhdu3aV5LoUbuDAge7Pp3zqqafc6z/yyCOaM2eOvv/++0KVoHnz5mnz5s2aM2eOqlVzlcLXX3893zief/zjH+77tWrV0lNPPaVvv/1WzzzzjAIDAxUSEiIfHx9VqVLlnMeaPHmy0tPT9cUXXyg42FUCx48fr759++rNN99UdLRrzHpERITGjx8vu92uRo0a6dprr9X8+fOLVILmz5+v9evXa9euXe7P8fziiy/UpEkTrVixQq1bt9aePXv09NNPq1GjRpKk+vXPnBzYs2ePBg4cqKZNm0qS6tSpc9EZLhYlqIRVDg1Q8+rhWrsvSYs2H9HNrT33A14BAACKlW+Q64yMVccupEaNGql9+/b673//q65du2r79u1asmSJxowZI0lyOBx6/fXX9f3332v//v3KzMxURkZGocf8bNq0STExMe4CJEnt2rXLt953332n999/Xzt27FBKSoqys7Mv+iNhNm3apObNm7sLkCR16NBBTqdTW7ZscZegJk2a5JmNuWrVqlq/fv1FHSv3MWNiYtwFSJIaN26sChUqaNOmTWrdurWeeOIJ3Xffffryyy/Vo0cP3XTTTapbt64k6dFHH9VDDz2kX375RT169NDAgQOLNA7rYnjUmKDyqnsj15tt/ubDF1gTAACgHDEM1yVpVtxOX9ZWWPfee6+mTp2qkydPatKkSapbt666dOkiSXr77bf173//W88++6wWLlyoNWvWqGfPnsrMzCy2l2r58uUaNGiQ+vTpo59++kmrV6/WCy+8UKzHyC3nUrQchmHI6XSWyLEk18x2f//9t6699lotWLBAjRs31vTp0yVJ9913n3bu3Kk777xT69evV6tWrTRu3LgSyyJRgkpFXKzr84KWbDuqjOz8HwILAAAAa918882y2WyaPHmyvvjiC91zzz3u8UHLli3TDTfcoDvuuEPNmzdXnTp1tHXr1kLvOzY2Vnv37tXBgwfdy37//fc86/z222+qWbOmXnjhBbVq1Ur169dXfHx8nnX8/PzkcJz/d8nY2FitXbtWqamp7mXLli2TzWZTw4YNC535YuR8f3v37nUv27hxoxITE9W4cWP3sgYNGujxxx/XL7/8ogEDBmjSpEnu52JiYvTggw9q2rRpevLJJ/Xxxx+XSNYclKBS0KRamKLD/JWW6dAfO49bHQcAAABnCQkJ0S233KKRI0fq4MGDGjJkiPu5+vXra+7cufrtt9+0adMmPfDAA3lmPruQHj16qEGDBho8eLDWrl2rJUuW6IUXXsizTv369bVnzx59++232rFjh95//333mZIctWrV0q5du7RmzRodPXpUGRkZ+Y41aNAgBQQEaPDgwdqwYYMWLlyoRx55RHfeeaf7UriicjgcWrNmTZ7bpk2b1KNHDzVt2lSDBg3SqlWr9Oeff+quu+5Sly5d1KpVK506dUrDhw/XokWLFB8fr2XLlmnFihWKjY2VJI0YMUJz5szRrl27tGrVKi1cuND9XEmhBJUCwzDUvZHrbNCCzUyVDQAA4InuvfdenThxQj179swzfucf//iHrrzySvXs2VNdu3ZVlSpV1K9fv0Lv12azafr06Tp16pTatGmj++67T6+99lqeda6//no9/vjjGj58uK644gr99ttvevHFF/OsM3DgQPXq1UvdunVTVFRUgdN0BwUFac6cOTp+/Lhat26tG2+8UXFxcRo/fvzFvRgFSElJUYsWLfLc+vbtK8MwNHPmTEVERKhz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CLA6DryA0+lUq1at9Prrr0uSWrRooQ0bNujDDz+kBKHYff/99/r66681efJkNWnSRGvWrNGIESNUrVo13m/lHCXoEkVGRsput+vw4cN5lh8+fFhVqlSxKBW8wfDhw/XTTz/p119/VfXq1a2Og3Jq5cqVSkhI0JVXXule5nA49Ouvv2r8+PHKyMiQ3W63MCHKm6pVq6px48Z5lsXGxmrq1KkWJUJ59vTTT+u5557TrbfeKklq2rSp4uPjNXbsWEpQOceYoEvk5+enli1bav78+e5lTqdT8+fPV7t27SxMhvLKNE0NHz5c06dP14IFC1S7dm2rI6Eci4uL0/r167VmzRr3rVWrVho0aJDWrFlDAUKx69ChQ75p/7du3aqaNWtalAjlWVpammy2vL8O2+12OZ1OixKhtHAmqBg88cQTGjx4sFq1aqU2bdrovffeU2pqqu6++26ro6EcGjZsmCZPnqyZM2cqNDRUhw4dkiSFh4crMDDQ4nQob0JDQ/ONNwsODlalSpUYh4YS8fjjj6t9+/Z6/fXXdfPNN+vPP//URx99pI8++sjqaCiH+vbtq9dee001atRQkyZNtHr1av3rX//SPffcY3U0lDCmyC4m48eP19tvv61Dhw7piiuu0Pvvv6+2bdtaHQvlkGEYBS6fNGmShgwZUrph4JW6du3KFNkoUT/99JNGjhypbdu2qXbt2nriiSd0//33Wx0L5dDJkyf14osvavr06UpISFC1atV02223adSoUfLz87M6HkoQJQgAAACAV2FMEAAAAACvQgkCAAAA4FUoQQAAAAC8CiUIAAAAgFehBAEAAADwKpQgAAAAAF6FEgQAAADAq1CCAAAAAHgVShAAwGsYhqEZM2ZYHQMAYDFKEACgVAwZMkSGYeS79erVy+poAAAv42N1AACA9+jVq5cmTZqUZ5m/v79FaQAA3oozQQCAUuPv768qVarkuUVEREhyXao2YcIE9e7dW4GBgapTp46mTJmSZ/v169ere/fuCgwMVKVKlTR06FClpKTkWee///2vmjRpIn9/f1WtWlXDhw/P8/zRo0fVv39/BQUFqX79+vrxxx/dz504cUKDBg1SVFSUAgMDVb9+/XylDQBQ9lGCAAAe48UXX9TAgQO1du1aDRo0SLfeeqs2bdokSUpNTVXPnj0VERGhFStW6IcfftC8efPylJwJEyZo2LBhGjp0qNavX68ff/xR9erVy3OMl19+WTfffLPWrVunPn36aNCgQTp+/Lj7+Bs3btTs2bO1adMmTZgwQZGRkaX3AgAASoVhmqZpdQgAQPk3ZMgQffXVVwoICMiz/Pnnn9fzzz8vwzD04IMPasKECe7nrrrqKl155ZX64IMP9PHHH+vZZ5/V3r17FRwcLEmaNWuW+vbtqwMHDig6OlqXXXaZ7r77br366qsFZjAMQ//4xz/0yiuvSHIVq5CQEM2ePVu9evXS9ddfr8jISP33v/8toVcBAOAJGBMEACg13bp1y1NyJKlixYru++3atcvzXLt27bRmzRpJ0qZNm9S8eXN3AZKkDh06yOl0asuWLTIMQwcOHFBcXNx5MzRr1sx9Pzg4WGFhYUpISJAkPfTQQxo4cKBWrVqla665Rv369VP79u2L9L0CADwXJQgAUGqCg4PzXZ5WXAIDAwu1nq+vb57HhmHI6XRKknr37q34+HjNmjVLc+fOVVxcnIYNG6Z33nmn2PMCAKzDmCAAgMf4/fff8z2OjY2VJMXGxmrt2rVKTU11P79s2TLZbDY1bNhQoaGhqlWrlubPn39JGaKiojR48GB99dVXeu+99/TRRx9d0v4AAJ6HM0EAgFKTkZGhQ4cO5Vnm4+Pjnnzghx9+UKtWrdSxY0d9/fXX+vPPP/Xpp59KkgYNGqSXXnpJgwcP1ujRo3XkyBE98sgjuvPOOxUdHS1JGj16tB588EFVrlxZvXv31smTJ7Vs2TI98sgjhco3atQotWzZUk2aNFFGRoZ++ukndwkDAJQflCAAQKn5+eefVbVq1TzLGjZsqM2bN0tyzdz27bff6uGHH1bVqlX1zTffqHHjxpKkoKAgzZkzR4899phat26toKAgDRw4UP/617/c+xo8eLDS09P17rvv6qmnnlJkZKRuvPHGQufz8/PTyJEjtXv3bgUGBqpTp0769ttvi+E7BwB4EmaHAwB4BMMwNH36dPXr18/qKACAco4xQQAAAAC8CiUIAAAAgFdhTBAAwCNwdTYAoLRwJggAAACAV6EEAQAAAPAqlCAAAAAAXoUSBAAAAMCrUIIAAAAAeBVKEAAAAACvQgkCAAAA4FUoQQAAAAC8yv8D7RuF3U+kXuwAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", "\n", "# Plot the training and validation loss\n", "def plot_losses(train_losses, val_losses):\n", " plt.figure(figsize=(10, 5))\n", " plt.plot(train_losses, label='Training Loss')\n", " plt.plot(val_losses, label='Validation Loss')\n", " plt.xlabel('Epochs')\n", " plt.ylabel('Loss')\n", " plt.legend()\n", " plt.title('Training and Validation Loss for seq2seq')\n", " plt.show()\n", "\n", "plot_losses(train_losses, val_losses)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "w4FDUt1Vshjm", "outputId": "540d70b3-62f1-44f5-fab0-0c5cb9285578" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original: This is a test sentence.\n", "Translated: gefðu þrjú ráð halda heilsu borðaðu hollt næringarríkt mataræði gakktu máltíðirnar þínar innihaldi margs konar ávexti grænmeti magurt prótein heilkorn holla fitu þetta veita líkamanum nauðsynleg næringarefni virka best hjálpað koma veg langvinna sjúkdóma taktu þátt reglulegri hreyfing mikilvæg viðhalda sterkum beinum vöðvum hjarta æðaheilbrigði minnsta kosti 150 hóflegri þolþjálfun 75 öflugri viku fáðu fá gæðasvefn skiptir sköpum andlega vellíðan stjórna skapi bæta vitræna virkni heilbrigðan vöxt ónæmisvirkni 79 nóttu hverjir gulur þessir litir kallaðir blanda öðrum litum alla aðra liti sameina ýmsum hlutföllum auklitakerfinu notað ljós grænn rgb byggingu atóm grunnbygging alls efnis samsett þremur tegundum agna rafeindum lýsa má uppbyggingu miðjunni umkringdur rafeindaskýi kjarni gerður róteindir jákvætt nifteindir hlutlausar án hleðslu báðar þessar staðsettar miðju inniheldur mestan hluta umhverfis rafeindaský rafeindir neikvætt stöðugri kringum kjarnann skipt skeljar svigrúm hver skel geymt ákveðinn ystu skelinni kallast gildisskel efnafræðilega eiginleika hlutlausu atómi kjarnanum jafn þannig jákvæða neikvæða hleðslan jafnast atómið hefur enga heildarhleðslu einnig kallaður atómnúmer hvaða frumeind hvernig getum dregið meðal orkunotkun spara orku minnkum magn losnar virkjunum þessu orkusparandi tæki lýsingu einangra slökkva ljósum rafeindabúnaði þau notaðu bílar vörubílar helstu uppsprettur hjólreiðar fækka bílum veginum aftur dregur útblæstri ábyrgur úrgangi úrgangur brenndur niðurbrotinn hann skaðlegar lofttegundir fargaðu spilliefnum réttan endurvinna plast pappír gler mögulegt 4 orkugjafa endurnýjanlegir orkugjafar sólar vindorka valda lítilli engri styðjið orkufyrirtæki verkefni íhugið setja upp endurnýjanleg orkukerfi þínu 5 akið ef þarft skaltu ganga bílnum sé vel haldið forðast hraða hröðun hemlun lausagangi 6 meðvitaður vöruval sumar venjur gefa sér meiri en aðrar veldu umhverfisvænum umbúðum reyndu lágmarka þína úðabrúsa skaðleg þurftir erfiða ai aðstoðarmaður hef eigin persónulegu reynslu tilvist hins vegar forritaður ákvarðanir byggðar reikniritum rökfræði gögnum tímar lendi aðstæðum erfitt geta verið misvísandi upplýsingar margar mögulegar niðurstöður slíkum tilfellum hæfileika greina vega áhættu ávinning hvers valkosts komast niðurstöðu líklegast tilætluðum árangri\n" ] } ], "source": [ "# Translate a new sentence\n", "def translate_new_sentence(model, en_sentence, en_vocab, ic_vocab, max_len=MAX_LEN):\n", " model.eval()\n", " en_tensor = sentence_to_tensor(en_sentence, en_vocab, max_len).unsqueeze(0).to(DEVICE)\n", "\n", " # Start with the token as input to the decoder\n", " ic_input = torch.tensor([ic_vocab['']]).unsqueeze(0).to(DEVICE)\n", "\n", " translated_sentence = []\n", " with torch.no_grad():\n", " for _ in range(max_len):\n", " output = model(en_tensor, ic_input)\n", " output_token = output.argmax(dim=-1)[:, -1].item() # Get the most likely next token\n", "\n", " translated_sentence.append(output_token)\n", " if output_token == ic_vocab['']: # End token\n", " break\n", "\n", " # Update the input for the next time step (use the predicted token)\n", " ic_input = torch.tensor([output_token]).unsqueeze(0).to(DEVICE) # Convert output_token to tensor\n", "\n", " # Convert token IDs back to words\n", " translated_sentence = [k for k, v in ic_vocab.items() if v in translated_sentence]\n", " return \" \".join(translated_sentence)\n", "\n", "# Example sentence translation\n", "en_example_sentence = \"This is a test sentence.\"\n", "translated_ic_sentence = translate_new_sentence(model, en_example_sentence, en_vocab, ic_vocab)\n", "print(f\"Original: {en_example_sentence}\")\n", "print(f\"Translated: {translated_ic_sentence}\")\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "YbfHsa5PpW8G" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "N93ucaxdpW_d" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "NWPzmQ3zpXCi" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "HCxdDaispXHV" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "pHS_C_VTpXKu" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "lNvPqrwPpXNc" }, "outputs": [], "source": [] } ], "metadata": { "colab": { "provenance": [], "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 1 }