8장. PEFT와 LoRA 학습
손실 곡선 읽기
학생의 성적을 볼 때 문제집 점수만 보면 속기 쉽습니다. 같은 문제집을 세 번 풀면 답을 외워서라도 점수가 오릅니다. 그래서 처음 보는 모의고사 점수를 함께 봅니다. 문제집 점수는 오르는데 모의고사 점수가 떨어지기 시작하면, 이해하지 않고 답을 외우기 시작했다는 신호입니다. 학습 손실(문제집 벌점)과 검증 손실(모의고사 벌점)을 함께 보는 까닭이 이것입니다.
그림의 네 칸이 손실 곡선의 대표적인 네 가지 모양입니다. 첫 칸은 잘 배우는 중이고, 둘째 칸이 과적합 신호입니다. 셋째 칸은 거의 배우지 못하는 경우, 넷째 칸은 학습이 불안정한 경우입니다. 실습 4에서 그리는 곡선은 둘째 칸에 해당합니다.
모양별 해석과 조치
| 모양 | 해석 | 조치 | 학생으로 치면 |
|---|---|---|---|
| 둘 다 꾸준히 감소 | 잘 학습하는 중 | epoch 를 늘려 볼 수 있다 | 문제집도 모의고사도 오름 |
| 학습 손실만 감소, 검증 손실은 증가 | 과적합(학습 데이터를 외우는 중) | epoch 줄이기, 데이터 늘리기, dropout·r 조정 | 답만 외우기 시작 |
| 둘 다 거의 그대로 | 학습이 거의 안 됨 | 학습률 올리기, 데이터·템플릿 점검 | 공부를 안 함 |
| 손실이 튀거나 NaN | 학습이 불안정 | 학습률 낮추기, 정밀도 확인 | 컨디션이 들쭉날쭉 |
NaN(Not a Number)은 계산이 넘쳐 숫자가 아니게 된 값입니다.
실습의 손실 읽기
실습 3에서 실제로 찍힌 값입니다.
| epoch | 학습 손실 | 검증 손실 | 답 토큰 정확도 |
|---|---|---|---|
| 1 | 3.0900 | 3.1265 | 0.394 |
| 2 | 2.4227 | 3.1223 | 0.412 |
| 3 | 1.8684 | 3.2088 | 0.415 |
학습 손실은 3.09 → 2.42 → 1.87 로 꾸준히 내려갑니다. 검증 손실은 1 epoch 에서 2 epoch 사이에 3.1265 → 3.1223 으로 아주 조금 내려갔다가, 3 epoch 에 3.2088 로 다시 올라갑니다. 문제집 점수는 계속 오르는데 모의고사 점수는 2회차가 가장 좋고 3회차에 떨어진 것입니다. 과적합이 시작되었다는 신호로 읽습니다. 이 데이터와 설정이라면 2 epoch 에서 멈추는 쪽이 검증 손실로는 더 낫습니다.
다만 이번 학습의 목표는 "말투 바꾸기"입니다. 검증 손실은 낱말 하나하나를 정답과 똑같이 맞혔는지를 재므로, 말투가 바뀌었는지는 실습 4처럼 답을 직접 읽어 보아야 압니다. 손실과 실제 답을 함께 봅니다.
짧은 예시
import pandas as pd
# 실습 3에서 찍힌 epoch 별 손실(학습 손실은 화면에 찍힌 값 그대로)
log = pd.DataFrame({
"epoch": [1, 2, 3],
"train_loss": [3.0900, 2.4227, 1.8684],
"eval_loss": [3.126545, 3.122271, 3.208835],
})
# diff(): 바로 앞 행과의 차이. 첫 행은 앞이 없어 NaN
log["train_change"] = log["train_loss"].diff().round(4)
log["eval_change"] = log["eval_loss"].diff().round(4)
print(log.to_string(index=False))
# 결과: train_change 는 -0.6673, -0.5543 으로 계속 음수, eval_change 는 -0.0043 다음 0.0866 으로 양수
# idxmin(): 가장 작은 값이 있는 행 번호
best = log.loc[log["eval_loss"].idxmin(), "epoch"]
print("검증 손실이 가장 낮은 epoch:", best) # 결과: 검증 손실이 가장 낮은 epoch: 2이 코드가 뜻하는 것
성적표를 표로 만들고, 회차마다 점수가 얼마나 변했는지 한 열을 더 붙여 본 코드입니다. 여기서 성적표가 log, 회차별 변화가 diff() 열입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
pd.DataFrame({...}) | epoch 별 손실을 표로 | 회차별 성적표 |
.diff() | 바로 앞 회차와의 차이 | 지난번보다 몇 점 변했나 |
log["eval_loss"].idxmin() | 검증 손실이 가장 낮은 행 | 모의고사가 가장 좋았던 회차 |
학습 손실의 변화는 계속 음수(내려감)인데, 검증 손실의 변화는 3 epoch 에서 양수(올라감)로 바뀝니다. 이 부호가 바뀌는 지점이 과적합의 신호입니다.
주의할 점
- 손실 값의 크기 자체보다 두 곡선의 방향을 봅니다. 검증 손실이 학습 손실보다 큰 것은 흔한 일입니다.
- 검증 데이터가 32개로 적으면 곡선이 우연히 흔들리기도 합니다. 한 점만 보고 결론을 내리지 말고 답도 함께 읽습니다.
- 학습 손실은 화면에 소수 넷째 자리까지, 검증 손실은 여섯째 자리까지 찍힙니다. 이 장의 표는 찍힌 값을 그대로 옮겼습니다.