파인튜닝을 적용하여 LLM 응답의 문맥 오류 줄이기
왜 파인튜닝을 하게 되었는지
저는 PECSPERT 팀에 합류하며 AI 문장 완성 기능을 개발하였습니다.
문장 완성 기능은 사용자가 조합한 단어카드를 완전한 문장으로 고쳐주는 역할을 합니다.
저는 이 기능을 개발하기 위해 OpenAI의 gpt-4o-2024-08-06 모델을 활용해 기능에 맞는 프롬프트를 설계하여 기능 구현을 완성했으나, 결과 응답에서 문맥 오류가 빈번히 발생했습니다.
특히 자폐 스펙트럼 아동을 위한 교육용 툴에서는 문장이 정확하고 자연스러워야 했기 때문에 이런 오류는 큰 문제로 다가왔습니다.
기존에 제공되는 LLM은 범용적으로 훈련되어 있어 특정 도메인이나 언어 패턴에 맞게 조정이 필요하다는 점을 깨달았습니다. 그래서 파인튜닝을 통해 모델을 제가 원하는 방향으로 개선해보기로 결심했습니다.
이를 통해 문맥 오류를 줄이고, 아동이 이해하기 쉬운 구어체 문장을 생성하는 데 초점을 맞췄습니다.
파인튜닝을 진행하는 과정
이번 글에서는 조사 교정에 중점을 둔 학습 과정에 대해서만 다루며, 아래 단계를 통해 체계적으로 수행했습니다.
데이터 준비
효율적인 학습을 위해 약 30개의 데이터 샘플을 준비했습니다.
목표는 아동 친화적인 단어(예: “물”, “사과”)를 사용해 조사(을/를)를 상황에 맞게 교정하는 것이었습니다.
예를 들어, [“물”, “를”, “마시다”] 입력에 대해 “물을 마셔요” 같은 자연스러운 출력이 필요했습니다.
데이터를 JSONL 형식으로 변환해 OpenAI API에 맞췄으며, 아래는 대표적인 학습 데이터 예시입니다.
{"messages": [{"role": "system", "content": "당신은 단어 배열을 자연스러운 문장으로 보완하는 AI입니다. 사용자가 선택한 단어 사이에 필요한 조사, 접속어, 어미만 삽입하거나 문맥상 동사를 구어체로 바꿔주세요."},
{"role": "user", "content": "다음 단어 배열을 자연스러운 구어체 문장으로 완성하고, 필요한 조사나 접속어는 insertWords로, 어미나 구어체 변형은 transformedWords로 명시해주세요:\n\n[\"사과\", \"먹다\"]"},
{"role": "assistant", "content": "{\"insertWords\": [{\"index\": 1, \"word\": \"를\"}], \"transformedWords\": [{\"index\": 2, \"word\": \"먹어요\"}]}"}]}
모델 설정
기반 모델로 gpt-4o-2024-08-06을 선택하고, 하이퍼파라미터는 n_epochs를 "auto"로 설정해 데이터에 맞는 최적 학습 횟수를 보장했습니다.
여기서 n_epochs는 모델이 학습 데이터를 반복 학습하는 횟수를 의미하며, "auto"로 설정하면 OpenAI가 데이터 크기와 학습 패턴에 따라 적절한 반복 횟수를 자동으로 결정합니다.
추가로 batch_size를 1, learning_rate_multiplier를 2.0, seed를 1로 조정해 안정성과 재현성을 확보했습니다.
batch_size는 한 번에 학습하는 데이터 샘플 수로, 1로 설정해 소량 데이터에서도 세밀한 학습이 가능하도록 했습니다.
learning_rate_multiplier는 학습 속도를 조절하는 값으로, 2.0으로 설정해 학습이 빠르게 진행되도록 유도했습니다.
마지막으로 seed는 난수 생성의 초기값으로, 1로 고정해 동일한 조건에서 학습 결과를 재현할 수 있도록 했습니다.
학습 실행
데이터를 업로드하고 파인튜닝 작업을 시작했습니다.
파인튜닝을 실행하고 나면 OpenAI는 모델을 학습시키는 과정을 시각화된 형태로 제공합니다.
아래는 실제로 제가 학습을 진행했을 때의 대시보드 화면입니다.
학습 로그를 보면 아래와 같은 점을 알 수 있었습니다.
Loss는 초기에는 0.9 이상으로 시작했지만, 10 step 정도만에 거의 0으로 수렴했습니다.
여기서Loss는 모델의 예측값과 실제 정답 간의 차이를 나타내는 값으로, 값이 낮을수록 모델이 데이터를 더 잘 예측하고 있음을 의미합니다. 0에 가까워졌다는 것은 학습 데이터에 대한 오류가 거의 없어졌다는 뜻입니다.Accuracy는 초반 약 84%에서 시작하여, 12 step 이후 100%에 수렴한 뒤 이후 학습 동안 계속 유지되었습니다.
Accuracy는 모델이 입력 데이터를 얼마나 정확하게 예측했는지를 백분율로 나타낸 지표로, 100%에 도달했다는 것은 학습 데이터에 대해 모델이 완벽히 예측했다는 것을 보여줍니다. 다만, 이는 과적합 가능성을 시사할 수 있어 검증 데이터로 추가 확인이 필요할 수 있습니다.
즉, 모델이 비교적 소량의 데이터로도 빠르게 패턴을 학습했고, 그 뒤로도 오버피팅 없이 안정적으로 수렴한 것을 확인할 수 있었습니다.
OpenAI는 학습 과정에서 Checkpoint 저장, fine-tuned 모델 생성, 그리고 Usage Policy 평가를 자동으로 수행하며, 약 10분 만에 50 에포크를 완료했습니다.
사용된 데이터가 30개로 소량이었기 때문에 모델이 학습 데이터에 과도하게 적응해 새로운 데이터에 약할 가능성(과적합)을 염두에 두고 진행 상황을 주의 깊게 점검했습니다.
이는 일반화 성능을 높이기 위한 사전 대비였습니다.
테스트
학습이 모두 끝난 후, 새로운 입력들로 모델을 테스트 하며 결과가 기대에 미치는지 점검했습니다.
결과는 기대에 부합했으나, 데이터 부족으로 인한 한계도 확인되었습니다.
파인튜닝을 하고나서
파인튜닝 후 조사(을/를) 적용 정확도가 약 98%로 상승하며 문맥 오류가 크게 줄었습니다.
그러나 30개 데이터로는 여전히 한계가 있었습니다.
새로운 단어(예: “바나나”)가 포함된 입력에서는 가끔 “바나나를” 대신 “바나나가”로 출력되는 등 일반화 성능이 부족했습니다.
그래프에서 Loss가 0에 수렴하고 Accuracy가 1에 가까웠던 점을 보면, 훈련 데이터에 과도하게 맞춰진 과적합 징후로 보입니다.
느낀 점
파인튜닝은 LLM을 제 필요에 맞게 조정할 수 있는 강력한 도구라는 걸 깨달았습니다.
단 30개의 데이터로도 조사 교정 성능이 개선된 걸 보니, 데이터의 질과 양이 얼마나 중요한지 새삼 느꼈습니다.
다음엔 50~100개 이상의 데이터를 추가해 과적합을 줄이고, 검증 데이터를 활용해 일반화 성능을 높일 계획입니다.
또한, 학습 과정에서 실시간으로 그래프를 확인하며 진행 상황을 볼 수 있었던 점이 흥미로웠고, OpenAI의 대시보드가 직관적이었다는 점도 마음에 들었습니다.
다만, 적은 데이터로 시작한 탓에 결과가 제한적이었기 때문에, 더 많은 시간과 노력을 투자해 점진적으로 개선해나가려 합니다.
이 경험은 AI 모델을 커스터마이징하는 데 자신감을 주었고, 앞으로의 빠르게 변해가는 AI 시대 속에서 큰 도움이 될 것 같다고 느꼈습니다.