Tinker-tutorial: LLM’s fine-tunen met Thinking Machines Lab
Een praktische gids voor het implementeren van LoRA via Tinker AI om Qwen3-8B te trainen op Chain-of-Thought (CoT) financiële data, geoptimaliseerd voor generalisatie.
Het fine-tunen van grote taalmodellen betekent meestal dat je moet omgaan met gedistribueerde GPU-infrastructuur, clusterstoringen moet beheren en complexe trainingsscripts moet debuggen. Tinker lost dat voor je op.
Uitgebracht door Thinking Machines Lab van Mira Murati op 1 oktober 2025, is Tinker een trainings-API die alle infrastructuurcomplexiteit afhandelt terwijl jij volledige controle behoudt over je algoritmen en data. Je schrijft simpele Python-scripts met vier kernfuncties, en Tinker voert ze uit over gedistribueerde GPU’s voor een breed scala aan open-sourcemodellen zoals Llama 70B of Qwen 235B.
Het platform gebruikt Low-Rank Adaptation (LoRA) fine-tuning om kosten te verlagen en ondersteunt alles van supervised learning tot reinforcement learning. Onderzoeksteams aan Princeton, Stanford en Berkeley gebruiken het al voor hun werk.
In deze tutorial laat ik je zien hoe je Tinker installeert, de API begrijpt en een compleet financieel Q&A-model fine-tunet met het Qwen3-8B-basismodel. Wil je meer leren over fine-tuning met hands-on oefening, bekijk dan deze cursus over Fine-Tuning met Llama 3.
Wat is Tinker?
Thinking Machines Lab bouwde Tinker voor mensen die willen aanpassen hoe modellen leren zonder infrastructuurexperts te hoeven worden.
Wie gebruikt Tinker?
Het platform richt zich op drie groepen:
Onderzoekers die nieuwe trainingsmethoden verkennen
Ontwikkelaars die AI-producten bouwen met aangepast gedrag
Makers die resultaten van productiekwaliteit willen zonder enterprise-middelen.
Elke groep deelt dezelfde behoefte: ze weten wat ze willen dat hun model doet, maar standaard fine-tuninginterfaces geven niet genoeg controle.
Zo kunnen academische teams het gebruiken om nieuwe algoritmen te testen. Een scheikundelab wil misschien modellen trainen op domeinspecifieke redeneerpatronen die niet passen bij typische instruction-tuningtemplates. Een startup die een financiële-adviseurbot bouwt kan het model laten voldoen aan specifieke outputformaten en redeneerlijnen.
Al deze use-cases hebben gemeen dat ze het trainingsproces zelf moeten aanpassen, niet alleen datasets wisselen.
Wat maakt Tinker anders?
De meeste platforms optimaliseren voor één van twee dingen: gebruiksgemak of flexibiliteit. Tinkers benadering is dat die twee niet hoeven te botsen. Het platform geeft je low-level toegang tot training via vier kernoperaties, maar handelt al het andere automatisch af:
Regie over de trainingslus: Schrijf je eigen verliesfuncties, strategieën voor gradiëntaccumulatie of samplingpatronen.
Modelupdates: Geef precies aan hoe gewichten moeten veranderen tijdens optimalisatie.
Evaluatie: Genereer outputs of bereken waarschijnlijkheden op elk moment in de training.
State management: Sla training op en hervat met volledige controle over wat wordt bewaard.
Tinker stelt deze mogelijkheden bloot via vier API-primitieven die je in het hands-ongedeelte leert.
Dit werkt omdat de meeste trainingscomplexiteit uit infrastructuur komt, niet uit de algoritmen zelf. Een aangepaste trainingslus op je laptop draaien is eenvoudig. Het draaien op 100 GPU’s met failover en resourcescheduling is moeilijk. Tinker doet dat tweede, zodat jij je op het eerste kunt richten.
Waar Tinker past
Het AI-toolingecosysteem valt ruwweg uiteen in drie lagen: cloudcomputeproviders die ruwe GPU’s leveren, beheerde platforms die vooraf gedefinieerde workflows draaien, en frameworks die helpen trainingssystemen vanaf nul te bouwen. Tinker zit tussen de beheerde platforms en de frameworks in. Je krijgt meer controle dan platforms zoals Hugging Face AutoTrain, maar minder infrastructuurwerk dan het opzetten van een aangepaste cluster op Google Cloud Platform (GCP).
Tinker-prijzen en credits
Tinker hanteert transparante prijsstelling per token, variërend per modelgrootte en type bewerking. Het trainen van Qwen3-8B kost $0,40 per miljoen tokens. Het goede nieuws: nieuwe gebruikers ontvangen $150 aan credits zodra ze van de wachtlijst komen, wat ruim voldoende is voor meerdere experimentele trainingsruns zoals die in deze tutorial.
Tinker-voorbeeld: Qwen3-8B fine-tunen voor financiële Q&A
In deze sectie laat ik je een complete fine-tuningworkflow zien met Tinkers API. We fine-tunen Qwen3-8B op financiële vraag-en-antwoorddata met LoRA en leren alle vier de kernprimitieven van de API, terwijl we productiebest practices in actie zien.
Voor een gedetailleerder overzicht van het model, bekijk zeker dit artikel over Qwen3.
Belangrijke opmerking: Tinker is momenteel in beta met toegang via een wachtlijst. Als je toegang hebt, kun je meedoen en de code draaien. Sta je op de wachtlijst, dan kun je alsnog meelezen om te begrijpen hoe eenvoudig het fine-tuningproces met Tinker is. Zodra je toegang krijgt, kun je meteen aan de slag.
Trainingsresultaten en checkpointselectie
Laten we eerst naar de trainingsresultaten kijken. Begrijpen wat er gebeurde helpt je deze patronen te herkennen wanneer je je eigen fine-tuningjobs draait.
We fine-tuneden Qwen3-8B op de FinCoT-dataset, een chain-of-thought dataset voor financiële redenering, met LoRA met rank 32. Na het filteren op sequenties niet langer dan 10.000 tokens, hadden we 7.244 trainingsvoorbeelden en 500 voorbeelden voor validatie.
De training draaide 904 iteraties over vier epochs en duurde ongeveer drie uur, terwijl Tinker alle gedistribueerde GPU-coördinatie afhandelde.
Een epoch is één volledige doorgang door de hele trainingsdataset. Omdat er 226 batches per epoch waren (7.244 voorbeelden gedeeld door een batchgrootte van 32), kwamen de vier epochs uit op 904 iteraties.
Trainingsresultaten analyseren
De onderstaande grafiek volgt drie metriekwaarden: training loss (blauw), validatieloss (rood) en learning rate (groen).
Vroege training (iteraties 0-400) ziet er gezond uit: zowel de training- als validatieloss dalen samen scherp, van boven 1,4 naar onder 0,8 en blijven binnen ongeveer 0,1 van elkaar.
Deze periode laat zien dat het model effectief generaliseerbare patronen in de data leert. De learning rate (groene lijn) loopt soepel op tijdens de eerste 200 iteraties, omdat warmup de training stabiliseert.
Rond iteratie 400-600 verandert het beeld. De trainingloss blijft dalen, maar de validatieloss vlakt af rond 0,75-0,8, waardoor de kloof oploopt tot 0,13 terwijl het model begint te overfitten. Tegen iteratie 600-900 wordt de divergentie duidelijk: de trainingloss daalt naar 0,39 terwijl de validatieloss stijgt naar 0,8, wat laat zien dat het model is verschoven van het leren van redeneerpatronen naar het memoriseren van voorbeelden.
Dit patroon komt vaak voor bij het fine-tunen van redeneermodellen. Als je geïnteresseerd bent in hoe redeneervermogen zich ontwikkelt tijdens training, bekijk dan deze tutorial over het fine-tunen van DeepSeek R1, die vergelijkbare dynamiek verkent.
Het model opgeslagen bij checkpoint-400 biedt de beste generalisatie, met een trainingloss van 0,68, een validatieloss van 0,73 en een kleine kloof van slechts 0,05. Ondanks een hogere trainingloss dan de laatste checkpoint, gaat het beter om met nieuwe vragen. De laagste trainingloss levert zelden het beste model op; daarom zijn validatiemetrieken belangrijk.
We verifiëren dit later door het model op checkpoint-400 te vergelijken met het basismodel met een LLM-rechter. Voor nu lopen we stap voor stap door het bouwen van deze fine-tuningworkflow.
Stap 1: Installeer Tinker en richt je omgeving in
Let op: De volgende stappen splitsen een script op dat ongeveer 300 regels lang is. Omdat uitleg is verweven met codeblokken, raden we aan het volledige script in een nieuw tabblad te openen terwijl je volgt, voor het complete beeld.
Je hebt Python 3.11 of later nodig en een stabiele internetverbinding. Omdat Tinker de GPU-training op hun servers uitvoert, is een goede verbinding belangrijker dan een krachtige computer.
Begin met inloggen op de Tinker-console en maak een API-sleutel aan. Sla deze sleutel op in een .env-bestand in je projectmap:
Zodra je bent ingericht, wordt de Tinker-console je centrale hub voor het monitoren van trainingsruns en het beheren van checkpoints.
De Tinker-console volgt al je trainingsruns met kerngegevens: unieke run-ID’s, basismodel, LoRA-rank en tijden van laatste requests. Je kunt in deze interface zoeken, filteren en meerdere experimenten beheren.
Installeer de vereiste packages. Tinker heeft peerdependencies die niet automatisch installeren, dus specificeer ze expliciet:
pip install tinker transformers torch datasets python-dotenv numpyMogelijk gemaakt door
De packages transformers en torch bieden tokenisatie en tensorbewerkingen die Tinker intern gebruikt. De datasets-bibliotheek verzorgt het laden van trainingsdata van Hugging Face.
Richt nu je imports in en een helperfunctie voor retries. Bij training op externe servers kun je tijdelijke verbindingsfouten zien die niet per se betekenen dat er echt iets mis is. Je trainingsjob draait nog steeds prima op Tinkers infrastructuur. Deze retry-wrapper handelt die tijdelijke fouten automatisch af:
import time
import numpy as np
from dotenv import load_dotenv
from datasets import load_dataset
import tinker
from tinker import types
defwith_retry(future, max_attempts=3, delay=5):"""Simple retry logic for API futures"""for attempt inrange(max_attempts):try:return future.result()except Exception as e:if attempt == max_attempts -1:raise
time.sleep(delay)Mogelijk gemaakt door
Deze functie neemt een future-object (een object dat een bewerking vertegenwoordigt die nog niet klaar is) van Tinkers API en probeert tot drie keer het resultaat op te halen, met vijf seconden wachten tussen pogingen. De meeste tijdelijke fouten lossen binnen dit venster op.
Stap 2: Initialiseer de ServiceClient en laad de dataset
De ServiceClient is je toegangspunt tot Tinker. Hij zoekt beschikbare modellen en regelt authenticatie:
Je gebruikt hem na deze initiële setup niet veel meer. Hij bestaat vooral om trainings- en samplingclients voor specifieke modellen te maken.
Nu is het tijd om de FinCoT-dataset te laden. Die bevat financiële vragen gekoppeld aan stapsgewijze redeneerlijnen en eindantwoorden. Anders dan simpele Q&A-datasets leert FinCoT het model om zijn werk te laten zien vóórdat het antwoorden geeft—een belangrijke vaardigheid voor financiële adviesapplicaties waar gebruikers de onderbouwing willen begrijpen.
De dataset bevat een SFT-split (supervised fine-tuning) met complete redeneerlijnen en een RL-split voor reinforcement learning. Gebruik de SFT-split voor training en neem een steekproef uit de RL-split voor validatie om te zorgen dat het model generaliseert naar andere voorbeelden.
train_data_raw = dataset["SFT"]# 7,686 examples with reasoning chains
val_data_raw = dataset["RL"].shuffle(seed=42).select(range(500))# 500 validation examplesprint(f"Loaded {len(train_data_raw)} training examples")print(f"Loaded {len(val_data_raw)} validation examples")Mogelijk gemaakt door
Stap 3: Maak je LoRA-trainingsclient
Maak nu een LoRA-trainingsclient voor Qwen3-8B:
training_client = service_client.create_lora_training_client(
base_model="Qwen/Qwen3-8B",
rank=32)Mogelijk gemaakt door
Laten we uiteenzetten wat hier gebeurt:
Qwen/Qwen3-8B: Dit is een model met 8 miljard parameters, krachtig genoeg voor echte taken maar nog efficiënt om te trainen. Een mooi sweet spot om te leren. Je ziet alle beschikbare modellen in Tinkers modellensuite.
LoRA (Low-Rank Adaptation): In plaats van alle 8 miljard parameters te updaten, traint LoRA kleine „adapter”-lagen die het gedrag van het basismodel aanpassen. Zie het als het toevoegen van custom lenzen aan een camera in plaats van de hele camera te herbouwen. Het basismodel blijft bevroren op Tinkers servers; je traint alleen deze kleine adapters.
rank=32: Dit bepaalt hoeveel trainbare parameters je LoRA-adapters bevatten. Een rank van 32 werkt goed voor datasets met 5.000-10.000 voorbeelden. Grotere datasets hebben mogelijk rank=64 of rank=128 nodig voor meer adaptatiecapaciteit.
Voor een diepere duik in hoe LoRA wiskundig werkt en hoe je rankparameters afstemt, bekijk Tinkers LoRA-primer of DataCamps uitgebreide gids over Low-Rank Adaptation.
Taalmodellen werken niet direct met woorden. Ze werken met „tokens”, stukjes tekst. Een tokenizer breekt tekst op in die stukjes. „Financial” kan bijvoorbeeld één token zijn, terwijl „understanding” kan splitsen in „under” en „standing.”
De tokenizer zet tekst om in nummers (token-ID’s) die het model kan verwerken. Door de tokenizer van de trainingsclient te nemen, zorg je dat je precies dezelfde tokenisatie gebruikt als Qwen3-8B verwacht.
Tinker heeft je trainingsdata nodig in een formaat genaamd types.Datum. Dit formaat scheidt de modelinput van de configuratie van de verliesfunctie, zodat je precies kunt bepalen welke tokens bijdragen aan de training.
Bij het fine-tunen van taalmodellen wil je doorgaans dat het model leert hoe het goede antwoorden genereert, niet dat het de vragen memoriseert. Dat doe je door verschillende gewichten toe te kennen aan verschillende delen van de input:
Prompttokens (de vraag): Gewicht = 0,0 (niet van leren)
Completiontokens (het antwoord): Gewicht = 1,0 (wel van leren)
Laten we de datatransformatiefunctie stap voor stap opbouwen. Begin met de functiedeclaratie:
Verschillende modellen verwachten verschillende formatting voor gesprekken met meerdere beurten. Qwen3 gebruikt speciale tokens zoals <|im_start|> en <|im_end|> om berichtgrenzen te markeren. Splits elk bericht in „observatie”-delen (rolheaders) en „actie”-delen (de eigenlijke inhoud):
# Qwen3 chat format - split into observation and action parts
user_ob ="<|im_start|>user\n"
user_ac =f"{example['Question']}<|im_end|>"
assistant_ob ="\n<|im_start|>assistant\n"# Include both reasoning process AND final answer
assistant_ac =f"{example['Reasoning_process']}\n\nFinal Answer: {example['Final_response']}<|im_end|>"Mogelijk gemaakt door
De FinCoT-dataset levert gestructureerde redeneringen, dus concatenëren we de velden Reasoning_process en Final_response. Dit leert het model zijn werk te laten zien vóór het antwoord.
Tokenizeer elk deel apart
Om bij te houden waar gewichten moeten gelden, moet elk berichtdeel apart worden getokeniseerd.
# Tokenize each part separately to track weight boundaries
user_ob_tokens = tokenizer.encode(user_ob, add_special_tokens=False)
user_ac_tokens = tokenizer.encode(user_ac, add_special_tokens=False)
assistant_ob_tokens = tokenizer.encode(assistant_ob, add_special_tokens=False)
assistant_ac_tokens = tokenizer.encode(assistant_ac, add_special_tokens=False)# Combine all tokens
all_tokens = user_ob_tokens + user_ac_tokens + assistant_ob_tokens + assistant_ac_tokensMogelijk gemaakt door
Filter te lange sequenties
Sommige FinCoT-voorbeelden bevatten zeer gedetailleerde redeneerlijnen die buiten het comfortabele contextvenster van Qwen3-8B vallen. Hoewel het model technisch 32.768 tokens ondersteunt, kunnen zeer lange sequenties training instabiel maken:
# Check if sequence exceeds max lengthiflen(all_tokens)> max_length:returnNone# Skip this exampleMogelijk gemaakt door
Door voorbeelden boven 10.000 tokens te filteren, verwijder je slechts 5-6% van de data, terwijl je de betrouwbaarheid van de training aanzienlijk verbetert.
Ken gewichten toe om te sturen waar het model van leert
Zet gewichten op 0,0 voor de vraag (zodat het model niet leert om vragen te voorspellen) en 1,0 voor het antwoord (zodat het leert goede reacties te genereren):
# Weights: only train on assistant's answer (action part)
weights = np.array([0.0]*len(user_ob_tokens)+[0.0]*len(user_ac_tokens)+[0.0]*len(assistant_ob_tokens)+[1.0]*len(assistant_ac_tokens))Mogelijk gemaakt door
Shift tokens en gewichten voor next-token prediction
Taalmodellen voorspellen het volgende token in een sequentie. Als het model tokens 0-9 ziet, moet het token 10 voorspellen. Je targets zijn dus altijd de input één positie vooruit geschoven:
# CRITICAL: Shift tokens AND weights for next-token prediction
input_tokens_model = all_tokens[:-1]
target_tokens = all_tokens[1:]
weights_shifted = weights[1:]Mogelijk gemaakt door
Belangrijk: je moet de gewichten samen met de tokens shiften. Als je de gewichten niet shiftt, raakt de verliesberekening uitgelijnd: het model wordt getraind om het eerste antwoordtoken te voorspellen, maar het gewicht op die positie is nog 0,0 vanuit de prompt. Deze uitlijningsbug kan voorkomen dat het model goed leert.
Geef de geformatteerde data terug
Tot slot retourneert de functie prepare_datum() de geformatteerde data, klaar voor verwerking.
return types.Datum(
model_input=types.ModelInput.from_ints(tokens=input_tokens_model),
loss_fn_inputs=dict(weights=weights_shifted, target_tokens=target_tokens),)Mogelijk gemaakt door
Door de gedefinieerde functie toe te passen op de ruwe trainings- en validatiesubsets, kunnen we nu de hele dataset verwerken:
# Process and filter training data
training_data_raw =[prepare_datum(example)for example in train_data_raw]
training_data =[d for d in training_data_raw if d isnotNone]
skipped =len(train_data_raw)-len(training_data)print(f"Processed {len(training_data)} examples (skipped {skipped} too-long sequences)")# Output: Processed 7,244 examples (skipped 442 too-long sequences)# Process validation data
val_data_raw_processed =[prepare_datum(example)for example in val_data_raw]
val_data =[d for d in val_data_raw_processed if d isnotNone]print(f"Validation set: {len(val_data)} examples")Mogelijk gemaakt door
Stap 5: Train het model met de trainingslus
De trainingslus gebruikt twee van Tinkers kern-API-primitieven: forward_backward en optim_step. Laten we hem stap voor stap opbouwen met validatietracking om overfitting vroeg te detecteren.
Definieer een validatielossfunctie
Definieer eerst een validatielossfunctie. Anders dan trainingloss vertelt validatieloss je hoe goed je model generaliseert naar onzichtbare data. Dit is cruciaal om overfitting te detecteren.
defcompute_validation_loss(val_data, batch_size=100):"""Compute loss on validation set (forward only, no backward)"""
batch_indices = np.random.choice(len(val_data), size=min(batch_size,len(val_data)), replace=False)
batch =[val_data[i]for i in batch_indices]# Forward pass only (no backward!)
fwd_future = training_client.forward(batch, loss_fn="cross_entropy")
fwd_result = with_retry(fwd_future)# Calculate per-token loss
loss_sum = fwd_result.metrics["loss:sum"]
total_completion_tokens =sum(
np.sum(np.array(val_data[i].loss_fn_inputs["weights"].data)>0)for i in batch_indices
)return loss_sum / total_completion_tokens if total_completion_tokens >0else0Mogelijk gemaakt door
De methode forward() berekent de loss zonder gradiënten te berekenen, wat het efficiënt maakt voor evaluatie waarbij je alleen prestaties wilt meten en geen gewichten wilt updaten. Het berekenen van validatieloss voegt minimale overhead toe (alleen een forward pass, geen gradiënten) maar geeft vroegtijdige waarschuwing wanneer de kloof tussen training- en validatieloss groter wordt dan 0,2—een signaal dat je model aan het memoriseren is in plaats van te leren.
Configureer trainingsparameters
We moeten het aantal epochs en de learning rate definiëren. LoRA vereist significant hogere learning rates dan volledige fine-tuning, typisch 10-20x groter.
# Training configuration
n_samples =len(training_data)# 7,244
n_epochs =4# More epochs for smaller dataset
batch_size =32# Calculate optimal LR for Qwen3-8B with LoRA# Formula: base_lr * lora_multiplier * (2000 / hidden_size) ** exponent# For Qwen: base=5e-5, multiplier=10, hidden_size=4096, exponent=0.0775
learning_rate =5e-5*10.0*(2000/4096)**0.0775# ≈ 4.7e-4Mogelijk gemaakt door
De formule houdt rekening met modelgrootte (Qwen3-8B heeft een hidden size van 4.096) en gebruikt empirisch bepaalde exponenten die per modelfamilie variëren, zoals gedocumenteerd in het Tinker-cookbook. Voor Qwen-modellen is de exponent 0,0775, terwijl Llama-modellen 0,781 gebruiken. In ons geval levert dit een learning rate op rond 4,7e-4, wat zorgt voor stabiele convergentie zonder gradiëntexplosies.
Stel learning rate-warmup in
Starten met de volledige learning rate kan vroeg in de training gradiëntexplosies veroorzaken wanneer het model nog niet aan de taak is aangepast. Warmup verhoogt de learning rate geleidelijk van bijna nul naar de doelwaarde over de eerste 200 iteraties. Je zag dit duidelijk in de eerdere trainingsvisualisatie, waar de learning rate (groene lijn) soepel oploopt tijdens de eerste 200 iteraties.
# Warmup configuration
warmup_steps =200# Calculate iterations from epochs
num_iterations = n_epochs *(n_samples // batch_size)# 4 * 226 = 904
checkpoint_interval =200
validation_interval =50Mogelijk gemaakt door
Start de trainingslus
Na het initialiseren van lijsten om verliezen bij te houden, kunnen we de trainingslus starten:
losses =[]
per_token_losses =[]
val_losses =[]for iteration inrange(num_iterations):# Sample random batch
batch_indices = np.random.choice(len(training_data), size=batch_size, replace=False)
batch =[training_data[i]for i in batch_indices]# Apply learning rate warmupif iteration < warmup_steps:
current_lr = learning_rate *(iteration +1)/ warmup_steps
else:
current_lr = learning_rateMogelijk gemaakt door
De warmuplogica schaalt de learning rate geleidelijk op tijdens de eerste 200 iteraties en voorkomt zo vroege instabiliteit.
Roep Tinkers kerntrainingsprimitieven aan
In elke iteratie worden Tinkers kernprimitieven als volgt aangeroepen:
# API Primitive 1: forward_backward - compute gradients
fwdbwd_future = training_client.forward_backward(batch, loss_fn="cross_entropy")# API Primitive 2: optim_step - update parameters
optim_future = training_client.optim_step(types.AdamParams(learning_rate=current_lr))# Wait for results with retry logic
fwdbwd_result = with_retry(fwdbwd_future)
optim_result = with_retry(optim_future)Mogelijk gemaakt door
forward_backward berekent gradiënten door te bepalen hoe fout de voorspellingen van het model zijn en in welke richting elke parameter moet worden aangepast. Het gebruikt cross-entropieloss, die meet hoe goed de voorspelde waarschijnlijkheidsverdeling van het model overeenkomt met de daadwerkelijke volgende tokens. optim_step werkt de modelparameters daadwerkelijk bij op basis van die gradiënten met de Adam-optimizer.
Merk op dat beide methoden meteen „future”-objecten retourneren. Hierdoor kan Tinker meerdere bewerkingen gelijktijdig verwerken, wat het proces versnelt. Het aanroepen van with_retry(future) wacht op het voltooien van die specifieke bewerking.
Houd verliesmetriek bij en toon ze
We berekenen zowel totale als per-tokenverliezen en voegen ze toe aan de respectieve lijsten:
# Track loss
loss_sum = fwdbwd_result.metrics["loss:sum"]
total_completion_tokens =sum(
np.sum(np.array(training_data[i].loss_fn_inputs["weights"].data)>0)for i in batch_indices
)
per_token_loss = loss_sum / total_completion_tokens
losses.append(loss_sum)
per_token_losses.append(per_token_loss)if iteration %10==0:
warmup_indicator ="🔥"if iteration < warmup_steps else""print(f"{warmup_indicator} Iteration {iteration} | Train: {per_token_loss:.4f} | LR: {current_lr:.6f}")Mogelijk gemaakt door
Per-tokenloss normaliseert de loss naar het aantal antwoordtokens, wat interpretatie over verschillende batchgroottes heen makkelijker maakt. Een goede trainingsrun start typisch met per-tokenloss rond 1,2-1,5 en daalt onder 0,8 tegen checkpoint-400. Als je loss boven 2,0 start of niet daalt na 50 iteraties, controleer dan je datavoorbereiding en learning rate.
Voeg periodieke validatiechecks en checkpoints toe
Door elke 200 iteraties gewichten op te slaan, maak je snapshots om te vergelijken. Zoals je eerder zag, generaliseert checkpoint-400 beter dan de laatste checkpoint, ondanks hogere trainingloss. Sla altijd meerdere checkpoints op en evalueer ze op achtergehouden data. De checkpoints blijven op Tinkers servers na afloop van je script.
# Compute validation loss periodicallyif iteration % validation_interval ==0:
val_loss = compute_validation_loss(val_data)
val_losses.append((iteration, val_loss))
gap = val_loss - per_token_loss
print(f" 📊 Iteration {iteration} | Train: {per_token_loss:.4f} | Val: {val_loss:.4f} | Gap: {gap:+.4f}")# Checkpoint every 200 iterationsif iteration >0and iteration % checkpoint_interval ==0:
training_client.save_weights_for_sampler(name=f"fincot-checkpoint-{iteration}")Mogelijk gemaakt door
Tinker organiseert checkpoints in twee categorieën: full-state checkpoints (om de training te hervatten bij onderbreking) en samplergewichten (lichte checkpoints voor inferentie). Merk op dat checkpoint-400 in beide formaten verschijnt, waardoor het eenvoudig is om zowel door te trainen als het model te deployen.
Als je trainingsrun wordt onderbroken, kun je hervatten vanaf elke opgeslagen checkpoint met de full-stategewichten, zodat je niet vanaf nul hoeft te beginnen.
Nadat de training is voltooid, sla je de uiteindelijke modelgewichten op:
sampling_client = training_client.save_weights_and_get_sampling_client(
name="financial-qa-qwen3-8b-lora")Mogelijk gemaakt door
De gewichten worden opgeslagen op Tinkers servers, niet op je computer. De LoRA-adapters vereisen doorgaans slechts tientallen megabytes. Tinker kan ze desgewenst exporteren voor gebruik met externe inferentieproviders als je het model buiten hun infrastructuur wilt deployen.
Stap 7: Test het model met voorbeeldvragen
Test ten slotte je fijn-afgestelde model met de sample-API-primitief. Stel eerst de samplingparameters in:
sampling_params = types.SamplingParams(
max_tokens=200,
temperature=0.7,
top_p=0.9,
stop_sequences=["<|im_end|>"])Mogelijk gemaakt door
Laten we deze parameters toelichten:
max_tokens: Maximale lengte van de gegenereerde reactie (200 tokens is grofweg 150 woorden).
temperature: Bepaalt de willekeur in generatie. Lagere waarden (0,1-0,5) maken de output gefocust en deterministisch; hogere waarden (0,7-1,0) laten meer creativiteit toe. 0,7 balanceert samenhang en variatie.
top_p (nucleus sampling): Neemt alleen de kleinste set tokens in overweging waarvan de cumulatieve waarschijnlijkheid deze waarde overschrijdt. 0,9 betekent „neem alleen tokens die samen voor 90% van de waarschijnlijkheidsmassa zorgen.” Dit voorkomt dat het model zeer onwaarschijnlijke tokens kiest.
stop_sequences: Zegt tegen het model te stoppen met genereren wanneer het deze sequentie tegenkomt. <|im_end|> is de eindemarkering van de sequentie.
Genereer reacties voor testvragen:
questions =["What are the main risks associated with investing in stocks?","How does diversification help reduce portfolio risk?"]for question in questions:
model_input = types.ModelInput.from_ints(tokenizer.encode(question))
response = with_retry(
sampling_client.sample(
prompt=model_input,
num_samples=1,
sampling_params=sampling_params
))
answer = tokenizer.decode(response.sequences[0].tokens)print(f"Q: {question}")print(f"A: {answer}\n")Mogelijk gemaakt door
Hier zijn twee voorbeeldoutputs van het fijn-afgestelde model (ingekort ter illustratie):
Q: What are the main risks associated with investing in stocks?
A: Investing in stocks carries several key risks. Market risk represents the potential for stock prices to decline due to economic downturns or market volatility. Company-specific risk arises from poor management decisions, competitive pressures, or operational failures that affect individual stocks. Liquidity risk occurs when you cannot sell shares quickly without significantly impacting the price. Additionally, investors face inflation risk, where returns may not keep pace with rising prices...
Q: How does diversification help reduce portfolio risk?
A: Diversification reduces portfolio risk by spreading investments across different asset classes, sectors, and geographic regions. When you hold multiple uncorrelated assets, losses in one investment can be offset by gains in others. For example, if technology stocks decline but healthcare stocks rise, a diversified portfolio experiences less volatility than one concentrated in technology alone. The key principle is that different assets respond differently to market conditions...Mogelijk gemaakt door
Het response-object bevat een lijst sequences omdat je meerdere samples per prompt kunt aanvragen. Benader de tokens via sequences[0].tokens en decodeer ze terug naar tekst met dezelfde tokenizer.
Je hebt nu alle vier de kern-API-primitieven gedemonstreerd:
forward_backward: Bereken gradiënten op je trainingsdata
optim_step: Update modelparameters met de Adam-optimizer
save_weights_and_get_sampling_client: Bewaar je fijn-afgestelde model
sample: Genereer voorspellingen met het fijn-afgestelde model
Ditzelfde workflowpatroon strekt zich uit tot meer geavanceerde trainingsparadigma’s. Voor reinforcement learning of voorkeuroptimalisatie gebruik je dezelfde primitieven maar met andere verliesfuncties en dataformaten. Als je geïnteresseerd bent in het alignen van modellen met menselijke voorkeuren, bekijk dan technieken voor preference fine-tuning, die op dezelfde basis voortbouwen. Het Tinker-cookbook biedt voorbeelden voor deze geavanceerde scenario’s.
Maar hoe weet je of het fine-tunen de prestaties echt heeft verbeterd? In plaats van te vertrouwen op subjectieve indrukken, heb je rigoureuze evaluatie nodig. In de volgende sectie zie je resultaten van een LLM-as-judge-evaluatie die het fijn-afgestelde model vergelijkt met het basis Qwen3-8B-model op 10 diverse financiële vragen.
Het fijn-afgestelde model evalueren met een LLM-rechter
Om prestaties objectief te meten, gebruikten we LLM-as-judge: GPT-4o evalueerde checkpoint-400 tegenover basis Qwen3-8B op 10 diverse financiële vragen, waarbij elke reactie werd gescoord op nauwkeurigheid, helderheid, volledigheid en financiële terminologie.
Het fijn-afgestelde model scoorde 8,5/10, vergeleken met 6,5 voor het basismodel, en won alle 10 vergelijkingen. De vonnissen verklaren waarom: het levert complete uitleg met zelfverzekerde, gestructureerde redenering, terwijl het basismodel aarzelt met „I think” en „maybe” en gedachten onvolledig laat.
Dit bevestigt de betere prestaties in de praktijk van checkpoint-400. De lagere trainingloss bij iteratie 900 had ons memorisatie gegeven, geen redenering.
Je hebt gezien hoe Tinker fine-tuning vereenvoudigt zonder concessies te doen aan controle. Vier kern-API-primitieven, forward_backward, optim_step, save_weights_and_get_sampling_client en sample, geven je de bouwstenen voor aangepaste trainingsworkflows, terwijl Tinker de gedistribueerde infrastructuur afhandelt.
Het financiële Q&A-model dat we bouwden, laat productiebest practices zien: validatietracking signaleerde overfitting vroeg, checkpoint-400 presteerde beter dan het eindmodel door te focussen op generalisatie, en LLM-as-judge-evaluatie bevestigde een verbetering van 2 punten ten opzichte van het basismodel. Deze patronen gelden of je nu 8B- of 70B-parametermodellen fine-tunet.
Het platform is in beta met toegang via een wachtlijst, maar de concepten die je hebt geleerd kun je direct toepassen zodra je toegang krijgt. De trainingsruns die ik voor deze tutorial deed (inclusief mislukte en experimentele) kostten 150 startcredits, dus met de initiële credits kun je deze tutorial 6 keer draaien plus extra experimenten—ruim voldoende om te leren en te itereren op je eigen fine-tuningprojecten.
Wat nu? Probeer fine-tunen op je domeinspecifieke data, experimenteer met verschillende LoRA-ranks en learning rates, of verken geavanceerde trainingsparadigma’s zoals reinforcement learning from human feedback. Het Tinker-cookbook biedt voorbeelden voor deze scenario’s. Denk nu alvast na over je use-case—welk gedrag wil je dat je model leert?
Wil je een bredere skillset ontwikkelen in het trainen en fine-tunen van de nieuwste AI-modellen voor productie, bekijk dan de Associate AI Engineer for Developers-carrièretrack.
Ik ben een contentmaker op het gebied van data science met meer dan 2 jaar ervaring en een van de grootste achterbannen op Medium. Ik schrijf graag uitgebreide artikelen over AI en ML met een vleugje sarcastische stijl, want je moet toch íets doen om ze wat minder saai te maken. Ik heb meer dan 130 artikelen en een DataCamp-cursus gemaakt, en er is nog een nieuwe in de maak. Mijn content is door meer dan 5 miljoen paar ogen gezien, van wie 20k volgers werden op zowel Medium als LinkedIn.
Leer hoe je AI in softwareapplicaties kunt integreren met behulp van API's en open-sourcebibliotheken. Begin vandaag nog aan je reis om AI-ingenieur te worden!
Het fine-tunen van grote taalmodellen betekent meestal dat je moet omgaan met gedistribueerde GPU-infrastructuur, clusterstoringen moet beheren en complexe trainingsscripts moet debuggen. Tinker lost dat voor je op.
Uitgebracht door Thinking Machines Lab van Mira Murati op 1 oktober 2025, is Tinker een trainings-API die alle infrastructuurcomplexiteit afhandelt terwijl jij volledige controle behoudt over je algoritmen en data. Je schrijft simpele Python-scripts met vier kernfuncties, en Tinker voert ze uit over gedistribueerde GPU’s voor een breed scala aan open-sourcemodellen zoals Llama 70B of Qwen 235B.
Het platform gebruikt Low-Rank Adaptation (LoRA) fine-tuning om kosten te verlagen en ondersteunt alles van supervised learning tot reinforcement learning. Onderzoeksteams aan Princeton, Stanford en Berkeley gebruiken het al voor hun werk.
In deze tutorial laat ik je zien hoe je Tinker installeert, de API begrijpt en een compleet financieel Q&A-model fine-tunet met het Qwen3-8B-basismodel. Wil je meer leren over fine-tuning met hands-on oefening, bekijk dan deze cursus over Fine-Tuning met Llama 3.
Wat is Tinker?
Thinking Machines Lab bouwde Tinker voor mensen die willen aanpassen hoe modellen leren zonder infrastructuurexperts te hoeven worden.
Wie gebruikt Tinker?
Het platform richt zich op drie groepen:
Elke groep deelt dezelfde behoefte: ze weten wat ze willen dat hun model doet, maar standaard fine-tuninginterfaces geven niet genoeg controle.
Zo kunnen academische teams het gebruiken om nieuwe algoritmen te testen. Een scheikundelab wil misschien modellen trainen op domeinspecifieke redeneerpatronen die niet passen bij typische instruction-tuningtemplates. Een startup die een financiële-adviseurbot bouwt kan het model laten voldoen aan specifieke outputformaten en redeneerlijnen.
Al deze use-cases hebben gemeen dat ze het trainingsproces zelf moeten aanpassen, niet alleen datasets wisselen.
Wat maakt Tinker anders?
De meeste platforms optimaliseren voor één van twee dingen: gebruiksgemak of flexibiliteit. Tinkers benadering is dat die twee niet hoeven te botsen. Het platform geeft je low-level toegang tot training via vier kernoperaties, maar handelt al het andere automatisch af:
Tinker stelt deze mogelijkheden bloot via vier API-primitieven die je in het hands-ongedeelte leert.
Dit werkt omdat de meeste trainingscomplexiteit uit infrastructuur komt, niet uit de algoritmen zelf. Een aangepaste trainingslus op je laptop draaien is eenvoudig. Het draaien op 100 GPU’s met failover en resourcescheduling is moeilijk. Tinker doet dat tweede, zodat jij je op het eerste kunt richten.
Waar Tinker past
Het AI-toolingecosysteem valt ruwweg uiteen in drie lagen: cloudcomputeproviders die ruwe GPU’s leveren, beheerde platforms die vooraf gedefinieerde workflows draaien, en frameworks die helpen trainingssystemen vanaf nul te bouwen. Tinker zit tussen de beheerde platforms en de frameworks in. Je krijgt meer controle dan platforms zoals Hugging Face AutoTrain, maar minder infrastructuurwerk dan het opzetten van een aangepaste cluster op Google Cloud Platform (GCP).
Tinker-prijzen en credits
Tinker hanteert transparante prijsstelling per token, variërend per modelgrootte en type bewerking. Het trainen van Qwen3-8B kost $0,40 per miljoen tokens. Het goede nieuws: nieuwe gebruikers ontvangen $150 aan credits zodra ze van de wachtlijst komen, wat ruim voldoende is voor meerdere experimentele trainingsruns zoals die in deze tutorial.
Bron: Thinking Machines Lab
Tinker-voorbeeld: Qwen3-8B fine-tunen voor financiële Q&A
In deze sectie laat ik je een complete fine-tuningworkflow zien met Tinkers API. We fine-tunen Qwen3-8B op financiële vraag-en-antwoorddata met LoRA en leren alle vier de kernprimitieven van de API, terwijl we productiebest practices in actie zien.
Voor een gedetailleerder overzicht van het model, bekijk zeker dit artikel over Qwen3.
Belangrijke opmerking: Tinker is momenteel in beta met toegang via een wachtlijst. Als je toegang hebt, kun je meedoen en de code draaien. Sta je op de wachtlijst, dan kun je alsnog meelezen om te begrijpen hoe eenvoudig het fine-tuningproces met Tinker is. Zodra je toegang krijgt, kun je meteen aan de slag.
Trainingsresultaten en checkpointselectie
Laten we eerst naar de trainingsresultaten kijken. Begrijpen wat er gebeurde helpt je deze patronen te herkennen wanneer je je eigen fine-tuningjobs draait.
We fine-tuneden Qwen3-8B op de FinCoT-dataset, een chain-of-thought dataset voor financiële redenering, met LoRA met rank 32. Na het filteren op sequenties niet langer dan 10.000 tokens, hadden we 7.244 trainingsvoorbeelden en 500 voorbeelden voor validatie.
De training draaide 904 iteraties over vier epochs en duurde ongeveer drie uur, terwijl Tinker alle gedistribueerde GPU-coördinatie afhandelde.
Een epoch is één volledige doorgang door de hele trainingsdataset. Omdat er 226 batches per epoch waren (7.244 voorbeelden gedeeld door een batchgrootte van 32), kwamen de vier epochs uit op 904 iteraties.
Trainingsresultaten analyseren
De onderstaande grafiek volgt drie metriekwaarden: training loss (blauw), validatieloss (rood) en learning rate (groen).
Vroege training (iteraties 0-400) ziet er gezond uit: zowel de training- als validatieloss dalen samen scherp, van boven 1,4 naar onder 0,8 en blijven binnen ongeveer 0,1 van elkaar.
Deze periode laat zien dat het model effectief generaliseerbare patronen in de data leert. De learning rate (groene lijn) loopt soepel op tijdens de eerste 200 iteraties, omdat warmup de training stabiliseert.
Rond iteratie 400-600 verandert het beeld. De trainingloss blijft dalen, maar de validatieloss vlakt af rond 0,75-0,8, waardoor de kloof oploopt tot 0,13 terwijl het model begint te overfitten. Tegen iteratie 600-900 wordt de divergentie duidelijk: de trainingloss daalt naar 0,39 terwijl de validatieloss stijgt naar 0,8, wat laat zien dat het model is verschoven van het leren van redeneerpatronen naar het memoriseren van voorbeelden.
Dit patroon komt vaak voor bij het fine-tunen van redeneermodellen. Als je geïnteresseerd bent in hoe redeneervermogen zich ontwikkelt tijdens training, bekijk dan deze tutorial over het fine-tunen van DeepSeek R1, die vergelijkbare dynamiek verkent.
Het model opgeslagen bij checkpoint-400 biedt de beste generalisatie, met een trainingloss van 0,68, een validatieloss van 0,73 en een kleine kloof van slechts 0,05. Ondanks een hogere trainingloss dan de laatste checkpoint, gaat het beter om met nieuwe vragen. De laagste trainingloss levert zelden het beste model op; daarom zijn validatiemetrieken belangrijk.
We verifiëren dit later door het model op checkpoint-400 te vergelijken met het basismodel met een LLM-rechter. Voor nu lopen we stap voor stap door het bouwen van deze fine-tuningworkflow.
Stap 1: Installeer Tinker en richt je omgeving in
Let op: De volgende stappen splitsen een script op dat ongeveer 300 regels lang is. Omdat uitleg is verweven met codeblokken, raden we aan het volledige script in een nieuw tabblad te openen terwijl je volgt, voor het complete beeld.
Je hebt Python 3.11 of later nodig en een stabiele internetverbinding. Omdat Tinker de GPU-training op hun servers uitvoert, is een goede verbinding belangrijker dan een krachtige computer.
Begin met inloggen op de Tinker-console en maak een API-sleutel aan. Sla deze sleutel op in een
.env-bestand in je projectmap:Zodra je bent ingericht, wordt de Tinker-console je centrale hub voor het monitoren van trainingsruns en het beheren van checkpoints.
De Tinker-console volgt al je trainingsruns met kerngegevens: unieke run-ID’s, basismodel, LoRA-rank en tijden van laatste requests. Je kunt in deze interface zoeken, filteren en meerdere experimenten beheren.
Installeer de vereiste packages. Tinker heeft peerdependencies die niet automatisch installeren, dus specificeer ze expliciet:
De packages
transformersentorchbieden tokenisatie en tensorbewerkingen die Tinker intern gebruikt. Dedatasets-bibliotheek verzorgt het laden van trainingsdata van Hugging Face.Richt nu je imports in en een helperfunctie voor retries. Bij training op externe servers kun je tijdelijke verbindingsfouten zien die niet per se betekenen dat er echt iets mis is. Je trainingsjob draait nog steeds prima op Tinkers infrastructuur. Deze retry-wrapper handelt die tijdelijke fouten automatisch af:
Deze functie neemt een future-object (een object dat een bewerking vertegenwoordigt die nog niet klaar is) van Tinkers API en probeert tot drie keer het resultaat op te halen, met vijf seconden wachten tussen pogingen. De meeste tijdelijke fouten lossen binnen dit venster op.
Stap 2: Initialiseer de ServiceClient en laad de dataset
De
ServiceClientis je toegangspunt tot Tinker. Hij zoekt beschikbare modellen en regelt authenticatie:Je gebruikt hem na deze initiële setup niet veel meer. Hij bestaat vooral om trainings- en samplingclients voor specifieke modellen te maken.
Nu is het tijd om de FinCoT-dataset te laden. Die bevat financiële vragen gekoppeld aan stapsgewijze redeneerlijnen en eindantwoorden. Anders dan simpele Q&A-datasets leert FinCoT het model om zijn werk te laten zien vóórdat het antwoorden geeft—een belangrijke vaardigheid voor financiële adviesapplicaties waar gebruikers de onderbouwing willen begrijpen.
De dataset bevat een SFT-split (supervised fine-tuning) met complete redeneerlijnen en een RL-split voor reinforcement learning. Gebruik de SFT-split voor training en neem een steekproef uit de RL-split voor validatie om te zorgen dat het model generaliseert naar andere voorbeelden.
Stap 3: Maak je LoRA-trainingsclient
Maak nu een LoRA-trainingsclient voor Qwen3-8B:
Laten we uiteenzetten wat hier gebeurt:
Voor een diepere duik in hoe LoRA wiskundig werkt en hoe je rankparameters afstemt, bekijk Tinkers LoRA-primer of DataCamps uitgebreide gids over Low-Rank Adaptation.
Taalmodellen werken niet direct met woorden. Ze werken met „tokens”, stukjes tekst. Een tokenizer breekt tekst op in die stukjes. „Financial” kan bijvoorbeeld één token zijn, terwijl „understanding” kan splitsen in „under” en „standing.”
De tokenizer zet tekst om in nummers (token-ID’s) die het model kan verwerken. Door de tokenizer van de trainingsclient te nemen, zorg je dat je precies dezelfde tokenisatie gebruikt als Qwen3-8B verwacht.
Stap 4: Zet data om naar Tinkers formaat
Tinker heeft je trainingsdata nodig in een formaat genaamd
types.Datum. Dit formaat scheidt de modelinput van de configuratie van de verliesfunctie, zodat je precies kunt bepalen welke tokens bijdragen aan de training.Bij het fine-tunen van taalmodellen wil je doorgaans dat het model leert hoe het goede antwoorden genereert, niet dat het de vragen memoriseert. Dat doe je door verschillende gewichten toe te kennen aan verschillende delen van de input:
Laten we de datatransformatiefunctie stap voor stap opbouwen. Begin met de functiedeclaratie:
Formatteer het gesprek met Qwen3’s chattemplate
Verschillende modellen verwachten verschillende formatting voor gesprekken met meerdere beurten. Qwen3 gebruikt speciale tokens zoals
<|im_start|>en<|im_end|>om berichtgrenzen te markeren. Splits elk bericht in „observatie”-delen (rolheaders) en „actie”-delen (de eigenlijke inhoud):De FinCoT-dataset levert gestructureerde redeneringen, dus concatenëren we de velden
Reasoning_processenFinal_response. Dit leert het model zijn werk te laten zien vóór het antwoord.Tokenizeer elk deel apart
Om bij te houden waar gewichten moeten gelden, moet elk berichtdeel apart worden getokeniseerd.
Filter te lange sequenties
Sommige FinCoT-voorbeelden bevatten zeer gedetailleerde redeneerlijnen die buiten het comfortabele contextvenster van Qwen3-8B vallen. Hoewel het model technisch 32.768 tokens ondersteunt, kunnen zeer lange sequenties training instabiel maken:
Door voorbeelden boven 10.000 tokens te filteren, verwijder je slechts 5-6% van de data, terwijl je de betrouwbaarheid van de training aanzienlijk verbetert.
Ken gewichten toe om te sturen waar het model van leert
Zet gewichten op 0,0 voor de vraag (zodat het model niet leert om vragen te voorspellen) en 1,0 voor het antwoord (zodat het leert goede reacties te genereren):
Shift tokens en gewichten voor next-token prediction
Taalmodellen voorspellen het volgende token in een sequentie. Als het model tokens 0-9 ziet, moet het token 10 voorspellen. Je targets zijn dus altijd de input één positie vooruit geschoven:
Belangrijk: je moet de gewichten samen met de tokens shiften. Als je de gewichten niet shiftt, raakt de verliesberekening uitgelijnd: het model wordt getraind om het eerste antwoordtoken te voorspellen, maar het gewicht op die positie is nog 0,0 vanuit de prompt. Deze uitlijningsbug kan voorkomen dat het model goed leert.
Geef de geformatteerde data terug
Tot slot retourneert de functie prepare_datum() de geformatteerde data, klaar voor verwerking.
Door de gedefinieerde functie toe te passen op de ruwe trainings- en validatiesubsets, kunnen we nu de hele dataset verwerken:
Stap 5: Train het model met de trainingslus
De trainingslus gebruikt twee van Tinkers kern-API-primitieven:
forward_backwardenoptim_step. Laten we hem stap voor stap opbouwen met validatietracking om overfitting vroeg te detecteren.Definieer een validatielossfunctie
Definieer eerst een validatielossfunctie. Anders dan trainingloss vertelt validatieloss je hoe goed je model generaliseert naar onzichtbare data. Dit is cruciaal om overfitting te detecteren.
De methode
forward()berekent de loss zonder gradiënten te berekenen, wat het efficiënt maakt voor evaluatie waarbij je alleen prestaties wilt meten en geen gewichten wilt updaten. Het berekenen van validatieloss voegt minimale overhead toe (alleen een forward pass, geen gradiënten) maar geeft vroegtijdige waarschuwing wanneer de kloof tussen training- en validatieloss groter wordt dan 0,2—een signaal dat je model aan het memoriseren is in plaats van te leren.Configureer trainingsparameters
We moeten het aantal epochs en de learning rate definiëren. LoRA vereist significant hogere learning rates dan volledige fine-tuning, typisch 10-20x groter.
De formule houdt rekening met modelgrootte (Qwen3-8B heeft een hidden size van 4.096) en gebruikt empirisch bepaalde exponenten die per modelfamilie variëren, zoals gedocumenteerd in het Tinker-cookbook. Voor Qwen-modellen is de exponent 0,0775, terwijl Llama-modellen 0,781 gebruiken. In ons geval levert dit een learning rate op rond 4,7e-4, wat zorgt voor stabiele convergentie zonder gradiëntexplosies.
Stel learning rate-warmup in
Starten met de volledige learning rate kan vroeg in de training gradiëntexplosies veroorzaken wanneer het model nog niet aan de taak is aangepast. Warmup verhoogt de learning rate geleidelijk van bijna nul naar de doelwaarde over de eerste 200 iteraties. Je zag dit duidelijk in de eerdere trainingsvisualisatie, waar de learning rate (groene lijn) soepel oploopt tijdens de eerste 200 iteraties.
Start de trainingslus
Na het initialiseren van lijsten om verliezen bij te houden, kunnen we de trainingslus starten:
De warmuplogica schaalt de learning rate geleidelijk op tijdens de eerste 200 iteraties en voorkomt zo vroege instabiliteit.
Roep Tinkers kerntrainingsprimitieven aan
In elke iteratie worden Tinkers kernprimitieven als volgt aangeroepen:
forward_backwardberekent gradiënten door te bepalen hoe fout de voorspellingen van het model zijn en in welke richting elke parameter moet worden aangepast. Het gebruikt cross-entropieloss, die meet hoe goed de voorspelde waarschijnlijkheidsverdeling van het model overeenkomt met de daadwerkelijke volgende tokens.optim_stepwerkt de modelparameters daadwerkelijk bij op basis van die gradiënten met de Adam-optimizer.Merk op dat beide methoden meteen „future”-objecten retourneren. Hierdoor kan Tinker meerdere bewerkingen gelijktijdig verwerken, wat het proces versnelt. Het aanroepen van
with_retry(future)wacht op het voltooien van die specifieke bewerking.Houd verliesmetriek bij en toon ze
We berekenen zowel totale als per-tokenverliezen en voegen ze toe aan de respectieve lijsten:
Per-tokenloss normaliseert de loss naar het aantal antwoordtokens, wat interpretatie over verschillende batchgroottes heen makkelijker maakt. Een goede trainingsrun start typisch met per-tokenloss rond 1,2-1,5 en daalt onder 0,8 tegen checkpoint-400. Als je loss boven 2,0 start of niet daalt na 50 iteraties, controleer dan je datavoorbereiding en learning rate.
Voeg periodieke validatiechecks en checkpoints toe
Door elke 200 iteraties gewichten op te slaan, maak je snapshots om te vergelijken. Zoals je eerder zag, generaliseert checkpoint-400 beter dan de laatste checkpoint, ondanks hogere trainingloss. Sla altijd meerdere checkpoints op en evalueer ze op achtergehouden data. De checkpoints blijven op Tinkers servers na afloop van je script.
Tinker organiseert checkpoints in twee categorieën: full-state checkpoints (om de training te hervatten bij onderbreking) en samplergewichten (lichte checkpoints voor inferentie). Merk op dat checkpoint-400 in beide formaten verschijnt, waardoor het eenvoudig is om zowel door te trainen als het model te deployen.
Als je trainingsrun wordt onderbroken, kun je hervatten vanaf elke opgeslagen checkpoint met de full-stategewichten, zodat je niet vanaf nul hoeft te beginnen.
Voor de volledige API-referentie van deze methoden, zie Tinkers documentatie over training en sampling.
Stap 6: Sla je fijn-afgestelde model op
Nadat de training is voltooid, sla je de uiteindelijke modelgewichten op:
De gewichten worden opgeslagen op Tinkers servers, niet op je computer. De LoRA-adapters vereisen doorgaans slechts tientallen megabytes. Tinker kan ze desgewenst exporteren voor gebruik met externe inferentieproviders als je het model buiten hun infrastructuur wilt deployen.
Stap 7: Test het model met voorbeeldvragen
Test ten slotte je fijn-afgestelde model met de
sample-API-primitief. Stel eerst de samplingparameters in:Laten we deze parameters toelichten:
max_tokens: Maximale lengte van de gegenereerde reactie (200 tokens is grofweg 150 woorden).temperature: Bepaalt de willekeur in generatie. Lagere waarden (0,1-0,5) maken de output gefocust en deterministisch; hogere waarden (0,7-1,0) laten meer creativiteit toe. 0,7 balanceert samenhang en variatie.top_p(nucleus sampling): Neemt alleen de kleinste set tokens in overweging waarvan de cumulatieve waarschijnlijkheid deze waarde overschrijdt. 0,9 betekent „neem alleen tokens die samen voor 90% van de waarschijnlijkheidsmassa zorgen.” Dit voorkomt dat het model zeer onwaarschijnlijke tokens kiest.stop_sequences: Zegt tegen het model te stoppen met genereren wanneer het deze sequentie tegenkomt.<|im_end|>is de eindemarkering van de sequentie.Genereer reacties voor testvragen:
Hier zijn twee voorbeeldoutputs van het fijn-afgestelde model (ingekort ter illustratie):
Het response-object bevat een lijst
sequencesomdat je meerdere samples per prompt kunt aanvragen. Benader de tokens viasequences[0].tokensen decodeer ze terug naar tekst met dezelfde tokenizer.Je hebt nu alle vier de kern-API-primitieven gedemonstreerd:
forward_backward: Bereken gradiënten op je trainingsdataoptim_step: Update modelparameters met de Adam-optimizersave_weights_and_get_sampling_client: Bewaar je fijn-afgestelde modelsample: Genereer voorspellingen met het fijn-afgestelde modelDitzelfde workflowpatroon strekt zich uit tot meer geavanceerde trainingsparadigma’s. Voor reinforcement learning of voorkeuroptimalisatie gebruik je dezelfde primitieven maar met andere verliesfuncties en dataformaten. Als je geïnteresseerd bent in het alignen van modellen met menselijke voorkeuren, bekijk dan technieken voor preference fine-tuning, die op dezelfde basis voortbouwen. Het Tinker-cookbook biedt voorbeelden voor deze geavanceerde scenario’s.
Maar hoe weet je of het fine-tunen de prestaties echt heeft verbeterd? In plaats van te vertrouwen op subjectieve indrukken, heb je rigoureuze evaluatie nodig. In de volgende sectie zie je resultaten van een LLM-as-judge-evaluatie die het fijn-afgestelde model vergelijkt met het basis Qwen3-8B-model op 10 diverse financiële vragen.
Het fijn-afgestelde model evalueren met een LLM-rechter
Om prestaties objectief te meten, gebruikten we LLM-as-judge: GPT-4o evalueerde checkpoint-400 tegenover basis Qwen3-8B op 10 diverse financiële vragen, waarbij elke reactie werd gescoord op nauwkeurigheid, helderheid, volledigheid en financiële terminologie.
Het fijn-afgestelde model scoorde 8,5/10, vergeleken met 6,5 voor het basismodel, en won alle 10 vergelijkingen. De vonnissen verklaren waarom: het levert complete uitleg met zelfverzekerde, gestructureerde redenering, terwijl het basismodel aarzelt met „I think” en „maybe” en gedachten onvolledig laat.
Dit bevestigt de betere prestaties in de praktijk van checkpoint-400. De lagere trainingloss bij iteratie 900 had ons memorisatie gegeven, geen redenering.
Bekijk het vergelijkingsscript en de gedetailleerde resultaten om vergelijkbare evaluaties op jouw modellen uit te voeren.
Conclusie
Je hebt gezien hoe Tinker fine-tuning vereenvoudigt zonder concessies te doen aan controle. Vier kern-API-primitieven,
forward_backward,optim_step,save_weights_and_get_sampling_clientensample, geven je de bouwstenen voor aangepaste trainingsworkflows, terwijl Tinker de gedistribueerde infrastructuur afhandelt.Het financiële Q&A-model dat we bouwden, laat productiebest practices zien: validatietracking signaleerde overfitting vroeg, checkpoint-400 presteerde beter dan het eindmodel door te focussen op generalisatie, en LLM-as-judge-evaluatie bevestigde een verbetering van 2 punten ten opzichte van het basismodel. Deze patronen gelden of je nu 8B- of 70B-parametermodellen fine-tunet.
Het platform is in beta met toegang via een wachtlijst, maar de concepten die je hebt geleerd kun je direct toepassen zodra je toegang krijgt. De trainingsruns die ik voor deze tutorial deed (inclusief mislukte en experimentele) kostten 150 startcredits, dus met de initiële credits kun je deze tutorial 6 keer draaien plus extra experimenten—ruim voldoende om te leren en te itereren op je eigen fine-tuningprojecten.
Wat nu? Probeer fine-tunen op je domeinspecifieke data, experimenteer met verschillende LoRA-ranks en learning rates, of verken geavanceerde trainingsparadigma’s zoals reinforcement learning from human feedback. Het Tinker-cookbook biedt voorbeelden voor deze scenario’s. Denk nu alvast na over je use-case—welk gedrag wil je dat je model leert?
Wil je een bredere skillset ontwikkelen in het trainen en fine-tunen van de nieuwste AI-modellen voor productie, bekijk dan de Associate AI Engineer for Developers-carrièretrack.