0% found this document useful (0 votes)
19 views4 pages

Seq2Seq Translation Model in PyTorch

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views4 pages

Seq2Seq Translation Model in PyTorch

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

assignment-9

November 12, 2024

[2]: import torch


import [Link] as nn
import [Link] as optim
from [Link] import DataLoader, Dataset
from collections import Counter
from itertools import chain

# Sample parallel sentences for demonstration (replace with actual data)


source_sentences = ["hello", "how are you", "good morning"]
target_sentences = ["hola", "cómo estás", "buenos días"]

# Vocabulary building function


def build_vocab(sentences):
counter = Counter(chain.from_iterable([Link]() for s in sentences))
vocab = {word: idx + 3 for idx, (word, _) in enumerate(counter.
↪most_common())}

vocab["<pad>"] = 0
vocab["<sos>"] = 1
vocab["<eos>"] = 2
return vocab

# Build vocabulary for source and target languages


source_vocab = build_vocab(source_sentences)
target_vocab = build_vocab(target_sentences)

# Tokenize function
def tokenize(sentence, vocab):
tokens = ["<sos>"] + [Link]() + ["<eos>"]
return [vocab[token] if token in vocab else vocab["<pad>"] for token in␣
↪tokens]

# Prepare data for training


train_data = [([Link](tokenize(src, source_vocab)), torch.
↪tensor(tokenize(tgt, target_vocab)))

for src, tgt in zip(source_sentences, target_sentences)]

# Define Dataset and DataLoader

1
class TranslationDataset(Dataset):
def __init__(self, data):
[Link] = data

def __len__(self):
return len([Link])

def __getitem__(self, idx):


return [Link][idx]

dataset = TranslationDataset(train_data)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True, collate_fn=lambda␣
↪x: x)

# Encoder model
class Encoder([Link]):
def __init__(self, input_dim, emb_dim, hidden_dim, n_layers):
super(Encoder, self).__init__()
[Link] = [Link](input_dim, emb_dim)
[Link] = [Link](emb_dim, hidden_dim, n_layers, batch_first=True)

def forward(self, src):


embedded = [Link](src)
outputs, (hidden, cell) = [Link](embedded)
return outputs, hidden, cell

# Attention model
class Attention([Link]):
def __init__(self, hidden_dim):
super(Attention, self).__init__()
[Link] = [Link](hidden_dim * 2, hidden_dim)
self.v = [Link](hidden_dim, 1, bias=False)

def forward(self, hidden, encoder_outputs):


src_len = encoder_outputs.shape[1]
hidden = hidden[-1].unsqueeze(1).repeat(1, src_len, 1)
energy = [Link]([Link]([Link]((hidden, encoder_outputs),␣
↪dim=2)))

attention = self.v(energy).squeeze(2)
return [Link](attention, dim=1)

# Decoder model with attention


class Decoder([Link]):
def __init__(self, output_dim, emb_dim, hidden_dim, n_layers, attention):
super(Decoder, self).__init__()
self.output_dim = output_dim
[Link] = [Link](output_dim, emb_dim)

2
[Link] = [Link](emb_dim + hidden_dim, hidden_dim, n_layers,␣
↪batch_first=True)
self.fc_out = [Link](hidden_dim * 2, output_dim)
[Link] = attention

def forward(self, tgt, hidden, cell, encoder_outputs):


tgt = [Link](1)
embedded = [Link](tgt)
attn_weights = [Link](hidden, encoder_outputs)
context = [Link](attn_weights.unsqueeze(1), encoder_outputs)
lstm_input = [Link]((embedded, context), dim=2)
output, (hidden, cell) = [Link](lstm_input, (hidden, cell))
prediction = self.fc_out([Link]((output, context), dim=2).squeeze(1))
return prediction, hidden, cell

# Seq2Seq model combining encoder and decoder


class Seq2Seq([Link]):
def __init__(self, encoder, decoder, device):
super(Seq2Seq, self).__init__()
[Link] = encoder
[Link] = decoder
[Link] = device

def forward(self, src, tgt):


encoder_outputs, hidden, cell = [Link](src)
outputs = [Link]([Link][0], [Link][1], [Link].
↪output_dim).to([Link])

input = tgt[:, 0]
for t in range(1, [Link][1]):
output, hidden, cell = [Link](input, hidden, cell,␣
↪encoder_outputs)

outputs[:, t] = output
input = [Link](1)
return outputs

# Hyperparameters and model initialization


INPUT_DIM = len(source_vocab)
OUTPUT_DIM = len(target_vocab)
EMB_DIM = 256
HIDDEN_DIM = 512
N_LAYERS = 2

encoder = Encoder(INPUT_DIM, EMB_DIM, HIDDEN_DIM, N_LAYERS)


attention = Attention(HIDDEN_DIM)
decoder = Decoder(OUTPUT_DIM, EMB_DIM, HIDDEN_DIM, N_LAYERS, attention)
device = [Link]('cuda' if [Link].is_available() else 'cpu')
model = Seq2Seq(encoder, decoder, device).to(device)

3
# Training setup
optimizer = [Link]([Link](), lr=0.001)
criterion = [Link](ignore_index=target_vocab["<pad>"])

# Training loop
def train(model, dataloader, optimizer, criterion):
[Link]()
epoch_loss = 0
for batch in dataloader:
src, tgt = zip(*batch)
src, tgt = [Link].pad_sequence(src,␣
↪padding_value=source_vocab["<pad>"], batch_first=True), \

[Link].pad_sequence(tgt,␣
↪padding_value=target_vocab["<pad>"], batch_first=True)

src, tgt = [Link](device), [Link](device)

optimizer.zero_grad()
output = model(src, tgt)

output_dim = [Link][-1]
output = output[:, 1:].reshape(-1, output_dim)
tgt = tgt[:, 1:].reshape(-1)

loss = criterion(output, tgt)


[Link]()
[Link]()
epoch_loss += [Link]()
return epoch_loss / len(dataloader)

# Training epochs
for epoch in range(10):
loss = train(model, dataloader, optimizer, criterion)
print(f'Epoch {epoch+1}, Loss: {loss:.4f}')

Epoch 1, Loss: 2.0400


Epoch 2, Loss: 1.8393
Epoch 3, Loss: 1.5252
Epoch 4, Loss: 1.2470
Epoch 5, Loss: 0.8623
Epoch 6, Loss: 0.5609
Epoch 7, Loss: 0.4295
Epoch 8, Loss: 0.1870
Epoch 9, Loss: 0.2638
Epoch 10, Loss: 0.1014

Common questions

Powered by AI

Padding is used to ensure that all input sequences have the same length within a batch. This uniformity is essential for parallel processing in neural networks. During training, the torch.nn.utils.rnn.pad_sequence function pads each sequence with a special '<pad>' token up to the length of the longest sequence in the batch. This operation is crucial for maintaining computational consistency and efficiency in the training process .

Parameter initialization is crucial for ensuring convergence and avoiding issues like vanishing gradients. In the described model, key parameters like embedding and hidden dimensions for the LSTM layers are initialized with values 256 and 512, respectively. These initializations provide a starting point that allows the model to learn effectively throughout training, balancing the trade-off between expressiveness and stability across its layers .

The Adam optimizer is used for its adaptive learning rate feature, which combines the advantages of RMSProp and momentum techniques. It efficiently handles sparse gradients and requires less parameter tuning. This makes it well-suited for the translation model, enhancing convergence speed. However, Adam can sometimes converge to suboptimal solutions or over-fit if not counterbalanced by techniques such as weight decay, particularly in complex models. Therefore, careful monitoring and, if necessary, adjustment of learning rates and regularization are advisable .

The vocabulary for both source and target languages is constructed using a function that counts word frequencies across all sentences and assigns an index to each unique word. Three special tokens are used: '<pad>' for padding sequences to the same length, '<sos>' to denote the start of a sentence, and '<eos>' to indicate the end of a sentence. These tokens are crucial for managing input lengths and sequence boundaries during model training .

The Seq2Seq model consists of an encoder and a decoder. The encoder processes input sequences through embedding and LSTM layers, outputting hidden states and cell states. These are fed into the decoder along with the target sequences. The decoder includes attention mechanisms that weight encoder outputs to focus on relevant input parts during translation. It uses LSTM and a dense layer to generate predictions at each time step, propagating hidden states iteratively for sequential prediction until an end-of-sequence token is produced .

The inclusion of both source and target sentences in the training dataset allows the model to learn direct mappings between different languages, enhancing cross-linguistic understanding. This setup enables the Seq2Seq model to capture the syntactic and semantic transformations necessary for accurate translation, facilitating bilingual embedding space development. Such an approach leads to better generalization and translation performance, as it directly trains the network on relevant input-output patterns .

Model performance is assessed by tracking loss values, which indicate prediction accuracy during training. The decline in loss from 2.0400 in epoch 1 to 0.1014 in epoch 10 reflects improved alignment between predicted and target sequences, signaling effective learning. Steady reduction in loss suggests successful weight adjustments through gradient descent, enhancing model generalization and indicative of the model's growing capacity to accurately capture sequence-to-sequence mappings .

The attention module in the translation model allows the decoder to focus on specific parts of the input sequence at each decoding step. It calculates alignment scores using a linear layer and a vector to compute a weighted sum across encoder outputs, generating attention weights that highlight relevant input features. This mechanism helps in capturing dependencies across different parts of the input, improving translation accuracy by allowing the decoder to select contextually important data .

The model uses LSTM layers within both the encoder and decoder to manage variable-length input and output sequences by leveraging their capacity to retain information across time steps. The encoder LSTM processes whole input sequences to produce fixed-length hidden and cell state outputs that summarize context, regardless of input size. The decoder LSTM then utilizes these states, augmented by attention-derived weights, to generate output sequences, dynamically adjusting to sequence lengths during runtime due to its inherent design .

The training loop iterates over batches of data, running the forward pass of the model to produce predictions, and computes loss using cross-entropy on these predictions against the target sequences (excluding padding). It accumulates gradients and uses the optimizer (Adam) to update model parameters, thus minimizing the loss. This process involves zeroing the gradients, a backward pass to propagate them, and an optimization step to adjust the weights based on computed gradients. The loop is repeated across multiple epochs to iteratively reduce training loss .

You might also like