jamtur01's picture
Upload folder using huggingface_hub
9c6594c verified
"""Demo of a simple LSTM language model.
Code is adapted from the PyTorch examples at
https://github.com/pytorch/examples/blob/main/word_language_model
"""
from collections.abc import Iterator, Sized
from typing import Optional
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch import Tensor
from torch.optim import Optimizer
from torch.utils.data import DataLoader, Sampler
from pytorch_lightning.core import LightningModule
from pytorch_lightning.demos.transformer import WikiText2
class SimpleLSTM(nn.Module):
def __init__(
self, vocab_size: int = 33278, ninp: int = 512, nhid: int = 512, nlayers: int = 4, dropout: float = 0.2
):
super().__init__()
self.vocab_size = vocab_size
self.drop = nn.Dropout(dropout)
self.encoder = nn.Embedding(vocab_size, ninp)
self.rnn = nn.LSTM(ninp, nhid, nlayers, dropout=dropout, batch_first=True)
self.decoder = nn.Linear(nhid, vocab_size)
self.nlayers = nlayers
self.nhid = nhid
self.init_weights()
def init_weights(self) -> None:
nn.init.uniform_(self.encoder.weight, -0.1, 0.1)
nn.init.zeros_(self.decoder.bias)
nn.init.uniform_(self.decoder.weight, -0.1, 0.1)
def forward(self, input: Tensor, hidden: tuple[Tensor, Tensor]) -> tuple[Tensor, Tensor]:
emb = self.drop(self.encoder(input))
output, hidden = self.rnn(emb, hidden)
output = self.drop(output)
decoded = self.decoder(output).view(-1, self.vocab_size)
return F.log_softmax(decoded, dim=1), hidden
def init_hidden(self, batch_size: int) -> tuple[Tensor, Tensor]:
weight = next(self.parameters())
return (
weight.new_zeros(self.nlayers, batch_size, self.nhid),
weight.new_zeros(self.nlayers, batch_size, self.nhid),
)
class SequenceSampler(Sampler[list[int]]):
def __init__(self, dataset: Sized, batch_size: int) -> None:
super().__init__()
self.dataset = dataset
self.batch_size = batch_size
self.chunk_size = len(self.dataset) // self.batch_size
def __iter__(self) -> Iterator[list[int]]:
n = len(self.dataset)
for i in range(self.chunk_size):
yield list(range(i, n - (n % self.batch_size), self.chunk_size))
def __len__(self) -> int:
return self.chunk_size
class LightningLSTM(LightningModule):
def __init__(self, vocab_size: int = 33278):
super().__init__()
self.model = SimpleLSTM(vocab_size=vocab_size)
self.hidden: Optional[tuple[Tensor, Tensor]] = None
def on_train_epoch_end(self) -> None:
self.hidden = None
def training_step(self, batch: tuple[Tensor, Tensor], batch_idx: int) -> Tensor:
input, target = batch
if self.hidden is None:
self.hidden = self.model.init_hidden(input.size(0))
self.hidden = (self.hidden[0].detach(), self.hidden[1].detach())
output, self.hidden = self.model(input, self.hidden)
loss = F.nll_loss(output, target.view(-1))
self.log("train_loss", loss, prog_bar=True)
return loss
def prepare_data(self) -> None:
WikiText2(download=True)
def train_dataloader(self) -> DataLoader:
dataset = WikiText2()
return DataLoader(dataset, batch_sampler=SequenceSampler(dataset, batch_size=20))
def configure_optimizers(self) -> Optimizer:
return torch.optim.SGD(self.parameters(), lr=20.0)