- Je maakt expliciet welke antwoordtokens een SFT-voorbeeld laten meetellen.
- Je verschuift een loss-masker samen met de doelen en voorkomt een fout van één positie.
Een leerling moet een vraag beantwoorden, niet de vraag overschrijven. Zo kan supervised fine-tuning (SFT) een taalmodel van gewenste antwoorden laten leren, terwijl de vraag wel als context beschikbaar blijft. Dat vraagt een precies tokenformaat én een masker voor de juiste doelen.
Bij instructietuning veranderen de voorbeelden en het gewenste gedrag. De volgende-tokenloss kan dezelfde blijven. In deze les kiezen we assistant-only loss: antwoordinhoud en het einde van een assistantbericht tellen, andere tokens niet.
1. Maak rollen expliciet
Ons eigen speelgoedformaat gebruikt BOS=1, eindmarker=2 en rolmarkers system=3, user=4, assistant=5. Inhoudstokens beginnen bij ID 10. Een userbericht [10] gevolgd door assistantantwoord [11] wordt [1,4,10,2,5,11,2].
messages = [
{'role':'user','tokens':[10]},
{'role':'assistant','tokens':[11]}]
ids,learn = serialize_chat(messages)
print(ids) # [1 4 10 2 5 11 2]
print(learn.astype(int))
# [0 0 0 0 0 1 1]
De laatste twee vlaggen markeren antwoord 11 en zijn eindmarker. BOS, rolmarkers en userinhoud zijn geen antwoorddoelen. De rol komt uit gestructureerde metadata; tekst die toevallig “assistant” zegt verandert die metadata niet.
Maak serialize_chat voor de opgegeven berichtenlijst en int64-inhoudstokens. System mag alleen vooraan staan en de hele reeks heeft maximaal 512 tokens. Onbekende rollen of ongeldige inhoud geven ValueError.
Dit formaat is een eigen oefencontract. Een echt geladen model gebruikt zijn eigen tokenizer en chattemplate. Een template bepaalt de serialisatie, maar vormt geen beveiligingsgrens tegen promptinjectie.
012. Verschuif doelen en vlaggen samen
De modelrij voor inputtoken t voorspelt de volgende token. Inputs worden daarom ids[:-1], targets ids[1:] en het doelmasker learn[1:]. De vlag hoort bij wat je probeert te voorspellen, niet bij de token die je invoert.
x,y,mask = sft_pairs(ids,learn)
print(x) # [1 4 10 2 5 11]
print(y) # [4 10 2 5 11 2]
print(mask.astype(int))
# [0 0 0 0 1 1]
print(x[mask]) # [5 11]
De rolmarker 5 is zelf geen antwoordinhoud, maar zijn uitvoer voorspelt het eerste antwoordtoken 11 en telt dus wel mee. Een onverschoven masker mist dat eerste doel. Dat is de typische fout van één positie.
Maak sft_pairs met onafhankelijke kopieën. In een gesprek met meerdere assistantbeurten tellen hier alle antwoorden. Alleen de laatste beurt trainen vraagt een bewust ander masker.
023. Deel door het aantal antwoorddoelen
Neem drie logitrijen met twee mogelijke tokens. De eerste rij is prompt en telt niet; beide antwoordrijen geven hun juiste token kans .75. Hun gemiddelde negatieve logkans is −log(.75), ongeveer .2877.
m is het doelmasker, M het aantal True-posities, y de target en p zijn modelkans. De som loopt over tijdposities t. Een volledig leeg doelmasker weigeren we, zodat een lege trainingsbatch opvalt.
z = np.array([[10.,-10.],
[0.,np.log(3)],
[np.log(3),0.]])
target = np.array([0,1,0])
mask = np.array([0,1,1],bool)
loss,grad = sft_loss(z,target,mask)
print(round(loss,4)) # .2877
print(np.round(grad,3))
# [[ 0. 0. ]
# [ .125 -.125]
# [-.125 .125]]
Maak sft_loss met stabiele logkansen en nulgradiënten op niet-geselecteerde logitrijen. De noemer is twee antwoorddoelen, niet drie inputrijen. Promptcontext kan nog steeds de latere antwoorden en verborgen gradiënten beïnvloeden; nul promptlogitgradiënten zeggen niet dat de vraag wordt genegeerd.
Lange antwoorden leveren binnen zo’n samengevoegde batch meer doelen dan korte. Gemiddelde loss per antwoord is een ander leerdoel. Kies de reductie expliciet en controleer de kwaliteit op apart gehouden taken; lage trainingsloss garandeert geen waarheid of veiligheid.
03Wat neem je mee?
- Een chattemplate maakt rollen en tokenvolgorde precies.
- Het leermasker verschuift samen met de targets.
- Assistant-only loss middelt over geselecteerde antwoordtokens.
Hierna vergelijk je twee antwoorden om een voorkeursscore te leren.