모델 운영

MLOPS / 81번째 글

파국적 망각 — 새로 가르치면 알던 것을 잊는다

미세조정한 모델이 목표 과제는 잘하는데 그 밖에서 이상해지는 현상입니다. 왜 일어나는지, 목표 점수만 보면 왜 안 보이는지, 그리고 건드리는 범위·리허설·학습률로 얼마나 줄일 수 있는지 정리합니다.

PALDYN Team13 MIN READ

지난 글에서 어댑터를 배포하는 길을 정리했다. 그 길을 다 만들고 나서 실제로 가장 자주 오는 신고는 이런 모양이다. 「고객 문의 분류는 확실히 좋아졌는데, 요약을 시키면 예전보다 못합니다.」

목표 과제 점수는 올랐다. 배포 게이트도 통과했다. 그런데 그 모델을 쓰는 다른 자리들이 조금씩 나빠졌다. 이것을 파국적 망각(catastrophic forgetting)이라 부른다 — 새 과제를 학습하는 동안 이전에 할 줄 알던 것이 함께 지워지는 현상이다.

왜 일어나는가

원인은 단순하다. 신경망에는 「분류 담당 파라미터」와 「요약 담당 파라미터」가 따로 없다. 하나의 가중치 행렬이 두 능력 모두에 관여한다.

미세조정은 새 데이터에 대한 손실을 줄이는 방향으로 가중치를 움직인다.

θt+1=θt−η∇θLnew(θt)\theta_{t+1} = \theta_t - \eta \nabla_\theta \mathcal{L}_{\text{new}}(\theta_t)

이 식에는 예전 능력에 대한 항이 아예 없다. 새 손실만 보고 내려가는 것이고, 그 방향이 예전 능력을 지탱하던 값에서 멀어지는 방향이어도 막을 것이 없다. 예전 데이터를 한 줄도 안 보여 주었으니 모델 입장에서는 그 능력을 지킬 이유가 없다.

「망각」이라는 이름이 조금 오해를 부른다. 지식이 삭제된 것이 아니라 그 지식을 꺼내던 경로 위의 값들이 다른 곳으로 옮겨 간 것이다. 실제로 원래 데이터를 조금만 다시 보여 주면 빠르게 회복하는 경우가 많은데, 완전히 사라진 것이라면 그렇게 빨리 돌아오지 않는다.

목표 점수만 보면 안 보인다

이 현상이 오래 방치되는 이유는 원리보다 측정에 있다. 미세조정을 할 때 우리가 만드는 평가셋은 거의 항상 목표 과제의 평가셋이다. 그 축에서 보면 학습은 계속 성공하고 있다.

새로 가르치는 동안 원래 알던 것이 내려간다

두 곡선을 같은 그림에 얹어야 비로소 결정할 것이 생긴다. 목표 점수는 스텝이 늘수록 계속 오르지만 대체로 위로 눕고, 일반 능력은 어느 지점부터 눈에 띄게 내려온다. 둘의 합이 가장 큰 자리는 목표 점수가 최고인 자리보다 앞에 있다.

그러니 미세조정을 시작하기 전에 보존 세트(retention set)를 먼저 만들어 둔다. 목표 과제와 전혀 상관없는, 그러나 그 모델이 계속 할 줄 알아야 하는 것들을 모은 100~300문제다. 학습 중에 이것도 같이 재면 위 그림이 실제로 그려진다.

무엇을 담을지는 세 갈래로 나눠 보면 빠짐없이 챙길 수 있다.

갈래 무엇이 무너지나 보존 세트에 담을 것
일반 능력 요약·번역·코드·추론 같은 원래 잘하던 것 서비스에서 실제로 쓰는 다른 프롬프트 30~50개
형식과 지시 이행 JSON을 내라고 해도 산문이 섞이고, 길이 지시를 무시한다 구조화 출력 요청과 길이·언어 지시 20~30개
안전 정렬 거절해야 할 요청에 답하기 시작한다 거절이 정답인 요청 30개 이상

세 번째가 가장 자주 빠지고 가장 늦게 발견된다. 정렬은 베이스 모델이 사후 학습으로 얻은 성질이라 가중치를 움직이면 함께 흔들린다. 목표 과제와 무관한 도메인으로 미세조정했는데 거절률이 눈에 띄게 떨어지는 일이 실제로 일어난다. 안전이 요구되는 서비스라면 이 축은 회귀 테스트의 필수 항목으로 둔다.

줄이는 법 1 — 얼마나 건드릴지부터 정한다

망각을 줄이는 손잡이 중 가장 효과가 크고 가장 먼저 잡아야 하는 것은 정규화 기법이 아니라 애초에 몇 개의 파라미터를 움직이게 할 것인가다.

건드리는 파라미터가 많을수록 잊을 것도 많아진다

LoRA가 망각에 강한 이유가 여기 있다. 베이스 가중치는 얼어 있고 움직이는 것은 저랭크 행렬 쌍뿐이라, 원래 능력을 지탱하던 값 자체는 그대로 남는다. 표현할 수 있는 변화의 폭이 랭크로 제한되니 크게 배울 수 없는 대신 크게 잊을 수도 없다. 어댑터를 떼면 정확히 원래 모델로 돌아온다는 성질도 여기서 온다.

다만 랭크를 올리고 적용 범위를 넓히면 이 보호막은 얇아진다. 랭크 128에 MLP 층까지 붙이면 움직이는 파라미터가 전체의 몇 퍼센트에 이르고, 그때의 성질은 전체 미세조정 쪽에 가깝다. 「LoRA를 썼으니 망각은 없다」가 아니라 「랭크가 낮은 LoRA는 망각이 적다」가 맞는 문장이다.

줄이는 법 2 — 예전 데이터를 섞는다

리허설(rehearsal)은 새 데이터에 예전 분포의 데이터를 일정 비율 섞어 학습하는 방법이다. 손실 함수에 예전 능력에 대한 항이 없는 것이 원인이었으니, 데이터로 그 항을 만들어 넣는 셈이다.

# 배치의 일부를 예전 분포로 고정한다
new_ds = load_dataset("./support-tickets")       # 목표 과제
old_ds = load_dataset("./general-instructions")  # 보존하고 싶은 것

rehearsal_ratio = 0.15
n_old = int(len(new_ds) * rehearsal_ratio / (1 - rehearsal_ratio))

mixed = concatenate_datasets([
    new_ds,
    old_ds.shuffle(seed=0).select(range(n_old)),
]).shuffle(seed=0)

비율은 10~30% 사이에서 고른다. 실무에서 5%는 대체로 효과가 약하고, 50%를 넘기면 목표 과제 학습 자체가 느려진다. 15%쯤에서 시작해 보존 세트 점수를 보며 조정하는 것이 편하다.

문제는 섞을 예전 데이터를 어디서 구하느냐다. 베이스 모델의 사후 학습 데이터는 대개 공개돼 있지 않다. 세 가지 현실적인 선택지가 있다.

  • 공개 지시 데이터셋을 쓴다. 분포가 정확히 같지는 않지만 「일반적인 지시 이행」이라는 성질은 상당히 붙잡아 준다. 가장 손쉬운 출발점이다
  • 베이스 모델로 직접 만든다. 서비스에서 쓰는 다른 프롬프트들을 미세조정 전 모델에 넣어 응답을 받아 두고, 그것을 정답으로 삼는다(데이터 합성 글의 방식이 그대로 쓰인다). 「미세조정 전 모델처럼 답하라」를 데이터로 적는 것이라 보존 목적에는 가장 정확하다
  • 출력 분포 자체를 붙잡는다. 데이터를 섞는 대신 손실에 항을 하나 더한다

L=Ltask+λ⋅KL ⁣(pθ0(⋅∣x) ∥ pθ(⋅∣x))\mathcal{L} = \mathcal{L}_{\text{task}} + \lambda \cdot \mathrm{KL}\!\left(p_{\theta_0}(\cdot \mid x) \,\|\, p_{\theta}(\cdot \mid x)\right)

θ0\theta_0는 미세조정 전 모델이다. 새 과제를 배우되 원래 모델의 출력 분포에서 너무 멀어지지 말라는 뜻이고, λ\lambda가 그 고삐의 세기다. DPO를 비롯한 선호 학습 계열이 참조 모델을 옆에 두고 도는 것도 같은 이유다. 대신 학습 중에 모델을 두 벌 들고 있어야 하므로 메모리와 시간이 늘어난다.

줄이는 법 3 — 학습률과 에폭

가장 흔한 망각의 원인은 기법 선택이 아니라 너무 세게, 너무 오래 돌린 것이다.

  • 학습률이 크면 한 걸음이 크고, 큰 걸음은 원래 값에서 멀리 데려간다. 전체 미세조정이라면 1e-5 언저리, LoRA라면 1e-4 언저리에서 시작한다
  • 에폭을 늘리면 같은 데이터를 반복해 보며 그쪽으로 더 깊이 눌린다. 소규모 데이터에 3에폭을 넘기면 목표 점수는 거의 안 오르고 보존 점수만 내려가는 구간에 들어가기 쉽다

그리고 데이터가 좁을수록 망각이 심하다. 한 가지 형식의 짧은 응답 2,000건으로 학습하면 모델은 「나는 항상 이렇게 답하는 존재」라고 배운다. 목표 과제 데이터 안에서도 길이와 형식을 조금 섞어 두면 이 쏠림이 눈에 띄게 줄어든다.

무엇부터 할 것인가

순서는 대체로 이렇다.

  1. 보존 세트를 먼저 만든다. 안 보이면 어떤 대책도 효과를 잴 수 없다. 세 갈래를 각각 채운다
  2. 낮은 랭크의 LoRA로 시작한다. 대부분의 사내 과제는 여기서 끝난다
  3. 학습률과 에폭을 낮춰 본다. 보존 점수가 회복되면서 목표 점수가 유지되는 구간이 있는지 본다
  4. 그래도 모자라면 리허설을 15%쯤 넣는다. 예전 데이터는 베이스 모델로 직접 만드는 쪽이 정확하다
  5. 여기까지도 안 되면 그 과제가 정말 미세조정으로 풀 문제인지 되돌아본다. 검색이나 프롬프트로 갈 자리였을 수 있다

정리

파국적 망각은 미세조정의 부작용이 아니라 미세조정이 하는 일 그 자체의 뒷면이다. 손실 함수에 예전 능력에 대한 항이 없으니 지켜질 이유가 없다.

  • 목표 과제 점수만 재면 이 현상은 끝까지 안 보인다. 보존 세트를 학습 시작 전에 만들어 둔다
  • 안전 정렬은 목표 과제와 무관한 학습에서도 흔들린다. 거절이 정답인 문제를 보존 세트에 반드시 넣는다
  • 가장 큰 손잡이는 「얼마나 건드릴 것인가」다. 낮은 랭크의 LoRA가 강한 이유가 여기 있다
  • 리허설과 KL 항은 손실 함수에 빠져 있던 항을 데이터나 정규화로 다시 넣는 두 가지 방법이다

읽어주셔서 감사합니다. 😊

LATEST

모델 운영의 최신 글

모델 운영2026.09.04

KV 캐시 양자화 — 가중치보다 이쪽이 먼저 넘친다

긴 문맥에서 GPU 메모리를 실제로 잡아먹는 것은 가중치가 아니라 KV 캐시입니다. 캐시 크기를 계산하는 법, K와 V를 다르게 다뤄야 하는 이유, 어디까지 줄여도 되는지를 정리합니다.

16 MIN
모델 운영2026.09.04

양자화 보정 — 데이터 128개가 모델 품질을 정한다

양자화에서 스케일을 정하는 절차가 보정입니다. 무엇을 재는지, 데이터를 어디서 몇 개 뽑아야 하는지, 자르는 지점을 어떻게 고르는지, 그리고 잘못된 보정이 어떤 모양으로 드러나는지를 정리합니다.

21 MIN
모델 운영2026.09.03

과제 특화 증류 — 큰 모델의 답을 작은 모델에 옮긴다

범용 성능이 아니라 우리 과제 하나만 잘하는 작은 모델을 만드는 방법입니다. 교사에게 무엇을 받아야 하는지, 데이터를 어떻게 모으고 거르는지, 손익 분기가 어디인지를 정리합니다.

15 MIN