Przejdź do głównej treści

Wprowadzenie do Q-learningu: samouczek dla początkujących

Poznaj najpopularniejszy bezmodelowy algorytm uczenia ze wzmocnieniem w samouczku w Pythonie.
Zaktualizowano 22 lip 2026  · 11 min Czytać

Eksploruj z AI

Otwórz w ChatGPTOtwórz w ClaudeOtwórz w Perplexity

Nagłówek Q-learning

Uczenie ze wzmocnieniem (RL) to część ekosystemu uczenia maszynowego, w której agent uczy się poprzez interakcję ze środowiskiem, aby wypracować optymalną strategię osiągania celów. Różni się to od nadzorowanych algorytmów uczenia maszynowego, gdzie musimy wczytać i przetwarzać dane. Uczenie ze wzmocnieniem nie wymaga danych wejściowych — zamiast tego uczy się ze środowiska i systemu nagród, by podejmować lepsze decyzje.

Na przykład w grze Mario, jeśli postać wykona losową akcję (np. ruch w lewo), może na jej podstawie otrzymać nagrodę. Po wykonaniu akcji agent (Mario) znajduje się w nowym stanie i proces powtarza się aż do momentu, gdy postać dotrze do końca planszy lub zginie. 

Ten epizod będzie powtarzany wielokrotnie, aż Mario nauczy się poruszać po środowisku, maksymalizując nagrody. 

Uczenie ze wzmocnieniem

Grafika: autor

Uczenie ze wzmocnieniem można rozbić na pięć prostych kroków:

  1. Agent znajduje się w stanie zerowym w danym środowisku.
  2. Podejmie akcję na podstawie określonej strategii.
  3. Otrzyma nagrodę lub karę w zależności od tej akcji.
  4. Uczy się na podstawie wcześniejszych ruchów i optymalizuje strategię. 
  5. Proces powtarza się, aż znajdziemy optymalną strategię. 

Dowiedz się więcej z naszego samouczka Wprowadzenie do uczenia ze wzmocnieniem. Poznasz dokładniej, jak działa RL, wraz z przykładami kodu. 

W tym samouczku poznamy Q-learning i zrozumiemy, dlaczego potrzebujemy Deep Q-learningu. Co więcej, nauczysz się tworzyć i trenować algorytmy Q-learningu od podstaw, używając Numpy i Gymnasium.

Uwaga: jeśli dopiero zaczynasz z uczeniem maszynowym, polecamy ścieżkę kariery Machine Learning Scientist with Python, aby lepiej zrozumieć uczenie ze wzmocnieniem i Q-learning. 

Czym jest Q-learning?

Q-learning to bezmodelowy, oparty na wartościach, off-policy algorytm, który znajduje najlepszą sekwencję akcji na podstawie bieżącego stanu agenta. „Q” oznacza jakość. Jakość reprezentuje, jak cenna jest dana akcja w maksymalizacji przyszłych nagród.  

Algorytmy model-based używają funkcji przejścia i nagrody do oszacowania optymalnej polityki i zbudowania modelu. Z kolei algorytmy model-free uczą się konsekwencji swoich działań z doświadczenia, bez funkcji przejścia i nagrody. 

Metoda value-based trenuje funkcję wartości, aby nauczyć się, który stan jest bardziej wartościowy, i podjąć odpowiednią akcję. Natomiast metody policy-based trenują bezpośrednio politykę, aby nauczyć się, jaką akcję podjąć w danym stanie.

W podejściu off-policy algorytm ocenia i aktualizuje politykę inną niż ta, której używa do podejmowania akcji. Dla kontrastu, algorytm on-policy ocenia i ulepsza tę samą politykę, której używa do działania.  

Kluczowe pojęcia w Q-learningu

Zanim przejdziemy do działania Q-learningu, musimy poznać kilka przydatnych pojęć, by zrozumieć jego podstawy. 

  • Stany (s): bieżąca pozycja agenta w środowisku. 
  • Akcja (a): krok wykonany przez agenta w określonym stanie. 
  • Nagrody: za każdą akcję agent otrzymuje nagrodę lub karę. 
  • Epizody: koniec etapu, gdy agent nie może podjąć nowej akcji. Dzieje się tak, gdy agent osiągnął cel lub poniósł porażkę. 
  • Q(St+1, a): oczekiwana optymalna wartość Q wykonania akcji w danym stanie. 
  • Q(St, At): bieżące oszacowanie Q(St+1, a).
  • Tablica Q: agent utrzymuje tablicę Q z zestawami stanów i akcji.
  • Różnice czasowe (TD): służą do oszacowania oczekiwanej wartości Q(St+1, a) przy użyciu bieżącego i poprzedniego stanu oraz akcji. 

Jak działa Q-learning?

Poznamy szczegóły działania Q-learningu na przykładzie zamarzniętego jeziora. W tym środowisku agent musi przejść przez zamarznięte jezioro od startu do celu, nie wpadając w dziury. Najlepszą strategią jest dotrzeć do celu najkrótszą ścieżką. 

Wizualizacja Q-learningu

Gif: autor

Tablica Q

Agent użyje tablicy Q, aby podjąć jak najlepszą akcję na podstawie oczekiwanej nagrody dla każdego stanu w środowisku. Mówiąc prosto, tablica Q to struktura danych z zestawami akcji i stanów, a do aktualizacji wartości w tej tablicy używamy algorytmu Q-learning. 

Funkcja Q

Funkcja Q wykorzystuje równanie Bellmana i przyjmuje jako wejście stan (s) i akcję (a). Równanie upraszcza obliczanie wartości stanów i wartości stan-akcja. Równanie Bellmana

Grafika z freecodecamp.org

Algorytm Q-learning

Proces Q-learningu

Grafika: autor

Inicjalizacja tablicy Q

Najpierw zainicjalizujemy tablicę Q. Zbudujemy ją z kolumnami odpowiadającymi liczbie akcji i wierszami odpowiadającymi liczbie stanów.

W naszym przykładzie postać może poruszać się w górę, dół, w lewo i w prawo. Mamy cztery możliwe akcje i cztery stany (start, bezczynność, zła ścieżka i koniec). Złą ścieżkę możesz też rozumieć jako wpadnięcie do dziury. Zainicjalizujemy tablicę Q wartościami równymi 0. 

Tablica Q 1

Grafika: autor

Wybór akcji

Drugi krok jest dość prosty. Na początku agent wybierze losową akcję (dół lub prawo), a przy drugim przebiegu użyje zaktualizowanej tablicy Q do wyboru akcji. 

Wykonanie akcji

Wybór akcji i jej wykonanie będą się powtarzać wielokrotnie, aż pętla treningowa się zakończy. Pierwsza akcja i stan są wybierane z użyciem tablicy Q. W naszym przypadku wszystkie wartości w tablicy Q są zerowe. 

Następnie agent wykona ruch w dół i zaktualizuje tablicę Q z użyciem równania Bellmana. Z każdym ruchem będziemy aktualizować wartości w tablicy Q i wykorzystywać je do wyznaczenia najlepszego kursu działania. 

Początkowo agent jest w trybie eksploracji i wybiera losowe akcje, by poznać środowisko. Strategia epsilon-greedy to prosty sposób równoważenia eksploracji i eksploatacji. Epsilon oznacza prawdopodobieństwo wyboru eksploracji; gdy jest mniejsze, częściej eksploatujemy. 

Na starcie wskaźnik epsilon jest wysoki, czyli agent eksploruje. W trakcie poznawania środowiska epsilon maleje i agent zaczyna je eksploatować. Podczas eksploracji z każdą iteracją agent coraz pewniej szacuje wartości Q.

Tablica Q 2

Grafika: autor

W przykładzie z zamarzniętym jeziorem agent nie zna środowiska, więc na start wykonuje losową akcję (ruch w dół). Jak widać na obrazku powyżej, tablica Q jest aktualizowana przy użyciu równania Bellmana.

Pomiar nagród

Po wykonaniu akcji zmierzymy wynik i nagrodę. 

  • Nagroda za dotarcie do celu: +1
  • Nagroda za złą ścieżkę (wpadnięcie do dziury): 0
  • Nagroda za bezczynność lub poruszanie się po lodzie: 0. 

Aktualizacja tablicy Q

Zaktualizujemy funkcję Q(St, At) przy użyciu równania. Wykorzystuje ono oszacowane wartości Q z poprzedniego epizodu, współczynnik uczenia oraz błąd różnic czasowych. Błąd TD oblicza się z użyciem natychmiastowej nagrody, zdyskontowanej maksymalnej oczekiwanej przyszłej nagrody oraz wcześniejszego oszacowania Q. 

Proces powtarza się wielokrotnie, aż tablica Q zostanie zaktualizowana, a funkcja Q zmaksymalizowana. 

Równanie Q-learningu

Grafika: autor | Wizualizacja równań: Thomas Simonini

Na początku agent eksploruje środowisko, aby zaktualizować tablicę Q. Gdy tablica jest gotowa, agent zaczyna eksploatować i podejmować lepsze decyzje. Tablica Q 3

Grafika: autor

W przypadku zamarzniętego jeziora agent nauczy się wybierać najkrótszą ścieżkę do celu i unikać dziur. 

Samouczek Q-learning w Pythonie 

W tej sekcji zbudujemy nasz model Q-learning od podstaw, używając środowiska Gymnasium, Pygame i Numpy. Ten samouczek w Pythonie to zmodyfikowana wersja notatnika Thomasa Simoniniego. Obejmuje inicjalizację środowiska i tablicy Q, zdefiniowanie polityki greedy, ustawienie hiperparametrów, stworzenie i uruchomienie pętli treningowej oraz ewaluacji, a także wizualizację wyników.   

Jeśli masz problemy z utworzeniem i uruchomieniem pętli treningowej, możesz zajrzeć do kodu źródłowego z wynikami.   

Przygotowanie środowiska

Skonfiguruj wirtualny ekran

Najpierw zainstalujemy wszystkie zależności potrzebne do wygenerowania nagrania (GIF). Będziemy potrzebować wirtualnego ekranu (pyvirtualdisplay), aby renderować środowisko i nagrywać klatki. 

Uwaga: używając %%capture wyciszamy wynik komórki Jupyter. 

%%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()

Zainstaluj zależności

Teraz zainstalujemy zależności, które pomogą nam utworzyć, uruchomić i ocenić pętlę treningową. 

  • gymnasium: używany do inicjalizacji środowiska FrozenLake-v1.
  • pygame: używany do interfejsu FrozenLake-v1.
  • numPy: używany do tworzenia i obsługi tablicy Q.
%%capture
!pip install gymnasium
!pip install pygame
!pip install numpy

!pip install imageio imageio_ffmpeg

Import pakietów

Zaimportujemy teraz wymagane biblioteki. 

  • Imageio służy do tworzenia animacji. 
  • tqdm służy do pasków postępu. 
import numpy as np
import gymnasium as gym
import random
import imageio
from tqdm.notebook import trange

Środowisko Frozen Lake w Gymnasium 

Stworzymy nieśliski świat 4x4, korzystając z biblioteki Frozen Lake w Gymnasium

  • Dostępne są dwie siatki: „4x4” i „8x8”.
  • Jeśli is_slippery=True, agent może nie poruszać się w zamierzonym kierunku ze względu na śliską powierzchnię zamarzniętego jeziora. 

Po zainicjalizowaniu środowiska przeprowadzimy jego analizę. 

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

Istnieje 16 unikalnych pól w środowisku wyświetlanych w losowych pozycjach. 

Observation Space Discrete(16)
Sample observation 15

Sprawdźmy liczbę akcji i wyświetlmy losową akcję. 

Przestrzeń akcji:

  • 0: ruch w lewo
  • 1: ruch w dół
  • 2: ruch w prawo
  • 3: ruch w górę

Funkcja nagrody:

  • Dotarcie do celu: +1
  • Wpadnięcie do dziury: 0
  • Pozostanie na lodzie: 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

Utwórz i zainicjalizuj tablicę Q

Tablica Q ma kolumny będące akcjami i wiersze będące stanami. Możemy użyć Gymnasium, aby znaleźć przestrzeń akcji i stanów. Następnie wykorzystamy te informacje do stworzenia tablicy Q. 

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

Aby zainicjalizować tablicę Q, utworzymy tablicę Numpy o wymiarach przestrzeni stanów i akcji. Utworzymy macierz 16 × 4. 

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)

Polityka epsilon-greedy

W poprzedniej sekcji poznaliśmy strategię epsilon-greedy, która równoważy eksplorację i eksploatację. Z prawdopodobieństwem 1 − ɛ eksploatujemy, a z prawdopodobieństwem ɛ eksplorujemy. 

W epsilon_greedy_policy:

  1. Generujemy liczbę losową z przedziału 0–1.
  2. Jeśli liczba jest większa niż epsilon, eksploatujemy. Oznacza to, że agent wybierze akcję o najwyższej wartości dla danego stanu.
  3. W przeciwnym razie eksplorujemy (wybieramy losową akcję). 
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

Zdefiniuj politykę greedy

Wiesz już, że Q-learning to algorytm off-policy, co oznacza, że polityka podejmowania akcji i aktualizacji funkcji są różne. 

W tym przykładzie polityka epsilon-greedy jest polityką działania, a polityka greedy — polityką aktualizacji. 

Polityka greedy będzie też polityką końcową po wytrenowaniu agenta. Służy do wyboru najwyższej wartości stan–akcja z tablicy Q.

def greedy_policy(Qtable, state):
  action = np.argmax(Qtable[state])
  return action

Hiperparametry modelu

Te hiperparametry są używane w pętli treningowej, a ich dostrajanie może dać lepsze wyniki. 

Agent musi wystarczająco eksplorować przestrzeń stanów, by nauczyć się dobrego przybliżenia wartości; potrzebujemy więc stopniowego spadku epsilon. Jeśli tempo spadku jest zbyt duże, agent może utknąć, bo nie poznał wystarczająco przestrzeni stanów.

  • Jest 10 000 epizodów treningowych i 100 epizodów ewaluacyjnych.
  • Współczynnik uczenia to 0,7.
  • Używamy środowiska "FrozenLake-v1" z 99 maksymalnymi krokami na epizod.
  • Gamma (stopa dyskontowa) to 0,95.
  • eval_seed: ziarno ewaluacji dla środowiska.
  • Początkowe prawdopodobieństwo eksploracji epsilon wynosi 1,0, a minimalne 0,05.
  • Wykładnicze tempo spadku dla epsilon to 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           

Trenowanie modelu 

W pętli treningowej:

  1. Utwórz pętlę po epizodach treningowych.
  2. Najpierw zmniejszamy epsilon. Z każdym epizodem potrzebujemy coraz mniej eksploracji, a więcej eksploatacji. 
  3. Resetujemy środowisko.
  4. Tworzymy zagnieżdżoną pętlę po maksymalnych krokach.
  5. Wybieramy akcję przy użyciu polityki epsilon-greedy. 
  6. Wykonujemy akcję (At) i obserwujemy oczekiwaną nagrodę (Rt+1) oraz stan (St+1).
  7. Wykonujemy akcję (a) i obserwujemy wynikowy stan (s') oraz nagrodę (r).
  8. Aktualizujemy funkcję Q przy użyciu wzoru. 
  9. Jeśli done= True, kończymy epizod i przerywamy pętlę.
  10. Na koniec zmieniamy bieżący stan na nowy. 
  11. Po zakończeniu wszystkich epizodów treningowych funkcja zwróci zaktualizowaną tablicę Q. 
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

Zajęło nam to 3 sekundy, aby ukończyć 10 000 epizodów treningowych. 

Qtable_frozenlake = train(n_training_episodes, min_epsilon, max_epsilon, decay_rate, env, max_steps, Qtable_frozenlake)

Wyniki epizodów treningowych

Jak widać, wytrenowana tablica Q ma wartości i agent użyje ich teraz do poruszania się po środowisku i osiągnięcia celu.  

Qtable_frozenlake
array([[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.        ]])

Ewaluacja

Funkcja evaluate_agent uruchamia się przez n_eval_episodes epizodów i zwraca średnią oraz odchylenie standardowe nagrody. 

  1. W pętli najpierw sprawdzimy, czy ustawiono ziarno ewaluacji. Jeśli nie, resetujemy środowisko bez ziarna. 
  2. Pętla zagnieżdżona będzie działać do max_steps.
  3. Agent podejmie akcję o maksymalnej oczekiwanej przyszłej nagrodzie w danym stanie, korzystając z tablicy Q. 
  4. Obliczamy nagrodę.
  5. Zmieniamy stan.
  6. Jeśli done (agent wpadł do dziury lub osiągnął cel), przerywamy pętlę.
  7. Dodajemy wyniki do listy.
  8. Na końcu z tych wyników obliczamy średnią i odchylenie standardowe. 
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_reward

Jak widać, otrzymaliśmy idealny wynik z zerowym odchyleniem standardowym. Oznacza to, że nasz agent osiągnął cel we wszystkich 100 epizodach. 

# 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.00

Wizualizacja wyniku

Do tej pory pracowaliśmy na liczbach, a do demonstracji potrzebujemy stworzyć animowany GIF agenta od startu do osiągnięcia celu. 

  1. Najpierw utworzymy stan, resetując środowisko z losową liczbą całkowitą 0–500. 
  2. Wyrenderujemy środowisko, używając trybu rdb_array, aby utworzyć tablicę obrazu. 
  3. Następnie dołączymy img do tablicy images
  4. W pętli będziemy wykonywać kroki przy użyciu tablicy Q i renderować obraz dla każdego kroku. 
  5. Na koniec użyjemy tej tablicy oraz imageio, aby stworzyć GIF w tempie jednej klatki na 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)

Jeśli pracujesz w notatniku Jupyter, możesz wyświetlić GIF za pomocą funkcji Image z 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')

Możesz teraz podzielić się tymi wynikami ze współpracownikami i kolegami z klasy albo opublikować je w mediach społecznościowych.

Najczęstsze pytania o Q-learning

Jakie są wady Q-learningu?

Proces uczenia w Q-learningu jest kosztowny dla agenta, zwłaszcza na początku. Dlaczego? Aby zbiec do optymalnej polityki, każda para stan–akcja musi być często odwiedzana.

Dlaczego Q-learning nazywa się Q-learningiem?

W Q-learningu „Q” oznacza jakość. Reprezentuje, jak użyteczna jest dana akcja w osiąganiu przyszłych nagród, co służy do stworzenia mapowania stan–akcja maksymalizującego oczekiwane nagrody.

Dlaczego Q-learning jest off-policy?

W Q-learningu aktualizowana polityka różni się od polityki zachowania (podejmowania akcji), dlatego mówi się, że to algorytm off-policy.

Czy Q-learning zawsze zbiega?

Tak. Podczas treningu algorytm zawsze zbiega do optymalnej polityki.

Dlaczego potrzebujemy deep Q-learningu?

Q-learning to prosty algorytm zaprojektowany dla mniejszych i dyskretnych środowisk. W przypadku dużego środowiska potrzebna byłaby ogromna tablica Q stanów i akcji, która wymagałaby dużo pamięci i mocy obliczeniowej do treningu. Z kolei Deep Q-learning zastępuje tablicę Q siecią neuronową, aby obsługiwać duże środowiska z ciągłymi akcjami i stanami.

Tematy

Kursy uczenia maszynowego

course

Projektowanie przepływów pracy uczenia maszynowego w Pythonie

4 godz.
12.6K
Naucz się tworzyć pipeline’y, które przetrwają próbę czasu.
Zobacz szczegóły
Rozpocznij Kurs
Zobacz więcej
Morty Proxy This is a proxified and sanitized view of the page, visit original site.