일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 백준
- 4948
- 1101
- 파이썬
- 15649
- 손실함수
- 백트래킹
- 1002
- 실버
- 설정
- Mac
- 재귀
- 경사하강법
- 그리디 알고리즘
- 밑바닥부터 시작하는 딥러닝
- end to end
- n과 m
- 개발환경
- 9020
- Python
- N-Queen
- BOJ
- 가상환경
- streamlit
- 파이싼
- 신경망 학습
- 기계학습
- pyenv
- Today
- Total
파이톨치
[BoostCamp AI Tech] Training Process 본문
학습 파이프라인의 전체적인 개요는 데이터 준비부터 모델 학습까지 일련의 단계를 효율적으로 연결하는 것을 목적으로 한다. 각각의 단계는 학습 과정에서 중요한 역할을 담당한다.
학습 반복 루프 (전체)
먼저, 어떤 작업(Task)을 수행할지 결정해야 한다. 이 작업에 적합한 데이터를 구성하고, Dataset 클래스와 DataLoader를 선언하여 모델을 학습시킬 준비를 한다. 이후 모델을 선택하고 학습을 진행하는 전체적인 과정을 반복하게 된다.
Dataset과 DataLoader
학습 과정에서 데이터를 처리하고 모델 학습에 사용하는 핵심 클래스이다. Dataset과 DataLoader를 활용하면 데이터를 불러오고 전처리하며 배치(Batch)로 나누어 학습에 적합한 형태로 제공할 수 있다.
왜 사용하는가?
데이터를 단순하게 line-by-line으로 학습 루프에 직접 구현할 수 있지만, 이 경우 코드가 복잡해지고 유지 관리가 어려워진다. 또한 다양한 기능을 직접 구현하는 것은 많은 어려움이 따른다. 따라서 더 나은 가독성과 모듈성을 위해 이러한 작업을 학습 루프에서 분리하고 별도의 클래스로 관리하는 것이 이상적이다. PyTorch는 이러한 작업을 쉽게 처리할 수 있는 Dataset과 DataLoader 클래스를 제공한다.
Dataset
Dataset은 PyTorch의 기본 torch.utils.data.Dataset 클래스를 상속받아 정의하며, 다양한 소스(예: CSV, 이미지 파일)에서 데이터를 로드하고 전처리하는 방법을 정의한다. __len__과 __getitem__이라는 두 가지 필수 구성 요소를 통해 전체 데이터의 길이와 특정 인덱스에 해당하는 데이터를 반환하도록 구현한다. 예를 들어, 이미지 전처리나 CSV 파일로부터 필요한 정보를 선택하는 함수를 구성하고 __getitem__을 통해 사용할 수 있다.
DataLoader
Dataset으로부터 데이터를 배치 단위로 로드하는 역할을 한다. 이를 통해 메모리 사용을 최적화하면서 학습 속도를 향상시키고, 셔플, 반복, 자동 배치 생성, 샘플링 등 다양한 데이터 로딩 과정을 조정할 수 있다.
DataLoader 설정
다양한 옵션을 제공하며, 주요 옵션은 다음과 같다:
- batch_size: 배치로 처리할 데이터의 크기
- shuffle: 데이터의 순서를 무작위로 섞을지 여부
- num_workers: 데이터 로딩에 사용할 병렬 처리 워커의 수
- drop_last: 마지막 배치 크기가 지정한 batch_size보다 작을 경우 이를 버릴지 여부
num_workers의 개수는 어디까지 늘릴 수 있는가?
num_workers는 데이터를 병렬로 로드하기 위해 사용되는 프로세스의 수를 결정한다. 이 값은 CPU 코어의 수와 시스템 메모리 용량에 따라 결정된다. 일반적으로, num_workers의 최댓값은 시스템의 CPU 코어 수에 의해 제한되지만, 최적의 값은 데이터 로딩 속도와 시스템 리소스의 균형을 고려하여 실험적으로 결정하는 것이 좋다.
너무 많은 워커를 사용하면 오히려 메모리 사용량이 급증하고 시스템이 느려질 수 있으므로, 일반적으로 CPU 코어 수 또는 그보다 약간 적은 값을 설정하는 것이 효율적이다.
모델 선언
모델 선언 단계에서는 학습에 필요한 모델을 정의하고, 앞서 정의한 Dataset과의 상호 작용을 통해 입력과 정답을 조절한다. 이 과정에서는 기존에 제공되는 모델 아키텍처를 활용하거나, 특정 작업(Task)에 맞춰 커스텀 모델을 구성할 수 있다.
모델 구성
모델은 다음 두 가지 방식으로 구성할 수 있다:
- Custom CNN: 직접 필요한 네트워크 아키텍처를 정의하여 원하는 형태의 커스텀 CNN(Convolutional Neural Network)을 만들 수 있다. 이 경우, 각 계층(layer)을 세세하게 설정하고 조합하여 사용자의 요구에 맞는 모델을 구축한다.
- 라이브러리 활용: torchvision이나 timm과 같은 PyTorch 기반의 다양한 라이브러리를 활용해 사전 정의된 네트워크 아키텍처(ResNet, EfficientNet 등)를 쉽게 불러와 사용할 수 있다. 이를 통해 복잡한 모델을 처음부터 구현하지 않아도 되고, 사전 학습된 가중치(Weights)를 활용해 학습 속도를 향상시킬 수 있다.
torch.nn.Module의 서브클래스
모든 PyTorch 모델은 torch.nn.Module의 서브클래스로 구현된다. 이를 통해 모델을 정의하고 각 레이어(layer)들을 손쉽게 구성할 수 있다. 중요한 점은, 모델뿐만 아니라 __init__ 함수 내에 정의하는 각 레이어들(예: nn.Conv2d, nn.Linear, nn.ReLU) 또한 torch.nn.Module을 상속받는 클래스들이다. 따라서 이 구조를 활용하면 계층적이고 모듈화된 방식으로 복잡한 네트워크를 구현할 수 있다.
__init__과 forward 메서드
- __init__: 모델의 초기화 메서드로, 네트워크에서 사용할 모든 레이어를 정의하고 초기화한다.
- forward: 데이터가 모델을 통과할 때 수행되는 연산을 정의한다. 이 메서드에서는 앞서 정의한 레이어들을 이용해 입력 데이터를 처리하고 최종 출력을 생성한다.
모델의 가중치 저장 방법
모델을 학습한 후, 가중치(Weights)를 저장하는 것이 일반적인데, 특정 가중치만 선택적으로 저장할 수도 있다. 이를 위해서는 다음과 같은 방법을 사용한다:
- state_dict(): PyTorch 모델의 모든 매개변수(parameters)와 버퍼(buffers)를 담고 있는 딕셔너리로, 필요한 가중치만 추출하여 저장할 수 있다. state_dict에는 각 레이어에 포함된 모든 학습 가능한 파라미터들이 키-값 쌍으로 저장되어 있다.
torch.save(model.state_dict(), 'model_weights.pth')
특정 가중치 저장: 전체 가중치를 저장하는 대신, 특정 레이어의 가중치만 저장하고 싶다면 state_dict에서 필요한 부분만 선택하여 저장할 수 있다.
torch.save(model.layer1.state_dict(), 'layer1_weights.pth')
모델의 상태 변경: model.train()과 model.eval()
- model.train(): 모델을 학습 모드로 설정한다. 이 모드는 드롭아웃(Dropout)이나 배치 정규화(Batch Normalization) 같은 레이어에 영향을 준다. 이 레이어들은 학습 시에만 사용되며, 평가(evaluation) 시에는 다른 방식으로 작동한다.
- model.eval(): 모델을 평가 모드로 설정한다. 이 모드에서는 드롭아웃이 비활성화되고 배치 정규화가 학습 중에 계산된 통계값을 사용한다. 이를 통해 예측 과정에서 안정적인 출력을 얻을 수 있다.
model.train()과 model.eval()의 적용 범위
model.train()이나 model.eval()을 호출하면, 해당 모델을 이루고 있는 모든 레이어에 그 상태가 적용된다. 즉, 모델을 구성하는 각 레이어들이 모두 torch.nn.Module의 서브클래스이기 때문에, 이 호출은 모델 전체에 걸쳐 일괄적으로 적용된다. 따라서 개별 레이어를 따로 설정할 필요 없이 한 번의 호출로 모델 전체의 상태를 변경할 수 있다.
이러한 메서드를 올바르게 사용함으로써 학습 시와 평가 시의 모델 동작을 효과적으로 제어할 수 있다.
학습
학습을 진행하기 위해서는 다음과 같은 요소들을 선언해야 한다.
첫째, 손실 함수(Loss Function)를 정의해야 한다. 손실 함수는 모델의 현재 상태에서 예측값과 실제값 사이의 차이를 수치적으로 나타내며, 이 손실값을 최소화하는 방향으로 모델의 파라미터를 조정하여 모델을 학습하고 최적화하는 데 도움을 준다. 손실 함수를 선택할 때는 문제의 유형(회귀, 분류 등)과 특성에 맞는 함수를 선택하는 것이 중요하다. 문제의 유형마다 다양한 손실 함수가 존재하며, 원하는 학습 방향에 따라 적합한 손실 함수를 선택할 수 있다. 예를 들어, 지도 학습에서는 Supervised Learning Loss Function이나 Contrastive Loss 등이 있다.
손실 함수
손실 함수의 예로는 CrossEntropyLoss가 있다. CrossEntropyLoss는 모델이 정확한 클래스에 대해 높은 확률을 부여하도록 유도하는 함수로, 다중 클래스 분류 문제에 적합하다. PyTorch에서 제공하며, 다양한 옵션을 지원한다.
- weight: 각 클래스에 대한 가중치를 조절하여 클래스 불균형 문제를 다루는 데 도움을 준다.
- size_average와 reduce: 이전 버전의 PyTorch에서 사용되었으며, 배치 내의 각 손실 값을 평균 내는지 여부를 결정했다. 최신 버전에서는 reduction 파라미터로 대체되어 사용되지 않는다.
- ignore_index: 특정 인덱스의 레이블을 무시하고 싶을 때 사용하며, 이 인덱스에 해당하는 레이블은 손실 계산에서 제외된다.
- reduction: 배치 크기로 계산된 손실 값을 어떻게 다룰지를 결정하는 파라미터로, none은 계산된 손실 값을 그대로 반환하며, mean은 손실 값을 배치 크기로 평균내고, sum은 손실 값을 모두 더한 값을 반환한다.
- label_smoothing: 레이블의 ‘0’과 ‘1’ 값을 완화하여 모델이 너무 확신하지 않도록 만듦. 예를 들어, label_smoothing=0.1일 때, 1은 0.9로, 0은 0.1로 조정된다. 이 기법은 모델이 과적합되는 것을 방지하면서 일반화 성능을 향상시키는 데 도움을 준다.
다른 손실 함수로는 Multi-class Classification에 사용되는 CrossEntropyLoss, Negative Log Likelihood Loss (NLLLoss), Binary Classification에 사용되는 BCELoss, 그리고 BCELoss와 Sigmoid를 결합한 BCEWithLogitsLoss가 있다.
Custom Loss는 CrossEntropyLoss 외에도, 어떻게 학습을 진행하고 싶은지에 따라 사용자 정의 손실 함수를 구성할 수 있다. 예를 들어, 데이터 불균형을 더 효과적으로 학습하기 위해 F1 Loss나 Focal Loss를 참고하여 구성할 수 있으며, Multi-label classification의 경우 각 클래스를 이진 분류 문제로 처리하여 손실을 계산한 후, 추론 시 앙상블이나 후처리를 적용하여 가장 확률이 높은 클래스를 선택하는 로직을 구성할 수 있다. 즉, 문제에 맞는 데이터와 모델이 있을 때, 어떻게 학습할지를 결정하고 이에 맞는 손실 함수를 구성하고 선택하는 것이 중요하다.
Optimizer
모델의 학습 과정에서 손실 함수를 최소화하는 모델 파라미터를 찾는 과정은 최적화 알고리즘에 의해 자동화된다. 주요 최적화 알고리즘으로는 SGD(Stochastic Gradient Descent)와 Adam(Adaptive Moment Estimation)이 있다.
SGD는 전통적인 최적화 방법으로, 각 스텝마다 무작위로 선택된 하나의 데이터 샘플에 대해 Gradient를 계산하여 파라미터를 업데이트한다. 이 방법은 데이터의 전체 집합을 사용하는 대신, 샘플 하나씩을 사용하여 파라미터를 조정하므로, 계산량이 줄어들고 빠른 업데이트가 가능하다. 그러나, SGD는 학습 과정에서 노이즈가 많아질 수 있으며, 수렴 속도가 느릴 수 있다.
Adam은 가장 널리 사용되는 최적화 기법 중 하나로, 각 파라미터의 학습률을 적응적으로 조정한다. 이는 초기 학습 속도를 가속화하고, 최적화의 안정성을 높여주는 특징이 있다. Adam은 모멘텀과 RMSprop의 장점을 결합하여, 학습률을 각 파라미터에 맞게 조정하고, 학습을 더 빠르고 안정적으로 진행할 수 있도록 도와준다.
문제의 특성에 따라 최적화되는 속도나 성능은 다를 수 있다. 예를 들어, 데이터 크기, 노이즈의 정도, 배치 크기 등에 따라 다르게 작용할 수 있다. “더 빠른 수렴 속도를 원하는지?”, “더 안정적인 수렴을 원하는지?”, “배치 크기를 매우 크게 두고 학습하고 싶은지?” 등 학습의 목적과 특성에 따라 적합한 최적화 알고리즘이 달라진다. 일반적으로 Adam이 널리 추천되지만, 일반화 성능 측면에서는 오히려 SGD가 더 나은 결과를 보일 수 있다. 관련된 연구와 논문에서는 이러한 내용을 다루고 있으며, 실험을 통해 다양한 최적화 알고리즘의 성능을 비교하고, 필요한 파라미터 설정을 조정하는 것이 중요하다.
따라서, 최적화 알고리즘의 선택은 학습 과정의 목표와 데이터의 특성에 맞추어 신중히 결정해야 하며, 다양한 알고리즘을 실험하여 최적의 결과를 도출하는 것이 바람직하다.
LearningRate Scheduler
StepLR은 학습률을 일정 주기마다 감소시키는 방식이다. 이 스케줄러는 모델이 빠르게 초기 수렴을 이루었을 때, 주기적으로 학습률을 줄여서 수렴을 안정화하고자 할 때 유용하다. 주기적으로 학습률을 조정하여 모델의 학습 과정을 조절할 수 있다.
ExponentialLR은 학습률을 일정 주기마다 지수적으로 감소시킨다. 이 방법은 학습 초기부터 학습률을 부드럽게 감소시키고자 할 때 유용하다. 초기에는 상대적으로 높은 학습률로 시작하여 점차 감소시킴으로써, 안정적인 학습 과정을 유지할 수 있다.
CosineAnnealingLR은 학습률을 cosine의 일부 곡선 형태로 조절한다. 초기에는 높은 학습률에서 시작하여 점차 감소시키다가 다시 증가시키는 방식이다. 이 스케줄러는 여러 주기에 걸쳐 학습률을 조정하면서 장기간에 걸쳐 최적화 성능을 개선하고자 할 때 적합하다.
ReduceLROnPlateau는 검증 데이터셋의 성능 개선이 이루어지지 않을 때 학습률을 감소시키는 방식이다. 과적합을 방지하고, 성능 향상이 정체되었을 때 학습률을 조정하여 추가적인 학습 성능 개선을 도모하고자 할 때 사용된다. 검증 성능을 모니터링하며 학습률을 조절함으로써 모델의 성능을 극대화할 수 있다.
학습률은 모델의 파라미터 업데이트 크기를 결정하며, 너무 높은 학습률은 학습 과정에서 불안정하게 만들 수 있고, 너무 낮은 학습률은 수렴 속도를 느리게 하고 최적의 해에 도달하기 전에 학습이 멈출 수 있다. 따라서 스케줄러는 초기에는 높은 학습률을 설정하여 빠르게 학습을 진행하고, 점차 학습률을 낮춰 수렴 과정을 안정화하는 역할을 한다.
학습설계