Skip to main content

Hugging Face Accelerate, Weights & Biases로 초강력 업그레이드

이 글에서는 Hugging Face Accelerate를 W&B와 함께 사용하는 방법을 단계별로 살펴보며, 분산 학습과 평가를 얼마나 쉽게 수행할 수 있는지 보여드립니다. 이 글은 AI 번역본입니다. 오역이 있을 경우 댓글로 알려주세요.
Created on September 12|Last edited on September 12
PyTorch 유연합니다. 필요에 따라 원하는 방식으로 맞춤 설정할 수 있습니다. 즉, 여러분이 직접 또한 프로젝트의 95%에서는 신경 쓰지 않아도 될 저수준 하드웨어 커스터마이징까지 모두 처리합니다.
PyTorch의 가장 큰 어려움 중 하나는 다양한 하드웨어 구성(CPU/GPU/TPU)에 맞게 코드를 적응시키는 일입니다. 혼합 정밀도 학습, 그래디언트 누적 등과 관련된 보일러플레이트 코드를 많이 유지해야 합니다. 게다가 일부 고수준 라이브러리는 학습 루프를 포함한 엔지니어링 요소를 모두 추상화해 주지만, 여전히 해당 라이브러리의 API에 익숙해져야 합니다. 또한 사용자 정의 동작을 주입하기 위해 어떤 메서드와 함수를 재정의해야 하는지도 따로 배워야 합니다.
그렇다면 다중 GPU·TPU·fp16에 필요한 보일러플레이트만 깔끔하게 추상화해 주면서, 기존의 순정 PyTorch 코드를 그대로 사용할 수 있게 해 주는 라이브러리가 있다면 어떨까요? Hugging Face Accelerate 바로 그 목적을 위해 만들어졌습니다!
이 글에서는 무엇을 살펴볼지에 대해 허깅 페이스 Accelerate가 제공하는 것과 분산 학습·평가 및 통합을 얼마나 쉽게 수행할 수 있는지 Weights & Biases.
이번 글에서 다룰 내용은 다음과 같습니다:


목차



시작해 봅시다!

왜 Hugging Face Accelerate를 써야 할까요?

이 글을 더 읽기 전에, 왜 처음부터 Accelerate를 써야 하는지 궁금하실 수 있습니다. Accelerate는 실제로 어떤 문제를 해결할까요?
Accelerate가 해결하는 핵심 과제는 다음과 같습니다 분산 학습예를 들어 프로젝트 초기에 특정 사항을 확인하기 위해 단일 GPU에서 모델을 돌려 볼 수 있지만, 프로젝트가 커지면 기존 코드를 멀티 GPU 시스템으로 확장해 학습 속도를, 그러니까 말 그대로 더 빠르게 가속하고 싶은 필요를 느끼게 될 수 있습니다.
그런 경우 Hugging Face Accelerate를 사용하면 CPU, GPU, 멀티 GPU, TPU 어디서든 정확히 같은 코드를 그대로 학습에 쓸 수 있습니다. 순수 PyTorch만으로는 불가능합니다. PyTorch에서는 어떤 학습 환경에서도 파이프라인이 잘 돌아가도록 수많은 if-else 분기를 직접 작성해야 합니다. 또 PyTorch 코드를 디버깅하려면 GPU보다 CPU에서 실행하는 편이 더 의미 있는 오류를 내주는 경우가 많아 도움이 됩니다.
아, 잠깐만요. 아직 더 있습니다. Accelerate를 사용하면 다음과 같은 추가 장점도 있습니다:
  • CPU, GPU, TPU 등 서로 다른 학습 환경을 처리하기 위해 필요한 보일러플레이트 코드를 걷어낼 수 있습니다.
  • 동일한 코드를 그대로 사용해 CPU, GPU, 멀티 GPU, 멀티 노드에서 학습할 수도 있습니다.
  • 분산 평가를 수행하는 편리한 방법입니다.
  • 혼합 정밀도와 그래디언트 누적에 필요한 보일러플레이트 코드를 걷어낼 수 있습니다.
  • 분산 환경에서 로깅과 추적을 강화합니다.
  • 분산 환경에서 학습 상태를 편리하게 저장할 수 있습니다.
  • 완전 샤딩 데이터 병렬 학습
  • DeepSpeed 통합.
  • 분산 환경에서 편리한 로깅을 위한 다양한 실험 트래커(예: Weights & Biases) 통합.
  • 분산 학습을 실행할 수 있는 편리한 CLI 명령을 제공합니다.
  • Jupyter Notebook에서 분산 학습을 실행할 수 있는 편리한 함수입니다.
이 글에서는 이러한 기능을 하나씩 살펴보���습니다.
이 글에서 언급되는 많은 용어와 코드 부분에는 클릭 가능한 링크(파란색 표시)가 포함되어 있습니다. 자세한 정보는 링크된 웹사이트를 방문하시길 권장합니다.
💡

Hugging Face Accelerate 설치 및 구성

Hugging Face Accelerate를 사용하기 전에 먼저 설치해야 합니다. pip 또는 conda로 설치할 수 있습니다.
pip install accelerate
OR
conda install -c conda-forge accelerate
Accelerate는 빠르게 성장하는 라이브러리로, 매일 새로운 기능이 추가되고 있습니다. 아직 릴리스되지 않은 기능을 사용하기 위해 GitHub 저장소에서 설치하는 것을 추천합니다. 터미널에서 다음 명령을 실행하면 됩니다:
pip install git+https://github.com/huggingface/accelerate
Accelerate를 설치했다면, 현재 시스템에 맞게 설정해야 합니다. 다음 명령을 실행하고 표시되는 질문에 순서대로 답변하세요:
accelerate config
구성이 제대로 되었는지 확인하려면 완료 후 다음 명령을 실행하세요:
accelerate env
아래는 혼합 정밀도를 사용하는 단일 머신의 두 GPU를 설명하는 예시 출력입니다.
- `Accelerate` version: 0.11.0.dev0
- Platform: Linux-5.10.0-15-cloud-amd64-x86_64-with-debian-11.3
- Python version: 3.7.12
- Numpy version: 1.19.5
- PyTorch version (GPU?): 1.12.0+cu102 (True)
- `Accelerate` default config:
- compute_environment: LOCAL_MACHINE
- distributed_type: MULTI_GPU
- mixed_precision: fp16
- use_cpu: False
- num_processes: 2
- machine_rank: 0
- num_machines: 1
- main_process_ip: None
- main_process_port: None
- main_training_function: main
- deepspeed_config: {}
- fsdp_config: {}
만약 Apple Silicon Mac을 사용하고 있다면, 이제 Accelerate는 해당 환경에서의 학습을 기본적으로 지원합니다 Apple Silicon M1 GPU. 이를 사용하려면 이 질문에 대해 MPS를 선택하세요:
Which type of machine are you using?
Apple Silicon에서 학습을 활성화했을 때 구성은 다음과 같아야 합니다.
compute_environment: LOCAL_MACHINE
deepspeed_config: {}
distributed_type: MPS
downcast_bf16: 'no'
fsdp_config: {}
machine_rank: 0
main_process_ip: null
main_process_port: null
main_training_function: main
mixed_precision: 'no'
num_machines: 1
num_processes: 1
use_cpu: false
Apple Silicon에서 모델을 학습하기 전에 알아두어야 할 몇 가지 주의사항이 있습니다. 자세한 내용은 문서를 참조하세요. 여기.

비교 및 대비: 일반적인 PyTorch 학습 루프

다음은 여러분이 익숙할 기본적인 PyTorch 학습 루프입니다:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
for batch in training_dataloader:
optimizer.zero_grad()
inputs, targets = batch
inputs = inputs.to(device)
targets = targets.to(device)
outputs = model(inputs)
loss = loss_function(outputs, targets)
optimizer.step()
scheduler.step()
이것은 CPU나 단일 GPU에서만 실행되는 기본 학습 루프입니다(또한 fp16/bf16 혼합 정밀도나 그래디언트 누적과 같은 최신 기법도 지원하지 않습니다).
분산 학습과 fp16/그래디언트 누적을 활성화하려면 수많은 if-else 문을 추가해야 해서 코드 유지보수가 어렵고 오류가 발생하기 쉽습니다.
다음으로, 🤗 Accelerate가 몇 줄의 코드만 추가하면 혼합 정밀도와 그래디언트 누적을 지원하면서 멀티 GPU/TPU/멀티 노드 학습을 매끄럽게 통합하는 방법을 살펴보겠습니다.

비교 및 대비: Hugging Face Accelerate 학습 루프

from accelerate import Accelerator
accelerator = Accelerator()

model, optimizer, training_dataloader, scheduler = accelerator.prepare(
model, optimizer, training_dataloader, scheduler
)

for batch in training_dataloader:
optimizer.zero_grad()
inputs, targets = batch
outputs = model(inputs)
loss = loss_function(outputs, targets)
accelerator.backward(loss)
optimizer.step()
scheduler.step()
위의 학습 루프는 CPU, GPU, 멀티 GPU, TPU, 멀티 노드에서 모두 실행할 수 있습니다. 기존의 순정 PyTorch 코드를 원하는 어떤 하드웨어에도 손쉽게 확장 가능한, 더 견고한 형태로 바꾸는 데 얼마나 적은 노력이 들었는지 확인해 보세요!
위의 학습 루프를 조금 더 자세히 살펴보겠습니다.
먼저 임포트합니다 Accelerator 메인 클래스를 임포트하고 인스턴스화합니다:
from accelerate import Accelerator

accelerator = Accelerator()
참고: The Accelerator 스크립트 전반에서 Accelerator가 제공하는 편리한 함수와 메서드를 활용하려면, 클래스는 스크립트 시작 시점이나 가능한 한 이른 단계에서 인스턴스화해야 합니다.
💡
기존 항목을 모두 제거해야 합니다 .cuda() 또는 .to(device) 호출입니다. accelerator 객체가 이를 자동으로 처리하여 해당 객체들을 올바른 디바이스에 배치합니다.
어떤 이유로 자동 디바이스 배치를 비활성화하고 직접 처리하려면, 다음 인자를 전달하여 비활성화할 수 있습니다 device_placement=False 초기화할 때 Accelerator 클래스.
다음으로 모델, 옵티마이저, 학습/검증 데이터 로더, 그리고 학습률 스케줄러를 다음에 전달해야 합니다 accelerator.prepare() 메서드입니다. 객체를 전달하는 순서는 prepare() 메서드는 무엇이든 상관없습니다. 중요한 것은 전달했던 순서와 동일한 순서로 언패킹하는 것입니다. 이렇게 하면 학습을 위한 준비가 모두 완료됩니다.
예를 들어 Hugging Face Accelerate는 사용 가능한 모든 GPU/TPU 코어에 걸쳐 데이터 로더를 샤딩하여 각 코어가 학습 데이터셋의 서로 다른 부분을 보도록 합니다. 또한 각 반복의 시작 시점에 모든 프로세스의 난수 상태가 동기화됩니다.
실제 배치 크기는 사용 중인 디바이스 수에 스크립트에서 설정한 배치 크기를 곱한 값입니다. 예를 들어, 학습 데이터로더를 만들 때 배치 크기를 16으로 설정하고 4개의 GPU로 학습하면, 실제 배치 크기는 16 × 4 = 64가 됩니다.
💡
학습률 스케줄러는 다음에만 전달해야 합니다 prepare() 스케줄러를 각 옵티마이저 스텝마다 진행(step)해야 할 때.
💡
또한 분산 환경에서 학습하는 경우 학습 데이터로더의 길이가 달라질 수 있습니다. 따라서 학습 데이터로더의 길이를 사용하는 모든 처리는(예: 전체 학습 스텝 수를 기록하려는 경우) 다음 이후에 호출해야 합니다. prepare() 메서드.
눈치채셨겠지만 Accelerator 는 Hugging Face Accelerate 프레임워크 전반을 결속하는 핵심 클래스입니다. 실제로 그것이 어떻게 작동하는지 자세히 살펴보겠습니다.

The 가속기 클래스

The Accelerator 이 프레임워크를 완성하는 핵심은 해당 클래스이며, 이 글의 다음 부분에서 유용한 메서드들도 함께 살펴보게 됩니다. 특히 인스턴스화할 때 중요한 인자들은 아래와 같습니다.
  • device_placement: 로 설정 True 적절한 디바이스로 객체를 자동 배치하도록 하려면 이 옵션을 켜세요. 이상적으로는 켜 두는 것이 좋습니다. 수동으로 디바이스 배치를 처리하려면 꺼도 됩니다.
  • split_batches: 로 설정하면 True 그러면 배치가 디바이스들에 나누어집니다. 예를 들어, 4개의 GPU가 있는 머신에서 데이터 로더를 초기화할 때 배치 크기를 4로 설정했다면, 각 GPU에서의 실제 배치 크기는 4/4 = 1이 됩니다. 다음을 설정하면 False, 그러면 모든 GPU를 합친 유효 배치 크기는 4 * 4 = 16이 됩니다. 이상적으로는 다음과 같이 설정하는 것이 좋습니다 False.
  • mixed_precision: Accelerate는 혼합 정밀도 로직을 자동으로 처리하므로, 혼합 정밀도와 완전 정밀도 사이를 전환하기 위한 if-else 문을 작성할 필요가 없습니다. 혼합 정밀도를 비활성화하려면 'no'를 전달하세요. 혼합 정밀도를 활성화하려면 'fp16'만 전달하면 됩니다. 또한 Accelerate는 bf16도 지원하므로, 활성화하려면 'bf16'을 전달하세요.
  • gradient_accumulation_steps: 🤗 Accelerate는 그래디언트 누적 로직도 자동으로 처리하여 보일러플레이트 코드를 크게 줄여 줍니다. 그래디언트 누적 단계 수만 전달하면 되며, 이 글의 뒷부분에서 보게 되듯 컨텍스트 매니저를 통해 나머지는 Accelerate가 알아서 처리합니다.
  • cpu: 만약 True, GPU가 있어도 CPU에서만 학습하도록 강제합니다. 디버깅할 때 유용합니다.
  • log_with: 사용할 실험 추적기. Weights & Biases를 사용하려면 다음을 전달하세요 wandb 이제 실험 추적에 Weights & Biases를 사용할 준비가 모두 완료되었습니다.
Accelerate가 받아들이는 인자는 이보다 더 많으며, 여기에서 하나하나 모두 다루기는 어렵습니다. The 문서 꽤 잘 정리되어 있으니, 인자들을 한 번 살펴보세요 여기.

그라디언트 누적 수행

더 큰 배치 크기로 학습해야 하지만 GPU 메모리가 제한적이라면, 그라디언트 누적은 효과적인 전략입니다.
그라디언트 누적은 지정한 스텝 수만큼 그라디언트를 누적해 더 큰 배치 크기를 모사합니다. Hugging Face Accelerate에서 그라디언트 누적을 사용하려면 다음 인자를 전달하기만 하면 됩니다 gradient_accumulation_steps 시작하면서 필요한 개수로 Accelerator 클래스를 사용하고 학습 루프를 그 안에 감싸세요 accumulate() 컨텍스트 매니저.
다음은 Hugging Face Accelerate에서 그라디언트 누적을 활성화한 학습 루프 예시입니다:
from accelerate import Accelerator

accelerator = Accelerator(gradient_accumulation_steps=2)

model, optimizer, training_dataloader, scheduler = accelerator.prepare(
model, optimizer, training_dataloader, scheduler
)

for batch in training_dataloader:
# accumulate context manager
with accelerate.accumulate(model):
optimizer.zero_grad()
inputs, targets = batch
outputs = model(inputs)
loss = loss_function(outputs, targets)
accelerator.backward(loss)
optimizer.step()
scheduler.step()
🤗 Accelerate에서 그라디언트 누적을 얼마나 쉽게 사용할 수 있는지 확인해 보세요.
💡

그라디언트 클리핑 수행

그라디언트 클리핑은 신경망에서 그라디언트 폭주를 방지하기 위한 유용한 기법입니다. 혼합 정밀도와 함께 그라디언트 클리핑을 수행하는 경우에는 다음을 권장합니다 스케일 해제 먼저 그라디언트를 처리하세요.
아래는 PyTorch의 성명입니다 문서:
다음에 의해 생성된 모든 그라디언트 scaler.scale(loss).backward() 스케일됩니다. 매 단계 사이에 매개변수의 .grad 속성을 수정하거나 확인하려면 backward() 그리고 scaler.step(optimizer)먼저 스케일을 해제해야 합니다. 예를 들어, 그라디언트 클리핑은 전체 노름을 조정하기 위해 그라디언트 집합을 조작합니다(자세한 내용은 torch.nn.utils.clip_grad_norm_()) 또는 최댓값(자세한 내용은 torch.nn.utils.clip_grad_value_()) 가 사용자 지정 임계값 이하인지 확인합니다. 스케일을 해제하지 않고 클리핑을 시도하면 그라디언트의 노름/최댓값도 스케일된 상태이므로, 원래 비스케일 그라디언트를 기준으로 한 임계값은 무효가 됩니다.
unscale_ 은(는) 각 … 사이클에서 한 번만 호출해야 합니다 optimizer 당당 step 호출은 해당 단계의 모든 그라디언트가 optimizer의 매개변수에 그라디언트가 모두 누적된 뒤에만 호출하세요. 호출은 unscale_ 특정 항목에 대해 두 번 optimizer 사이 step RuntimeError를 발생시킵니다.
💡
순수 PyTorch에서 혼합 정밀도와 그래디언트 클리핑을 사용하는 학습 루프는 다음과 같습니다:
scaler = GradScaler()

for epoch in epochs:
for input, target in data:
optimizer.zero_grad()
with autocast():
output = model(input)
loss = loss_fn(output, target)
scaler.scale(loss).backward()

# Unscales the gradients of optimizer's assigned params in-place
scaler.unscale_(optimizer)

# Since the gradients of optimizer's assigned params are unscaled, clips as usual:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)

# optimizer's gradients are already unscaled, so scaler.step does not unscale them,
# although it still skips optimizer.step() if the gradients contain infs or NaNs.
scaler.step(optimizer)

# Updates the scale for next iteration.
scaler.update()
보시다시피 학습 루프에서 혼합 정밀도, 그래디언트 클리핑, 그래디언트 누적을 한꺼번에 사용하면 상용구 코드가 크게 늘어납니다. 그 결과 코드 유지보수가 더 어려워집니다.
다행히 Hugging Face Accelerate를 사용하면 그래디언트 클리핑을 훨씬 더 효율적으로 수행할 수 있습니다:
from accelerate import Accelerator

max_grad_norm = 1.0
accelerator = Accelerator(mixed_precision="fp16", gradient_accumulation_steps=2)

model, optimizer, training_dataloader, scheduler = accelerator.prepare(
model, optimizer, training_dataloader, scheduler
)

for batch in training_dataloader:
# accumulate context manager (for gradient accumulation)
with accelerate.accumulate(model):
optimizer.zero_grad()
inputs, targets = batch
outputs = model(inputs)
loss = loss_function(outputs, targets)
accelerator.backward(loss)
# gradient clipping
if accelerator.sync_gradients:
accelerator.clip_grad_norm_(model.parameters(), max_grad_norm)
optimizer.step()
scheduler.step()
위 학습 루프는 혼합 정밀도 학습, 그래디언트 누적, 그래디언트 클리핑을 수행합니다. 순수 PyTorch 학습 루프와 비교하면 훨씬 간결해진 것을 확인할 수 있습니다.
이제 그래디언트 클리핑 부분에서 무슨 일이 일어나는지 자세히 살펴보겠습니다:
accelerator.sync_gradients 현재 그래디언트가 모든 프로세스 간에 동기화되고 있는지 확인합니다. 그리고 대신 torch.nn.utils.clip_grad_norm_ ,다음을 사용하는 것이 좋습니다 accelerator.clip_grad_norm_. 내부적으로, Accelerate의 clip_grad_norm_ 는 그래디언트를 클리핑하기 전에 먼저 그래디언트의 스케일을 되돌리는(unscale) 작업을 수행합니다. 소스 코드를 참고해 보세요. 여기 그리고 위 개념들을 다루는 이슈 여기.

분산 평가 수행하기

순수 PyTorch만으로 분산 평가를 시도해 본 적이 있다면, 그 과정이 얼마나 까다로운지 잘 아실 겁니다. Hugging Face Accelerate는 분산 평가를 최대한 쉽게 수행할 수 있는 편리한 방법을 제공합니다.
Hugging Face Accelerate의 gather_for_metrics() 모든 프로세스에서 예측값과 레이블을 모아 지표를 계산하는 수집 메서드입니다. 또한, gather_for_metrics() 데이터셋 끝부분의 일부 샘플이 모든 워커에 균등하게 배치가 나뉘도록 중복될 수 있으므로, 마지막 배치에서 중복 항목을 제거합니다. gather_for_metrics() 수집 과정에서 중복된 데이터를 자동으로 제거하여 지표 계산이 올바르게 이루어지도록 합니다. 아래는 분산 평가를 보여 주는 간단한 코드 예시입니다.
for inputs, targets in validation_dataloader:
predictions = model(inputs)
# Gather all predictions and targets
all_predictions, all_targets = accelerator.gather_for_metrics((predictions, targets))
metrics = calculate_metrics(all_predictions, all_targets)
분산 평가를 수행하지 않고 분산 학습만 하려면, 검증 데이터 로더는 밖에 두면 됩니다 prepare() 메서드.

프로세스 실행하기

Hugging Face Accelerate는 분산 시스템에서 원하는 방식으로 프로세스를 실행할 수 있도록 유용한 메서드들도 제공합니다.
다음 내용의 대부분은 Accelerate 문서에서 발췌했습니다 여기.

단일 서버에서 실행할 때

여러 대의 서버를 사용 중이고 각 서버에서 한 번씩만 실행해야 하는 작업이 있다면, 다음을 사용할 수 있습니다 is_local_main_process.
if accelerator.is_local_main_process:
do_thing_once_per_server()
대부분의 Accelerator 메서드는 함께 사용할 수 있는 데코레이터 대응 버전도 제공합니다. 예를 들어, 다음과 같이 함수를 감쌀 수 있습니다 on_local_main_process() 데코레이터를 사용하면 함수 실행에서도 동일한 동작을 구현할 수 있습니다:
@accelerator.on_local_main_process
def do_my_thing():
"Something done once per server"
do_thing_once_per_server()

모든 서버에서 한 번만 실행하기

모든 서버에서 한 번만 실행해��� 하는 구문에는 다음을 사용하세요 is_main_process:
if accelerator.is_main_process:
do_thing_once()
마찬가지로, 데코레이터 대응을 사용해 함수 실행을 감쌀 수 있습니다:
@accelerator.on_main_process
def do_my_thing():
"Something done once per server"
do_thing_once()

특정 프로세스에서

특정 전체 프로세스 인덱스나 로컬 프로세스 인덱스에서만 함수를 실행해야 한다면, 이를 위한 유사한 데코레이터들을 사용할 수 있습니다:
@accelerator.on_local_process(local_process_idx=0)
def do_my_thing():
"Something done on process index 0 on each server"
do_thing_on_index_zero_on_each_server()

@accelerator.on_process(process_index=0)
def do_my_thing():
"Something done on process index 0"
do_thing_on_index_zero()

인쇄

모든 프로세스에서 출력하면 콘솔 로그가 넘쳐서 읽기 어려워집니다. 프로세스마다 한 번만 출력하려면 Hugging Face Accelerate가 제공하는 print 메서드를 사용하세요. 이는 편리하게 출력할 수 있는 방법입니다. 기존에 사용하던 출력 코드를 다음으로 바꾸면 됩니다 print Accelerate의 print 메서드입니다. 내부적으로는 현재 프로세스가 로컬 메인 프로세스인지 여부만 확인합니다. 소스 코드를 확인해 볼 수 있습니다 여기.
accelerator.print("My thing I want to print!")

실행 지연시키기

가끔은 일부 실행을 뒤로 미뤄야 할 때가 있습니다. 파이썬 스크립트를 실행하면 명령문이 순서대로 실행됩니다. 분산 환경(예: 여러 GPU에서 스크립트를 실행하는 경우)에서는 각 프로세스(또는 GPU)가 모든 명령문을 같은 순서로 실행합니다. 다만 일부 프로세스가 다른 프로세스보다 더 빨리 명령을 처리할 수 있습니다.
추가 명령을 실행하기 전에 모든 프로세스가 특정 지점에 도달할 때까지 기다려야 할 수도 있습니다. 예를 들어 모델을 저장하기 전에 모든 프로세스가 해당 지점까지의 명령을 실행했는지(즉, 모든 프로세스의 학습이 끝났는지) 확인해야 합니다. 스크립트에서 모든 프로세스가 특정 지점에 도달할 때까지 대기하려면 Accelerate의 wait_for_everyone() 그 특정 지점에서.
accelerator.wait_for_everyone()
이 명령은 먼저 도달한 모든 프로세스를, 다른 모든 프로세스가 그 지점에 도달할 때까지 차단합니다.

상태 저장 및 불러오기

전달된 객체나 모델을 저장하려면 prepare() 스크립트 시작 부분에서는 메서드 대신 다음을 사용하세요 unwrap_model() 분산 과정에서 추가된 모든 특수 모델 래퍼를 제거하려면 Accelerate의 save() 대신에 torch.save(). 내부적으로, Accelerate의 save() 메서드는 객체를 머신(또는 서버)당 한 번만 저장합니다. 소스 코드를 확인해 볼 수 있습니다 여기. 또한 모델을 저장하기 전에 모든 프로세스가 완료될 때까지 종료된 프로세스를 일시 정지해 두는 것이 유용합니다. wait_for_everyone() (위에서 설명한 내용에 따라). 위에서 언급한 지침을 정확히 따른 간단한 예시는 다음과 같습니다.
model = MyModel()
model = accelerator.prepare(model)
accelerator.wait_for_everyone()
# Unwrap
model = accelerator.unwrap_model(model)
state_dict = model.state_dict()
# Use accelerator.save()
accelerator.save(state_dict, "my_state.pkl")

나중에 학습 상태를 저장해 두었다가 이어서 재개하고 싶을 때가 많습니다. 이를 위해서는 모델, 옵티마이저, RNG 생성기, 그리고 GradScaler를 저장하고 다시 불러와야 합니다. Hugging Face Accelerate에는 이를 빠르게 수행할 수 있는 두 가지 편의 함수가 포함되어 있습니다:
  • 사용하세요 save_state() 위에서 언급한 모든 항목을 폴더 위치에 저장하기 위해
  • 사용하세요 load_state() 이전에 save_state로 저장해 둔 모든 항목을 불러오기 위해
다음을 통해 사용자 정의 객체를 등록해 저장할 수도 있습니다 register_for_checkpointing() 메서드. 객체에 state_dict 그리고 a load_state_dict 해당 기능을 갖추고 체크포인팅에 등록되어 있다면, Hugging Face Accelerate는 위의 두 메서드를 사용해 어떤 객체든 저장하고 불러올 수 있습니다.
다음은 훈련 중 체크포인팅을 사용해 상태를 저장하고 다시 불러오는 예시입니다(Hugging Face Accelerate에서 가져와 일부 수정). 문서)
from accelerate import Accelerator
import torch

accelerator = Accelerator()

my_scheduler = torch.optim.lr_scheduler.StepLR(my_optimizer, step_size=1, gamma=0.99)
my_model, my_optimizer, my_training_dataloader = accelerate.prepare(my_model, my_optimizer, my_training_dataloader)

# Register the LR scheduler
accelerate.register_for_checkpointing(my_scheduler)

# Save the starting state
accelerate.save_state("my/save/path")

# Perform training
# training loop here ...

# Restore previous state
accelerate.load_state("my/save/path")

로깅

Hugging Face Accelerate에는 분산 환경에서의 로깅을 처리하기 위한 자체 로깅 유틸리티가 있습니다. 기본 Python 로깅을 다음으로 교체해야 합니다 로깅 Accelerate의 모듈 로깅 유틸리티입니다. 간단한 예시는 다음과 같습니다:
from accelerate.logging import get_logger

logger = get_logger(__name__)

# logs on all processes
logger.info("My log", main_process_only=False)
# logs only on main process
logger.debug("My log", main_process_only=True)

Weights & Biases로 실험 추적하기

분산 환경에서 실험 추적기를 사용하는 일은 다소 복잡할 수 있지만, Hugging Face Accelerate 덕분에 상당히 간편해졌습니다. Hugging Face Accelerate에서 Weights & Biases를 사용하려면 먼저 다음을 전달해야 합니다 wandblog_with 초기화하는 동안의 매개변수 Accelerator 클래스.
from accelerate import Accelerator
accelerator = Accelerator(log_with="wandb")
실험을 시작할 때, Accelerator.init_trackers() 프로젝트 설정에 사용해야 합니다. init_trackers() 다음 매개변수를 입력으로 받습니다.
  • project_name프로젝트 이름입니다. 이는 당신의 wandb.init() 백그라운드에서 project 인자를 사용합니다.
  • config: 기록할 구성입니다. 전달되는 인자입니다 wandb.init()의 config 인자를 내부적으로 사용합니다.
  • init_kwargs: 특정 트래커의 구성에 전달할 중첩된 kwargs 딕셔너리입니다. __init__ 함수입니다. 또한 다음과 같은 다른 인수들을 전달할 수 있습니다. wandb.init() 이 인수에는 키-값 쌍으로 전달됩니다.
Hugging Face Accelerate를 사용해 W&B 런을 초기화하는 예시는 다음과 같습니다.
from accelerate import Accelerator

accelerator = Accelerator()
hps = {"num_epochs": 5, "learning_rate": 1e-4, "batch_size": 16}
accelerator.init_trackers(
"my_project",
config=hps,
init_kwargs={
"wandb": {
"notes": "testing accelerate pipeline",
"tags": ["tag_a", "tag_b"],
"entity": "gladiator",
}
},
)
W&B 추적을 초기화했다면, 이제 Accelerate의 기능을 사용해 어떤 데이터든 기록할 수 있습니다. log() 이전에 했던 것처럼 메서드로 wandb.log()또한 현재 스텝 번호를 함께 전달하여, 기록된 데이터를 학습 루프의 특정 스텝과 연결할 수 있습니다.
accelerator.log({"train_loss": 1.12, "valid_loss": 0.8}, step=1)
학습을 마쳤다면 다음을 실행하세요 Accelerator.end_training() 모든 트래커가 종료 처리 기능이 있다면 이를 실행할 수 있도록 합니다. 이는 다음을 호출하는 것과 동일합니다 wandb.finish() 런을 종료하고 모든 데이터를 업로드합니다.
accelerator.end_training()
Hugging Face Accelerate가 내부에서 무엇을 하는지 알고 싶다면, 다음을 확인해 보세요 WandBTracker 클래스 여기.

분산 코드 실행하기

이제 Hugging Face Accelerate를 사용해 분산 환경에서 학습하는 방법을 알았으니, 분산 학습에 맞게 수정한 실제 코드를 실행할 차례입니다. 첫 번째 단계는 모든 코드를 다음으로 감싸는 것입니다 main() 함수.
from accelerate import Accelerator

def main():
accelerator = Accelerator()

model, optimizer, training_dataloader, scheduler = accelerator.prepare(
model, optimizer, training_dataloader, scheduler
)

for batch in training_dataloader:
optimizer.zero_grad()
inputs, targets = batch
outputs = model(inputs)
loss = loss_function(outputs, targets)
accelerator.backward(loss)
optimizer.step()
scheduler.step()


if __name__ == "__main__":
main()
메인 함수 안에 다른 중간 함수들도 함께 감쌀 수 있습니다:
def main():
function_which_does_data_processing()
function_which_does_training()
function_which_does_evaluation()

if __name__ == "__main__":
main()
다음으로, 다음 명령으로 실행해야 합니다 accelerate launch.
실행하는 것을 권장합니다 accelerate config 가급적이면 accelerate launch를 사용하기 전에 환경을 원하는 대로 구성하세요. 그렇지 않으면 🤗 Accelerate가 시스템 구성에 따라 매우 기본적인 기본값을 사용합니다.
💡
Hugging Face Accelerate에는 accelerate launch를 통해 시스템에서 코드를 실행할 수 있도록 도와주는 전용 CLI 명령이 있습니다. 이 명령은 다양한 플랫폼에서 스크립트를 실행하는 데 필요한 여러 명령을 한꺼번에 감싸 제공하므로, 각 명령을 일일이 기억하지 않아도 됩니다.
다음 명령으로 스크립트를 빠르게 실행할 수 있습니다:
accelerate launch {script_name.py} --arg1 --arg2 ...
명령의 맨 앞에 accelerate launch만 붙이면 됩니다. 그다음에는 평소처럼 스크립트에 추가 인자와 파라미터를 넘기세요!
이 방식은 다양한 torch spawn 메서드를 실행하므로, 기대되는 환경 변수들도 여기에서 모두 수정할 수 있습니다. 예를 들어, 단일 GPU에서 accelerate launch를 사용하는 방법은 다음과 같습니다:
CUDA_VISIBLE_DEVICES="0" accelerate launch {script_name.py} --arg1 --arg2 ...
더 많은 옵션을 살펴보려면 문서를 참고하세요 여기.

Jupyter 노트북에서 분산 학습 실행하기

분산 환경에 익숙한 분이라면, 예전에는 Jupyter 노트북에서 다중 GPU 학습을 지원하지 않았다는 점을 알고 계실 겁니다. 이제 Hugging Face Accelerate의 notebook_launcher() , 이제 Jupyter 노트북에서도 어떤 형태의 분산 코드든 실행할 수 있습니다. 앞서 본 것처럼, 전체 코드를 하나의 함수로 감싸야 합니다. 그런 다음 그 함수와 인자(튜플 형태), 그리고 학습에 사용할 프로세스 개수를 함께 전달하면 됩니다 notebook_launcher(). (자세한 내용은 문서 자세한 내용은 여기에서 확인하세요).
from accelerate import notebook_launcher
# the arguments that the main function takes
args = ("fp16", 42, 64)
notebook_launcher(main, args, num_processes=2)
이 주제에 대해 더 자세히 알아보려면 다음을 읽어 보세요 문서.

기타 기능

완전 샤딩 데이터 병렬 처리 (FSDP)

다음에서 문서:
더 큰 배치 크기로 초대형 모델을 빠르게 학습하려면 Fully Sharded Data Parallel(FSDP)을 사용할 수 있습니다. 이 데이터 병렬 방식은 옵티마이저 상태, 그래디언트, 파라미터를 샤딩하여 더 많은 데이터와 더 큰 모델을 적합하게 합니다. 자세한 내용과 장점을 알아보려면 다음을 확인하세요 Fully Sharded Data Parallel 블로그.
FSDP에 대해 더 자세히 알아보기 여기.

DeepSpeed

Hugging Face Accelerate에는 또한 통합 기능이 있습니다 Microsoft의 DeepSpeed사용 방법을 알아보려면 다음을 참조하세요 문서.

제한된 리소스로 대형 모델 활용하기

수십억 개의 파라미터를 가진 모델을 제한된 리소스에서 로드해야 한다면 Hugging Face Accelerate의 기능을 사용할 수 있습니다. 사용하는 방법과 그 기술적 배경은 다음을 참조하세요 문서또한 멋진 마님 애니메이션 과정을 설명합니다.

CUDA 메모리 부족 오류 피하기

다음에서 문서:
학습 스크립트를 실행할 때 가장 답답한 오류 중 하나는 “CUDA 메모리 부족(Out-of-Memory)”입니다. 이 오류가 발생하면 스크립트를 처음부터 다시 시작해야 하고, 진행 상황이 모두 사라지며, 대부분의 개발자는 스크립트를 한 번 실행해 두고 계속 돌려두길 원하기 때문입니다.
Accelerate는 다음을 기반으로 한 유틸리티를 제공합니다 토마 이 기능을 제공하기 위해
이 기능을 사용하려면 메인 학습 함수를 다음으로 감싸야 합니다 @find_executable_batch_size(starting_batch_size=8) 데코레이터입니다. 전체 예제를 확인해 보세요 여기.

Hugging Face Accelerate로 TPU에서 학습하기

Hugging Face Accelerate를 사용하더라도 TPU에서의 학습은 멀티 GPU에서의 학습과 조금 다를 수 있습니다. 이 가이드 Accelerate 팀은 주의해야 할 지점과 그 이유, 그리고 전반적인 모범 사례를 보여 주는 것을 목표로 합니다.

요약

이 글에서는 다음과 같이 사용할 수 있는 방법을 살펴보았습니다 Hugging Face Accelerate 분산 환경을 위한 보일러플레이트 코드를 걷어 내고, 순수한 PyTorch 방식으로 작업할 수 있도록 해 줍니다. Accelerate가 제공하는 기능은 이 외에도 많으며, 자세한 내용은 다음 문서에서 확인할 수 있습니다 문서그들의 문서는 꽤 잘 되어 있고, 또한 사용 방법 가이드 그리고 개념 가이드. 또한 다음과 같이 할 수도 있습니다 발표 보기 제공한 Sylvain Gugger Weights & Biases에서 YouTube 채널 자세한 세부 사항을 설명하는 Accelerate 라이브러리.
Hugging Face Accelerate가 실제로 어떻게 동작하는지 보려면 다음을 확인하세요 예제 Accelerate 팀에서 제공했습니다. Hugging Face Transformers 또한 훌륭한 예제 Accelerate 라이브러리를 활용합니다.
다른 보고서도 확인해 보세요 완전 연결 폭넓은 주제를 아우르며 다룹니다.

이 글은 AI로 번역되었습니다. 의역이나 오역이 보이면 댓글로 알려 주세요. 원문 보고서는 다음 링크에서 확인하실 수 있습니다: 원문 보고서 보기