IL-0428 BigScience · 2022-03-04 (게시일)ai-infra
GPU 320~384개로 돌린 대형 모델 시험 학습이 멈추고 그때마다 노드가 내려갔다
BigScience 는 176B 모델 학습을 시작하기 전에 Jean Zay 의 A100 80GB 8-GPU 노드에서 100B~200B 모델로 시험 학습을 돌렸다. GPU 320~384개를 한 작업에 쓰자 학습이 멈췄다. 몇몇 GPU 가 무작위로 응답하지 않았고 시스템 전체가 타임아웃이 날 때까지 멈췄다. 멈출 때마다 노드 몇 대가 내려가 재부팅 전까지 돌아오지 않았다. 한때는 52개 노드 가운데 13개가 내려가 있었다.
작성자는 모델을 층 방향과 hidden 방향으로 따로 키우며 경계를 찾았다. hidden 을 `1024*14` 로 두면 40층 100B 에서 멈췄고, 층을 80 으로 두면 `1024*12` 145B 에서 멈췄다. 두 실험 모두 노드 사이 트래픽이 어느 수준을 넘으면 시스템이 실패한다는 것을 보였고, `all_reduce` 나 `broadcast` 패킷 하나의 크기 문제는 아니었다. py-spy 로 보니 노드마다 프로세스 6개는 `train_step` 을 마치고 다음 `all_reduce` 로 넘어갔고 2개는 `broadcast` 에 남아 있었다. 원인 후보로 apex 의 `FusedAdam`, PyTorch, NCCL, 시스템 내부 문제를 들었지만 어느 것도 확정하지 못했다.
`CUDA_LAUNCH_BLOCKING=1` 을 켜면 CUDA 연산이 동기로 돌면서 멈춤이 사라졌다. 이 규모에서는 성능 저하도 거의 없었다. 작성자는 파이썬 trace 모듈로 프로세스 320개의 호출을 14GB 분량으로 기록하며 원인을 더 찾았다. 그러다 최종 코드를 시험하는 일로 넘어가야 했고 노드를 더 잃을 수 없어 조사를 멈췄다. 팀은 당분간 `CUDA_LAUNCH_BLOCKING=1` 로 우회하기로 했다.
- 심각도
- –
- 영향 범위
- Test runs of 100B to 200B models on 320 to 384 A100 GPUs hung; each hanging run left nodes down until rebooted, with 13 of 52 nodes down at one point
- 영향 사용자
- –
- 지역
- –
- 감지까지
- –
- 복구까지
- –
증상
A100 GPU 320~384개로 돌린 대형 모델 시험 학습이 멈췄다. 몇몇 GPU 가 무작위로 응답하지 않았고 시스템 전체가 타임아웃이 날 때까지 멈춰 있었다. 멈출 때마다 노드 몇 대가 내려갔다.
멈춤은 규모에 따라 달랐다. 100B 미만 모델은 40개 노드에서 TP=8/PP=10/DP=4 로 돌았고, 200B 모델도 10개 노드에서는 돌았다. 100B 모델을 20~40개 노드에서 돌리면 멈췄다. hidden 을 고정하고 층을 늘리자 10층 25B 와 20층 50B 는 됐고 40층 100B 는 iteration 1 을 마친 뒤 멈췄다. 층을 80 으로 고정하고 hidden 을 늘리자 `1024*10` 100B 는 됐고 `1024*12` 145B 는 멈췄다. 40개 노드에서는 매번 실패했고 20개 노드에서는 가끔 실패했다.
`CUDA_LAUNCH_BLOCKING=0` 인 비동기 실행으로 200B 모델의 두 번째 iteration 을 재면 GPU 160개에 GBS 2048 은 멈출 때가 있었고 GPU 320개에 GBS 2048 은 늘 멈췄다.
py-spy 로 노드 0 과 1 의 파이썬 호출 스택을 떠 보니 노드마다 프로세스 6개는 `train (megatron/training.py:915)` 에 있었고, 2개는 `_aggregate_total_loss (deepspeed/runtime/pipe/engine.py:540)` 를 거쳐 `broadcast (torch/distributed/distributed_c10d.py:1191)` 에 있었다. 6개는 `train_step` 을 마치고 `done_cuda` 의 `all_reduce` 로 넘어가 있었다. 작성자는 나머지 2개가 `train_step` 을 끝내지 못한 채 이미 떠난 6개에 broadcast 하다 멈췄다고 추정했다. 나중에 모든 프로세스에 py-spy 를 돌렸을 때는 여러 프로세스가 응답하지 않아 어디서 멈췄는지 알 수 없었다.
멈추는 설정을 돌릴 때마다 노드 몇 대를 잃었다. 한때는 52개 노드 가운데 13개가 내려가 진단을 이어 갈 수 없었다. 작성자가 있는 곳과 Jean Zay 사이에는 10시간 시차가 있어 노드를 재부팅해 줄 사람이 현지에 없었다. 대부분의 노드는 다음 날 아침에야 돌아왔다.
작성자는 크래시 뒤 돌아오지 않은 노드에 내부 문제가 있다고 의심했지만, 같은 200B 모델을 10개 노드 묶음으로 시험했을 때는 문제가 없었다. 일주일 전에도 심각한 문제를 일으켰던 apex 의 `FusedAdam`, 그리고 PyTorch, NCCL, 시스템 내부 문제도 후보로 들었다. 패킷 하나의 크기 문제는 아니었다. hidden 을 그대로 두고 층만 4분의 1 로 줄이면 잘 돌았기 때문이다.
원인
- 촉발
- 100B 이상 모델을 20~40개 노드에 걸쳐 돌려 노드 사이 NCCL 트래픽이 어느 수준을 넘으면 멈춤이 시작됐다.
감지
–
조치
- `CUDA_LAUNCH_BLOCKING=1` 을 설정하자 멈춤이 사라졌다. 성능을 여러 번 확인해 보니 이 규모에서는 속도 저하가 거의 없었고, 팀은 이 우회책을 당분간 쓰기로 했다.
후속 조치
–
교훈
멈춘 프로세스가 어디서 멈췄는지 알려면 py-spy 로 모든 프로세스의 호출 스택을 뜨거나 파이썬 trace 모듈로 모든 호출을 기록할 수 있다. trace 를 켜면 속도는 느려졌지만 멈춤은 그대로 일어났다. 작성자는 trace 가 멈춘 프로세스를 디버깅하는 데 아주 쓸모 있었다고 봤다. 다만 처음부터 추적하면 데이터 로더와 준비 코드의 쓸모없는 기록까지 쌓이므로 `train_step` 바로 앞에서 추적을 시작하는 편이 나았다. 멈춘 작업을 살피는 두 번째 `srun` 에는 `--gres=gpu:0` 을 줘야 첫 `srun` 이 끝날 때까지 막히지 않는다. 먼저 `salloc` 으로 GPU 를 잡아 두면 SLURM 이 프로세스를 죽여도 그 노드에 들어갈 수 있다.
출처
관련 사례
–
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0428
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0428/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.