初始化项目,由ModelHub XC社区提供模型
Model: Marco333/qwen2.5-0.5b-game-commands-stt Source: Original Platform
This commit is contained in:
134
train.py
Normal file
134
train.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
Training script: Fine-tune Qwen2.5-0.5B-Instruct for game command recognition from noisy STT.
|
||||
|
||||
Based on:
|
||||
- arxiv:2502.12923 approach (structured JSON output, synthetic command data)
|
||||
- TRL v1.3.0 SFTTrainer with LoRA (PEFT)
|
||||
- Target: llama.cpp GGUF compatible output (Qwen2 architecture)
|
||||
|
||||
Dataset: Marco333/game-commands-noisy-stt (conversational messages format)
|
||||
Model: Qwen/Qwen2.5-0.5B-Instruct -> fine-tuned -> merge LoRA -> push to Hub
|
||||
|
||||
Usage:
|
||||
pip install trl peft transformers datasets accelerate torch
|
||||
python train.py
|
||||
"""
|
||||
|
||||
import torch
|
||||
from datasets import load_dataset
|
||||
from trl import SFTTrainer, SFTConfig
|
||||
from peft import LoraConfig
|
||||
|
||||
# =============================================================================
|
||||
# Configuration - edit these for your use case
|
||||
# =============================================================================
|
||||
|
||||
MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
|
||||
DATASET_NAME = "Marco333/game-commands-noisy-stt"
|
||||
OUTPUT_DIR = "./qwen2.5-0.5b-game-commands"
|
||||
HUB_MODEL_ID = "Marco333/qwen2.5-0.5b-game-commands-stt"
|
||||
|
||||
# Training hyperparameters
|
||||
LEARNING_RATE = 2e-4 # Higher LR for LoRA (10x base)
|
||||
NUM_EPOCHS = 5
|
||||
BATCH_SIZE = 8
|
||||
GRAD_ACCUM_STEPS = 2
|
||||
MAX_LENGTH = 512 # Short sequences for command recognition
|
||||
WARMUP_RATIO = 0.05
|
||||
|
||||
# LoRA configuration
|
||||
LORA_R = 32
|
||||
LORA_ALPHA = 16
|
||||
LORA_DROPOUT = 0.05
|
||||
|
||||
|
||||
def main():
|
||||
print(f"Training {MODEL_NAME} on {DATASET_NAME}")
|
||||
dataset = load_dataset(DATASET_NAME)
|
||||
|
||||
peft_config = LoraConfig(
|
||||
r=LORA_R,
|
||||
lora_alpha=LORA_ALPHA,
|
||||
lora_dropout=LORA_DROPOUT,
|
||||
bias="none",
|
||||
task_type="CAUSAL_LM",
|
||||
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
|
||||
)
|
||||
|
||||
training_args = SFTConfig(
|
||||
output_dir=OUTPUT_DIR,
|
||||
num_train_epochs=NUM_EPOCHS,
|
||||
per_device_train_batch_size=BATCH_SIZE,
|
||||
per_device_eval_batch_size=BATCH_SIZE,
|
||||
gradient_accumulation_steps=GRAD_ACCUM_STEPS,
|
||||
learning_rate=LEARNING_RATE,
|
||||
lr_scheduler_type="cosine",
|
||||
warmup_ratio=WARMUP_RATIO,
|
||||
bf16=True,
|
||||
max_length=MAX_LENGTH,
|
||||
packing=False,
|
||||
logging_steps=10,
|
||||
logging_first_step=True,
|
||||
disable_tqdm=True,
|
||||
logging_strategy="steps",
|
||||
eval_strategy="epoch",
|
||||
save_strategy="epoch",
|
||||
save_total_limit=2,
|
||||
load_best_model_at_end=True,
|
||||
metric_for_best_model="eval_loss",
|
||||
push_to_hub=True,
|
||||
hub_model_id=HUB_MODEL_ID,
|
||||
hub_strategy="end",
|
||||
report_to="none",
|
||||
assistant_only_loss=True,
|
||||
seed=42,
|
||||
dataloader_num_workers=2,
|
||||
)
|
||||
|
||||
trainer = SFTTrainer(
|
||||
model=MODEL_NAME,
|
||||
args=training_args,
|
||||
train_dataset=dataset["train"],
|
||||
eval_dataset=dataset["test"],
|
||||
peft_config=peft_config,
|
||||
)
|
||||
|
||||
print("Starting training...")
|
||||
train_result = trainer.train()
|
||||
print(f"Done! Loss: {train_result.training_loss:.4f}")
|
||||
trainer.save_model()
|
||||
|
||||
# Merge LoRA into base model for GGUF compatibility
|
||||
print("Merging LoRA...")
|
||||
from peft import AutoPeftModelForCausalLM
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
merged = AutoPeftModelForCausalLM.from_pretrained(OUTPUT_DIR, dtype=torch.bfloat16, device_map="auto")
|
||||
merged = merged.merge_and_unload()
|
||||
merged_dir = f"{OUTPUT_DIR}-merged"
|
||||
merged.save_pretrained(merged_dir)
|
||||
tok = AutoTokenizer.from_pretrained(MODEL_NAME)
|
||||
tok.save_pretrained(merged_dir)
|
||||
|
||||
#print("Pushing to Hub...")
|
||||
#merged.push_to_hub(HUB_MODEL_ID, commit_message="Merged model - LoRA into Qwen2.5-0.5B for game commands")
|
||||
#tok.push_to_hub(HUB_MODEL_ID, commit_message="Add tokenizer")
|
||||
#print(f"Model: https://huggingface.co/{HUB_MODEL_ID}")
|
||||
|
||||
# Quick inference test
|
||||
print("\nInference test:")
|
||||
from transformers import pipeline
|
||||
pipe = pipeline("text-generation", model=merged_dir, dtype=torch.bfloat16, device_map="auto")
|
||||
system = "You are a game command interpreter. The user's input is noisy speech-to-text from a microphone in a gaming environment. Your job is to identify the intended game command from the noisy input.\n\nValid commands: Attack, CastSpell, CloseDoor, Crouch, Defend, DropItem, Heal, Interact, Jump, OpenDoor, OpenInventory, OpenMap, PauseGame, PickUp, Reload, SaveGame, Sprint, Stop, SwitchWeapon, UseItem\n\nRespond with ONLY a JSON object: {\"command\": \"<CommandName>\"}\nIf the input doesn't match any command, respond: {\"command\": \"Unknown\"}"
|
||||
|
||||
for inp in ["opun da dur", "attak enami", "hel me", "pic it op", "hello how are you"]:
|
||||
out = pipe([{"role": "system", "content": system}, {"role": "user", "content": inp}], max_new_tokens=50, do_sample=False)
|
||||
print(f" '{inp}' -> {out[0]['generated_text'][-1]['content']}")
|
||||
|
||||
print("\n\nGGUF conversion (for llama.cpp):")
|
||||
print(f" python llama.cpp/convert_hf_to_gguf.py {HUB_MODEL_ID} --outtype f16 --outfile model.gguf")
|
||||
print(f" ./llama-quantize model.gguf model_q4.gguf Q4_K_M")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user