부스트캠프 AI Tech 4기

(NLP 기초대회) PyTorch Lightning 이론

쉬엄쉬엄블로그 2023. 7. 15. 11:06
728x90

이 색깔은 주석이라 무시하셔도 됩니다.

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 레이어를 설계

Iterative Learning

  • Train & Validation

    • 보통 1epoch마다 validation 나옴
  • 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에서는 추상화된 형태로 제공
  • Keras vs. PyTorch Lightning

Structured Organized

Deep Learning process

  • PyTorchLightning

    • LightningDataModule
      • PyTorch.utils.data.Dataset
    • LightningModule
      • nn.Module을 확장시켜놓은 것
        • 흐름을 자동적으로 잡아줌
    • Traniner
  • 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
    • conda install pytorch-lightning -c conda-forge

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)