Del 3 af 5: Tilpasning af foruddannede modeller
Velkommen tilbage! I vores sidste artikel byggede vi et RAG-system, der giver AI adgang til dine specifikke oplysninger. I dag tager vi det et skridt videre — vi skal faktisk ændre, hvordan en AI-model tænker og reagerer ved at fine-tune den. Jeg vil bruge en open-source-model til dette demo-eksempel.
RAG vs Fine-Tuning: Hvad er forskellen?
Tænk på det på denne måde:
RAG er som at give nogen en opslagsbog. De er stadig den samme person, men nu har de adgang til specifikke oplysninger, når de besvarer spørgsmål.
Fine-tuning er som at sende nogen på specialiseret træning. Du ændrer faktisk, hvordan de tænker og reagerer ud fra dine specifikke krav.
Hvornår skal du fine-tune?
Fine-tuning er kraftfuldt, men det er ikke altid nødvendigt. Overvej fine-tuning, når:
- Du har brug for, at AI'en anvender en specifik tone eller stil
- Dit domæne har specialiseret terminologi eller begreber
- Du ønsker konsistente svar på tværs af mange forskellige scenarier
- RAG ikke giver dig den svarskvalitet, du har brug for
- Du har tilstrækkelig træningsdata (normalt hundredvis af eksempler)
- Du har brug for, at modellen fungerer offline eller i air-gapped-miljøer
Opsætning af dit miljø
Vi bruger Google Colab med en T4 GPU til dette tutorial, men du kan tilpasse dette til ethvert CUDA-kompatibelt miljø:
# Install required packages !pip install bitsandbytesimport os import torch from datasets import Dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, BitsAndBytesConfig ) from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, PeftModel
Valg af den rette model
Til dette tutorial bruger vi TinyLlama-1.1B, men her er nogle fremragende muligheder til forskellige behov:
# Ultra-light models (good for experimentation) # model_name = "distilgpt2" # 82M parameters # model_name = "gpt2" # 124M parameters # model_name = "EleutherAI/gpt-neo-125M" # 125M parameters# Small but capable models # model_name = "microsoft/DialoGPT-medium" # 355M parameters # model_name = "microsoft/DialoGPT-large" # 762M parameters model_name = "TinyLlama/TinyLlama-1.1B-Chat-v1.0" # 1.1B parameters - choosing this one # For production use (if you have more GPU memory) # model_name = "microsoft/phi-2" # 2.7B parameters # model_name = "stabilityai/stablelm-2-1_6b" # 1.6B parameters
Forberedelse af dine træningsdata
Nøglen til vellykket fine-tuning er høj-kvalitets træningsdata. Her er, hvordan vi strukturerer det:
# Sample dataset for MyNextDeveloper (MND)
data = {
"text": [
"User asks: Write a 3-bullet overview of MND.nAssistant: - Remote-first, founded 2022 in Mumbain- Staff augmentation + full-cycle web/API, UI/UX, AI/MLn- Agile/TDD, POSH culture, transparent pricing",
"User asks: Where is MND headquartered?nAssistant: Malabar Hill, Mumbai",
"User asks: What services does MND offer?nAssistant: Staff augmentation, API development, web development, UI/UX design, AI/ML solutions",
"User asks: What is MND's tech stack?nAssistant: Angular, React, Next.js, Node.js, Django, Python, Docker, AWS",
"User asks: What is MND's pricing model?nAssistant: Project pricing starting at $10,000 with hourly rates between $25 and $49",
"User asks: What is MND's mission?nAssistant: To solve the trust gap between startups and engineers by emphasizing empathy, communication, and transparency",
"User asks: What is MND's culture like?nAssistant: Agile practices, test-driven development, and POSH-compliant culture",
"User asks: When was MND founded?nAssistant: 2022"
]
}
# Convert to HuggingFace dataset
dataset = Dataset.from_dict(data)
Vigtige principper for træningsdata:
- Brug konsistent formatering (bemærk "User asks:" og "Assistant:" mønsteret)
- Hold svar faktiske og præcise
- Dæk de vigtigste oplysninger om dit domæne
- Kvalitet over kvantitet: 50 perfekte eksempler er bedre end 500 middelmådige
Effektiv træning med LoRA og kvantisering
I stedet for at fine-tune hele modellen (hvilket kræver enorm GPU-hukommelse), bruger vi to effektivitetsteknikker:
1. Kvantisering (4-bit)
Kvantisering er en kompressionsteknik, der bruges til at gøre store sprogmodeller (LLM'er) mindre og hurtigere uden at reducere nøjagtigheden væsentligt.
- Normalt lagres LLM-vægte som 32-bit flydende kommaetal (FP32).
- Kvantisering reducerer denne præcision til 16-bit (FP16/BF16), 8-bit (INT8), 4-bit (INT4) eller endnu lavere.
👉 Eksempel:
- En model med 10 milliarder parametre i FP32 har brug for ~40 GB hukommelse.
- Hvis vi kvantiserer den til INT8 (8-bit) → har den kun brug for ~10 GB.
- Hvis vi går til INT4 (4-bit) → kun ~5 GB.
⚡ Hvorfor er det nyttigt?
- Gør modeller kan køre på mindre GPU'er (eller endda CPU'er).
- Accelererer inferens.
- Lille afvejning i nøjagtighed, men ofte ubetydelig.
# Configure 4-bit quantization bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_use_double_quant=True, bnb_4bit_compute_dtype=torch.float16 )# Load model with quantization model = AutoModelForCausalLM.from_pretrained( model_name, quantization_config=bnb_config, device_map="auto", torch_dtype=torch.float16 )
2. LoRA (Low-Rank Adaptation)
LoRA er en parametereffektiv fine-tuning (PEFT) metode.
Normalt, for at fine-tune en enorm LLM (som LLaMA-65B eller GPT-J), ville vi have brug for hundredvis af GB GPU-hukommelse. LoRA løser dette ved at:
- Fryse de originale modelværkte.
- Tilføje små træningsbare matricer (low-rank adapters) inden for modellag.
- Under fine-tuning opdateres kun disse små matricer.
👉 Eksempel:
- Fuld fine-tuning af en 65B-model kunne kræve ~1 TB GPU-hukommelse.
- Med LoRA træner du kun nogle få millioner parametre → har brug for < 20 GB GPU-hukommelse.
⚡ Hvorfor er det nyttigt?
- Gør fine-tuning af massive LLM'er muligt på forbrugerhardware (1–2 GPU'er).
- Nemt at "merge" eller "unmerge" adapters → du kan hurtigt skifte opgaver.
- Opnår ofte præstation tæt på fuld fine-tuning.
# Configure LoRA based on model architecture if "TinyLlama" in model_name or "Llama" in model_name: target_modules = ["q_proj", "k_proj", "v_proj", "o_proj"] elif "gpt" in model_name.lower() or "DialoGPT" in model_name: target_modules = ["c_attn", "c_proj"] else: target_modules = ["q_proj", "v_proj"]lora_config = LoraConfig( r=8, # Rank of adaptation lora_alpha=16, # LoRA scaling parameter target_modules=target_modules, lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" ) # Apply LoRA to the model model = get_peft_model(model, lora_config) model.print_trainable_parameters()
Vi træner kun 0,2% af parametrene!
Træning af modellen
# Tokenize the data def tokenize_function(examples): tokenized_inputs = tokenizer( examples["text"], truncation=True, padding="max_length", max_length=512, return_tensors="pt" ) # Create labels by copying input tokens tokenized_inputs["labels"] = tokenized_inputs["input_ids"].clone() return tokenized_inputs# Split dataset train_dataset = dataset.select(range(8)) eval_dataset = dataset.select(range(8, 11)) # Apply tokenization train_dataset = train_dataset.map(tokenize_function, batched=True) eval_dataset = eval_dataset.map(tokenize_function, batched=True) # Configure training training_args = TrainingArguments( output_dir="./mnd-finetune-outputs", num_train_epochs=5, per_device_train_batch_size=4, per_device_eval_batch_size=4, gradient_accumulation_steps=2, warmup_steps=10, learning_rate=3e-4, weight_decay=0.01, logging_steps=1, save_steps=30, eval_strategy="steps", eval_steps=15, save_total_limit=2, load_best_model_at_end=True, fp16=True, report_to=None # Disable wandb logging ) # Create trainer and start training trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, tokenizer=tokenizer, ) print("Starting training...") trainer.train() # Save the adapter adapter_dir = "./mnd-finetune-outputs/final_adapter" model.save_pretrained(adapter_dir) tokenizer.save_pretrained(adapter_dir)
Test af den fine-tuned model
def load_model_for_inference():
"""Load the fine-tuned model for inference"""
# Load base model
base_model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
torch_dtype=torch.float16
)
# Load the fine-tuned adapter
model = PeftModel.from_pretrained(base_model, adapter_dir)
model = model.merge_and_unload()
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(adapter_dir)
return model, tokenizer
def generate_response(model, tokenizer, prompt, max_length=256, temperature=0.7):
"""Generate response for a given prompt"""
formatted_prompt = f"User asks: {prompt}nAssistant:"
inputs = tokenizer.encode(formatted_prompt, return_tensors="pt")
inputs = inputs.to(model.device)
with torch.no_grad():
outputs = model.generate(
inputs,
max_length=max_length,
temperature=temperature,
top_p=0.9,
do_sample=True,
pad_token_id=tokenizer.eos_token_id,
repetition_penalty=1.1
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
assistant_response = response.split("Assistant:")[-1].strip()
return assistant_response
# Load fine-tuned model and test
model, tokenizer = load_model_for_inference()
test_prompts = [
"What makes MND different from other development companies?",
"Can you tell me about MND's team?",
"What is the company culture at MND?"
]
for prompt in test_prompts:
response = generate_response(model, tokenizer, prompt)
print(f"Q: {prompt}")
print(f"A: {response}n")
Google Colab
Her er Google Colab-linket til denne artikel, som du kan køre med et enkelt klik: link
De reelle omkostninger
I modsætning til kommercielle API'er er dine omkostninger primært:
- Indledende opsætning: GPU-tid til træning
- Lagring: Modelværkte (~4GB for TinyLlama med LoRA adapters)
- Inferens: Din egen hardware eller cloud GPU-instanser
For en lille model som TinyLlama kan du køre inferens på:
- Google Colab (gratis tier med begrænsninger)
- AWS t3.medium med GPU (~$0,05/time)
- Din egen hardware (RTX 3060 eller bedre)
Bedste praksis fra virkelig erfaring
1. Start små og skalér op Begynd med distilgpt2 eller gpt2 til at teste dine data og proces, derefter flyt til større modeller.
2. Overvåg for overfitting Med små datasæt kan modeller memorere i stedet for at lære. Se på din evalueringstab.
3. Formatkonsistens er kritisk Det nøjagtige format på dine træningsdata betyder enormt meget. Vær konsistent med punktuation, mellemrum og struktur.
4. Test med usete spørgsmål Test altid med spørgsmål, der ikke er i dine træningsdata, for at sikre generalisering.
5. Gem regelmæssige kontrolpunkter Træning kan blive afbrudt. Gem hyppigt og test mellemliggende kontrolpunkter.
Almindelige fejl og løsninger
Problem: Model genererer gentaget eller meningsløs tekst Løsning: Sænk læringsraten, øg regularisering eller forbedre træningsdatakvaliteten
Problem: Model glemmer generel viden Løsning: Inkludér nogle generelle eksempler i dine træningsdata, eller brug en større basemodel
Problem: Svarene er for generiske Løsning: Gør dine træningseksempler mere specifikke og detaljerede
Problem: GPU-hukommelsesproblemer Løsning: Reducér batch-størrelse, brug mere aggressiv kvantisering, eller gradient checkpointing
Kombinering med RAG
Her er det kraftfulde: du kan kombinere din fine-tuned model med RAG for det bedste fra begge verdener:
- Fine-tune til domæneindsigt, tone og generel virksomhedsviden
- Brug RAG til aktuel information, specifikke dokumenter eller detaljerede tekniske specifikationer
Dette giver dig en model, der "tænker" som din virksomhed, men kan få adgang til opdateret information.
Hvad der kommer næste
I vores næste artikel blir vi helt custom — vi bygger en sprogmodel fra bunden, helt din, der køres på din hardware med dine data.
Fine-tuning af open-source-modeller giver dig hidtil uset kontrol over din AI-assistent. Du kan sikre, at den forstår dit domæne, taler med din stemme og aldrig sender dine data til tredjeparter. Med moderne effektivitetsteknikker som LoRA og kvantisering er det mere tilgængeligt end nogensinde.
Fremtiden for AI handler ikke bare om at bruge en anden persons model — det handler om at gøre AI helt din egen.
Kommende: Artikel 4 — "Bygning af din egen sprogmodel: Lille men kraftig"


