목차
오늘은 그동안 기초 모델로 GPT-2 구조를 이용해서 나만의 한국어 LLM 모델을 진행하는 과정 중 한국어 성능 향상에 실패한 원인을 분석 정리해 보도록 하겠습니다. 이전에도 여러 번 삽질을 하기는 했지만, 열악한 환경에서 반복해서 실패를 경험하니 이것을 계속해야 할 까라는 생각까지 들기도 합니다. 하여간 문제를 잘 분석하고 대응 방법을 고려해 봐야겠습니다.

나만의 모델 한국어 LLM 모델 성능
나만의 한국어 LLM 모델이라는 자체 프로젝트를 진행하기 전에 사전 실험을 통해 제가 선별한 한국어 학습용 데이터셋의 정합성과 이를 통해 학습하면 한국어 성능에 긍정적인 변화가 발생하는 것은 확인했었습니다. 하지만, 같은 데이터와 비슷한 훈련 레시피를 썼는데도 GPT‑2(Medium) + Unigram 32k 토크나이저 조합은 한국어 능력 향상을 보이지 않고, 훈련을 반복할수록 오히려 정체/후퇴가 나타났습니다.
처음 계획은 합리적이었습니다. “한국어에 맞춘 SentencePiece + Unigram로 토크나이저를 생성하면 한국어에 더 적합하게 조사·어미를 섬세하게 배우겠지?” 그래서 GPT‑2(Medium)의 기존 토크나이저를 새롭게 생성한 한국어 전용 토크나이저로 교체하여 기본 한국어 모델(Pretraining)을 만들었습니다. 이어서 Phase‑A(PT 0.6 + preSFT 0.4) 학습을 통해 한국어 능력을 끌어올릴 계획이었어요.
하지만 한국어 LLM 모델이 생성 결과는 기대와 달랐습니다. 한국어 문장은 생성하지만, 의미와 맥락이 전혀 없더군요. 물론 조사 등은 잘 이어졌지만, 문장이 의미를 가져야 하는데 전혀 엉뚱한 이야기가 표현되더군요. 또 기본적인 상식과 관련한 내용 역시 확보하지 못했어요. 물론, 이 단계에서는 지시/응답에 대한 훈련은 거의 이루어지지 않았으므로, 다음 단계인 Phase‑B(PT 0.2 + preSFT 0.3 + SFT 0.5)를 추가도 더 진행해 봤죠. 하지만, 결과는 더 난감했습니다. Phase-B까지 학습한 모델은 Pretraining 단계의 기본 모델보다도 한국어 능력이 떨어지는 결과를 낳았습니다.
아주 엉망이더군요. 예를 들면 다음과 같이 문장을 생성하더라고요.
“그러므로 그래서 그러므로 그래서…”, “즉 즉 즉…”, “… 하는 것이다. 하는 것이다. 하는 것이다.”
로그를 보면, 그리디 디코딩(가장 가능성 높은 토큰을 계속 고르는 방식)에서는 uni/bi‑gram 다양도(d1/d2)가 크게 떨어지고, 문장 길이는 짧은 루프로 수축했습니다. 샘플링 디코딩(확률적으로 선택)은 이를 완화했지만 품질 들쭉날쭉 문제가 커졌습니다.
토크나이저 교체로 인한 한국어 LLM 성능 문제
토크나이저는 긴 문장을 작은 조각(토큰)으로 잘라 모델이 다루기 쉽게 만드는 도구입니다. 토크나이저를 바꾸면, 같은 문장이라도 잘리는 방식과 조각의 개수가 달라집니다. Unigram 32k를 쓰면 한국어의 조사나 어미 같은 요소를 더 잘 구분할 수 있지만, 그만큼 드물게 나타나는 조합이 많이 생길 수 있습니다. 그러면 한 문장을 표현하는 데 필요한 토큰 수의 평균이 늘어나고, 전체 데이터에서 드문 조합의 비중이 커질 수 있습니다. (통계 용어로는 분포의 ‘꼬리’가 두꺼워진다고 말합니다).
이러한 변화는 훈련과 추론(생성)에서 다음과 같은 영향을 주더군요.
첫째, 드문 조합이 늘어나면 언어 모델은 다음 토큰을 맞히는 일이 어려워집니다. 그 결과 한국어 LLM 모델은 확실한 선택으로 기울고, 생성 단계에서 그 경향이 도드라집니다. 특히 그리디 디코딩처럼 가장 가능성이 높은 토큰만 고르는 방식에선, “그리고/하지만/따라서” 같은 연결어가 반복되는 문장이 흔히 나타납니다.
둘째, 우리는 보통 1,024 토큰처럼 고정된 길이로 문장을 묶어 훈련하고(EOS는 블록마다 1회), 그 경계에서 문제가 커집니다. 블록의 끝에 가까울수록 출력이 비정상적으로 짧아지거나, 다음 블록의 시작에서 ‘정의: …’, ‘질문: …’ 같은 머리말이 자주 반복되는 양상이 나타납니다.
셋째, SFT 단계에서는 정답처럼 보이는 말투를 빨리 익히지만, 내용이 비어 있는 경우가 늘어납니다. 표면은 단정하지만 실제로는 질문을 바꿔 말하거나, 불필요한 길이만 늘어나는 식의 출력이 늘어납니다.
라벨 마스킹 문제도 겹칠 수 있습니다. 원칙은 간단합니다. 프롬프트 구간의 모든 토큰은 손실 계산에서 제외하고(-100), 한국어 LLM 모델이 만들어야 하는 응답만 손실을 줍니다. 그런데 이 원칙이 지켜지지 않아 프롬프트 일부에 손실이 걸리면, 모델은 프롬프트를 조금 변형해 베끼는 쪽이 손실을 줄이는 길이라고 오해할 수 있습니다. 이렇게 되면 질문을 그대로 따라 치거나, 질문 문구를 살짝 바꿔 늘이는 출력이 잦아집니다.
GPT‑2 구조의 절대 위치, 정규화 방식, 표현 폭의 한계
토크나이저를 바꾼 뒤 생긴 불안정성은 GPT‑2의 구조적 특성과 관련이 있었습니다. GPT‑2는 설계상 다음과 같은 제약을 가집니다.
① 절대 위치 임베딩
GPT‑2는 토큰의 위치를 절대 좌표로 기억합니다. 예를 들어 문장을 1,024 토큰 단위로 잘라 학습하면, 모델은 ‘특정 위치 근처에는 늘 비슷한 형태의 문장이 온다’고 인식하게 됩니다. 그 결과 문단이 바뀔 때마다 모델이 이전 패턴을 그대로 반복하거나, 새로운 문단의 첫머리에 같은 문구(예: “정의: …”, “요약하면 …”)를 자주 붙이는 현상이 발생합니다.
② Post‑LayerNorm 구조
GPT‑2는 각 층의 마지막에 정규화를 적용합니다. 이런 구조는 학습이 불안정할 때 그래디언트(오차 전파)가 과도하게 커지거나 진동하기 쉽습니다. 특히 긴 문장이나 복잡한 문맥을 학습할 때 이런 진동이 누적되면, 모델이 짧은 문장 반복이나 의미 없는 되풀이로 수렴하기 쉽습니다.
③ FFN(피드포워드) 표현 폭 제한
GPT‑2의 내부 연산 폭은 비교적 좁습니다. 영어처럼 단어 단위가 명확한 언어에는 충분하지만, 어미와 조사 변화가 많은 한국어에서는 세부 패턴을 표현하는 데 한계가 있습니다. 이런 제약은 한국어 문장에서 형태 변화나 문맥 전환이 잦을수록 더 뚜렷하게 드러납니다.
④ 배치 크기의 한계
12GB VRAM 환경에서는 FlashAttention‑2를 제대로 활용하지 못하거나 불안정하게 동작할 수 있습니다. 이 경우 한 번에 처리할 수 있는 문장 묶음(배치)의 크기가 작아지고, 평균화 효과가 줄어듭니다. 배치가 작을수록 학습 과정의 노이즈가 커져, 위에서 언급한 위치 편향이나 반복 문제가 완화되지 못한 채 남게 됩니다.
결과적으로, 토크나이저 교체로 인한 분포 변화와 GPT‑2의 구조적 한계, 그리고 작은 배치 크기가 서로 얽혀 Phase‑A 단계의 성능 정체와 Phase‑B 단계의 성능 하락으로 이어졌습니다.
한국어 LLM 모델 훈련 중 관찰된 현상과 원인 정리
여기서 말하는 ‘로그’는 실제 한국어 LLM 모델 학습 과정에서 터미널이나 로그 파일에 출력된 기록을 뜻합니다. 학습이 진행되는 동안 남는 메시지, 경고, 손실 곡선 등을 자세히 살펴보면 문제의 원인을 추적할 수 있습니다. 이 실험에서도 그런 기록을 분석하여 다음과 같은 사실을 확인했습니다.
- LoRA/QLoRA 설정 문제없음
구성 자체는 올바르게 작동했습니다. 하지만 GPU 메모리가 제한되어 유효 배치 크기를 충분히 확보하지 못하면, 학습 중 생기는 편향을 평균화하기 어려워집니다. - 특수 토큰 관련 경고 메시지
예를 들어 “The tokenizer has new PAD/BOS/EOS tokens…”라는 문구가 자주 출력되었습니다. 이런 경고는 단순해 보이지만, 토큰 ID가 모델 설정과 불일치하면 손실 계산이나 EOS 처리 과정에서 오류가 발생합니다. 그 결과 모델이 프롬프트를 그대로 따라 쓰거나 의미 없이 반복하는 문제가 생길 수 있습니다. - FlashAttention‑2 설치 오류
일부 환경에서 nvcc(컴파일러)가 없어서 FlashAttention‑2가 비활성화되었습니다. 이 기능이 없으면 배치당 처리량이 줄고, 학습 속도와 안정성이 모두 떨어집니다. 이로 인해 문맥 단절이나 짧은 문장 반복 같은 증상이 더 자주 나타났습니다. - 그리디와 샘플링 결과 비교
그리디 디코딩(가장 확률이 높은 토큰만 선택)은 문장 반복이 심해졌고, 샘플링(확률에 따라 선택)은 일시적으로 완화 효과가 있었지만, 토크나이저 분포나 구조 불안정성 자체를 해결하지는 못했습니다.
이러한 기록을 종합하면, 단순히 하이퍼파라미터를 바꾸거나 디코딩 방식을 조정하는 것으로는 근본적인 문제를 해결할 수 없다는 점이 명확해집니다. 결국 핵심은 토크나이저와 한국어 LLM 모델의 구조가 서로 얼마나 잘 맞느냐에 있으며, 구조적 일관성을 유지하는 것이 성능을 안정적으로 높이는 방법임을 알게 됐죠.
정리하면, 한국어 LLM의 성능을 높이려면 ‘한국어에 더 특화된 토크나이저’를 새로 만들어야 한다는 생각이 자연스럽게 듭니다. 그러나 실제 실험 결과는 반대였습니다. 토크나이저를 바꾸면 데이터의 분포가 달라지고, 그에 따라 학습 과정 전체가 흔들릴 수 있습니다. 이런 변화는 토큰 길이 증가, 희귀 조합 확대, 문장 경계 처리 불안정, 배치 크기 제한 같은 여러 문제를 동시에 일으켜 결과적으로 성능 저하로 이어질 수 있습니다.
같은 데이터와 동일한 학습 일정이라도, 토크나이저와 모델 구조가 얼마나 잘 맞느냐가 성능을 결정짓는 핵심 요인이라는 사실이 명확해졌습니다. 토크나이저가 모델이 세상을 읽는 기준이라면, 아키텍처는 그 세상을 해석하는 틀입니다. 두 요소가 조화를 이룰 때 비로소 안정적이고 일관된 한국어 성능을 얻을 수 있습니다. 이것이 GPT‑2에서 Qwen3로의 전환이 단순한 모델 교체가 아니라, 구조적 필연이었던 것 같습니다.
- 나만의 한국어 AI 모델 만들기 #1 – SentencePiece와 GPT-2 토크나이저
- Corpus(말뭉치) 준비와 데이터 전처리 – 한국어 AI 모델 만들기 #2
- SentencePiece 토크나이저 정의와 HF 래핑 – 나만의 모델 만들기 #3
- Custom model 생성 및 safetensors 저장 방법 – 나만의 모델 만들기 #4