Views
No views yet
| 지표 | 수치 | 비고 |
|---|---|---|
| 인접 정확도 (±1점) | 87.5% | 인간 채점관 수준의 실무 합격선 |
| 1점 적중률 | 86.0% | |
| Macro F1-Score | 0.5348 |
| 항목 | 값 |
|---|---|
| 방식 | QLoRA (4-bit NF4) |
| LoRA rank | 32 |
| LoRA alpha | 32 |
| Epochs | 3 |
| Learning rate | 3e-5 |
| Optimizer | adamw_8bit |
| Max length | 1536 |
| Framework | unsloth / trl SFTTrainer |
1import torch
2import re
3from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
4
5BASE_MODEL_ID = "unsloth/Meta-Llama-3.1-8B-bnb-4bit"
6WRITING_ADAPTER = "i-route-ai/iroute-writing-ai"
7
8bnb_config = BitsAndBytesConfig(
9 load_in_4bit=True,
10 bnb_4bit_quant_type="nf4",
11 bnb_4bit_compute_dtype=torch.float16,
12 bnb_4bit_use_double_quant=True,
13)
14
15tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL_ID)
16tokenizer.pad_token = tokenizer.eos_token
17
18model = AutoModelForCausalLM.from_pretrained(
19 BASE_MODEL_ID,
20 quantization_config=bnb_config,
21 device_map="auto",
22)
23model.load_adapter(WRITING_ADAPTER, adapter_name="writing")
24model.set_adapter("writing")
25
26RELAXED_INSTRUCTION = """주어진 지시문과 학생의 답안을 분석하여, 부족한 점과 개선 방향을 포함한 피드백을 작성하고 맨 마지막에 1점부터 4점 사이의
27최종 점수를 부여하시오.
28
29[유연하고 관대한 채점 기준]
30- 4점: 지시문의 핵심 요구사항을 잘 파악하였고 전반적인 흐름이 우수한 답안 (사소한 결함은 너그럽게 만점 처리)
31- 3점: 지시문은 이해했으나 근거가 다소 평이하거나 논리의 깊이가 아쉬운 일반적인 답안
32- 2점: 지시문의 키워드만 겨우 나열했거나 주장의 근거가 심각하게 부족한 답안
33- 1점 (최하점): 같은 말을 무의미하게 반복하거나 꼼수가 명백한 답안"""
34
35ALPACA_PROMPT = "Below is an instruction that describes a task, paired with an input that provides further context. Write a response that
36appropriately completes the request.\n\n### Instruction:\n{}\n\n### Input:\n{}\n\n### Response:\n{}"
37
38student_answer = "선인장은 줄기에 물을 저장해서 사막에서 살 수 있다."
39safe_input = student_answer[:700] # OOM 방지용 700자 제한
40
41prompt = ALPACA_PROMPT.format(RELAXED_INSTRUCTION, safe_input, "")
42inputs = tokenizer([prompt], return_tensors="pt").to("cuda")
43
44with torch.no_grad():
45 outputs = model.generate(
46 **inputs,
47 max_new_tokens=512,
48 temperature=0.1,
49 top_p=0.9,
50 pad_token_id=tokenizer.eos_token_id,
51 )
52
53response = tokenizer.decode(outputs[0], skip_special_tokens=True).split("### Response:\n")[-1].strip()
54print(response)