Files
2026-07-13 13:17:40 +08:00

172 lines
5.6 KiB
Python

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchmetrics import Accuracy
from ray import train
from ray.train.lightning._lightning_utils import import_lightning
pl = import_lightning()
class LinearModule(pl.LightningModule):
def __init__(self, input_dim, output_dim, strategy="ddp", fail_epoch=-1) -> None:
super().__init__()
self.linear = nn.Linear(input_dim, output_dim)
self.loss = []
self.strategy = strategy
self.restored = train.get_checkpoint() is not None
self.fail_epoch = fail_epoch
def forward(self, input):
if isinstance(input, dict) and len(input) == 1:
input = list(input.values())[0]
return self.linear(input)
def training_step(self, batch):
if not self.restored and self.fail_epoch == self.current_epoch:
raise RuntimeError
output = self.forward(batch)
loss = torch.sum(output)
self.log("loss", loss)
return loss
def validation_step(self, val_batch, batch_idx):
loss = self.forward(val_batch)
self.loss.append(loss)
return {"val_loss": loss}
def test_step(self, batch, batch_idx):
loss = self.forward(batch)
return {"test_loss": loss}
def on_validation_epoch_end(self) -> None:
avg_loss = torch.stack(self.loss).mean()
self.log("val_loss", avg_loss)
self.loss.clear()
def predict_step(self, batch, batch_idx):
return self.forward(batch)
def configure_optimizers(self):
if self.strategy == "fsdp":
# Feed FSDP wrapped model parameters to optimizer
return torch.optim.AdamW(self.trainer.model.parameters(), lr=0.1)
else:
return torch.optim.AdamW(self.parameters(), lr=0.1)
class DoubleLinearModule(pl.LightningModule):
def __init__(self, input_dim_1, input_dim_2, output_dim) -> None:
super().__init__()
self.linear_1 = nn.Linear(input_dim_1, output_dim)
self.linear_2 = nn.Linear(input_dim_2, output_dim)
self.loss = []
def forward(self, batch):
input_1 = batch["input_1"]
input_2 = batch["input_2"]
return self.linear_1(input_1) + self.linear_2(input_2)
def training_step(self, batch):
output = self.forward(batch)
loss = torch.sum(output)
self.log("loss", loss)
return loss
def validation_step(self, val_batch, batch_idx):
loss = self.forward(val_batch)
self.loss.append(loss)
return {"val_loss": loss}
def on_validation_epoch_end(self) -> None:
print("Validation Epoch:", self.current_epoch)
avg_loss = torch.stack(self.loss).mean()
self.log("val_loss", avg_loss)
self.loss.clear()
def predict_step(self, batch, batch_idx):
return self.forward(batch)
def configure_optimizers(self):
return torch.optim.AdamW(self.parameters(), lr=0.1)
class DummyDataModule(pl.LightningDataModule):
def __init__(self, batch_size: int = 8, dataset_size: int = 256) -> None:
super().__init__()
self.batch_size = batch_size
self.train_data = torch.randn(dataset_size, 32)
self.val_data = torch.randn(dataset_size, 32)
self.test_data = torch.randn(dataset_size, 32)
def train_dataloader(self):
return DataLoader(self.train_data, batch_size=self.batch_size)
def val_dataloader(self):
return DataLoader(self.val_data, batch_size=self.batch_size)
def test_dataloader(self):
return DataLoader(self.test_data, batch_size=self.batch_size)
class LightningMNISTClassifier(pl.LightningModule):
def __init__(self, lr: float, layer_1: int, layer_2: int):
super(LightningMNISTClassifier, self).__init__()
self.lr = lr
# mnist images are (1, 28, 28) (channels, width, height)
self.layer_1 = torch.nn.Linear(28 * 28, layer_1)
self.layer_2 = torch.nn.Linear(layer_1, layer_2)
self.layer_3 = torch.nn.Linear(layer_2, 10)
self.accuracy = Accuracy(task="multiclass", num_classes=10, top_k=1)
self.val_acc_list = []
self.val_loss_list = []
def forward(self, x):
batch_size, channels, width, height = x.size()
x = x.view(batch_size, -1)
x = self.layer_1(x)
x = torch.relu(x)
x = self.layer_2(x)
x = torch.relu(x)
x = self.layer_3(x)
x = torch.log_softmax(x, dim=1)
return x
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=self.lr)
def training_step(self, train_batch, batch_idx):
x, y = train_batch
logits = self.forward(x)
loss = F.nll_loss(logits, y)
acc = self.accuracy(logits, y)
self.log("ptl/train_loss", loss)
self.log("ptl/train_accuracy", acc)
return loss
def validation_step(self, val_batch, batch_idx):
x, y = val_batch
logits = self.forward(x)
loss = F.nll_loss(logits, y)
acc = self.accuracy(logits, y)
self.val_acc_list.append(acc)
self.val_loss_list.append(loss)
return {"val_loss": loss, "val_accuracy": acc}
def on_validation_epoch_end(self):
avg_loss = torch.stack(self.val_loss_list).mean()
avg_acc = torch.stack(self.val_acc_list).mean()
self.log("ptl/val_loss", avg_loss)
self.log("ptl/val_accuracy", avg_acc)
self.val_acc_list.clear()
self.val_loss_list.clear()
def predict_step(self, batch, batch_idx, dataloader_idx=None):
x = batch
logits = self.forward(x)
return torch.argmax(logits, dim=-1)