Load Packages

In [0]:
# File manipulation imports for Google Colab
from google.colab import drive
drive.mount('/content/drive')
import os
os.chdir("/content/drive/My Drive/Colab Notebooks/Seq2Seq_Translator")
Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&response_type=code&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly

Enter your authorization code:
··········
Mounted at /content/drive
In [0]:
# Imports
import math
import time
import spacy
import torch
import random
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torchtext
from torchtext.datasets import Multi30k
from torchtext.data import Field, BucketIterator
In [0]:
# Setting the device to cuda
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
In [0]:
# Check GPU
!nvidia-smi
Sun May 24 21:20:08 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82       Driver Version: 418.67       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla P100-PCIE...  Off  | 00000000:00:04.0 Off |                    0 |
| N/A   36C    P0    31W / 250W |   2157MiB / 16280MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

Loading Dictionaries

In [0]:
# Download english dictionary
!python -m spacy download en
Requirement already satisfied: en_core_web_sm==2.2.5 from https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.2.5/en_core_web_sm-2.2.5.tar.gz#egg=en_core_web_sm==2.2.5 in /usr/local/lib/python3.6/dist-packages (2.2.5)
Requirement already satisfied: spacy>=2.2.2 in /usr/local/lib/python3.6/dist-packages (from en_core_web_sm==2.2.5) (2.2.4)
Requirement already satisfied: requests<3.0.0,>=2.13.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (2.23.0)
Requirement already satisfied: blis<0.5.0,>=0.4.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (0.4.1)
Requirement already satisfied: numpy>=1.15.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (1.18.4)
Requirement already satisfied: srsly<1.1.0,>=1.0.2 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (1.0.2)
Requirement already satisfied: preshed<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (3.0.2)
Requirement already satisfied: murmurhash<1.1.0,>=0.28.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (1.0.2)
Requirement already satisfied: plac<1.2.0,>=0.9.6 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (1.1.3)
Requirement already satisfied: catalogue<1.1.0,>=0.0.7 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (1.0.0)
Requirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (46.3.0)
Requirement already satisfied: wasabi<1.1.0,>=0.4.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (0.6.0)
Requirement already satisfied: tqdm<5.0.0,>=4.38.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (4.41.1)
Requirement already satisfied: thinc==7.4.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (7.4.0)
Requirement already satisfied: cymem<2.1.0,>=2.0.2 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->en_core_web_sm==2.2.5) (2.0.3)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->en_core_web_sm==2.2.5) (1.24.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->en_core_web_sm==2.2.5) (2020.4.5.1)
Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->en_core_web_sm==2.2.5) (2.9)
Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->en_core_web_sm==2.2.5) (3.0.4)
Requirement already satisfied: importlib-metadata>=0.20; python_version < "3.8" in /usr/local/lib/python3.6/dist-packages (from catalogue<1.1.0,>=0.0.7->spacy>=2.2.2->en_core_web_sm==2.2.5) (1.6.0)
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.6/dist-packages (from importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy>=2.2.2->en_core_web_sm==2.2.5) (3.1.0)
✔ Download and installation successful
You can now load the model via spacy.load('en_core_web_sm')
✔ Linking successful
/usr/local/lib/python3.6/dist-packages/en_core_web_sm -->
/usr/local/lib/python3.6/dist-packages/spacy/data/en
You can now load the model via spacy.load('en')
In [0]:
# Download german dictionary
!python -m spacy download de
Requirement already satisfied: de_core_news_sm==2.2.5 from https://github.com/explosion/spacy-models/releases/download/de_core_news_sm-2.2.5/de_core_news_sm-2.2.5.tar.gz#egg=de_core_news_sm==2.2.5 in /usr/local/lib/python3.6/dist-packages (2.2.5)
Requirement already satisfied: spacy>=2.2.2 in /usr/local/lib/python3.6/dist-packages (from de_core_news_sm==2.2.5) (2.2.4)
Requirement already satisfied: plac<1.2.0,>=0.9.6 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (1.1.3)
Requirement already satisfied: requests<3.0.0,>=2.13.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (2.23.0)
Requirement already satisfied: thinc==7.4.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (7.4.0)
Requirement already satisfied: tqdm<5.0.0,>=4.38.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (4.41.1)
Requirement already satisfied: wasabi<1.1.0,>=0.4.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (0.6.0)
Requirement already satisfied: catalogue<1.1.0,>=0.0.7 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (1.0.0)
Requirement already satisfied: numpy>=1.15.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (1.18.4)
Requirement already satisfied: srsly<1.1.0,>=1.0.2 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (1.0.2)
Requirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (46.3.0)
Requirement already satisfied: preshed<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (3.0.2)
Requirement already satisfied: blis<0.5.0,>=0.4.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (0.4.1)
Requirement already satisfied: cymem<2.1.0,>=2.0.2 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (2.0.3)
Requirement already satisfied: murmurhash<1.1.0,>=0.28.0 in /usr/local/lib/python3.6/dist-packages (from spacy>=2.2.2->de_core_news_sm==2.2.5) (1.0.2)
Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->de_core_news_sm==2.2.5) (3.0.4)
Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->de_core_news_sm==2.2.5) (2.9)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->de_core_news_sm==2.2.5) (1.24.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests<3.0.0,>=2.13.0->spacy>=2.2.2->de_core_news_sm==2.2.5) (2020.4.5.1)
Requirement already satisfied: importlib-metadata>=0.20; python_version < "3.8" in /usr/local/lib/python3.6/dist-packages (from catalogue<1.1.0,>=0.0.7->spacy>=2.2.2->de_core_news_sm==2.2.5) (1.6.0)
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.6/dist-packages (from importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy>=2.2.2->de_core_news_sm==2.2.5) (3.1.0)
✔ Download and installation successful
You can now load the model via spacy.load('de_core_news_sm')
✔ Linking successful
/usr/local/lib/python3.6/dist-packages/de_core_news_sm -->
/usr/local/lib/python3.6/dist-packages/spacy/data/de
You can now load the model via spacy.load('de')
In [0]:
# Loading dictionaries
spacy_english = spacy.load('en')
spacy_german = spacy.load('de')
In [0]:
# Tokenization function: english
# The '[::-1]' is needed because the text order is flipped
def tokenize_english(text):
    return [token.text for token in spacy_english.tokenizer(text)][::-1]
In [0]:
# Tokenization function: german
def tokenize_german(text):
    return [token.text for token in spacy_german.tokenizer(text)]
In [0]:
# Source language
SOURCE = Field(tokenize = tokenize_english, init_token = '<sos>', eos_token = '<eos>', lower = True)
In [0]:
# Target language
TARGET = Field(tokenize = tokenize_german, init_token = '<sos>', eos_token = '<eos>', lower = True) 
In [0]:
# Train-test split
train_data, valid_data, test_data = Multi30k.splits(exts = ('.en', '.de'), fields = (SOURCE, TARGET))
In [0]:
# Vizualising the train data
print(train_data.examples[0].src)
print(train_data.examples[0].trg)
['.', 'bushes', 'many', 'near', 'outside', 'are', 'males', 'white', ',', 'young', 'two']
['zwei', 'junge', 'weiße', 'männer', 'sind', 'im', 'freien', 'in', 'der', 'nähe', 'vieler', 'büsche', '.']
In [0]:
print('Train dataset length: ' + str(len(train_data.examples)))
print('Validation dataset length: ' + str(len(valid_data.examples)))
print('Test dataset length: ' + str(len(test_data.examples)))
Train dataset length: 29000
Validation dataset length: 1014
Test dataset length: 1000
In [0]:
# Creating the SOURCE and TARGET vocabularies
SOURCE.build_vocab(train_data, min_freq = 2)
TARGET.build_vocab(train_data, min_freq = 2)

Building the Model

In [0]:
class Encoder(nn.Module):
    
    # Constructor method
    def __init__(self, input_dims, emb_dims, hid_dims, n_layers, dropout):
        super().__init__()

        # Model layers
        self.hid_dims = hid_dims
        self.n_layers = n_layers
        self.embedding = nn.Embedding(input_dims, emb_dims)
        self.rnn = nn.LSTM(emb_dims, hid_dims, n_layers, dropout = dropout)
        self.dropout = nn.Dropout(dropout)

    # Forward method for training
    def forward(self, src):
        
        # Model execution
        embedded = self.dropout(self.embedding(src))
        outputs, (h, cell) = self.rnn(embedded)

        return h, cell
In [0]:
class Decoder(nn.Module):
    
    # Constructor method
    def __init__(self, output_dims, emb_dims, hid_dims, n_layers, dropout):
        super().__init__()
        
        # Model layers
        self.output_dims = output_dims
        self.hid_dims = hid_dims
        self.n_layers = n_layers
        self.embedding = nn.Embedding(output_dims, emb_dims)
        self.rnn = nn.LSTM(emb_dims, hid_dims, n_layers, dropout = dropout)
        self.fc_out = nn.Linear(hid_dims, output_dims)
        self.dropout = nn.Dropout(dropout)
        
    # Forward method for training
    def forward(self, input, h, cell):
              
        # Model execution
        input = input.unsqueeze(0)   
        embedded = self.dropout(self.embedding(input))     
        output, (h, cell) = self.rnn(embedded, (h, cell))
        pred = self.fc_out(output.squeeze(0))
        
        return pred, h, cell
In [0]:
class Seq2Seq(nn.Module):
    
    # Constructor method
    def __init__(self, encoder, decoder, device):
        super().__init__()
        
        # Model components
        self.encoder = encoder
        self.decoder = decoder
        self.device = device
        
    # Forward method for training
    def forward(self, src, trg, teacher_forcing_rate = 0.5):
        
        # Model execution
        batch_size = trg.shape[1]
        target_length = trg.shape[0]
        target_vocab_size = self.decoder.output_dims
        outputs = torch.zeros(target_length, batch_size, target_vocab_size).to(self.device)
        h, cell = self.encoder(src)
        input = trg[0,:]
        
        for t in range(1, target_length):

            output, h, cell = self.decoder(input, h, cell)
            outputs[t] = output
            top = output.argmax(1) 
            input = trg[t] if (random.random() < teacher_forcing_rate) else top
        
        return outputs
In [0]:
# Hyperparameters
batch_size = 32
input_dimensions = len(SOURCE.vocab)
output_dimensions = len(TARGET.vocab)
encoder_embedding_dimensions = 256
decoder_embedding_dimensions = 256
hidden_layer_dimensions = 512
num_layers = 2
encoder_dropout = 0.5
decoder_dropout = 0.5
epochs = 30
grad_clip = 1
lowest_validation_loss = float('inf')
In [0]:
# Data generators
train_iterator, valid_iterator, test_iterator = BucketIterator.splits((train_data, valid_data, test_data), 
                                                                        batch_size = batch_size, 
                                                                        device = device)
In [0]:
# Enconder instance
encod = Encoder(input_dimensions, 
                encoder_embedding_dimensions,
                hidden_layer_dimensions, 
                num_layers, 
                encoder_dropout)
In [0]:
# Decor instance
decod = Decoder(output_dimensions, 
                decoder_embedding_dimensions,
                hidden_layer_dimensions, 
                num_layers, 
                decoder_dropout)
In [0]:
# Model instance
model = Seq2Seq(encod, decod, device).to(device)
In [0]:
# Create model
model
Out[0]:
Seq2Seq(
  (encoder): Encoder(
    (embedding): Embedding(5893, 256)
    (rnn): LSTM(256, 512, num_layers=2, dropout=0.5)
    (dropout): Dropout(p=0.5, inplace=False)
  )
  (decoder): Decoder(
    (embedding): Embedding(7855, 256)
    (rnn): LSTM(256, 512, num_layers=2, dropout=0.5)
    (fc_out): Linear(in_features=512, out_features=7855, bias=True)
    (dropout): Dropout(p=0.5, inplace=False)
  )
)
In [0]:
def initialize_weights(m):
    for name, param in m.named_parameters():
        nn.init.uniform_(param.data, -0.1, 0.1)
In [0]:
# Including the weight initialization function on the model
model.apply(initialize_weights)
Out[0]:
Seq2Seq(
  (encoder): Encoder(
    (embedding): Embedding(5893, 256)
    (rnn): LSTM(256, 512, num_layers=2, dropout=0.5)
    (dropout): Dropout(p=0.5, inplace=False)
  )
  (decoder): Decoder(
    (embedding): Embedding(7855, 256)
    (rnn): LSTM(256, 512, num_layers=2, dropout=0.5)
    (fc_out): Linear(in_features=512, out_features=7855, bias=True)
    (dropout): Dropout(p=0.5, inplace=False)
  )
)
In [0]:
# Defining the loss function to calculate model error
criterion = nn.CrossEntropyLoss(ignore_index = TARGET.vocab.stoi[TARGET.pad_token])
In [0]:
# Creating an optimizer to update the model weights after each epoch
optimizer = optim.Adam(model.parameters())
In [0]:
def train_model(model, iterator, optimizer, criterion, clip):
    
    # Initialize the training method
    model.train()
    
    # Initialize epoch error
    epoch_loss = 0
    
    # Loop through iterator (data generator)
    for i, batch in enumerate(iterator):
        
        # Collect source and target data
        src = batch.src
        trg = batch.trg
        
        # Zero gradients
        optimizer.zero_grad()
        
        # Predict
        output = model(src, trg)
        
        # Adjust prediction shape
        output_dims = output.shape[-1]
        output = output[1:].view(-1, output_dims)
        trg = trg[1:].view(-1)
        
        # Calculate loss
        loss = criterion(output, trg)
        
        # Initialize backpropagation
        loss.backward()
        
        # Calculate the derivative gradients to update weights
        torch.nn.utils.clip_grad_norm_(model.parameters(), clip)
        
        # Apply weight optimization
        optimizer.step()
        
        # Store epoch error
        epoch_loss += loss.item()
        
    return epoch_loss / len(iterator)
In [0]:
def evaluate_model(model, iterator, criterion):
    
    # Initialize evaluation method
    model.eval()
    
    # Initialize epoch error
    epoch_loss = 0
    
    # Predicting
    with torch.no_grad():
    
        # Loop through iterator (data generator)
        for i, batch in enumerate(iterator):

            # Extract source and target data
            src = batch.src
            trg = batch.trg

            # Predict
            output = model(src, trg, 0)

            # Adjust prediction shape
            output_dim = output.shape[-1]
            output = output[1:].view(-1, output_dim)
            trg = trg[1:].view(-1)

            # Model loss
            loss = criterion(output, trg)
            
            # Store epoch error
            epoch_loss += loss.item()
        
    return epoch_loss / len(iterator)

Train Model

In [0]:
# Loop through epochs to train odel
for epoch in range(epochs):
    
    # Store start time
    start_time = time.time()
    
    # Training
    train_loss = train_model(model, train_iterator, optimizer, criterion, grad_clip)
    
    # Validation
    valid_loss = evaluate_model(model, valid_iterator, criterion)
    
    # Store end time
    end_time = time.time()
    
    # Check lowest error and save the model by doing a checkpoint of the best performing model
    if valid_loss < lowest_validation_loss:
        lowest_validation_loss = valid_loss
        torch.save(model.state_dict(), 'models/seq2seq.pt')
    
    # Print
    print(f'Epoch: {epoch+1:02} | Time: {np.round(end_time-start_time,0)}s')
    print(f'\t Training error: {train_loss:.4f}')
    print(f'\t Validation Error: {valid_loss:.4f}')
Epoch: 01 | Time: 53.0s
	 Training error: 3.0340
	 Validation Error: 3.6917
Epoch: 02 | Time: 53.0s
	 Training error: 2.7115
	 Validation Error: 3.6485
Epoch: 03 | Time: 53.0s
	 Training error: 2.5477
	 Validation Error: 3.5898
Epoch: 04 | Time: 53.0s
	 Training error: 2.4221
	 Validation Error: 3.5336
Epoch: 05 | Time: 53.0s
	 Training error: 2.2868
	 Validation Error: 3.5662
Epoch: 06 | Time: 53.0s
	 Training error: 2.1759
	 Validation Error: 3.6335
Epoch: 07 | Time: 53.0s
	 Training error: 2.0799
	 Validation Error: 3.5997
Epoch: 08 | Time: 53.0s
	 Training error: 1.9717
	 Validation Error: 3.6085
Epoch: 09 | Time: 54.0s
	 Training error: 1.9058
	 Validation Error: 3.6265
Epoch: 10 | Time: 54.0s
	 Training error: 1.8162
	 Validation Error: 3.6797
Epoch: 11 | Time: 54.0s
	 Training error: 1.7466
	 Validation Error: 3.6288
Epoch: 12 | Time: 54.0s
	 Training error: 1.6704
	 Validation Error: 3.6528
Epoch: 13 | Time: 54.0s
	 Training error: 1.6080
	 Validation Error: 3.7270
Epoch: 14 | Time: 54.0s
	 Training error: 1.5554
	 Validation Error: 3.7336
Epoch: 15 | Time: 54.0s
	 Training error: 1.4994
	 Validation Error: 3.7599
Epoch: 16 | Time: 53.0s
	 Training error: 1.4450
	 Validation Error: 3.7641
Epoch: 17 | Time: 54.0s
	 Training error: 1.3961
	 Validation Error: 3.7791
Epoch: 18 | Time: 54.0s
	 Training error: 1.3473
	 Validation Error: 3.8986
Epoch: 19 | Time: 54.0s
	 Training error: 1.3109
	 Validation Error: 3.9076
Epoch: 20 | Time: 54.0s
	 Training error: 1.2673
	 Validation Error: 3.9060

Evaluate Model

In [0]:
# Loading trained model
model.load_state_dict(torch.load('models/seq2seq.pt'))
Out[0]:
<All keys matched successfully>
In [0]:
# Evaluate model
test_loss = evaluate_model(model, test_iterator, criterion)
In [0]:
# Test error
print(f'Test Error: {test_loss:.4f}')
Test Error: 3.5281

Translating

In [0]:
def translate_language(model, iterator, num_translations = 5):
    
    with torch.no_grad():
    
        # Loop through iterador
        for i, batch in enumerate(iterator):
            
            # While inside the num_translations, translate
            if i < num_translations :
                
                # Extract SOURCE and TARGET
                # Doing so to compare the predicted translation with the true translation
                src = batch.src
                trg = batch.trg

                # Model prediction
                output = model(src, trg, 0)
                
                # All predictions
                preds = torch.tensor([[torch.argmax(x).item()] for x in output])
                
                # Prints
                print('Original English Text: ' + str([SOURCE.vocab.itos[x] for x in src][1:-1][::-1]))
                print('Translated German Text (Expected Output): ' + str([TARGET.vocab.itos[x] for x in trg][1:-1]))
                print('Translated German Text (Model Prediction): ' + str([TARGET.vocab.itos[x] for x in preds][1:-1]))
                print('\n')
In [0]:
# Generating random text to be translated
_, _, iterator_translate = BucketIterator.splits((train_data, valid_data, test_data), 
                                                 batch_size = 1, 
                                                 device = device)
In [0]:
# Translation
translation = translate_language(model, iterator_translate)
Original English Text: ['two', 'men', 'wearing', 'hats', '.']
Translated German Text (Expected Output): ['zwei', 'männer', 'mit', 'mützen', '.']
Translated German Text (Model Prediction): ['zwei', 'männer', 'mit', 'sonnenbrillen', '.']


Original English Text: ['young', 'woman', 'climbing', 'rock', 'face']
Translated German Text (Expected Output): ['junge', 'frau', 'klettert', 'auf', 'felswand']
Translated German Text (Model Prediction): ['eine', 'junge', 'frau', ',', 'die']


Original English Text: ['a', 'woman', 'is', 'playing', 'volleyball', '.']
Translated German Text (Expected Output): ['eine', 'frau', 'spielt', 'volleyball', '.']
Translated German Text (Model Prediction): ['eine', 'frau', 'spielt', 'volleyball', '.']


Original English Text: ['three', 'men', 'are', 'walking', 'up', 'hill', '.']
Translated German Text (Expected Output): ['drei', 'männer', 'gehen', 'bergauf', '.']
Translated German Text (Model Prediction): ['drei', 'männer', 'gehen', 'durch', 'den']


Original English Text: ['an', 'army', 'officer', 'is', 'inspecting', 'something', '.']
Translated German Text (Expected Output): ['ein', '<unk>', 'inspiziert', 'etwas', '.']
Translated German Text (Model Prediction): ['ein', '<unk>', 'wird', '<unk>', '.']