토니의 연습장

LLM train/eval/generate 간단한 예시 본문

AI 일반/모델, 아키텍처, 구현

LLM train/eval/generate 간단한 예시

bellmake 2025. 9. 18. 10:36

 

train 하면서 주기적으로 evaluation 하고 sample text 를 generation

학습하면서 수치적 평가를 병행하며, 동시에 생성 샘플을 통해 성능을 직관적으로 확인해 볼 수 있게 함

 

def train_model_simple(model, train_loader, val_loader, optimizer, device, num_epochs,
                       eval_freq, eval_iter, start_context, tokenizer):
    # Initialize lists to track losses and tokens seen
    train_losses, val_losses, track_tokens_seen = [], [], []
    tokens_seen, global_step = 0, -1

    # Main training loop
    for epoch in range(num_epochs):
        model.train()  # Set model to training mode
        
        for input_batch, target_batch in train_loader:
            optimizer.zero_grad() # Reset loss gradients from previous batch iteration
            loss = calc_loss_batch(input_batch, target_batch, model, device)
            loss.backward() # Calculate loss gradients
            optimizer.step() # Update model weights using loss gradients
            tokens_seen += input_batch.numel()
            global_step += 1

            # Optional evaluation step
            if global_step % eval_freq == 0:
                train_loss, val_loss = evaluate_model(
                    model, train_loader, val_loader, device, eval_iter)
                train_losses.append(train_loss)
                val_losses.append(val_loss)
                track_tokens_seen.append(tokens_seen)
                print(f"Ep {epoch+1} (Step {global_step:06d}): "
                      f"Train loss {train_loss:.3f}, Val loss {val_loss:.3f}")

        # Print a sample text after each epoch
        generate_and_print_sample(
            model, tokenizer, device, start_context
        )

    return train_losses, val_losses, track_tokens_seen


def evaluate_model(model, train_loader, val_loader, device, eval_iter):
    model.eval()
    with torch.no_grad():
        train_loss = calc_loss_loader(train_loader, model, device, num_batches=eval_iter)
        val_loss = calc_loss_loader(val_loader, model, device, num_batches=eval_iter)
    model.train()
    return train_loss, val_loss


def generate_and_print_sample(model, tokenizer, device, start_context):
    model.eval()
    context_size = model.pos_emb.weight.shape[0]
    encoded = text_to_token_ids(start_context, tokenizer).to(device)
    with torch.no_grad():
        token_ids = generate_text_simple(
            model=model, idx=encoded,
            max_new_tokens=50, context_size=context_size
        )
    decoded_text = token_ids_to_text(token_ids, tokenizer)
    print(decoded_text.replace("\n", " "))  # Compact print format
    model.train()

 

1. evaluate_model

  • 목적: 손실(loss) 계산
    모델이 현재 학습 상황에서 얼마나 잘 맞추는지, 학습/검증 데이터셋 일부(eval_iter 배치)로 평균 손실값을 구한다.
  • 동작:
    • calc_loss_loader를 이용해서 train_loader와 val_loader에서 각각 일정 수의 배치를 꺼내 손실 평균을 계산.
    • 학습을 멈추고(eval()), 그래디언트 추적 끄고(no_grad()), 평가 끝난 후 다시 train()으로 돌려놓음.
  • 출력: 숫자 2개 → (train_loss, val_loss).
    즉, 지표 계산용 함수.

2. generate_and_print_sample

  • 목적: 텍스트 생성
    현재까지 학습된 모델로, 지정한 시작 문맥(start_context)에 이어지는 텍스트를 만들어서 출력.
  • 동작:
    • 시작 문맥을 토크나이즈 후 디바이스로 올림.
    • generate_text_simple로 최대 50개 토큰을 새로 생성.
    • 이를 디코딩해서 사람이 읽을 수 있는 문자열로 변환.
    • 출력 시 줄바꿈을 공백으로 바꿔 한 줄로 보기 좋게 만듦.
  • 출력: 실제 문자열 (콘솔에 찍힘).
    즉, 샘플 확인용 함수.

차이 요약

항목 evaluate_model generate_and_print_sample
목적 손실 측정(성능 평가) 텍스트 생성(샘플 확인)
입력 데이터 train_loader, val_loader (배치 단위 데이터셋) start_context (텍스트 문자열)
출력 평균 손실 값 (숫자 2개) 생성된 텍스트 (문자열, 콘솔 출력)
사용 시점 주기적 성능 모니터링 에폭 종료 시 모델이 “언어”를 얼마나 배웠는지 감각적으로 확인
결과 활용 학습 곡선/조기 종료 판단 질적 평가(샘플 문장 자연스러움 등)

  • evaluate_model은 수치적 평가를 해주는 함수,
  • generate_and_print_sample은 질적(텍스트) 샘플링을 보여주는 함수.

둘을 합쳐 쓰면, “숫자로도 확인 + 실제 출력물로도 확인”하면서 학습 과정을 점검할 수 있음.