Begreper & referanser
Alle nøkkelbegrepene, formlene og referansene fra Dyp forsterkningslæring: DQN, samlet på én side. Bruk denne som oppslag når du leser, øver flashcards eller tar quiz.
Begreper
Sentrale begreper fra kapittelet med korte definisjoner.
Å erstatte en tabell med en parametrisert funksjon, for eksempel et nevralt nettverk , som regner ut verdier fra features i tilstanden og derfor også gir svar for tilstander den aldri har sett.
Et nevralt nettverk som tar tilstanden som input og har én utgang per handling, slik at ett forward pass gir alle og grådig valg er argmax over utgangene.
At alle Q-verdiene regnes ut med de samme vektene . Ett gradientsteg på én overgang endrer derfor også Q-verdiene til mange andre tilstander: det gir generalisering, men også ustabilitet.
Deep Q-Network: Q-learning der Q-tabellen er byttet ut med et Q-nettverk, stabilisert med replay buffer og target-nettverk.
Et minne med fast kapasitet som lagrer overganger . Treningen trekker tilfeldige minibatcher fra det, noe som bryter korrelasjonen mellom påfølgende steg og lar agenten gjenbruke erfaring.
En frosset kopi av Q-nettverket som bare brukes til å regne ut målene, og som synkroniseres med online-nettet hvert -te steg. Det gir stabile treningsmål.
At utforskningsraten i -greedy starter høyt, ofte på 1, og senkes gradvis mot en liten minsteverdi etter hvert som Q-verdiene blir pålitelige.
At agenten maksimerer belønningen slik den faktisk er definert ved å utnytte svakheter i belønningsdesignet, i stedet for å oppnå det designeren mente. Kalles også specification gaming.
Formler
Hver formel: hva den heter, hvordan den ser ut, og hva symbolene betyr.
DQN-målet
Målet regnes med target-nettets vekter . Når episoden slutter i (), er målet bare .
DQN-tapet
Gjennomsnittlig kvadrert TD-feil over minibatchen . Målene behandles som konstanter, så gradienten går bare gjennom .
Synkronisering av target-nettet
Mellom to synkroniseringer står stille, så målene flytter seg ikke for hvert gradientsteg.
Lineær ε-annealing
synker lineært fra til over steg og holdes deretter fast på .
Kodesnutter
Kodesnutter fra kapittelet, vist literal.
Hvor mye av en Q-tabell blir noen gang besøkt?
import numpy as np rng = np.random.default_rng(15)# intervaller per tilstandsvariabel, og antall variabler (f.eks. posisjon, fart, vinkel, vinkelfart)bins = 10 # @param 2..30dims = 4 # @param 1..6besok = 5000 # tilstander agenten har opplevd under trening # Agenten havner oftest nær midten av tilstandsrommetX = np.clip(rng.normal(0.5, 0.15, size=(besok, dims)), 0, 0.999)sett = {tuple(c) for c in np.floor(X * bins).astype(int)} totalt = bins ** dimsprint(f"celler i tabellen: {totalt}")print(f"besøkt minst én gang: {len(sett)} ({100 * len(sett) / totalt:.1f} %)")print(f"aldri besøkt, Q-verdien oppdateres aldri: {totalt - len(sett)}")Prøv: Dra bins og dims opp og se «besøkt minst én gang» falle mot 0 %, så «aldri besøkt» dekker nesten hele tabellen.
Ett gradientsteg flytter mange Q-verdier
import numpy as npimport matplotlib.pyplot as plt sentre = np.linspace(0, 1, 5) # fem features deles av alle tilstander# hvor langt hver feature «rekker», og tilstanden vi trener påbredde = 0.05 # @param 0.005..0.3 0.005s_trent = 0.30 # @param 0..1 0.05y, eta = 1.0, 0.5 # mål for den trente tilstanden og læringsrate def features(s): s = np.asarray(s)[..., None] return np.exp(-((s - sentre) ** 2) / bredde) w = np.zeros(5) # vektene til Q(s, fram); alle Q starter på 0def Q(s): return features(s) @ w s_alle = np.linspace(0, 1, 101)for_steg = Q(s_alle) # Q før steget: alt er 0w += eta * (y - Q(s_trent)) * features(s_trent) # ett gradientsteg på ett eksempeltilstander = [0.0, 0.25, 0.30, 0.35, 0.60, 0.90, 1.0]print("s: " + " ".join(f"{s:5.2f}" for s in tilstander))print("Q etter steg:" + " ".join(f"{Q(s):5.2f}" for s in tilstander))plt.figure()plt.plot(s_alle, Q(s_alle), label="Q etter steget")plt.plot(s_alle, for_steg, color="C1", label="Q før steget")plt.axvline(s_trent, linestyle="--", label="trent tilstand")plt.xlabel("Tilstand s")plt.ylabel("Q(s, fram)")plt.legend()plt.tight_layout()plt.show()Prøv: Dra bredde ned mot 0,005 og se «Q etter steg» flytte færre tilstander og kurven smalne; flytt s_trent og se hvilke naboer som følger med.
DQN-mål og tap for en minibatch
import numpy as np gamma = 0.9 # @param 0..1 0.05bruk_ferdig = 1 # @param 0..1r = np.array([0.0, 1.0, -1.0, 0.5]) # minibatch med fire overgangerer_slutt = np.array([0, 1, 0, 0]) # 1 = episoden sluttet i s'ferdig = er_slutt * bruk_ferdig # 0 = vi glemmer å gjenkjenne sluttenq_target_neste = np.array([[1.0, 2.0], # target-nettets Q(s', ·) [4.0, 3.0], [0.5, -0.5], [3.0, 3.5]])q_online = np.array([1.5, 2.0, 0.0, 3.0]) # online-nettets Q(s, a) y = r + gamma * (1 - ferdig) * q_target_neste.max(axis=1)feil = y - q_onlinefor i in range(4): status = "terminal" if er_slutt[i] else "ikke terminal" print(f"overgang {i} ({status}): r = {r[i]:4.1f} -> mål y = {y[i]:5.2f}, TD-feil = {feil[i]:5.2f}")print(f"MSE-tap: {np.mean(feil ** 2):.4f}")Prøv: Sett bruk_ferdig til 0 og se «mål y» for «overgang 1» (terminal) blåses opp; dra gamma til 0 og se målene bli bare r.
Ringbuffer, random.sample og DQN-mål
import random random.seed(4)KAPASITET = 6 # @param 3..9tilfeldig = 1 # @param 0..1GAMMA = 0.9buffer, pos = [], 0 def legg_til(overgang): global pos if len(buffer) < KAPASITET: buffer.append(overgang) else: buffer[pos] = overgang # skriv over den eldste pos = (pos + 1) % KAPASITET # Overgang: (steg, r, ferdig, target-nettets Q(s', ·))for t in range(9): ferdig = t % 4 == 3 # episoden slutter hvert fjerde steg legg_til((t, 1.0 if ferdig else 0.0, ferdig, [0.1 * t, 0.2 * t])) print(f"steg i bufferet: {[o[0] for o in buffer]}")batch = random.sample(buffer, 3) if tilfeldig else buffer[-3:] # minibatch på treprint("minibatch:")for t, r, ferdig, q_neste in batch: y = r if ferdig else r + GAMMA * max(q_neste) status = "terminal" if ferdig else "ikke terminal" print(f" steg {t} ({status}): r = {r}, mål y = {y:.2f}")Prøv: Dra KAPASITET ned og se hvilke steg som er borte fra «steg i bufferet»; sett tilfeldig til 0 og se «minibatch» bli tre påfølgende steg.
Reward hacking hos en lagerrobot
T = 120 # tidssteg i ett skiftr_gjentatt = 1.0 # @param -0.5..1 0.05 def belonning(ny_pakke): return 1.0 if ny_pakke else r_gjentatt # dagens design: +1 for hver skanning def skift(strategi): t, sum_r, sett, pakke = 0, 0.0, set(), 0 while t < T: if strategi == "hent ny pakke": pakke += 1 # hente og skanne en ny pakke tar 4 steg t += 4 else: t += 1 # skanne samme pakke igjen tar 1 steg sum_r += belonning(pakke not in sett) sett.add(pakke) return sum_r, len(sett) resultater = {s: skift(s) for s in ["hent ny pakke", "skann samme igjen"]}for s, (sum_r, ulike) in resultater.items(): print(f"{s:18s} belønning = {sum_r:6.1f} ulike pakker = {ulike}")print("en belønningsmaksimerende agent velger:", max(resultater, key=lambda s: resultater[s][0]))Prøv: Dra r_gjentatt ned fra 1 og finn verdien der «en belønningsmaksimerende agent velger» ikke lenger er «skann samme igjen».
Læringsmål
Hva du skal kunne etter å ha lest kapittelet.
- 01Forklar hvorfor en Q-tabell ikke skalerer, og hvordan et Q-nettverk generaliserer til tilstander det aldri har sett
- 02Forklar hvorfor vektdeling gjør at ett gradientsteg endrer Q-verdiene til mange tilstander, og hvorfor det kan gi ustabil trening
- 03Regn ut DQN-målet og det kvadrerte TD-tapet, også for terminale overganger
- 04Forklar hva replay buffer med tilfeldige minibatcher og et frosset target-nettverk løser hver for seg
- 05Regn ut under lineær annealing og tolk hvorfor utforskningen senkes gradvis
- 06Kjenn igjen reward hacking i et scenario og foreslå et bedre belønningsdesign