--- language: - en - ko license: apache-2.0 base_model: Qwen/Qwen2.5-3B-Instruct tags: - memory - multi-turn - dialogue - json-generation - lora - sft pipeline_tag: text-generation --- # Qwen2.5-3B Memory State Generator [Qwen2.5-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-3B-Instruct)를 멀티턴 대화에서 구조화된 메모리 상태를 추출하도록 파인튜닝한 모델입니다. 멀티턴 대화 파이프라인에서 라우팅 및 검색 전에 가장 먼저 실행되며, 이후 컴포넌트(Router, RAG, LLM)가 활용할 수 있는 `memory_state` JSON을 생성합니다. ``` 사용자 입력 → [Memory State Generator] → Router → LLM/VLM ``` --- ## 모델 설명 | | | |---|---| | **베이스 모델** | Qwen/Qwen2.5-3B-Instruct | | **파인튜닝 방식** | SFT + LoRA | | **학습 데이터** | DialogSum + QMSum | | **최대 시퀀스 길이** | 512 | | **LoRA rank** | 16 | | **GPU** | NVIDIA A100 40GB | | **Epoch** | 3 | | **최종 Validation Loss** | 0.693 | --- ## 출력 형식 대화를 입력하면 아래 형식의 JSON을 출력합니다. ```json { "memory_state": { "key_facts": ["사실1", "사실2"], "unresolved_refs": ["불명확한 지시어나 대명사"], "topic": "대화의 주제", "turn_count": 5 }, "memory_summary": "지금까지의 대화를 한 문장으로 요약한 내용" } ``` --- ## 사용법 ```python from transformers import AutoTokenizer, AutoModelForCausalLM import torch import json model_id = "your-username/qwen2.5-3b-memory-summary-v1" tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained( model_id, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True ) SYSTEM_PROMPT = """You are a Memory State Generator in a multi-turn dialogue system. Given a conversation, extract and output a structured memory state as JSON. Output format (strictly follow this): { "memory_state": { "key_facts": ["fact1", "fact2"], "unresolved_refs": ["any unclear references or pronouns"], "topic": "main topic of the conversation", "turn_count": }, "memory_summary": "One concise sentence summarizing the conversation so far." } Output only valid JSON. No explanation, no markdown.""" dialogue = """ A: RAG 파이프라인 구현 완료했어요. B: 모델은 어떤 걸 쓰기로 했어요? A: Qwen2.5-3B-Instruct로 결정했어요. LoRA로 파인튜닝할 예정입니다. """ messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": f"Conversation:\n{dialogue}"} ] input_text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) inputs = tokenizer(input_text, return_tensors="pt").to(model.device) with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=512, temperature=0.1, do_sample=True, pad_token_id=tokenizer.eos_token_id ) response = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True) parsed = json.loads(response) print(json.dumps(parsed, indent=2, ensure_ascii=False)) ``` --- ## 학습 정보 ### 데이터 | 데이터셋 | 크기 | 설명 | |---|---|---| | [DialogSum](https://huggingface.co/datasets/knkarthick/dialogsum) | 13,031개 | 일상 대화 + 사람이 작성한 요약문 | | [QMSum](https://huggingface.co/datasets/pszemraj/qmsum-cleaned) | 686개 | 회의록 + query 기반 요약 쌍 | 두 데이터셋 모두 `memory_state JSON` 형식으로 변환하여 SFT 학습에 사용했습니다. ### 학습 설정 ```python LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], ) SFTConfig( num_train_epochs=3, per_device_train_batch_size=1, gradient_accumulation_steps=16, learning_rate=2e-4, lr_scheduler_type="cosine", max_seq_length=512, bf16=True, ) ``` ### 학습 Loss | Step | Training Loss | Validation Loss | |---|---|---| | 100 | 14.578 | 0.896 | | 500 | 12.919 | 0.804 | | 1000 | 11.361 | 0.734 | | 1500 | 10.437 | 0.694 | | 2000 | 9.783 | 0.694 | | 2400 | 9.635 | 0.693 | --- ## 한계점 - 대화 형식에 따라 `turn_count` 추출이 부정확할 수 있습니다 - `key_facts`가 구체적인 사실 추출보다 추상적인 요약에 가깝게 나오는 경우가 있습니다 — synthetic 데이터 추가 학습으로 개선 예정입니다 - 짧은~중간 길이 대화에 최적화되어 있습니다 (최대 512 토큰) --- ## 라이선스 Apache 2.0