Varför golven finns
En dålig belöningssekvens kan svälta en prioriterad källa
ANDREA's bandit väljer fokusarmar efter UCB1-rankning. UCB-rankning beror på mean_reward(k), som beror på observerade förlustförbättringar. En sekvens av dokument med hög förlust från en prioriterad källa (säg dictionary) kan dra ner mean_reward(k). Nu rankas dictionary lågt, får få fokusdragningar, & dess mean_reward(k) kan inte återhämta sig (inga dragningar = inga färska observationer).
Samma risk gäller för vilken källa som helst som ANDREA's träningsdesigner vill ha med i mixen oavsett kortsiktig belöningsignal.
Golv som minimivikter
ANDREA:s träningskonfig specifiserar ett golv per källa: en miniminsamplingsvikt som källan får oavsett vad UCB-utdata säger. Golven sträcker sig från 0.0 till 1.0. Exempel:
hermes3-general golv = 0.8 (prioriterad konversationskälla)
chat golv = 0.8
dictionary golv = 0.7 (faktisk återkallelse-stöd)
gutenberg golv = 0.7 (prosa-sammanhang)
syntetisk-chatt floor = 0.0 (ingen floor; banditen bestämmer fritt)
Hur Floors Appliceras
Efter att UCB1 rankat armarna och dice control sammanställt fokusuppsättningar får varje källa en preliminär vikt. Sedan körs floor-tillämpning:
final_weight_k = max(tentative_weight_k, floor_k)
Om banditen tilldelade vikt 0.3 till hermes3-general men dess floor är 0.8, vinner floorn: slutlig vikt = 0.8. Banditens röst överstyrns uppåt endast; den överstyrns aldrig nedåt.
Olika konfigurationer, olika golv
ANDREA levererar flera träningskonfigurationer: chatbot, tool-caller, bash-commander. Varje konfiguration sätter olika golv för sina prioriterade källor. Chatbot-konfigurationen sätter hermes3-general & chat högt. Tool-caller sätter repo-docstrings högre. Bash-commander sätter repo-commits högre. Samma algoritm, olika prioriteringar.
Applicera ett golv
Memoriseringsrisken
Små Källor Memoriseras
ANDREA's datakällor varierar vilt i storlek. synthetic-chat har ungefär 1 400 dokument. gutenberg har 500 000+. Om banditen drar jämnt, tar synthetic-chat slut på sitt dokumentpool snabbt: efter 1 400 drag har varje dokument setts minst en gång. Dra 2 800 gånger & varje dokument har setts minst två gånger i genomsnitt.
Upprepad exponering för en liten uppsättning dokument leder till memorisering: modellen slutar lära generaliserbara mönster & börjar recitera specifika token-sekvenser från träningsdata. Memorisering är dåligt av två skäl: (1) det slösar kapacitet på inlärning utantill istället för generalisering, & (2) det kan läcka träningsdata genom generering.
Epoker som en proxy för memorering
Definiera en epok över källan k som ett fullständigt genomgång av alla dokument i k:
epochs_k = floor(lifetime_pulls_k / n_docs_k)
Om synthetic-chat (n_docs=1400) har dragits 2 800 gånger, epochs = floor(2800/1400) = 2: källan har setts igenom två gånger. Om gutenberg (n_docs=500 000) har dragits 100 000 gånger, epochs = floor(100000/500000) = 0: inte ännu en fullständig genomgång.
Straffet 1/(1+epochs)
När lifetime_pulls / n_docs > 1.0 tillämpas ett multiplikativt straff av ANDREA:
penalty = 1 / (1 + epochs)
final_weight = bandit_weight * penalty
Kurva:
| epochs | straff | viktminskning |
|---|---|---|
| 0 | 1.000 | ingen |
| 1 | 0.500 | hälften |
| 2 | 0.333 | en tredjedel |
| 3 | 0.250 | en fjärdedel |
| 5 | 0.167 | en sjättedel |
| 10 | 0.091 | en elfte |
Straffet växer med varje slutförd genomgång. Efter många epoch närmar sig källans vikt noll & banditen vilar den naturligt.
Varför Lifetime Pulls Bevaras Vid Omstarter
ANDREA:s träningskörningar sträcker sig över dagar. Krascher inträffar. Servrar startas om. Konfigurationer justeras & träningen återupptas från en checkpoint. Lifetime pulls bevaras genom alla dessa händelser: proxyn skriver pull-räknare till disk kontinuerligt.
Om pulls nollställs vid varje omstart kunde en liten källa effektivt återgå till epoch 0 varje gång träningen startas om. Straffet skulle aldrig ackumuleras, & memorering skulle fortsätta oavsett. Att bevara lifetime pulls gör straffet till en verklig, monoton-växande begränsning.
Beräkna en Epoch-straff
Avslutning av Bandit Curriculum Stack
Vad du har
Floors garanterar minimalsampling för prioriterade källor: final_weight = max(bandit_weight, floor_k). Epoch-straff begränsar memorisering på små källor: när lifetime_pulls/n_docs > 1, multipliceras vikten med 1/(1+epochs). Livstidsdragningar kvarstår över omstarter så straffet blir en monoton begränsning, inte en återställbar räknare.
Den Fullständiga Pipeline
Att sätta ihop alla fyra ANDREA bandit-aktiviteter (76-79):
1. Aktivitet 76 (UCB1). Varje steg beräknar UCB(k) = mean_reward(k) + 0.5 * sqrt(ln(N)/n_k). Argmax väljer en arm.
2. Aktivitet 77 (tärningsfaser). Fasgränser (var 7 till 42 steg) slår tärning för antal fokusarmar. Slumpmässiga armar först, UCB fyller resten. 25-33% av faserna körs helt slumpmässigt.
3. Aktivitet 78 (belöningsattribution). CUDA rapporterar förlust; EMA per källa spårar historik; belöning = max(0, EMA - förlust) * 1000. Skalad belöning matar mean_reward(k).
4. Aktivitet 79 (golv & epoker, denna lektion). Efter UCB-utdata lyfter golv prioriterade källor; epokstraff nedväger memorerade källor. Livstidsdragningar kvarstår.
Tillsammans: en bandit som anpassar sig (UCB1), utforskar pålitligt (tärningsfaser), får ärliga belöningsignaler (1000x skalning), respekterar träningsdesign-prioriteringar (golv), & undviker memorering (epoch-straff).
Referens
ANDREA whitepaper, avsnitt 3.5 & 3.6.