course

Förstärkningsinlärning (RL) är den del av maskininlärningsekosystemet där agenten lär sig genom att interagera med miljön för att få fram den optimala strategin för att nå målen. Det skiljer sig ganska mycket från övervakade maskininlärningsalgoritmer, där vi behöver mata in och bearbeta data. Förstärkningsinlärning kräver ingen data i förväg. I stället lär den sig av miljön och belöningssystemet för att fatta bättre beslut.
Exempelvis i tv-spelet Mario: om en figur utför en slumpmässig handling (t.ex. går åt vänster) kan den få en belöning baserat på den handlingen. Efter handlingen befinner sig agenten (Mario) i ett nytt tillstånd, och processen upprepas tills spelkaraktären når slutet av banan eller dör.
Detta avsnitt upprepas flera gånger tills Mario lär sig navigera i miljön genom att maximera belöningarna.

Bild av författaren
Vi kan bryta ner förstärkningsinlärning i fem enkla steg:
- Agenten är i starttillstånd i en miljö.
- Den kommer att utföra en handling baserat på en viss strategi.
- Den får en belöning eller bestraffning baserat på den handlingen.
- Genom att lära av tidigare drag och optimera strategin.
- Processen upprepas tills en optimal strategi hittas.
Lär dig mer genom att läsa vår handledning, en introduktion till förstärkningsinlärning. Du får utforska mer om hur förstärkningsinlärning fungerar med kodexempel.
I den här guiden lär vi oss om Q‑learning och förstår varför vi behöver Deep Q‑learning. Dessutom lär vi oss att skapa och träna Q‑learning‑algoritmer från grunden med Numpy och Gymnasium.
Obs: Om du är ny inom maskininlärning rekommenderar vi vår Machine Learning Scientist with Python-karriärväg för att bättre förstå förstärkningsinlärning och Q‑learning.
Vad är Q‑learning?
Q‑learning är en modellfri, värdebaserad, off‑policy‑algoritm som hittar den bästa följden av handlingar baserat på agentens aktuella tillstånd. ”Q” står för kvalitet. Kvalitet representerar hur värdefull handlingen är för att maximera framtida belöningar.
Modellbaserade algoritmer använder övergångs- och belöningsfunktioner för att uppskatta den optimala policyn och skapa modellen. I kontrast lär sig modellfria algoritmer konsekvenserna av sina handlingar genom erfarenhet utan övergångs- och belöningsfunktion.
Den värdebaserade metoden tränar värdefunktionen för att lära sig vilka tillstånd som är mer värdefulla och agera därefter. Policbaserade metoder tränar däremot policyn direkt för att lära sig vilken handling som ska tas i ett givet tillstånd.
I off‑policy utvärderar och uppdaterar algoritmen en policy som skiljer sig från policyn som används för att agera. Motsatsen är on‑policy, där algoritmen utvärderar och förbättrar samma policy som används för att agera.
Viktiga termer i Q‑learning
Innan vi går in på hur Q‑learning fungerar behöver vi några användbara termer för att förstå grunderna i Q‑learning.
- Tillstånd (s): agentens aktuella position i miljön.
- Handling (a): ett steg som agenten tar i ett visst tillstånd.
- Belöningar: för varje handling får agenten en belöning eller ett straff.
- Avsnitt: slutet på en omgång, där agenten inte kan ta nya handlingar. Det sker när agenten har nått målet eller misslyckats.
- Q(St+1, a): förväntat optimalt Q‑värde av att göra handlingen i ett visst tillstånd.
- Q(St, At): den aktuella uppskattningen av Q(St+1, a).
- Q‑tabell: agenten underhåller Q‑tabellen med uppsättningar av tillstånd och handlingar.
- Temporala differenser (TD): används för att uppskatta det förväntade värdet av Q(St+1, a) genom att använda nuvarande tillstånd och handling samt föregående tillstånd och handling.
Hur fungerar Q‑learning?
Vi ska lära oss i detalj hur Q‑learning fungerar med hjälp av exemplet frusen sjö. I den här miljön måste agenten korsa den frusna sjön från start till mål utan att falla i hålen. Den bästa strategin är att nå målet via kortaste vägen.

Gif av författaren
Q‑tabell
Agenten använder en Q‑tabell för att ta den bästa möjliga handlingen baserat på den förväntade belöningen för varje tillstånd i miljön. Enkelt uttryckt är en Q‑tabell en datastruktur med uppsättningar av handlingar och tillstånd, och vi använder Q‑learning‑algoritmen för att uppdatera värdena i tabellen.
Q‑funktion
Q‑funktionen använder Bellmans ekvation och tar tillstånd (s) och handling (a) som indata. Ekvationen förenklar beräkningen av tillståndsvärden och tillstånd‑handlingsvärden. 
Bild från freecodecamp.org
Q‑learning‑algoritm

Bild av författaren
Initiera Q‑tabell
Vi börjar med att initiera Q‑tabellen. Vi bygger tabellen med kolumner baserat på antalet handlingar och rader baserat på antalet tillstånd.
I vårt exempel kan figuren röra sig upp, ner, vänster och höger. Vi har fyra möjliga handlingar och fyra tillstånd (start, vila, fel väg och slut). Du kan också betrakta fel väg som att falla i ett hål. Vi initierar Q‑tabellen med värden satta till 0.

Bild av författaren
Välj en handling
Det andra steget är ganska enkelt. I början väljer agenten en slumpmässig handling (ner eller höger), och vid andra körningen använder den en uppdaterad Q‑tabell för att välja handling.
Utför en handling
Att välja en handling och utföra den upprepas flera gånger tills träningsloopen stoppas. Den första handlingen och det första tillståndet väljs med Q‑tabellen. I vårt fall är alla värden i Q‑tabellen noll.
Sedan rör sig agenten nedåt och uppdaterar Q‑tabellen med Bellmans ekvation. Vid varje drag uppdaterar vi värden i Q‑tabellen och använder dem också för att avgöra bästa åtgärd.
Inledningsvis är agenten i utforskningsläge och väljer slumpmässiga handlingar för att utforska miljön. Epsilon‑greedy‑strategin är en enkel metod för att balansera utforskning och utnyttjande. Epsilon står för sannolikheten att välja att utforska och utnyttjar när chansen att utforska är mindre.
I början är epsilon‑graden hög, vilket betyder att agenten är i utforskningsläge. Medan miljön utforskas minskar epsilon, och agenten börjar utnyttja miljön. Under utforskningen blir agenten mer självsäker i att uppskatta Q‑värden för varje iteration

Bild av författaren
I exemplet med frusen sjö känner agenten inte till miljön, så den tar en slumpmässig handling (rör sig nedåt) till att börja med. Som vi kan se i bilden ovan uppdateras Q‑tabellen med Bellmans ekvation.
Mäta belöningar
Efter att ha utfört handlingen mäter vi utfallet och belöningen.
- Belöningen för att nå målet är +1
- Belöningen för att ta fel väg (falla i hålet) är 0
- Belöningen för vila eller att röra sig på den frusna sjön är också 0.
Uppdatera Q‑tabell
Vi uppdaterar funktionen Q(St, At) med hjälp av ekvationen. Den använder föregående avsnitts uppskattade Q‑värden, inlärningshastighet och temporal differens‑fel. Temporal differens‑fel beräknas med omedelbar belöning, den diskonterade maximala förväntade framtida belöningen och den tidigare uppskattningen av Q‑värdet.
Processen upprepas flera gånger tills Q‑tabellen är uppdaterad och Q‑värdesfunktionen är maximerad.

Bild av författaren | Ekvationsbilder från Thomas Simonini
I början utforskar agenten miljön för att uppdatera Q‑tabellen. Och när Q‑tabellen är redo börjar agenten utnyttja och fatta bättre beslut. 
Bild av författaren
När det gäller frusen sjö lär sig agenten att ta kortaste vägen till målet och undvika att hoppa ner i hålen.
Q‑learning Python‑handledning
I den här delen bygger vi vår Q‑learning‑modell från grunden med Gymnasium‑miljön, Pygame och Numpy. Python‑guiden är en modifierad version av Notebooken av Thomas Simonini. Den innehåller initiering av miljö och Q‑tabell, definition av greedy‑policy, val av hyperparametrar, skapande och körning av träningsloop och utvärdering samt visualisering av resultaten.
Om du har problem med att skapa och köra din träningsloop kan du kolla källkoden med utdata.
Kom igång
Ställ in en virtuell skärm
Vi installerar först alla beroenden för att generera en reprisvideo (gif). Vi behöver en virtuell skärm (pyvirtualdisplay) för att rendera miljön och spela in bildrutorna.
Obs: genom att använda %%capture undertrycker vi utdata från Jupyter‑cellen.
%%capture
!pip install pyglet==1.5.1
!apt install python-opengl
!apt install ffmpeg
!apt install xvfb
!pip3 install pyvirtualdisplay
# Virtual display
from pyvirtualdisplay import Display
virtual_display = Display(visible=0, size=(1400, 900))
virtual_display.start()
Installera beroenden
Nu installerar vi beroenden som hjälper oss att skapa, köra och utvärdera träningsloopen.
- gymnasium: Används för att initiera miljön FrozenLake‑v1.
- pygame: Används för FrozenLake‑v1‑gränssnittet.
- numPy: Används för att skapa och hantera Q‑tabellen.
%%capture
!pip install gymnasium
!pip install pygame
!pip install numpy
!pip install imageio imageio_ffmpeg
Importera paketen
Nu importerar vi de bibliotek som behövs.
- Imageio används för att skapa animationen.
- tqdm används för förloppsindikatorer.
import numpy as np
import gymnasium as gym
import random
import imageio
from tqdm.notebook import trange
Gymnasium‑miljön Frusen sjö
Vi ska skapa en icke‑hal 4x4‑miljö med Frozen Lake‑biblioteket i Gymnasium.
- Det finns två rutnätsversioner, ”4x4” och ”8x8”.
- Om
is_slippery=Truekan agenten röra sig i en annan riktning än avsedd på grund av den hala isen.
Efter att ha initierat miljön gör vi en miljöanalys.
env = gym.make("FrozenLake-v1",map_name="4x4",is_slippery=False)
print("Observation Space", env.observation_space)
print("Sample observation", env.observation_space.sample()) # display a random observation
Det finns 16 unika tillstånd i miljön som visas på slumpmässiga positioner.
Observation Space Discrete(16)
Sample observation 15
Låt oss ta reda på antalet handlingar och visa en slumpmässig handling.
Handlingsutrymmet:
- 0: gå vänster
- 1: gå ner
- 2: gå höger
- 3: gå upp
Belöningsfunktion:
- Nå målet: +1
- Falla i hålet: 0
- Stanna på den frusna sjön: 0
print("Action Space Shape", env.action_space.n)
print("Action Space Sample", env.action_space.sample())
Action Space Shape 4
Action Space Sample 1
Skapa och initiera Q‑tabellen
Q‑tabellen har kolumner som handlingar och rader som tillstånd. Vi kan använda Gymnasium för att hitta handlingsutrymme och tillståndsutrymme. Vi använder sedan denna information för att skapa Q‑tabellen.
state_space = env.observation_space.n
print("There are ", state_space, " possible states")
action_space = env.action_space.n
print("There are ", action_space, " possible actions")
There are 16 possible states
There are 4 possible actions
För att initiera Q‑tabellen skapar vi en Numpy‑array av state_space och action_space. Vi skapar en 16 x 4‑array.
def initialize_q_table(state_space, action_space):
Qtable = np.zeros((state_space, action_space))
return Qtable
Qtable_frozenlake = initialize_q_table(state_space, action_space)
Epsilon‑greedy‑policy
I föregående avsnitt lärde vi oss epsilon‑greedy‑strategin som hanterar avvägningen mellan utforskning och utnyttjande. Med sannolikheten 1 − ɛ utnyttjar vi, och med sannolikheten ɛ utforskar vi.
I epsilon_greedy_policy kommer vi att:
- Generera ett slumptal mellan 0 och 1.
- Om slumptalet är större än epsilon utnyttjar vi. Det betyder att agenten tar den handling som har högst värde givet ett tillstånd.
- Annars utforskar vi (tar en slumpmässig handling).
def epsilon_greedy_policy(Qtable, state, epsilon):
random_int = random.uniform(0,1)
if random_int > epsilon:
action = np.argmax(Qtable[state])
else:
action = env.action_space.sample()
return action
Definiera greedy‑policy
Som vi nu vet är Q‑learning en off‑policy‑algoritm, vilket betyder att policyn för att agera och policyn för att uppdatera funktionen är olika.
I det här exemplet är epsilon‑greedy policyn agerande policy, och greedy‑policyn är uppdateringspolicy.
Greedy‑policyn blir också slutlig policy när agenten är tränad. Den används för att välja högsta tillstånds‑ och handlingsvärde från Q‑tabellen.
def greedy_policy(Qtable, state):
action = np.argmax(Qtable[state])
return action
Modellens hyperparametrar
Dessa hyperparametrar används i träningsloopen, och finjustering av dem ger bättre resultat.
Agenten behöver utforska tillräckligt mycket av tillståndsutrymmet för att lära sig bra värdeapproximation; därför behöver vi en gradvis avtagande epsilon. Om avtagandet är för snabbt kan agenten fastna eftersom den inte har utforskat tillräckligt.
- Det finns 10 000 tränings- och 100 utvärderingsavsnitt.
- Inlärningshastigheten är 0,7.
- Vi använder "FrozenLake‑v1" som miljö med 99 maximala steg per avsnitt.
- Gamma (diskonteringsfaktor) är 0,95.
- eval_seed: utvärderings‑seed för miljön.
- Utforskningsepsilon‑sannolikheten i början är 1,0 och miniminivån blir 0,05.
- Den exponentiella avtagandehastigheten för epsilon är 0,0005.
# Training parameters
n_training_episodes = 10000
learning_rate = 0.7
# Evaluation parameters
n_eval_episodes = 100
# Environment parameters
env_id = "FrozenLake-v1"
max_steps = 99
gamma = 0.95
eval_seed = []
# Exploration parameters
max_epsilon = 1.0
min_epsilon = 0.05
decay_rate = 0.0005
Träning av modellen
I träningsloopen kommer vi att:
- Skapa en loop för träningsavsnitt.
- Först minska epsilon. Vi behöver allt mindre utforskning och mer utnyttjande för varje avsnitt.
- Återställa miljön.
- Skapa en nästlad loop för maximalt antal steg.
- Välja handling med epsilon‑greedy‑policyn.
- Utföra handlingen (At) och observera den förväntade belöningen (Rt+1) och tillståndet (St+1).
- Ta handlingen (a) och observera det nya tillståndet (s') och belöningen (r).
- Uppdatera Q‑funktionen med formeln.
- Om
done= True, avsluta avsnittet och bryt loopen. - Till sist, ändra aktuellt tillstånd till det nya.
- När alla träningsavsnitt är klara returnerar funktionen den uppdaterade Q‑tabellen.
def train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable):
for episode in trange(n_training_episodes):
epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)
# Reset the environment
state = env.reset()
step = 0
done = False
# repeat
for step in range(max_steps):
action = epsilon_greedy_policy(Qtable, state, epsilon)
new_state, reward, done, info = env.step(action)
Qtable[state][action] = Qtable[state][action] + learning_rate * (reward + gamma * np.max(Qtable[new_state]) - Qtable[state][action])
# If done, finish the episode
if done:
break
# Our state is the new state
state = new_state
return Qtable
Det tog oss 3 sekunder att slutföra 10 000 träningsavsnitt.
Qtable_frozenlake = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_frozenlake)
Som vi kan se har den tränade Q‑tabellen värden, och agenten kommer nu att använda dessa värden för att navigera i miljön och nå målet.
Qtable_frozenlakearray([[0.73509189, 0.77378094, 0.77378094, 0.73509189], [0.73509189, 0. , 0.81450625, 0.77378094], [0.77378094, 0.857375 , 0.77378094, 0.81450625], [0.81450625, 0. , 0.77378094, 0.77378094], [0.77378094, 0.81450625, 0. , 0.73509189], [0. , 0. , 0. , 0. ], [0. , 0.9025 , 0. , 0.81450625], [0. , 0. , 0. , 0. ], [0.81450625, 0. , 0.857375 , 0.77378094], [0.81450625, 0.9025 , 0.9025 , 0. ], [0.857375 , 0.95 , 0. , 0.857375 ], [0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0. ], [0. , 0.9025 , 0.95 , 0.857375 ], [0.9025 , 0.95 , 1. , 0.9025 ], [0. , 0. , 0. , 0. ]])Utvärdering
evaluate_agent körs i
n_eval_episodesavsnitt och returnerar medelvärde och standardavvikelse för belöningen.
- I loopen kontrollerar vi först om det finns ett utvärderings‑seed. Om inte återställer vi miljön utan seed.
- Den nästlade loopen kör till max_steps.
- Agenten tar den handling som har högst förväntad framtida belöning i ett givet tillstånd enligt Q‑tabellen.
- Beräkna belöningen.
- Ändra tillståndet.
- Om klart (agenten faller i hålet eller målet har uppnåtts), bryt loopen.
- Lägg till resultaten.
- Till slut använder vi dessa resultat för att beräkna medelvärde och standardavvikelse.
def evaluate_agent(env, max_steps, n_eval_episodes, Q, seed): episode_rewards = [] for episode in range(n_eval_episodes): if seed: state = env.reset(seed=seed[episode]) else: state = env.reset() step = 0 done = False total_rewards_ep = 0 for step in range(max_steps): # Take the action (index) that have the maximum reward action = np.argmax(Q[state][:]) new_state, reward, done, info = env.step(action) total_rewards_ep += reward if done: break state = new_state episode_rewards.append(total_rewards_ep) mean_reward = np.mean(episode_rewards) std_reward = np.std(episode_rewards) return mean_reward, std_rewardSom du ser fick vi full poäng med noll standardavvikelse. Det betyder att vår agent nådde målet i alla 100 avsnitt.
# Evaluate our Agent mean_reward, std_reward = evaluate_agent(env, max_steps, n_eval_episodes, Qtable_frozenlake, eval_seed) print(f"Mean_reward={mean_reward:.2f} +/- {std_reward:.2f}")Mean_reward=1.00 +/- 0.00Visualisera resultatet
Hittills har vi bara jobbat med siffror, och för demon behöver vi skapa en animerad gif av agenten från start tills den når målet.
- Vi skapar först tillståndet genom att återställa miljön med ett slumpmässigt heltal 0–500.
- Rendera miljön med rdb_array för att skapa en bildarray.
- Lägg sedan till
imgiimages-arrayen.- I loopen tar vi steg med Q‑tabellen och renderar bilden för varje steg.
- Till sist använder vi denna array och imageio för att skapa en gif med en bildruta per sekund.
def record_video(env, Qtable, out_directory, fps=1): images = [] done = False state = env.reset(seed=random.randint(0,500)) img = env.render(mode='rgb_array') images.append(img) while not done: # Take the action (index) that have the maximum expected future reward given that state action = np.argmax(Qtable[state][:]) state, reward, done, info = env.step(action) # We directly put next_state = state for recording logic img = env.render(mode='rgb_array') images.append(img) imageio.mimsave(out_directory, [np.array(img) for i, img in enumerate(images)], fps=fps)Om du är i en Jupyter‑notebook kan du visa gif:en med funktionen Image från
IPython.display.video_path="/content/replay.gif" video_fps=1 record_video(env, Qtable_frozenlake, video_path, video_fps) from IPython.display import Image Image('./replay.gif')Du kan nu dela dessa resultat med kollegor och kurskamrater eller posta dem i sociala medier.
Vanliga frågor om Q‑learning
Vad är nackdelen med Q‑learning?
Inlärningsprocessen i Q‑learning är kostsam för agenten, särskilt i början. Varför? För att konvergera till en optimal policy måste varje par av tillstånd och handling besökas ofta.
Varför kallas det Q‑learning?
I Q‑learning står ”Q” för kvalitet. Det representerar hur användbar en given handling är för att uppnå framtida belöningar, vilket används för att skapa en kartläggning mellan tillstånd och handling för att maximera förväntade belöningar.
Varför är Q‑learning off‑policy?
I Q‑learning är den uppdaterade policyn annorlunda än beteende‑ (handlings‑)policyn, och därför kallas den en off‑policy‑algoritm.
Konvergerar Q‑learning alltid?
Ja. Under träningen konvergerar algoritmen alltid till den optimala policyn.
Varför behöver vi deep Q‑learning?
Ja. Q‑learning är en enkel algoritm utformad för en mindre och diskret miljö. För en större miljö skulle vi behöva en enorm Q‑tabell av tillstånd och handlingar som kräver mycket minne och beräkningar för att tränas. Deep Q‑learning ersätter däremot Q‑tabellen med ett neuralt nätverk för att hantera stora miljöer som innefattar kontinuerliga handlingar och tillstånd.
