DH. AI

[Boost Camp AI Tech] Week2 본문

[Boost Camp AI Tech]

[Boost Camp AI Tech] Week2

도환 2023. 3. 31. 03:01
Notion에 정리한 내용중 새로 알게된 내용과 중요하다고 생각되는 내용을 다시 정리하며 복습하기 위해서 쓰는 글.
Pytorch에 대해서 전반적으로 다룸.

1. Pytorch 기본

  • Pytorch는 역전파할때, Graph그릴때 실행시점에서 동시에 그림!! Dynamic Computation Graph 연산과정을 그래프로 그린것 → Computation Graph
  • Tensor - 다차원 Arrays 를 표현하는 Pytorch의 클래스. 사실상 numpy의 ndarray와 동일하다. Tensor를 생성하는 함수도 거의 동일. → GPU를 사용할 수 있냐 없냐가 차이가 있음 ex : torch.cuda.FloatTensor
  • Pytorch의 tensor는 GPU에 올려서 사용가능!!
if torch.cuda.is_available(): 
# GPU사용가능하면 해당 데이터를 cuda로 할당해라
    x_data_cuda = x_data.to('cuda')
x_data_cuda.device
  • view(텐서 차원 변경은 numpy의 reshape 대신 view를쓰자) reshape은 구조가 변경되면 메모리를 새로잡음.
a = torch.zeros(3, 2)
b = a.view(2, 3)
a.fill_(1)
# view는 같은 메모리 주소를 가지게 하고 표현하는 형태만 바꿔줌
# 따라서 b의 값도 1로 바꿔져 있음.
  • squeeze : 차원의 개수가 1인 차원을 삭제, unsqueeze : 차원의 개수가 1인 차원을 추가.
  • Tensor에서 행렬 곱셈은 numpy의 dot이 아닌 mm(matmul)을 쓴다. 벡터곱은 mm안되고 dot으로
  • mm은 boradcasting 지원 x, matmul은 boradcasting 지원 O
a = torch.rand(5,2, 3)
b = torch.rand(3)
a.matmul(b)
# 5는 보통 배치를 의미함 5,2,3 matmul 3 하면 5, 2이 나온다!

nn.functional

  • nn.functional 모듈을 통해서 다양한 수식 변환을 지원한다. -> 그때그때 찾아보자! ex : nn.functional.softmax(tensor, dim = 0)

AutoGrad

  • Pytorch의 핵심은 자동 미분 지원 → backward 함수 사용
w = torch.tensor(2.0, requires_grad=True) # 미분이 되는 대상 : requires_grad=True 지정
# 보통 Linear와 같은 함수를 쓰는데, requires_grad 가 전부 True로 되어있음!!
y = w**2
z = 10*y + 50
z.backward()
w.grad
  • 위의 requires_grad 인자 값은 fine tuning 시에 backbone의 네트워크를 freeze 시켜줄때 False로 두고 사용할 수도 있다.
  • 그게 귀찮다면 optimizer의 파라미터의 뒤에 붙는 fc의 파라미터만 넣어서 학습 시킬 수도 있다!

Pytorch 프로젝트 구조 이해하기

  • 개발 초기 단계에서는 대화식(주피터, 코랩) 개발과정이 유리 → 학습과정과 디버깅 등 지속적인 확인
  • 배포 및 공유 단계에서는 notebook 공유의 어려움. → 쉬운 재현의 어려움, 실행순서 꼬임.
  • DL 코드도 하나의 프로그램 → 개발 용이성 확보와 유지보수 향상 필요
  • 실행, 데이터, 모델, 설정, 로깅, 지표, 유틸리티 등 다양한 모듈들을 분리하여 프로젝트 템플릿화.

Pytorch-template : config 파일만 변경해주면서 프로젝트를 진행가능. 학부연구생 할때 mmdetection을 조금이나마 만져봤어서 꽤 익숙했음. 코드 하나하나 주석을 달며 공부 했지만 다시 이해가 필요할듯. 시간날때마다 강의 다시 들으면서 공부하기!

2. Pytorch 구조 학습하기

torch.nn.Module

  • Transformer나 ResNet같은 모델을 보면 레이어(블록) 반복의 연속이다. 이런 모델을 구현하기 위해 torch.nnModule을 사용한다.
  • torch.nn.Module : 딥러닝을 구성하는 Layer의 base class로써 일반적으로 나의 모델을 class로 정의하고 nn.Module을 상속받아서 사용한다.
  • 기본적으로 네가지 정의 Input, Output, Forward, Backward(weight값) 정의
  • 학습의 대상이 되는 weights를 parameter(tensor) 클래스로 정의. 
  • super().__init__() 으로 nn.Module의 생성자를 호출하는것.
    super()로 기반 클래스(부모 클래스)를 초기화해줌으로써, 기반 클래스의 속성을 subclass가 받아오도록 한다. 
    parameter, modules 등의 네트워크 학습에 있어서 중요한 특성을 포함하는 속성(attribute)들을 가져옴. forward도!
  • forward() 함수는 model 객체를 데이터와 함께 호출하면 자동으로 실행이됩니다.

nn.Parameter (클래스)

  • Tensor 객체의 상속 객체
  • nn.Module 내에 attribute(속성)가 될 때는 required_grad = True로 자동으로 지정되어 AutoGrad 학습 대상이 되는 Tensor들!
  • 우리가 직접 지정할 일은 잘 없다  -> torch.nn.Linear와 같은 함수 내부에 weight는 모두  nn.Parameter로 지정 되어 있어서 실제로는 다룰 일이 많이 없지만 알고 있자! 

Backward

  • Layer에 있는 Parameter들의 미분을 수행 (자동 미분으로 연산)
  • epoch 돌아가면서 Forward의 결과값 (model의 ouput=예측치)과 실제값 간의 차이(loss)에 대해 미분을 수행.
  • 해당 값을 이용하여 Parameter 업데이트. optimizer.zero_grad(), loss.backward(), optimizer.step()을 사용
  • 실제 backward는 Module 단계에서 직접 지정도 가능하긴 해;;
  • Module에서 backward와 optimizer오버라이딩
  • 사용자가 직접 미분 수식을 써야하는 부담.. 쓸일은 없으나 순서는 이해할 필요 있음

Dataset

  • 데이터의 입력 형태를 정의하는 클래스. 데이터를 입력하는 방식의 표준화! 데이터 형태에 따라 (Image, Text, Audio) 등에 따른 다른 입력정의.
  • 모든것을 데이터 생성 시점(init)에서 처리할 필요는 없다.
  • 예를 들어 Image를 Tensor객체로 변환하는 과정은 Dataset으로 데이터를 변환하면서 바로 수행할 수도(성민석 조교님은 그냥 이렇게 하시라고 하심!! 별 상관 없는 듯) 있지만, 모델에 먹이기 직전에 바꾸는 경우도 많다. -> Dataloader에서 데이터를 던져줄때!
  • 모델에 먹이기 직전에 바꾸는것 -> image의 Tensor 변화는 학습에 필요한 시점에 변환 getitem시에 변환된 Tensor를 반환해주는 것이 아니라, CPU에서는 tensor로 바꾸고 GPU로 넘겨주면 GPU는 학습을 한다. -> Dataloader에서 함
  • __init__() : Dataset 객체를 생성할때 데이터를 어떻게 불러올껀지 img같은 경우 data directory를 정의하던가 함..
  • __ len__() : 데이터의 전체 길이
  • __getitem__() : map-style !! 하나의 데이터를 가져올때 어떻게 반환을 해줄건지 보통 index같은 것을 사용함.

Transform

  • transforms : 데이터 전처리 하거나 데이터 agumentation할때 데이터를 조금씩 변형 해주거나.. 가능 (텐서로 바꿔주기도 가능 → ToTensor() : 0~1사이로 normalization해줌)
  • 데이터 셋을 전처리 하는 부분과, 데이터셋을 텐서(숫자)로 바꾸는 부분은 구분이 된다. → Transform에서 한다. Dataset은 하나의 이미지를 넘겨주는 역할

Dataloader

  • Dataset은 하나하나를 어떻게 처리할지를 정의했으면, Dataloader는 데이터를 묶어서 모델에 feeding(먹여주는) 해주는 역할 (batch, shuffle,,,) 가능
  • Data의 Batch를 생성해주는 클래스 학습직전(GPU feed전) 데이터의 변환을 책임.
  • Tensor로 변환 + Batch 처리가 메인 업무 병렬적인 데이터 전처리 코드의 고민 필요.
  • epoch가 한번 돌아가는 것은 dataloader가 한번 돌아가는 것.
  • batch_size에 따라서 마지막에 남는 데이터들을 버리던지 쓰던지 정해줄수 있음. shuffle도 정해줄 수 있다. 
  • 파라미터 collate_fn : 텍스트 데이터 다루다보면 0으로 패딩을 해줘야하는 경우가 있는데 배치 크기에 맞게 해줌
  • sampler는 데이터를 어떻게 뽑을지 index를 정해주는 기법입니다.
  • 프로젝트 폴더의 data_loader.py를 보면 dataloader안에 transform을 해줌

모델 불러오기

model.save()

  1. 학습의 결과를 저장하기 위한 함수.
  2. 모델 형태, 파라미터만도 저장 가능.
  3. 모델 학습 중간 과정의 저장을 통해 최선의 결과모델을 선택.
  4. 만들어진 모델을 외부 연구자와 공유하여 학습 재연성 향상.
  • 모델을 저장할때 pt나 pth를 사용한다. 보통 pt를 씀.
  • torch.save(model.state_dict()) : 모델의 파라미터를 저장(Ordereddict type으로 저장)
  • model.load_state_dict() 같은 모델(architecture)의 형태에서는 파라미터만 load하는방식!!
  • torch.save(model), model torch.load() : 모델의 architecture(코드로)와 함께 저장 python pickle형식

checkpoints

  1. 학습의 중간 결과를 저장하여 최선의 결과를 선택!!
  2. earlystopping 기법 사용시 이전 학습의 결과물을 저장
  3. loss와 metric 값을 지속적으로 확인 저장
  4. 일반적으로 epoch, loss, metric을 함께 저장하여 확인
  5. colab에서 지속적인 학습을 위해 필요

Pretrained model Transfer learning

  1. 다른 데이터셋으로 만든 모델을 현재 데이터에 적용
  2. 일반적으로 대용량 데이터셋으로 만들어진 모델의 성능 상승!!!
  3. 현재의 DL에서는 가장 일반적인 학습 기법!
  4. backbone architecture가 학습된 모델에서 일부분(fc)만 변경하여 학습을 수행함.
  • 불러올때는 TorchVision(다양한 기본 모델 제공)을 이용해서 불러올 수 있다.
  • NLP에서는 HuggingFace가 사실상 표준이다!
  • pretrained model을 활용 시 모델의 일부분을 frozen 시키고 나머지만 커스텀 데이터로 학습시킴!! -> fine tuing 방법은 가지고 있는 데이터 셋 크기, pretrained model 학습 데이터와 내가 가지고 있는 데이터 셋의 유사성, 에 따라 여러가지로 나뉜다.
  • pretrained model을 가져오는 것은 간단히 Trochvision의 models에서 가져와서 쓰면 된다. ImageNet은 1000개의 이미지를 맞춤!! 보통은 pretrained model을 가져와서 내 모델을 만들고 내 모델의 끝에 추가 Linear layer를 만들어준다. → Linear(1000,1)
  • for param in my_model.parameters() : param.requires_grad = False,
    for param in my_model.linear_layers.parameters() : param.requires_grad = True → 마지막 레이어를 제외하고 Frozen!

Monitoring tools for PyTorch -> 대회 진행하면서부터 자세히 공부하고 다뤄볼 생각!

Tensorboard

  • TensorFlow의 프로젝트로 만들어진 시각화 도구!
  • 학습 그래프, metric, 학습 결과의 시각화 지원
  • PyTorch도 연결 가능 → DL 시각화 핵심(기본) 도구. 거의 모든 딥러닝 FrameWork들은 Tensorboard와 연결할 수 있는 방법을 찾고있다.
  • 세부적인 코드에 대한 설명은 Colab에 있음.

Weight & biases (wandb)

  • 딥러닝 뿐만아니라 머신러닝 실험을 원할히 지원하기 위한 상용도구 → mlops 도구중에 하나로 생각된다.
  • 협업, code versioning, 실험 결과 기록 등 제공 (W and B) → code, model, data 등 부분을 나눠서 git처럼 사용 가능, metric 보드 사용해서 그때그때 모델에 점수를 올릴 수있음
  • MLOps의 대표적인 툴로 저변 확대 중
  • → 텐서보드도 좋지만 WandB는 프로젝트 별로 접근을 하기 때문에 공유를 하거나 다른 사람에게 프로젝트 형태로 실험을 공유할때 편하다.
  • 세부적인 코드에 대한 설명은 Colab에 있음.

3. PyTorch 활용하기

Multi - GPU 학습

  • 데이터가 굉장히 많고 모델도 커져서 이제는 하나의 GPU 만으로는 학습이 매우 오래걸림.. -> Multi GPU를 사용하자!
  • Single Node에 Multi GPU가 설치되어있다.
  • Multi GPU에 학습을 분산하는 두가지 방법
    1. 모델을 나누기 Model parallel 
    2. 데이터를 나누기 Data parallel
  • 모델을 나누는 것은 생각보다 예전부터 써왔음(AlexNet)
  • 모델의 병목, 파이프라인의 어려움 등으로 인해 모델 병렬화는 고난이도 과제. - 배치처리를 잘해줘야 해 모델 병렬화로 성능을 올리는 연구 분야로 자리잡음! → 흔하게 많이 쓰진 않음

Data parallel

  1. 데이터를 50만, 50만으로 나눠서 각각 돌림. 
  2. 각각의 GPU에서 나오는 Loss 값을 미분 해줘서 그 각각의 미분값의 평균을 가지고 전체 미분값을 구해줌!
  • 데이터를 나눠 GPU에 할당후 결과의 평균을 취함. minibatch 수식과 유사한데, 한번에 여러 GPU에서 수행.
  • Forward
    1. GPU가 여러 GPU들에게 데이터를 쪼개준다.
    2. 모델들을 각각의 GPU들에게 replicate 시켜준다.
    3. forward 연산을 실행.
    4. 결과값을 한번에 모음. - Global interpreter lock이라는 Python의 Multi processing 제약 때문에!
  • Backward
    1. 각각 4개의 loss gradient를 구해준다.
    2. gradient를 각각의 GPU에 뿌려준다.
    3. 각각의 GPU가 Backward 과정을 거친다. 모든 weight에 대해서 gradient 구함
    4. 최종적으로 gradient를 하나의 GPU에 뿌려주게된다. → 하나의 GPU가 모인 weight gradient로 평균을 내서 gradient를 업데이트 함
  • PyTorch에서는 두가지 방식을 제공함
  • DataParallel : 단순히 데이터를 분배한 후 평균을 취함 → GPU 사용 불균형 문제 발생, Batch 사이즈 감소(한 GPU가 많은 일을 하기 때문에 이 GPU에 맞춰서), GLI ( Global interpreter lock )
    parallel_model = torch.nn.DataParallel(model) → 모델 학습 직전에 이 코드만 써주면 된다.
  • DistributedDataParallel : 각 CPU 마다 process 생서하여 개별 GPU 에 할당 → 하나로 모으는 작업이 없음!! 각각이 forward, backward 하고 gradient 구해서 gradient가지고 개별적으로 연산해서 평균 냄.
    가능한 이유 : 각각이 GPU도 있지만 CPU도 할당을 해주기 때문!!! 
  • DistributedDataParallel은 사용이 좀 더 복잡하다.
    sampler를 사용 → sampler는 데이터를 어떻게 뽑을지 index를 정해주는 기법입니다. sampler를 정의해서 데이터로더에 넣어줘야함.
    pin_memory = True로 해야함 -> DRAM(메모리)에 데이터를 바로바로 올릴 수 있도록 절차를 간소하게 데이터를 저장하는 방식.
    num_workers (데이터를 불러올때 사용하는 서브 프로세스(subprocess) 개수 = CPU의 코어 개수)는 보통 GPU X 4개
  • aws나 gcp, 네이버 클라우드 등을 이용해서 언젠간 multi gpu를 사용해보자..!

Hyperparameter Tuning

  • Hyperparameter : 학습할때 사람이 지정해주는 여러가지 파라미터!

성능이 낮을때 크게 세가지 방법

  1. 모델 변경 → 이미 모델들이 잘 나와있어서 성능의 key 요인은 아니다
  2. 새로운 데이터 추가 or 기존 데이터 변경 : 성능에 가장 중요하다!! 데이터를 많이 모을수록 성능 높아짐!!
  3. 하이퍼파라미터 튜닝 → 생각보다 크지 않다… 마른 수건도 한번짜보자 하는 마인드로 하는것
  • 가장 기본적인 방법은 grid search VS random search
  • 최근에는 베이지안 기반 기법들이 주도!!!!

Ray  : 가장 대표적인 하이퍼 파라미터 튜닝 도구

  • 세부적인 코드에 대한 설명은 Colab에 있음.
  • 대회할때 마지막으로 성능을 쥐어짜보고 싶을때 한번 써보자!

Pytorch Troubleshooting 은 그때 그때 찾아보자..!

 

과제1 내용 간단 정리

torch.gather()

  • 대각선 요소만 가져올때 편한 함수! gather( input, dim, index )
import torch

A = torch.Tensor([[[1, 2],
                   [3, 4]],
                  [[5, 6],
                   [7, 8]]])

index=torch.arange(2).expand(2,2).reshape(2,1,2) # expand 할때에는는 마지막 axis의 차원이 같이야함
# print(f'index', index)

output = torch.gather(A, 1, torch.tensor( [[[0, 1]], [[0, 1]]]))

# out[i][j][k] = input[i][index[i][j][k]][k]

# print(A[0][0][0], A[0][1][1], A[1][0][0], A[1][1][1])
# out[0][0][0] = A[0][index[0][0][0]][0]
# out[0][0][1] = A[0][index[0][0][1]][1]
# out[1][0][0] = A[1][index[1][0][0]][0]
# out[1][0][1] = A[1][index[1][0][1]][1]
output = output.view(2,2)
print(output)
>>> tensor([[1., 4.],
            [5., 8.]])

buffer

  • Parameter : 역전파시 grad계산, 모델 저장시 저장. 
  • Tensor : 역전파시 grad를 게산하지 않아서 업데이트 되지않고, 모델 저장 시에도 무시된다.
  • buffer : 역전파시 grad계산 X, 모델 저장시 저장.  -> BatchNorm에서 사용된다고 한다..
 

apply

  • apply : 모델에 속하는 모든 module에 일일이 함수를 적용 해준다.
  • model.apply(weight_initialization) 과 같이 초기화도 가능하고, 모듈의 출력할때의 형식도 수정 가능하다.

hook

  • 프로그램의 실행 로직을 분석하거나, 프로그램에 추가적인 기능을 제공하고 싶을 때 사용 가능!
  • pytorch의 hook은 두가지로 나뉜다. tensor에 적용, module에 적용.
  • forward전, forward후 -> tensor에만 적용
  • full_backward -> tensor, module 모두 적용 가능

Pytorch를 사용하고는 있었지만 완벽하게 알지는 못했다. 이번 주차에 좋고 많은 강의들과 과제를 통해서 Pytorch와 친해질 수 있어서 좋았다! 특히 gather, buffer, apply, hook,등의 새로운 개념들을 알게 되어서 좋았다.

 

'[Boost Camp AI Tech]' 카테고리의 다른 글

[Boost Camp AI Tech] Week4  (0) 2023.04.30
[Boost Camp AI Tech] Week3  (0) 2023.04.29
[Boost Camp AI Tech] Week1  (4) 2023.03.20
[Review] 네이버 부스트 캠프 AI Tech 5기 합격 후기  (0) 2023.02.14