트랜스포머·PEFT 2일 과정4장 · Transformer Decoder와 작은 번역기7 / 17← 이전목차다음 →MetaContents

4장. Transformer Decoder와 작은 번역기

학습과 추론은 다르게 움직인다

학교 받아쓰기 연습과 실제 받아쓰기 시험을 견주어 봅니다. 연습(학습)에서는 선생님이 정답 문장을 다 알고 있으니, 문제지 한 장에 "1번: 첫 낱말은? 2번: 저는 다음은? …"을 한꺼번에 내고 동시에 채점합니다. 시험(추론)에서는 정답이 없습니다. 학생은 첫 낱말을 쓰고, 자기가 쓴 것을 보며 둘째 낱말을 씁니다. 앞 낱말을 쓰기 전에는 뒤 낱말을 쓸 수 없으니 차례로 갈 수밖에 없습니다.

안전, 점검, 보고서를, 요약해, 줘 다섯 토큰의 학습 문장에 Causal Mask 를 씌운 5×5 표로 다섯 Query 를 한 번에 계산하는 모습과, 생성할 때는 다음 토큰을 기다리는 모습을 견준 강사자료 그림

그림 위쪽은 학습입니다. "안전 점검 보고서를 요약해 줘" 다섯 토큰이 이미 다 있으므로, 5×5 점수표에 가림판을 씌워 다섯 위치(Q₁~Q₅)를 한 번에 계산합니다. 각 행에서 "참고" 칸은 자기와 앞쪽, "MASK" 칸은 뒤쪽입니다. 그림 아래쪽은 학습(순환 대기 없음)과 생성(다음 토큰을 기다림)의 차이를 적은 상자입니다.

학습은 정답을 한 칸 밀어 한 번에, 추론은 고른 토큰을 다시 넣으며 한 토큰씩이라는 두 카드를 견준 그림

학습과 추론 견주기

구분학습(Training)추론(Inference)
Decoder 입력정답 문장을 한 칸 민 것(Teacher Forcing)지금까지 모델이 생성한 토큰
계산 방식모든 위치를 한 번에 병렬로(마스크 사용)한 토큰씩 반복해 생성
끝나는 때정답 길이만큼<끝> 이 나오거나 최대 길이에 닿을 때
이 장의 코드translation_trainer.train()translation_model.generate(...)
받아쓰기로 치면정답을 보며 연습, 한꺼번에 채점혼자서 한 낱말씩 받아쓰기

그렇다면 학습에서 Causal Mask 는 왜 필요할까요? 다섯 위치를 한 번에 계산하면 정답 문장 전체가 입력에 들어 있습니다. 가리지 않으면 위치 2가 위치 3의 정답을 미리 보고 베낄 수 있습니다. 그러면 학습 손실은 낮아도 실제 생성에서는 아무것도 못 하는 모델이 됩니다. 반대로 실제 생성은 왜 한 토큰씩일까요? 다음 입력에는 방금 고른 토큰이 들어가야 하는데, 그 토큰을 고르기 전에는 그다음을 계산할 재료가 없기 때문입니다.

짧은 예시

Python
# 다 배운 모델을 "앞 낱말 → 다음 낱말" 사전으로 흉내 낸다(설명용 장난감)
next_word = {"<시작>": "저는", "저는": "학생", "학생": "입니다", "입니다": "<끝>"}

generated = ["<시작>"]          # 추론은 시작 토큰 하나에서 출발한다
max_new_tokens = 10             # 끝 토큰이 안 나와도 여기서 멈춘다

for step in range(max_new_tokens):
    # 모델은 지금까지 만든 것(generated)을 보고 다음 낱말 하나를 고른다
    word = next_word[generated[-1]]
    generated.append(word)      # 고른 낱말을 입력 뒤에 붙인다(자기회귀)
    print(step + 1, generated)
    if word == "<끝>":          # 종료 토큰이 나오면 멈춘다
        break
# 결과:
# 1 ['<시작>', '저는']
# 2 ['<시작>', '저는', '학생']
# 3 ['<시작>', '저는', '학생', '입니다']
# 4 ['<시작>', '저는', '학생', '입니다', '<끝>']

이 코드가 뜻하는 것

정답지 없이 혼자 받아쓰는 시험을 흉내 낸 코드입니다. 한 번 돌 때마다 낱말 하나를 고르고, 그 낱말을 붙인 줄로 다음 바퀴를 돕니다. 여기서 학생의 머릿속이 next_word, 답안지가 generated, 시험 시간 제한이 max_new_tokens 입니다.

줄하는 일쉽게 말하면
generated = ["<시작>"]시작 토큰에서 출발빈 답안지에 첫 칸만
next_word[generated[-1]]다음 낱말 고르기방금 쓴 낱말을 보고 다음을 씀
generated.append(word)고른 낱말을 붙이기쓴 것을 다시 읽을 거리로
if word == "<끝>": break종료 토큰에서 멈춤마침표 찍고 손 들기

학습 때는 네 위치를 한 번에 계산했지만, 여기서는 네 바퀴를 돌아야 합니다. 실습 3의 generate() 가 이 반복을 대신합니다. 실제 모델은 사전이 아니라 Decoder 전체를 한 바퀴마다 다시 계산합니다.

주의할 점

  • 추론에서 앞 낱말을 잘못 고르면 그 실수가 다음 입력이 되어 뒤까지 번질 수 있습니다. 학습 때는 늘 정답을 받았기 때문에, 모델은 이런 상황을 연습한 적이 없습니다.
  • 생성은 토큰 수만큼 반복하므로 긴 답일수록 오래 걸립니다. max_new_tokens 로 상한을 둡니다.
← 이전 절4장 · Decoder 블록과 전체 조립다음 절 →4장 · 작은 영한 번역기의 설계도