Media Mobile Esponenziale
Una Media Recente Smussata
Una media mobile esponenziale (EMA) traccia un valore dando più peso ai campioni recenti rispetto a quelli vecchi, con pesi che decadono esponenzialmente. Formula:
EMA(t) = (1 - alpha) EMA(t-1) + alpha value(t)
Dove alpha (il fattore di smoothing) si trova in (0, 1). ANDREA usa alpha = 0.1 per il tracciamento della loss per sorgente.
Termine per Termine
- value(t): ultima osservazione. Per ANDREA, si tratta della loss riportata da CUDA dopo un forward pass su un documento dalla sorgente k.
- EMA(t-1): valore EMA precedente per la sorgente k. Memorizzato nello stato proxy.
- alpha = 0.1: ogni nuova loss contribuisce al 10%; la storia cumulativa contribuisce al 90%.
- (1 - alpha) = 0.9: peso sulla storia.
Perché EMA invece della Media Semplice
Una media mobile semplice assegna lo stesso peso a ogni passo. Il passo 1 ha lo stesso peso del passo 100.000. Questo funziona se i dati sono stazionari. Le perdite di ANDREA NON sono stazionarie: la capacità del modello cresce durante l'addestramento, quindi la perdita di una sorgente al passo 5.000 differisce dalla sua perdita al passo 50.000.
EMA risolve questo. I vecchi valori di perdita svaniscono esponenzialmente. L'EMA riflette la realtà recente, non una media delle condizioni iniziali.
Per Sorgente
ANDREA mantiene una EMA per braccio (per sorgente). Sedici braccia = sedici EMA. Ogni passo aggiorna solo l'EMA della sorgente che è stata selezionata. Le altre 15 EMA rimangono congelate fino al loro prossimo pull.
Calcola un passo EMA
La Formula del Reward
Reward = Miglioramento, Scalato
ANDREA definisce la ricompensa per passo per il braccio k come:
reward_k = max(0, EMA_k(t-1) - loss_k(t)) * 1000
Tre parti:
1. EMA_k(t-1) - loss_k(t): miglioramento. Se la nuova loss è inferiore alla media mobile, la differenza è positiva: la sorgente k ha performato meglio del previsto.
2. max(0, ...): clippa i miglioramenti negativi a zero. Se la nuova loss è peggiore dell'EMA, nessuna ricompensa (ma nemmeno penalità).
3. \* 1000: scala per rendere il segnale comparabile al bonus di esplorazione UCB.
Perché max(0, ...)
Le ricompense negative spingerebbero mean_reward(k) verso il basso, creando un bias contro le braccia i cui errori fluttuano verso l'alto. Ma la fluttuazione è normale: un singolo documento difficile aumenta la perdita senza significare che la fonte sia cattiva. Il clipping a zero tratta la fluttuazione come 'nessuna informazione' piuttosto che 'penalità'.
Le fonti possono guadagnare ricompensa zero ripetutamente senza affondare. Il loro rango UCB rimane guidato dal bonus di esplorazione (alto quando n_k è piccolo) più le vittorie passate.
Cosa riporta CUDA
Ogni passaggio forward+backward, il kernel CUDA emette un record:
{source: 'hermes3-general', doc_index: 4231, loss: 4.520}
Il proxy riceve il record, cerca l'EMA per quella source, calcola la reward, aggiorna l'EMA, inserisce la reward nell'accumulatore mean_reward(k) del bandit.
Calcola una Reward
Adattare il Reward al Bonus di Esplorazione
Il Problema della Magnitudine
I miglioramenti della loss per passo sono piccoli. La loss scende da 4.521 a 4.520: differenza 0.001. Da 4.520 a 4.518: differenza 0.002. In un'intera esecuzione di training, le differenze raw vivono approssimativamente in [0, 0.01].
Ora guarda il bonus di esplorazione di UCB con C=0.5, N=1000 e n_k=20:
0.5 sqrt(ln(1000) / 20) = 0.5 sqrt(6.91 / 20) = 0.5 * 0.588 = 0.294
Il bonus è a 0.294. La ricompensa grezza è a 0.001. Il bonus è 300x più grande della ricompensa. L'argmax di UCB ordina quasi interamente in base al bonus; mean_reward fornisce essenzialmente zero segnale.
Risultato senza scaling: il bandit di ANDREA sceglie il braccio con il più piccolo n_k a ogni passo. Mean_reward viene ignorato. Il bandit diventa una politica di esplorazione pura.
La Soluzione: 1000x
Moltiplica la ricompensa grezza per 1000. Ora la ricompensa si attesta a 1.0 (vs grezza 0.001). Confronta con lo stesso bonus di esplorazione 0.294:
ricompensa scalata 1.0 vs bonus 0.294 = ricompensa prevale di 3.4x
Ora mean_reward domina il ranking UCB. L'esplorazione aggiunge sfumature alla coda (bracci rari ottengono un boost di 0.3), ma il corpo del ranking deriva dalla ricompensa osservata.
Perché 1000 (e non 10, e non 100.000)
Corrispondenza dell'ordine di grandezza. Le ricompense raw sono ~10^-3. Il bonus di esplorazione è ~10^0. La differenza è 10^3. Moltiplica la ricompensa raw per 10^3 per atterrare nello stesso range del bonus.
Scalare per 100x lascia la ricompensa a 0.1 (ancora meno del bonus 0.294 -> l'esplorazione domina ancora). Scalare per 100.000x porta la ricompensa a 100 (ora l'esplorazione non può influenzare nulla; UCB collassa sul greedy mean_reward). 1000x si trova nella zona funzionante dove entrambi i termini contribuiscono.
Calibrazione, non teoria
Il fattore 1000x è una calibrazione ingegneristica, non una costante teorica. Dipende da tre cose: scala della loss di training (cross-entropy su un vocabolario di 8K token è vicino a 4.5), tasso di decadimento della loss per step (lento), & costante UCB C=0.5. Cambia uno di quelli, & 1000 potrebbe non essere più il moltiplicatore giusto.
Ragionamento sul Fattore di Scalatura
Prossimo
Cosa Hai
L'attribuzione delle ricompense converte i report di loss di CUDA in un segnale pronto per UCB in tre operazioni: EMA per-source traccia la storia delle loss (alpha=0.1, lenta), reward = max(0, EMA - loss) clippa i negativi, & scaling 1000x abbina la magnitudine della reward a quella del bonus di esplorazione UCB.
Cosa Resta
I pavimenti e le penalità di epoca (attività 79) operano sopra l'output UCB. I pavimenti di origine garantiscono un campionamento minimo per le origini prioritarie indipendentemente dal rango UCB. Le penalità di epoca riducono il peso delle origini che sono state estratte più volte di quante ne abbiano documenti, prevenendo la memorizzazione di piccoli dataset mentre i grandi dataset rimangono freschi.
Riferimento
ANDREA whitepaper, sezione 3.3.