Del 3 av 5: Anpassning av förtränade modeller
Välkommen tillbaka! I vår senaste artikel byggde vi ett RAG-system som ger AI åtkomst till din specifika information. Idag tar vi det ett steg längre — vi kommer faktiskt att ändra hur en AI-modell tänker och svarar genom att finjustera den. Jag kommer att använda en öppen källkodsmodell för det här demonstrationsexemplet.
RAG vs finjustering: Vad är skillnaden?
Tänk på det på det här sättet:
RAG är som att ge någon en referensbok. De är fortfarande samma person, men nu har de åtkomst till specifik information när de svarar på frågor.
Finjustering är som att skicka någon på specialiserad utbildning. Du förändrar faktiskt hur de tänker och svarar baserat på dina specifika krav.
När bör du finjustera?
Finjustering är kraftfull, men det är inte alltid nödvändigt. Överväg finjustering när:
- Du behöver att AI antar en specifik ton eller stil
- Din domän har specialiserad terminologi eller koncept
- Du vill ha konsekventa svar i många olika scenarier
- RAG ger dig inte den svarkvalitet du behöver
- Du har tillräcklig träningsdata (vanligtvis hundratals exempel)
- Du behöver att modellen fungerar offline eller i luftgapade miljöer
Konfigurera din miljö
Vi använder Google Colab med en T4 GPU för den här självstudien, men du kan anpassa detta för någon CUDA-kompatibel 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
Välja rätt modell
För den här självstudien använder vi TinyLlama-1.1B, men här är några utmärkta alternativ för olika 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
Förbereda dina träningsdata
Nyckeln till framgångsrik finjustering är högkvalitativ träningsdata. Så här strukturerar vi 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)
Nyckelprinciper för träningsdata:
- Använd konsekvent formatering (notera mönstret "User asks:" och "Assistant:")
- Håll svaren faktiska och koncisa
- Täck den viktigaste informationen om din domän
- Kvalitet före kvantitet: 50 perfekta exempel slår 500 medelmåttiga
Effektiv träning med LoRA och kvantisering
Istället för att finjustera hela modellen (vilket kräver massiv GPU-minne) använder vi två effektivitetstekniker:
1. Kvantisering (4-bitars)
Kvantisering är en kompressionsteknik som används för att göra stora språkmodeller (LLM) mindre och snabbare utan att minska noggrannheten väsentligt.
- Normalt lagras LLM-vikter som 32-bitars flyttalsnummer (FP32).
- Kvantisering minskar denna precision till 16-bitars (FP16/BF16), 8-bitars (INT8), 4-bitars (INT4) eller ännu lägre.
👉 Exempel:
- En modell med 10 miljarder parametrar i FP32 behöver ~40 GB minne.
- Om vi kvantiserar den till INT8 (8-bitars) → behöver den bara ~10 GB.
- Om vi går till INT4 (4-bitars) → bara ~5 GB.
⚡ Varför är det användbart?
- Gör modeller kan köras på mindre GPU:er (eller till och med CPU:er).
- Snabbar upp inferens.
- Liten avvägning i noggrannhet, men ofta försumbar.
# 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 är en parametereffektiv finjusteringsmetod (PEFT).
Normalt, för att finjustera en enorm LLM (som LLaMA-65B eller GPT-J), skulle vi behöva hundratals GB GPU-minne. LoRA löser detta genom att:
- Frysa de ursprungliga modellvikterna.
- Lägga till små träningsbara matriser (low-rank-adaptrar) inuti modellskikten.
- Under finjustering uppdateras bara dessa små matriser.
👉 Exempel:
- Fullständig finjustering av en 65B-modell kan kräva ~1 TB GPU-minne.
- Med LoRA tränar du bara ett fåtal miljoner parametrar → behöver < 20 GB GPU-minne.
⚡ Varför är det användbart?
- Gör finjustering av massiva LLM:er möjligt på konsumenthårdvara (1–2 GPU:er).
- Enkelt att "slå samman" eller "dela upp" adaptrar → du kan snabbt byta uppgifter.
- Uppnår ofta prestanda nära fullständig finjustering.
# 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änar bara 0,2 % av parametrarna!
Träna 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)
Testa den finjusterade modellen
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
Här är Google Colab-länken för den här artikeln som du kan köra med ett klick: länk
De verkliga kostnaderna
Till skillnad från kommersiella API:er är dina kostnader främst:
- Initial konfiguration: GPU-tid för träning
- Lagring: Modellvikter (~4GB för TinyLlama med LoRA-adaptrar)
- Inferens: Din egen hårdvara eller molnbaserade GPU-instanser
För en liten modell som TinyLlama kan du köra inferens på:
- Google Colab (gratis nivå med begränsningar)
- AWS t3.medium med GPU (~$0,05/timme)
- Din egen hårdvara (RTX 3060 eller bättre)
Bästa metoder från verklig erfarenhet
1. Börja litet och skala upp Börja med distilgpt2 eller gpt2 för att testa dina data och process, sedan flytta till större modeller.
2. Övervaka överpassning Med små dataset kan modeller memorera snarare än lära sig. Håll ett öga på din utvärderingsförlust.
3. Formatkonsekvens är kritisk Det exakta formatet på dina träningsdata är oerhört viktigt. Var konsekvent med skiljetecken, mellanslag och struktur.
4. Testa med osedda frågor Testa alltid med frågor som inte finns i dina träningsdata för att säkerställa generalisering.
5. Spara vanliga checkpoints Träningen kan avbrytas. Spara ofta och testa mellanliggande checkpoints.
Vanliga fallgropar och lösningar
Problem: Modellen genererar repetitiv eller meningslös text Lösning: Sänk inlärningshastigheten, öka regulariseringen eller förbättra kvaliteten på träningsdata
Problem: Modellen glömmer allmän kunskap Lösning: Inkludera några allmänna exempel i dina träningsdata eller använd en större basmodell
Problem: Svaren är för generiska Lösning: Gör dina träningsexempel mer specifika och detaljerade
Problem: GPU-minnesproblem Lösning: Minska batchstorleken, använd mer aggressiv kvantisering eller gradientcheckpointing
Kombinera med RAG
Här är det kraftfulla: du kan kombinera din finjusterade modell med RAG för det bästa från båda världarna:
- Finjustera för domänförståelse, ton och allmän företagskunskap
- Använd RAG för aktuell information, specifika dokument eller detaljerade tekniska specifikationer
Detta ger dig en modell som "tänker" som ditt företag men kan få åtkomst till uppdaterad information.
Vad kommer härnäst
I vår nästa artikel går vi helt anpassad — byggande av en språkmodell från grunden, helt din, körs på din hårdvara med dina data.
Finjustering av öppen källkodsmodeller ger dig exempel kontroll över din AI-assistent. Du kan säkerställa att den förstår din domän, talar med din röst och aldrig skickar dina data till tredje parter. Med moderna effektivitetstekniker som LoRA och kvantisering är det mer tillgängligt än någonsin.
Framtiden för AI handlar inte bara om att använda någon annans modell — det handlar om att göra AI verkligen din.
Kommande: Artikel 4 — "Bygga din egen språkmodell: Liten men kraftfull"


