| import sys |
| import os |
| import torch |
| from torch.utils.data import DataLoader, TensorDataset |
| import torch.nn.functional as F |
| import torch.nn as nn |
| import torchutils as tu |
| from dataclasses import dataclass |
| from typing import Union |
| import numpy as np |
|
|
|
|
| @dataclass |
| class Config: |
| n_layers: int |
| embedding_size: int |
| hidden_size: int |
| vocab_size: int |
| device: str |
| seq_len: int |
| bidirectional: Union[bool, int] = False |
|
|
|
|
| class BahdanauAttention(nn.Module): |
| def __init__(self, hidden_size: int) -> None: |
| super().__init__() |
| self.hidden_size = hidden_size |
| self.linear_key = nn.Linear(hidden_size, hidden_size) |
| self.linear_query = nn.Linear(hidden_size, hidden_size) |
| self.cls = nn.Linear(hidden_size, 1) |
| self.tanh = nn.Tanh() |
|
|
| def forward(self, lstm_outputs, final_hidden): |
| |
| |
| keys = self.linear_key(lstm_outputs) |
| |
| query = self.linear_query(final_hidden) |
| query = query.unsqueeze(1) |
| |
| x = self.tanh(keys + query) |
| |
| x = self.cls(x) |
| |
| x = x.squeeze(-1) |
| |
| attention_weights = F.softmax(x, dim=-1) |
| |
| attention_weights_bmm = attention_weights.unsqueeze( |
| 1 |
| ) |
| |
|
|
| |
| context = torch.bmm(attention_weights_bmm, keys) |
| |
| context = context.squeeze(1) |
| |
|
|
| return context, attention_weights |
|
|
|
|
| class LSTMBahdanauAttention(nn.Module): |
| def __init__(self, config) -> None: |
| super().__init__() |
|
|
| |
| self.config = config |
| self.seq_len = self.config.seq_len |
| self.vocab_size = self.config.vocab_size |
| self.hidden_size = self.config.hidden_size |
| self.emb_size = self.config.embedding_size |
| self.n_layers = self.config.n_layers |
| self.device = self.config.device |
| self.bidirectional = bool(self.config.bidirectional) |
|
|
| self.embedding = nn.Embedding.from_pretrained( |
| torch.FloatTensor(np.zeros((self.vocab_size, self.emb_size))) |
| ) |
| self.lstm = nn.LSTM(self.emb_size, self.hidden_size, batch_first=True) |
| self.bidirect_factor = 2 if self.bidirectional == 1 else 1 |
| self.attn = BahdanauAttention(self.hidden_size) |
| self.clf = nn.Sequential( |
| nn.Linear(self.hidden_size, 128), nn.Dropout(), nn.Tanh(), nn.Linear(128, 1) |
| ) |
|
|
| def model_description(self): |
| direction = "bidirect" if self.bidirectional else "onedirect" |
| return f"rnn_{direction}_{self.n_layers}" |
|
|
| def forward(self, x): |
| embeddings = self.embedding(x) |
| outputs, (h_n, _) = self.lstm(embeddings) |
| |
| att_hidden, att_weights = self.attn(outputs, h_n[-1]) |
| out = self.clf(att_hidden) |
| return out, att_weights |
|
|