비동기 LoRA 학습에서 어댑터 슬롯이 하나 더 필요한 이유
TRL의 비동기 LoRA 동기화 코드를 따라 버전 지연 4에 슬롯 6개가 필요한 이유를 설명한다. v6~v11 가상 추적으로 로드·공개·언로드 순서와 표본 폐기 기준을 구분한다.

비동기 강화학습에서는 새 가중치를 학습하는 동안에도 이전 가중치로 시작한 생성 작업이 계속 돌아간다. LoRA 어댑터는 최신 버전 하나만 남겨 두면 충분할 것 같지만, 아직 끝나지 않은 요청이 이전 버전을 찾을 수 있다. 허용하는 버전 지연이 4라면 어댑터 슬롯은 왜 5개가 아니라 6개가 필요할까?
이 글에서는 2026년 11월 7일에 갱신된 TRL AsyncGRPOTrainer 코드 (새 창)를 바탕으로 버전별 LoRA 동기화 경로를 살펴본다. 아래의 v6~v11은 교체 순서를 설명하기 위한 가상 추적이며, 학습이나 성능 측정을 직접 실행한 결과는 아니다.
생성 완료 시각과 학습에 쓰는 시각이 다르다
롤아웃은 모델이 답이나 행동을 생성해 얻은 학습 표본이다. 비동기 방식에서는 생성 작업이 끝나는 순서대로 큐에 들어오고, 학습기는 준비된 표본을 가져가 가중치를 갱신한다. 생성 시간이 길어지거나 큐에서 대기하는 시간이 생기면 표본이 만들어질 때와 소비될 때의 모델 버전이 달라진다.
Harness Adapters 공개 사례 (새 창)의 그림은 여러 생성 세션이 끝난 뒤 작업 단위로 모여 학습 배치를 구성하는 과정을 보여 준다. 그림에 나온 세션 수나 토큰 예산은 해당 사례의 설정일 뿐 TRL의 보편적인 기본값은 아니다. 이 글에서 주목할 부분은 생성 중인 작업, 대기 큐, 학습 단계가 동시에 돌아간다는 점이다.
앞서 살펴본 TRL 코드에서는 현재 버전에서 큐에서 꺼낸 표본의 model_version을 뺀다. 그 차이가 max_staleness보다 크면 표본을 버리고, 같으면 조건을 통과한다. 즉, 지연 4는 4초를 뜻하지 않는다. 똑같이 10초를 기다렸더라도 그사이에 버전이 몇 번 갱신되었는지에 따라 판정이 달라진다.

다섯 버전을 유지하면서 여섯 번째를 불러온다
현재 버전이 v10이고 max_staleness=4인 가상 상황을 가정해 보자. 버전 차이만 따지면 허용 범위는 v6·v7·v8·v9·v10이다. 현재 버전까지 포함하므로 최대 5개다. 이 상태에서 v11을 배포하려면 교체하는 동안 잠깐이나마 v6~v11이 동시에 올라와 있어야 한다. 새 버전을 먼저 불러온 뒤에야 허용 범위를 벗어난 v6을 내리기 때문이다.
코드는 이 순서를 보장하기 위해 min_loras = max_staleness + 2 조건을 검사한다. 현재 버전을 유지하는 슬롯 하나와 교체 중 새 버전을 담는 슬롯 하나가 더해지는 셈이다. 4+2=6은 이 구현에서 요구하는 최소 슬롯 수일 뿐, 모든 LoRA 서버에 적용되는 고정값은 아니다. 또한 학습기 하나의 경로를 기준으로 한 수치이므로, 여러 학습기가 서버를 공유한다면 전체 어댑터 수를 별도로 계산해야 한다.
같은 공개 사례의 LoRA 그림 (새 창)은 기반 모델 하나에 여러 어댑터가 연결되는 구조를 보여 준다. 기반 가중치를 공유하더라도 각 어댑터의 식별 정보와 수명은 따로 관리해야 한다. 이 그림은 공유 구조를 설명하기 위한 것이며, 앞서 말한 6슬롯 계산을 측정하거나 증명하는 자료는 아니다.

로드가 끝난 뒤 새 버전을 알린다
해당 코드의 동기화 과정은 vLLM을 잠시 멈추고 어댑터를 저장한 뒤, 새 버전 이름으로 로드하고 실행을 재개하는 순서로 진행된다. 이어서 허용 범위를 벗어난 어댑터를 내리고, 마지막에 model_version과 롤아웃 워커가 참조하는 버전을 바꾼다. 비동기 방식이라고 해서 동기화 중의 일시 정지까지 없는 것은 아니다.
v11이라는 버전 번호를 워커에 먼저 알리고 실제 로드를 나중에 하면, 워커가 아직 서버에 올라오지 않은 어댑터를 요청할 수 있다. 반대로 슬롯을 아끼려고 v6을 먼저 내리면, 버전이 전환되기 직전까지 이전 버전을 가리키던 요청과 충돌할 수 있다. 이처럼 새 버전을 먼저 준비해 두고 나중에 공개하는 순서 때문에 여분의 슬롯이 필요하다.
v11로 전환된 뒤 큐에서 v6 표본을 꺼내면 버전 차이가 5라서 버려지고, v7 표본은 차이가 4이므로 지연 조건을 통과한다. 이는 어디까지나 학습 표본을 수용할지 결정하는 판정이다. 서버에서 어댑터를 내리거나 디스크에서 파일을 지우는 시점과는 다르다. 실제로 코드에서도 어댑터 파일을 언로드 시점보다 동기화 한 번만큼 더 남겨 두는데, 이는 경로가 뒤늦게 해석되는 요청을 배려한 처리다.
슬롯을 줄이면 받아들일 표본도 달라진다
가용 슬롯이 5개뿐이라면 이 경로에서는 max_staleness를 3으로 낮추는 방법을 생각할 수 있다. 이렇게 하면 현재 버전을 포함한 4개와 교체용 1개로 슬롯을 맞출 수 있다. 다만 현재 버전이 v10일 때 v6 표본은 허용 범위 밖으로 밀려난다. 메모리 설정 하나를 줄인 셈이지만, 이미 생성해 둔 작업 결과를 버리는 기준도 그만큼 엄격해진다.
반대로 슬롯을 늘리면 이전 어댑터를 더 오래 유지할 여유가 생기지만, 그렇다고 표본의 유효성까지 자동으로 보장되지는 않는다. 큐 길이, 큐 대기 시간, 버전 지연, 오래되어 버려진 표본 수를 함께 살펴보면 어느 구간에서 병목이 생기는지 파악하기 쉽다. 큐가 비어 학습기가 대기하는 상황과 큐가 밀려 표본이 오래되는 상황에는 같은 처방을 쓰기 어렵다.
실제 환경에 적용할 때는 먼저 설치된 TRL 버전의 동기화 경로와 서버의 LoRA 설정을 대조한다. 이 글에서 확인한 내용은 특정 커밋의 버전 관리 방식과 교체 순서이며, 학습 품질이나 처리량의 개선 폭은 측정하지 않았다. 슬롯 수를 정할 때는 유지할 버전 수에 교체 순간을 위한 한 자리를 더해야 하고, 지연 한도를 낮출 때는 어떤 표본이 새로 탈락하게 되는지까지 함께 따져 봐야 한다.
