(NLP 기초대회) PyTorch Lightning 이론
이 색깔은 주석이라 무시하셔도 됩니다.
PyTorch Lightning 소개
Deep Learning Blocks
- Deep Learning의 진행 단계
Deep Learning Process
Deep Learning Process
Data Preparation
- 입출력 데이터를 담는 Tensor를 생성하는 과정
Model Implementation
- 신경망 학습을 위한 모델을 구현하는 과정
Loss Implementation
- 모델이 얼마나 틀렸는지를 측정하기 위한 함수 설정
Updater Implementation
- 초기에 설정된 가중치에서 최적의 가중치로 조정하는 옵티마이저를 구현하는 과정
Iterative Learning
- 데이터 Feeding을 통한 모델 반복 학습 및 검증
Data Preparation
Load data
- Download
- Access to database
- Etc. …
Split data to Train / Valid / Test
- Valid는 과적합을 파악하기 위해서 사용
Prepare data feeding function
- 데이터를 Tensor화시키는 작업
Make Batch data
- 데이터를 배치화시키는 작업
Model Implementation (모델 구현)
- Model Implementation
- Implement a neural network model that fits the problem
- 문제에 맞는 신경망 모델을 구현
- Implement input and output layer for input and output data
- 입력 및 출력 데이터에 대한 입력 및 출력 계층을 구현
- Design hidden layer for good performance
- 우수한 성능을 위해 hidden 레이어를 설계
- Implement a neural network model that fits the problem
Iterative Learning
Train & Validation
- 보통 1epoch마다 validation 나옴
Test
- test 데이터는 데이터와 정답이 함께 존재
- 평가를 해야하기 때문
- test 데이터는 데이터와 정답이 함께 존재
PyTorch Lightning
- PyTorch Lightning에 대한 소개
Pytorch Lightning | DL Interface
- 신경망 개발자는 인터페이스만 다룰 수 있으면 복잡한 신경망을 다룰 수 있도록 해줌
Keras & PyTorch Lightning
Keras
기계학습 Framework보단 인터페이스의 역할
- 더 높은 수준의 더 직관적인 추상화 집합을 표현함으로써 신경망을 구성하기 쉽게 만들어준다.
다양한 기계학습 라이브러리와 호환
- MXNet, Deeplearning4j, Tensorflow, Microsoft Cognitive Toolkit 또는 Theano 위에서 수행 가능
PyTorch lIghtning은 PyTorch에서 사용하는 Keras 같은 것이라고 할 수 있음
PyTorch Lightning
- PyTorch에 대한 High-level 인터페이스 제공
- 복잡한 PyTorch 코드들을 추상화함으로써 다루고 싶은 문제들에만 집중할 수 있게 해줌
- 더 높은 수준의 자동화 기능 제공
- 기본 PyTorch에서는 사용자가 구현해야하는 것들을 PyTorch Lightning에서는 추상화된 형태로 제공
- PyTorch에 대한 High-level 인터페이스 제공
Keras vs. PyTorch Lightning
Structured Organized
Deep Learning process
PyTorchLightning
- LightningDataModule
- PyTorch.utils.data.Dataset
- LightningModule
- nn.Module을 확장시켜놓은 것
- 흐름을 자동적으로 잡아줌
- nn.Module을 확장시켜놓은 것
- Traniner
- LightningDataModule
Data Preparation
prepare_data()
는 다운로드 같은 기계적인 작업 (한번만 호출)setup()
은 GPU마다 들어가는 전처리 같은 작업 (여러번 호출)
Model Implemenation
nn.Module과 거의 똑같음
nn.Module 대신 pl.LightningModule으로 바꿈
- pl.LightningModule은 내부적으로 nn.Module을 상속받아서 작동됨
Optimizer
Train & Loss
Validation & Loss
Test & Loss
- 파란색 코드를 3줄로 구현할 수 있음
Plus
- Other API
- 소프트웨어 구현 난이도가 (상대적으로) 어려운 것
- Performance & bottleneck profier
- Run your code on any hadrware
- Run distributed training
- 16-bit precision
- 소프트웨어 구현 난이도가 (상대적으로) 쉬운 것
- Model checkpointing
- Logging
- Early stopping
- Visualization
- Metrics
- 소프트웨어 구현 난이도가 (상대적으로) 어려운 것
- Torch metrics
- 80개 이상의 PyTorch 메트릭 구현 모음과 사용자 지정 메트릭을 생성하기 위한 사용하기 쉬운 API
- PyTorch 모델 또는 PyTorch Lightning 내에서 TorchMetrics를 사용 가능
- 데이터는 항상 측정 항목과 동일한 기기에 배치
- 더 많은 상용구를 줄이기 위해 Lightning에서 메트릭 개체를 직접 기록 가능
- NLP metrics
- BERT Score
- BLEU Score
- Char Error Rate
- ChrF Score
- Extended Edit Distance
- Match Error Rate
- ROUGE Score
- Sacre BLEU Score
- SQuAD
- Translation Edit Rate (TER)
- Word Error Rate
- Word Info. Lost
- Word Info. Preserved
- …
- Torch metrics는 PyTorch를 지원하고 PyTorch는 GPU를 지원하기 때문에 GPU 활용하여 빠르게 평가할 수도 있음
PyTorch & MNIST
MNIST
데이터 소개
- 사람의 손으로 숫자를 적은 이미지
- 가로 28 * 세로 28로 구성된 흑백 이미지 (channel = 1)
- 어떤 숫자인지?
- 10개의 Class인 0~9의 숫자 중 하나로 분류하는 문제
- 사람의 손으로 숫자를 적은 이미지
MNIST 데이터의 입력과 출력
Data Preparation
데이터 다운로드 및 분할하기
# 이미지 변환기 # 참조: <https://github.com/pytorch/examples/blob/main/mnist/main.py> transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))]) # MNIST 데이터 다운 mnist_train = MNIST(os.getcwd(), train=True, download=True, transform=transform) mnist_test = MNIST(os.getcwd(), train=False, download=True, transform=transform) # Number of Train Datasets : 55000 # Number of Validation Datasets : 5000 mnist_train, mnist_val = random_split(mnist_train, [55000, 5000])
DataLoader로 변환
mnist_train_dataloader = DataLoader(mnist_train, batch_size=64, shuffle=True) # <-- shuffle is important! mnist_val_dataloader = DataLoader(mnist_val, batch_size=64) mnist_test_dataloader = DataLoader(mnist_test, batch_size=64)
Model Implementation
모델 네트워크 구현
class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.layer_1 = nn.Linear(28 * 28, 128) self.layer_2 = nn.Linear(128, 256) self.layer_3 = nn.Linear(256, 10) def forward(self, x): batch_size, channelds, width, height = x.size() # (batch_size, 1, 28, 28) -> (batch_size, 1*28*28) x = x.view(batch_size, -1) # layer 1 x = self.layer_1(x) x = torch.relu(x) # layer 2 x = self.layer_2(x) x = torch.relu(x) # layer 3 x = self.layer_3(x) # probability distribution over labels x = torch.log_softmax(x, dim=1) return x
Iterative Learning
학습 진행
for epoch in range(1, 3): # Train mode ----------------------------------------------------------------- net.train() for batch_idx, (data, target) in enumerate(mnist_train_dataloader): data, target = data.to(device), target.to(device) optimizer.zero_grad() # <- pytorch specific operation output = net(data) ## Loss calculation loss = F.nll_loss(output, target) loss.backward() optimizer.step() # <- parameter update 수행 if batch_idx % 100 == 0: print("Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}".format( epoch, batch_idx * len(data), len(mnist_train_dataloader.dataset), 100. * batch_idx / len(mnist_train_dataloader), loss.item() )) # ---------------------------------------------------------------------------- # Validation mode ------------------------------------------------------------ net.eval() val_loss = 0 correct = 0 with torch.no_grad(): for data, target in mnist_val_dataloader: data, target = data.to(device), target.to(device) output = net(data) ## Loss calculation val_loss = F.nll_loss(output, target, reduction='sum').item() pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() val_loss /= len(mnist_val_dataloader.dataset) print("\\n[Validation] Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n".format( val_loss, correct, len(mnist_val_dataloader.dataset), 100. * correct / len(mnist_val_dataloader.dataset) )) # ----------------------------------------------------------------------------
평가(검증과 동일)
net.eval() correct = 0 with torch.no_grad(): for data, target in mnist_test_dataloader: # Test mode ------------------------------------------------------------------ data, target = data.to(device), target.to(device) output = net(data) pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() # ---------------------------------------------------------------------------- print("\\n[Test] Accuracy: {}/{} ({:.0f}%)\\n".format( correct, len(mnist_test_dataloader.dataset), 100. * correct / len(mnist_test_dataloader.dataset) ))
Pytorch만 썼을 때의 문제점
- 모델을 학습하고 평가하는 반복 학습을 할때마다 dataloader를 매번 호출해야하며
- 모델과 데이터, 옵티마이저를 일일히 불러와서 코드가 중복이 되는 불편함이 있다.
- 모델, 데이터, 학습 및 평가가 구조적으로 정리되지 않아 가독성이 떨어진다.
PyTorch Lightning Code
Install
- 명령어를 통해 설치 : pip 또는 conda를 통해 설치
- pip install pytorch-lightning
- colab 사용시 pip 명령어 앞에 느낌표
- !pip install pytorch-lightning
- colab 사용시 pip 명령어 앞에 느낌표
- conda install pytorch-lightning -c conda-forge
- pip install pytorch-lightning
Training Process
Activate Training
Model Save & Load
PyTorch Lightning & MNIST
Data Preparation
데이터 다운로드 및 분할하기
def prepare_data(self): # download MNIST(os.getcwd(), train=True, download=True) MNIST(os.getcwd(), train=False, download=True) def setup(self, stage = None): # Assign train/val datasets for use in dataloaders if stage == "fit" or stage is None: mnist_full = MNIST(os.getcwd(), train=True, transform=self.transform) self.mnist_train, self.mnist_val = random_split(mnist_full, [55000, 5000]) # Assign test dataset for use in dataloader(s) if stage == "test" or stage is None: self.mnist_test = MNIST(os.getcwd(), train=False, transform=self.transform)
DataLoader로 변환
def train_dataloader(self): return DataLoader(self.mnist_train, batch_size=self.batch_size, shuffle=True) def val_dataloader(self): return DataLoader(self.mnist_val, batch_size=self.batch_size) def test_dataloader(self): return DataLoader(self.mnist_test, batch_size=self.batch_size)
Model Implementation
모델 네트워크 구현
class PLNet(pl.LightningModule): # Model Implementation ------------------------------------------------------- def __init__(self): super(PLNet, self).__init__() self.layer_1 = nn.Linear(28 * 28, 128) self.layer_2 = nn.Linear(128, 256) self.layer_3 = nn.Linear(256, 10) def forward(self, x): batch_size, channelds, width, height = x.size() # (batch_size, 1, 28, 28) -> (batch_size, 1*28*28) x = x.view(batch_size, -1) # layer 1 x = self.layer_1(x) x = torch.relu(x) # layer 2 x = self.layer_2(x) x = torch.relu(x) # layer 3 x = self.layer_3(x) # probability distribution over labels x = torch.log_softmax(x, dim=1) return x # ----------------------------------------------------------------------------
Iterative Learning
옵티마이저 정의와 학습 Step 구현
# Updater Implimentation ----------------------------------------------------- def configure_optimizers(self): optimizer = torch.optim.Adam(self.parameters(), lr=1e-3) scheduler = StepLR(optimizer, step_size=1) return [optimizer], [scheduler] # ---------------------------------------------------------------------------- # training Step -------------------------------------------------------------- def training_step(self, batch, batch_idx): data, target = batch output = self(data) ## loss calculation loss = F.nll_loss(output, target) return loss # ----------------------------------------------------------------------------
평가 및 검증
# Validation Step to Epoch --------------------------------------------------- def validation_step(self, batch, batch_idx): data, target = batch output = self(data) ## loss calculation loss = F.nll_loss(output, target) pred = output.argmax(dim=1, keepdim=True) correct = pred.eq(target.view_as(pred)).sum().item() return {"val_loss" : loss, "correct" : correct} def validation_epoch_end(self, outputs): avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean() self.log('val_loss', avg_loss) self.log('avg_val_loss', avg_loss) # ---------------------------------------------------------------------------- # Test Step to Epoch --------------------------------------------------------- def test_step(self, batch, batch_idx): data, target = batch output = self(data) pred = output.argmax(dim=1, keepdim=True) correct = pred.eq(target.view_as(pred)).sum().item()/ len(target) return {"correct": correct} def test_epoch_end(self, outputs): all_correct = sum([output["correct"] for output in outputs]) accuracy = all_correct / len(outputs) self.log("accuracy", accuracy) # ----------------------------------------------------------------------------
학습 실행
# Data Preparation dm = MNSTDataModule() pl_net = PLNet() # Train & Validation trainer = pl.Trainer(max_epochs = 3) trainer.fit(pl_net, datamodule=dm)
평가 실행
# Test trainer.test(datamodule=dm)
PyTorch Lightning을 사용할 때의 장점
- PyTorch Lightning 구조는 기존의 PyTorch 학습을 간단히 한 줄에 묶을 수 있고, 중복되는 Deep Learning Block을 Module들로 묶어서 모듈의 가독성과 재활용성을 높일 수 있다.
출처: 부스트캠프 AI Tech 4기(NAVER Connect Foundation)