मुख्य सामग्री पर जाएँ

Python में SARSA रिइनफोर्समेंट लर्निंग एल्गोरिदम: एक संपूर्ण मार्गदर्शिका

SARSA सीखें—एक ऑन-पॉलिसी रिइनफोर्समेंट लर्निंग एल्गोरिदम। इसके अपडेट नियम, हाइपरपैरामीटर्स, और Q-learning से अंतर को व्यावहारिक Python उदाहरणों और उसके इम्प्लीमेंटेशन के साथ समझें।
· 15 मि॰ पढ़ें

AI के साथ खोजें

रिइनफोर्समेंट लर्निंग (RL) मशीन लर्निंग का एक शक्तिशाली प्रतिमान है। RL में, सॉफ्टवेयर, जिसे आमतौर पर एजेंट कहा जाता है, ट्रायल-एंड-एरर के जरिए वातावरणों के साथ इंटरैक्ट करना सीखता है ताकि जटिल समस्याओं का समाधान किया जा सके—वह भी मानव हस्तक्षेप के बिना। RL एल्गोरिदम में, SARSA अपनी प्रभावी ऑन-पॉलिसी प्रकृति के लिए अलग दिखता है।

SARSA का अर्थ है State-Action-Reward-State-Action, जो एक चक्र का प्रतिनिधित्व करता है जिसे एजेंट समस्याओं को हल करने के लिए फॉलो करता है। यह चक्र एजेंट को अपनी पिछली गलतियों से सीखने और कभी-कभी नई चीज़ें आज़माने की अनुमति देता है। यह व्यवहार एल्गोरिदम को कुछ खास प्रकार की समस्याओं में विशेष रूप से प्रभावी बनाता है और इसे Q-learning जैसे ऑफ-पॉलिसी एल्गोरिदम से अलग करता है।

इस ट्यूटोरियल में, आप सीखेंगे कि SARSA कैसे काम करता है और आप इसे Python में कैसे इम्प्लीमेंट कर सकते हैं। आपकी समझ को ठोस बनाने के लिए, हम पूरे समय एक क्लासिक Taxi Ride समस्या का उपयोग करेंगे। हम SARSA के फायदे, सीमाएँ, और वास्तविक दुनिया के उपयोगों पर भी चर्चा करेंगे।

SARSA क्या है? संक्षिप्त उत्तर

SARSA, जिसका पूरा रूप State-Action-Reward-State-Action है, सीखने की प्रक्रिया में घटनाओं के क्रम का वर्णन करता है। यह विभिन्न परिस्थितियों में बेहतर निर्णय लेने के लिए कंप्यूटर प्रोग्राम (एजेंट) के लिए एक प्रभावी सीखने की विधि है।

SARSA के पीछे मुख्य विचार ट्रायल-एंड-एरर है। एजेंट किसी स्थिति में एक क्रिया करता है, परिणाम को देखता है, और नतीजे (अच्छे या बुरे) के आधार पर अपनी रणनीति समायोजित करता है। यह प्रक्रिया कई बार दोहराई जाती है, जिससे समय के साथ एजेंट के निर्णयों में सुधार होता है।

RL एल्गोरिदम में SARSA को खास बनाता है कि SARSA एजेंट द्वारा वास्तव में किए गए चुनावों से सीखता है, यहाँ तक कि जब वह नई चीजें आज़मा रहा होता है तब भी। यह तरीका तब विशेष रूप से उपयोगी होता है जब सीखने की यात्रा अंतिम परिणाम जितनी ही महत्वपूर्ण हो।

यह ऐसे है जैसे कोई रोबोट वास्तव में साइकिल चलाकर—गिरते-पड़ते हुए—चलाना सीख रहा हो, बजाय इसके कि सुरक्षा पहियों की मदद से A से B तक की सबसे छोटी राह ढूंढ ले।

ट्यूटोरियल के लिए अपना एनवायरनमेंट सेट करना

इस ट्यूटोरियल में, हम व्यापक रूप से Numpy और Gymnasium रिइनफोर्समेंट लर्निंग लाइब्रेरी का उपयोग करेंगे। जहाँ Numpy हमें SARSA एल्गोरिदम लिखने में मदद करेगा, वहीं Gymnasium हमें अपना काम जाँचने के लिए बिल्ट-इन एनवायरनमेंट्स देता है।

आइए निम्नलिखित कमांड्स के साथ एक नए वर्चुअल एनवायरनमेंट में इन्हें इंस्टॉल करते हैं:

$ conda create -n sarsa python=3.9 -y
$ conda activate sarsa
$ pip install "gymnasium[atari]" numpy matplotlib
$ pip install autorom[accept-rom-license]  # Downloading Gym env data files
$ AutoROM --accept-license  # Accepting the license for data files
$ pip install ipykernel  # Install Jupyter kernel manager
$ ipython kernel install --user --name=sarsa  # Add the new Conda env to Jupyter

आगे बढ़ने से पहले, मैं आपको हमारा Introduction to Reinforcement Learning लेख पढ़ने के लिए विशेष रूप से प्रोत्साहित करता हूँ। यह RF के पीछे की बुनियादी अवधारणाओं जैसे एजेंट्स, एनवायरनमेंट्स, exploration बनाम exploitation दुविधा, और Q-learning को कवर करता है।

Taxi-V3 एनवायरनमेंट की व्याख्या

पूरे ट्यूटोरियल के दौरान, हम Taxi-v3 एनवायरनमेंट का उपयोग करेंगे, जो Gymnasium लाइब्रेरी द्वारा उपलब्ध कराया गया एक क्लासिक रिइनफोर्समेंट लर्निंग समस्या है। यह 5x5 ग्रिड दुनिया में टैक्सी ड्राइवर के नेविगेशन का सिमुलेशन करता है ताकि यात्रियों को पिक-अप और ड्रॉप-ऑफ किया जा सके।

एनवायरनमेंट को लोड करने के लिए, हम Gymnasium की .make() मेथड का उपयोग rgb_array रेंडर मोड के साथ करते हैं (ताकि आगे चलकर एनवायरनमेंट को विज़ुअलाइज़ किया जा सके):

import gymnasium as gym
env = gym.make('Taxi-v3', render_mode='rgb_array')

एनवायरनमेंट 5x5 ग्रिड है जिसमें चार निर्दिष्ट स्थान हैं: लाल (R), हरा (G), पीला (Y), और नीला (B)। टैक्सी एक यादृच्छिक वर्ग से शुरू होती है और उसे रंगीन स्थानों में से किसी एक से यात्री को उठाकर किसी अन्य स्थान पर छोड़ना होता है। 

टैक्सी उत्तर, दक्षिण, पूर्व या पश्चिम की ओर बढ़ सकती है और यात्री को पिक-अप या ड्रॉप-ऑफ करने का प्रयास भी कर सकती है।

यहाँ हम Matplotlib के साथ एनवायरनमेंट की प्रारंभिक स्थिति को कैसे विज़ुअलाइज़ कर सकते हैं:

import matplotlib.pyplot as plt
# Reset the environment to get an initial state
# Each time we reset the environment, we get a new random state
initial_state, _ = env.reset()
# Render the initial state
img = env.render()
# Create a figure and display the environment
fig, ax = plt.subplots(figsize=(8, 8))
ax.imshow(img)
# Remove axis ticks
ax.set_xticks([])
ax.set_yticks([]);

एक सैंपल प्रारंभिक स्थिति जिसमें टैक्सी राइड रिइनफोर्समेंट लर्निंग समस्या को sarsa से हल किया जाएगा

पहले, हम एनवायरनमेंट को रीसेट करते हैं ताकि एक प्रारंभिक स्थिति मिल सके। फिर, हम इस प्रारंभिक स्थिति को render फ़ंक्शन से प्रदर्शित करते हैं, जिससे Numpy इमेज ऐरे मिलता है। Matplotlib का imshow() फ़ंक्शन इस ऐरे को लेकर बिना एक्सिस टिक के साफ़ विज़ुअलाइज़ेशन देता है।

Taxi-v3 ग्रिड दुनिया के लेआउट को एक मिनट दें—टैक्सी की स्थिति, बाधाएँ, यात्री स्थान, और गंतव्य पर ध्यान दें।

एजेंट (टैक्सी) को यात्री को सफलतापूर्वक छोड़ने पर +20 अंक मिलते हैं। अवैध पिक-अप या ड्रॉप-ऑफ पर -10 का रिवॉर्ड मिलता है। इसी दौरान, हर टाइम स्टेप पर -1 का रिवॉर्ड मिलता है, जिससे टैक्सी को काम जल्दी पूरा करने के लिए प्रोत्साहित किया जाता है।

Taxi-v3 एनवायरनमेंट का एक एपिसोड सफल ड्रॉप-ऑफ होने पर या अधिकतम टाइम स्टेप्स पूरे हो जाने पर समाप्त होता है।

# The number of states and actions
n_states = env.observation_space.n
n_actions = env.action_space.n
print(n_states)
print(n_actions)
500
6

एनवायरनमेंट के स्टेट स्पेस में 500 स्टेट्स हैं। प्रत्येक स्टेट का निरूपण इस प्रकार है:

  • टैक्सी की पंक्ति (0–4)
  • टैक्सी का कॉलम (0–4)
  • यात्री का स्थान (R, G, Y, B के लिए 0–3, या 4 यदि टैक्सी के अंदर)
  • गंतव्य स्थान (R, G, Y, B के लिए 0–3)
  • कुल स्टेट्स = 5 (पंक्तियाँ) × 5 (कॉलम) × 5 (यात्री स्थान) × 4 (गंतव्य स्थान) = 500।

एक्शन कोड इस प्रकार हैं:

  • 0: दक्षिण की ओर बढ़ें
  • 1: उत्तर की ओर बढ़ें
  • 2: पूर्व की ओर बढ़ें
  • 3: पश्चिम की ओर बढ़ें
  • 4: यात्री को पिक-अप करें
  • 5: यात्री को ड्रॉप-ऑफ करें

लक्ष्य यह है कि एजेंट एक इष्टतम नीति सीखे ताकि वह यात्रियों को कुशलतापूर्वक पिक-अप और ड्रॉप-ऑफ करके अपना कुल रिवॉर्ड अधिकतम कर सके।

SARSA इंटरैक्शन लूप

पूरे एल्गोरिदम को लिखने से पहले, आइए अपने एनवायरनमेंट का उपयोग करते हुए State-Action-Reward-State-Action चक्र कैसे काम करता है, यह देखते हैं।

सबसे पहले, हम परिभाषित करते हैं कि हम इंटरैक्शन कितने एपिसोड तक जारी रखना चाहते हैं। एक एपिसोड टैक्सी कार्य का पूरा रन होता है—प्रारंभिक स्थिति से लेकर या तो यात्री को सफलतापूर्वक छोड़ने तक या अधिकतम टाइम स्टेप्स तक पहुँचना। प्रत्येक एपिसोड एजेंट को अपने अनुभवों से सीखने और समय के साथ अपनी रणनीति सुधारने देता है।

n_episodes = 5000

अब, हम इंटरैक्शन लूप लिखते हैं:

for episode in range(n_episodes):
   state, _ = env.reset()
   done = False
   total_reward = 0
   steps = 0
   while not done:
       # Choose a random action
       action = env.action_space.sample()
       # Take the action and observe the result
       next_state, reward, terminated, truncated, _ = env.step(action)
       done = terminated or truncated
       # Update total reward and step count
       total_reward += reward
       steps += 1
       # Move to the next state
       state = next_state
   if episode % 1000 == 0:
       print(f"Episode {episode}, Total Reward: {total_reward}, Steps: {steps}")
Episode 0, Total Reward: -812, Steps: 200
Episode 1000, Total Reward: -830, Steps: 200
Episode 2000, Total Reward: -902, Steps: 200
Episode 3000, Total Reward: -522, Steps: 129
Episode 4000, Total Reward: -767, Steps: 200

ऊपर दिया गया कोड किसी भी लर्निंग एल्गोरिदम को लागू किए बिना मूल SARSA इंटरैक्शन चक्र को दर्शाता है:

  1. प्रत्येक एपिसोड की शुरुआत में एनवायरनमेंट रीसेट करें — (S), env.reset()।
  2. एक यादृच्छिक एक्शन लें — (A), env.step(action)। यह संस्करण इंटरैक्शन लूप को दिखाने के लिए रैंडम एक्शन्स का उपयोग करता है।
  3. रिवॉर्ड (R) और अगला स्टेट (S_1) प्राप्त करें, next_state, reward, ... = env.take(action)।
  4. नए स्टेट में एक्शन (A_1) लें।

ऊपर दिए गए इंटरैक्शन लूप में, टैक्सी एनवायरनमेंट में इधर-उधर सभी दिशाओं में घूमती रहती है और रैंडम एक्शन्स करती रहती है जब तक कि टाइम स्टेप्स समाप्त नहीं हो जाते।

SARSA इंटरैक्शन लूप को एनिमेट करना

आगे बढ़ने से पहले, आइए अपने इंटरैक्शन लूप्स को एनिमेट करने के लिए एक फीचर लागू करें। इससे हम दृष्टिगत रूप से देख पाएँगे कि टैक्सी एनवायरनमेंट के साथ कैसे इंटरैक्ट कर रही है।

एनिमेशन बनाना एक सरल प्रक्रिया होगी:

  • हर टाइम स्टेप पर, हम env.render() फ़ंक्शन का उपयोग करके एनवायरनमेंट की स्थिति को एक इमेज ऐरे में कैप्चर करते हैं।
  • हम इमेज ऐरेज़ को एक अलग वैरिएबल में इकट्ठा करते हैं।
  • moviepy नामक लाइब्रेरी का उपयोग करते हुए, हम सभी इमेज ऐरेज़ को जोड़कर एक सिंगल GIF बनाते हैं।

आइए कोड संशोधित करते हैं:

env = gym.make("Taxi-v3", render_mode="rgb_array")
n_episodes = 1
frames = []  # for animation
for episode in range(n_episodes):
   # Reset the environment
   state, _ = env.reset()
   # Capture the state as an image
   img = env.render()
   frames.append(img)
   done = False
   total_reward = 0
   steps = 0
   while not done:
       # Choose a random action
       action = env.action_space.sample()
       # Take the action and observe the result
       next_state, reward, terminated, truncated, _ = env.step(action)
       done = terminated or truncated
      
       # Capture the next state as an image
       img = env.render()
       frames.append(img)
       # Update total reward and step count
       total_reward += reward
       steps += 1
       # Move to the next state
       state = next_state

इस संस्करण में, हमने एपिसोड की संख्या केवल एक रखी है, क्योंकि एनवायरनमेंट स्टेट्स को इमेज के रूप में रेंडर करना काफी समय लेता है। हम अपनी इमेज ऐरेज़ को स्टोर करने के लिए एक खाली लिस्ट भी बनाते हैं। फिर इंटरैक्शन लूप पहले की तरह जारी रहता है। फर्क बस इतना है कि दो अतिरिक्त लाइनों में हम एनवायरनमेंट को इमेज के रूप में रेंडर करके frames में जोड़ते हैं।

अब, हमारे पास frames के अंदर 201 इमेज होनी चाहिए (एक अतिरिक्त स्टेट के लिए एक अतिरिक्त इमेज):

>>> len(frames)
201

आइए इन इमेजेज़ को moviepy लाइब्रेरी का उपयोग करके GIF में बदलें:

from moviepy.editor import ImageSequenceClip  # pip install moviepy
def create_gif(frames: list, filename, fps=5):
   """
   Creates a GIF animation from a list of RGBA NumPy arrays.
   Args:
       frames: A list of RGBA NumPy arrays representing the animation frames.
       filename: The output filename for the GIF animation.
       fps: The frames per second of the animation (default: 10).
   """
   clip = ImageSequenceClip(frames, fps=fps)
   clip.write_gif(filename, fps=fps)
# Example usage
create_gif(frames, "animation.gif", fps=25)  # saves the GIF locally

create_gif() फ़ंक्शन फ्रेम्स की लिस्ट लेता है और moviepy की ImageSequenceClip क्लास का उपयोग करके उन्हें GIF में बदल देता है। एक महत्वपूर्ण पैरामीटर है फ्रेम्स प्रति सेकंड, fps, जो GIF की अवधि को नियंत्रित करता है। प्रति सेकंड जितने अधिक फ्रेम होंगे, GIF उतना ही छोटा होगा।

अंत में, हम एक एपिसोड के फ्रेम्स को 25 FPS वाले GIF में बदलते हैं। परिणाम यहाँ है:

एक GIF जो टैक्सी राइड एनवायरनमेंट में एजेंट (टैक्सी) की रैंडम इंटरैक्शंस दिखाता है, जो State-Action-Reward-Action-State चक्र का प्रतिनिधित्व करता है

जैसा कि आप देख सकते हैं, टैक्सी को कुछ पता नहीं कि वह क्या कर रही है और वह यात्री के पास भी नहीं पहुँची। आइए इसकी नेविगेशन प्रणाली में SARSA जोड़कर इसे कुछ समझ देते हैं।

Python में SARSA का चरण-दर-चरण इम्प्लीमेंटेशन

हम SARSA के लिए कोड को शुरू से बनाएँगे ताकि आप हर चरण को स्पष्ट रूप से याद रखें।

1. Gymnasium एनवायरनमेंट सेट करना:

import gymnasium as gym
import numpy as np
import matplotlib.pyplot as plt
# Create the Taxi environment
env = gym.make("Taxi-v3", render_mode="rgb_array")

2. Q-टेबल को इनिशियलाइज़ करना

# Initialize Q-table
n_states = env.observation_space.n
n_actions = env.action_space.n
Q_table = np.zeros((n_states, n_actions))

इस चरण में, हम एक नया डेटा स्ट्रक्चर—Q-टेबल—प्रस्तुत करते हैं। इसके आयाम (स्टेट्स की संख्या) × (एक्शन्स की संख्या) होते हैं। हमारी एजेंट, टैक्सी ड्राइवर, के लिए टेबल कुछ इस तरह दिखेगी:

Q-टेबल का दृश्य निरूपण, जो Q-learning और SARSA दोनों रिइनफोर्समेंट लर्निंग एल्गोरिदम के लिए प्रमुख है।

शुरुआत में, Q-टेबल शून्यों से भरी होगी:

>>> Q_table.shape
(500, 6)

उसके बाद, जब एजेंट SARSA के मार्गदर्शन में एनवायरनमेंट के साथ इंटरैक्ट करना शुरू करेगा, तो वह Q-टेबल को Q-वैल्यूज़ से अपडेट करेगा। Q-वैल्यूज़ ऐसे स्कोर हैं जो एजेंट को बताते हैं कि दी गई स्थिति में कौन-सा एक्शन सबसे अच्छा है।

3. SARSA के हाइपरपैरामीटर्स परिभाषित करना

Q-टेबल इनिशियलाइज़ करने के बाद, हम SARSA के हाइपरपैरामीटर्स को सामान्य मानों पर सेट करते हैं (इन पर आगे बात करेंगे):

# SARSA parameters
alpha = 0.1  # Learning rate
gamma = 0.99  # Discount factor
epsilon = 0.1  # Exploration rate for epsilon-greedy policy
n_episodes = 20000

4. परफॉर्मेंस मैट्रिक्स के लिए स्टोरेज परिभाषित करना

फिर, हम दो सूचियाँ परिभाषित करते हैं ताकि परफॉर्मेंस मैट्रिक्स को स्टोर किया जा सके: प्रत्येक एपिसोड के लिए कुल रिवॉर्ड और टाइम स्टेप्स की संख्या। एजेंट का लक्ष्य है यथासंभव कम समय में अधिकतम रिवॉर्ड इकट्ठा करना:

# Lists to store performance metrics
episode_rewards = []
episode_lengths = []

5. एक्शन लेने के लिए एप्सिलॉन-ग्रीडी नीति

पिछले सेक्शन में हमारा एजेंट बिना मार्गदर्शन के था—वह रैंडम एक्शन्स ले रहा था। हम ड्राइवर को Epsilon-Greedy रणनीति देकर यह बदलना चाहते हैं:

def epsilon_greedy(state, epsilon):
   if np.random.random() < epsilon:
       # Take random action - explore
       return env.action_space.sample()
   else:
       # Take action with the highest Q-value - exploit
       return np.argmax(Q_table[state])

यह रणनीति exploration और exploitation के महत्वपूर्ण संतुलन को नियंत्रित करने के लिए बनाई गई है। epsilon की प्रायिकता के साथ, एजेंट रैंडम एक्शन लेकर एनवायरनमेंट को एक्सप्लोर करता है, जबकि 1-epsilon की प्रायिकता के साथ, वह Q-टेबल से सबसे उच्च Q-वैल्यू वाले एक्शन को चुनकर अपने वर्तमान ज्ञान का उपयोग करता है। यह तरीका एजेंट को नई, संभावित रूप से बेहतर रणनीतियों की खोज करने देता है, साथ ही जो सीखा है उसे भी उपयोग करता है।

6. SARSA ट्रेनिंग लूप लिखना

अंततः, हम SARSA ट्रेनिंग लूप लिखते हैं। लूप की शुरुआत पहले से परिचित है। फर्क सिर्फ इतना है कि हम वर्तमान स्टेट में कौन-सा एक्शन लेना है यह बताने के लिए epsilon_greedy() फ़ंक्शन का उपयोग करते हैं:

# SARSA training loop
for episode in range(n_episodes):
   state, _ = env.reset()
   action = epsilon_greedy(state, epsilon)
   done = False
   total_reward = 0
   steps = 0
   ...

फिर, हम while लूप शुरू करते हैं जो हमें टर्मिनेशन स्टेट तक इंटरैक्शन चक्र चलाने देता है:

# SARSA training loop
for episode in range(n_episodes):
   ...
   while not done:
       next_state, reward, terminated, truncated, _ = env.step(action)
       done = terminated or truncated
       next_action = epsilon_greedy(next_state, epsilon)

while लूप के अंदर, हम epsilon_greedy() द्वारा लौटाया गया एक्शन लेते हैं और अगला स्टेट, हमारी क्रिया का रिवॉर्ड, और क्या एपिसोड समाप्त हुआ या नहीं इसका बूलियन मान प्राप्त करते हैं।

फिर, हम महत्वपूर्ण भाग—SARSA के अपडेट नियम—पर आते हैं:

# SARSA training loop
for episode in range(n_episodes):
   ...
   while not done:
       next_state, reward, terminated, truncated, _ = env.step(action)
       done = terminated or truncated
       next_action = epsilon_greedy(next_state, epsilon)
       # SARSA update rule
       Q_table[state, action] += alpha * (
           reward + gamma * Q_table[next_state, next_action] - Q_table[state, action]
       )

अपडेट नियम निम्नलिखित सूत्र से आता है:

SARSA के अपडेट नियम का सूत्र

[Source]

हम इस सूत्र के पीछे की सहज समझ अगले सेक्शन में जानेंगे। अभी के लिए, इस सूत्र को कुछ गणितीय जादू की तरह मानें जो SARSA के नियमों के अनुसार हमारी Q-टेबल के Q-वैल्यूज़ को अपडेट करता है।

एक बार Q अपडेट करने के बाद, हम state और action वैरिएबल्स को प्राप्त हुए स्टेट और एक्शन में बदलते हैं, प्राप्त रिवॉर्ड को एपिसोड के कुल रिवॉर्ड में जोड़ते हैं, और टाइम स्टेप्स की संख्या बढ़ाते हैं।

# SARSA training loop
for episode in range(n_episodes):
   ...
   while not done:
       ...
       state = next_state
       action = next_action
       total_reward += reward
       steps += 1

while लूप तब तक चलता है जब तक हम अधिकतम टाइम स्टेप्स (टैक्सी एनवायरनमेंट के लिए 200) तक नहीं पहुँच जाते या टैक्सी सही स्थान पर अपने यात्री को सफलतापूर्वक छोड़ नहीं देती।

लूप समाप्त होने पर, हम कुल एपिसोड रिवॉर्ड और एपिसोड की लंबाई रिकॉर्ड करते हैं। हम हर 1000 एपिसोड्स पर औसत एपिसोड रिवॉर्ड और लंबाई भी प्रिंट करते हैं:

# SARSA training loop
for episode in range(n_episodes):
   ...
   while not done:
       ...
   episode_rewards.append(total_reward)
   episode_lengths.append(steps)
   if episode % 1000 == 0:
       avg_reward = np.mean(episode_rewards[-1000:])
       avg_length = np.mean(episode_lengths[-1000:])
       print(f"Episode {episode}, Avg Reward: {avg_reward:.2f}, Avg Length: {avg_length:.2f}")

यह रहा पूरा इंटरैक्शन लूप निष्पादित रूप में:

# SARSA training loop
for episode in range(n_episodes):
   state, _ = env.reset()
   action = epsilon_greedy(state, epsilon)
   done = False
   total_reward = 0
   steps = 0
   while not done:
       next_state, reward, terminated, truncated, _ = env.step(action)
       done = terminated or truncated
       next_action = epsilon_greedy(next_state, epsilon)
       Q_table[state, action] += alpha * (
           reward + gamma * Q_table[next_state, next_action] - Q_table[state, action]
       )
       state = next_state
       action = next_action
       total_reward += reward
       steps += 1
   episode_rewards.append(total_reward)
   episode_lengths.append(steps)
   if episode % 2000 == 0:
       avg_reward = np.mean(episode_rewards[-1000:])
       avg_length = np.mean(episode_lengths[-1000:])
       print(f"Episode {episode}, Avg Reward: {avg_reward:.2f}, Avg Length: {avg_length:.2f}")
Episode 0, Avg Reward: -551.00, Avg Length: 185.00
Episode 2000, Avg Reward: -4.37, Avg Length: 19.47
Episode 4000, Avg Reward: 1.98, Avg Length: 15.09
Episode 6000, Avg Reward: 2.29, Avg Length: 14.79
Episode 8000, Avg Reward: 2.06, Avg Length: 14.80
Episode 10000, Avg Reward: 2.16, Avg Length: 14.78
Episode 12000, Avg Reward: 2.06, Avg Length: 14.89
Episode 14000, Avg Reward: 2.33, Avg Length: 14.81
Episode 16000, Avg Reward: 2.36, Avg Length: 14.66
Episode 18000, Avg Reward: 2.53, Avg Length: 14.72

जैसा कि आप आउटपुट से देख सकते हैं, जैसे-जैसे हमने अधिक एपिसोड्स चलाए, औसत रिवॉर्ड और प्रति एपिसोड टाइम स्टेप्स की संख्या नाटकीय रूप से कम हो गई।

हम इसे विज़ुअली भी देख सकते हैं यदि हम episode_rewards और episode_lengths ऐरेज़ को प्लॉट करें:

# Plot the learning curve
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(episode_rewards)
plt.title("Episode Rewards")
plt.xlabel("Episode")
plt.ylabel("Total Reward")
plt.subplot(1, 2, 2)
plt.plot(episode_lengths)
plt.title("Episode Lengths")
plt.xlabel("Episode")
plt.ylabel("Number of Steps")
plt.tight_layout()
plt.show()

दो प्लॉट जो SARSA के दो परफॉर्मेंस मैट्रिक्स दिखाते हैं: कुल एपिसोड रिवॉर्ड और एपिसोड की लंबाई

बाएँ प्लॉट में प्रत्येक एपिसोड में प्राप्त कुल रिवॉर्ड दिखाया गया है। हम देख सकते हैं कि:

  • शुरुआत में, रिवॉर्ड कम और अत्यधिक परिवर्तनशील हैं, जो दर्शाता है कि एजेंट एक्सप्लोर कर रहा है और सीख रहा है।
  • समय के साथ, रिवॉर्ड में ऊपर की ओर रुझान है, जो संकेत देता है कि एजेंट अपनी नीति में सुधार कर रहा है।
  • अंत की ओर, रिवॉर्ड उच्च स्तर पर स्थिर होते दिखते हैं, जो दर्शाता है कि एजेंट ने एक काफ़ी अच्छी नीति सीख ली है।

दाएँ प्लॉट में प्रत्येक एपिसोड में लिए गए स्टेप्स की संख्या दिखाई गई है। हम देख सकते हैं कि:

  • शुरुआत में एपिसोड लंबे होते हैं, क्योंकि एजेंट उप-इष्टतम एक्शन्स ले रहा होता है।
  • सीखने की प्रगति के साथ, एपिसोड की लंबाई में सामान्यतः गिरावट का रुझान है।
  • अंततः एपिसोड की लंबाई स्थिर हो जाती है, जो सुझाव देती है कि एजेंट कार्य को अधिक कुशलता से पूरा करना सीख गया है।

कोड को फ़ंक्शंस में व्यवस्थित करना

कम समय में हमने बहुत कुछ कवर कर लिया है। अब एक कदम पीछे हटकर हम जो कुछ भी लिख चुके हैं उसे व्यवस्थित करते हैं। हम SARSA लागू करने के लिए उठाए गए प्रत्येक चरण के लिए फ़ंक्शन बनाएँगे।

सबसे पहले, एनवायरनमेंट बनाने का फ़ंक्शन:

import gymnasium as gym
import numpy as np
import matplotlib.pyplot as plt
from moviepy.editor import ImageSequenceClip
def create_environment(env_name="Taxi-v3", render_mode="rgb_array"):
   """Create and return a Gymnasium environment."""
   return gym.make(env_name, render_mode=render_mode)

फिर, दिए गए एनवायरनमेंट के अनुसार Q-टेबल इनिशियलाइज़ करने का फ़ंक्शन:

def initialize_q_table(env):
   """Initialize and return a Q-table for the given environment."""
   n_states = env.observation_space.n
   n_actions = env.action_space.n
   return np.zeros((n_states, n_actions))

Epsilon-greedy रणनीति जो एक एनवायरनमेंट, Q-टेबल, वर्तमान स्टेट और एप्सिलॉन को स्वीकार करती है:

def epsilon_greedy(env, Q_table, state, epsilon=0.1):
   """Epsilon-greedy action selection."""
   if np.random.random() < epsilon:
       return env.action_space.sample()
   else:
       return np.argmax(Q_table[state])

SARSA का अपडेट नियम, जिसे Q-टेबल, वर्तमान स्टेट, उस स्टेट में लिया गया एक्शन, उस एक्शन का रिवॉर्ड, अगला स्टेट और एक्शन चाहिए:

def sarsa_update(Q_table, state, action, reward, next_state, next_action, alpha, gamma):
   """Perform SARSA update on Q-table."""
   Q_table[state, action] += alpha * (
       reward + gamma * Q_table[next_state, next_action] - Q_table[state, action]
   )

अंत में, SARSA के साथ एजेंट को ट्रेन करने के लिए एक बड़ा फ़ंक्शन, जिसे एनवायरनमेंट, चलाने के लिए एपिसोड्स की संख्या, alpha, gamma, और epsilon पैरामीटर्स चाहिए:

def train_sarsa(env, n_episodes=20000, alpha=0.1, gamma=0.99, epsilon=0.1):
   """Train the agent using SARSA algorithm."""
   Q_table = initialize_q_table(env)
   episode_rewards = []
   episode_lengths = []
   for episode in range(n_episodes):
       state, _ = env.reset()
       action = epsilon_greedy(env, Q_table, state, epsilon)
       done = False
       total_reward = 0
       steps = 0
       while not done:
           next_state, reward, terminated, truncated, _ = env.step(action)
           done = terminated or truncated
           next_action = epsilon_greedy(env, Q_table, next_state, epsilon)
           sarsa_update(
               Q_table, state, action, reward, next_state, next_action, alpha, gamma
           )
           state = next_state
           action = next_action
           total_reward += reward
           steps += 1
       episode_rewards.append(total_reward)
       episode_lengths.append(steps)
   return Q_table, episode_rewards, episode_lengths

साथ ही, परफॉर्मेंस मैट्रिक्स प्लॉट करने का फ़ंक्शन:

def plot_learning_curve(episode_rewards, episode_lengths):
   """Plot the learning curve."""
   plt.figure(figsize=(12, 5))
   plt.subplot(1, 2, 1)
   plt.plot(episode_rewards)
   plt.title("Episode Rewards")
   plt.xlabel("Episode")
   plt.ylabel("Total Reward")
   plt.subplot(1, 2, 2)
   plt.plot(episode_lengths)
   plt.title("Episode Lengths")
   plt.xlabel("Episode")
   plt.ylabel("Number of Steps")
   plt.tight_layout()
   plt.show()

हमारा पहले वाला create_gif() फ़ंक्शन:

def create_gif(frames, filename, fps=5):
   """Creates a GIF animation from a list of frames."""
   clip = ImageSequenceClip(frames, fps=fps)
   clip.write_gif(filename, fps=fps)

और एक अन्य फ़ंक्शन जो एक संपूर्ण, सीखी हुई Q-टेबल का उपयोग करके रेंडरिंग के साथ एक एपिसोड चलाता है (एनिमेशन के उद्देश्य से):

def run_episode(env, Q_table, epsilon=0):
   """Run a single episode using the learned Q-table."""
   state, _ = env.reset()
   done = False
   total_reward = 0
   frames = [env.render()]
   while not done:
       action = epsilon_greedy(env, Q_table, state, epsilon)
       next_state, reward, terminated, truncated, _ = env.step(action)
       done = terminated or truncated
       frames.append(env.render())
       total_reward += reward
       state = next_state
   return frames, total_reward

अब, आइए सब कुछ निष्पादित करते हैं:

if __name__ == "__main__":
   env = create_environment()
  
   Q_table, episode_rewards, episode_lengths = train_sarsa(env, n_episodes=20000)
   plot_learning_curve(episode_rewards, episode_lengths)
  
   frames, total_reward = run_episode(env, Q_table)
   create_gif(frames, "images/sarsa_final_animation.gif", fps=1)

दो प्लॉट जो SARSA के दो परफॉर्मेंस मैट्रिक्स दिखाते हैं: कुल एपिसोड रिवॉर्ड और एपिसोड की लंबाई

परफॉर्मेंस प्लॉट्स अच्छे दिख रहे हैं। अब, बनाए गए GIF को देखते हैं:

एक GIF जो SARSA एल्गोरिदम से प्रशिक्षित रिइनफोर्समेंट लर्निंग एजेंट टैक्सी द्वारा यात्री के सफल पिक-अप और ड्रॉप-ऑफ को दर्शाता है

वाह! टैक्सी नीले वर्ग से यात्री को सही ढंग से उठाकर पीले वर्ग पर छोड़ रही है।

मैंने SARSA इम्प्लीमेंटेशन के लिए पूरा व्यवस्थित कोड GitHub gist में पेस्ट कर दिया है ताकि आप जब चाहें उसे देख सकें।

SARSA के अपडेट नियम के पीछे की सहज समझ

SARSA के केंद्र में उसका अपडेट नियम है, जो नियंत्रित करता है कि एजेंट अपने अनुभवों से कैसे सीखता है। आइए इस नियम को तोड़कर उसकी सहज समझ को जानें:

Q(s, a) = Q(s, a) + α [R + γ Q(s', a') - Q(s, a)]

घटकों को समझना

  • Q(s, a): स्टेट ‘s’ में एक्शन ‘a’ लेने का वर्तमान Q-वैल्यू।
  • α (alpha): लर्निंग रेट, जो नियंत्रित करता है कि नई जानकारी कितनी तेजी से शामिल हो।
  • R: एक्शन लेने के बाद प्राप्त रिवॉर्ड।
  • γ (gamma): डिस्काउंट फैक्टर, जो भविष्य के रिवॉर्ड्स के महत्व को निर्धारित करता है।
  • Q(s’, a’): अगले स्टेट-एक्शन जोड़े का अनुमानित Q-वैल्यू।

सीखने की प्रक्रिया

SARSA का अपडेट नियम एजेंट की पर्यावरण की समझ को नई अनुभूतियों के आधार पर Q-वैल्यूज़ को समायोजित करके परिष्कृत करने का लक्ष्य रखता है। यह इस प्रकार काम करता है:

  1. एजेंट एक एक्शन लेता है और रिवॉर्ड तथा अगला स्टेट देखता है।
  2. वह अपने वर्तमान Q-वैल्यू और देखे गए रिवॉर्ड व अगले स्टेट-एक्शन जोड़े के वैल्यू पर आधारित नए अनुमान के बीच का अंतर निकालता है।
  3. यह अंतर, लर्निंग रेट से स्केल होकर, Q-वैल्यू अपडेट करने में उपयोग होता है।

टेम्पोरल डिफरेंस त्रुटि

[R + γ * Q(s’, a’) — Q(s, a)] पद को टेम्पोरल डिफरेंस (TD) त्रुटि कहा जाता है। इसे आश्चर्य के माप के रूप में समझें:

  • पॉज़िटिव TD त्रुटि: परिणाम उम्मीद से बेहतर था।
  • नेगेटिव TD त्रुटि: परिणाम उम्मीद से बदतर था।
  • शून्य TD त्रुटि: परिणाम मौजूदा अनुमान से पूरी तरह मेल खाता है।

यह त्रुटि एजेंट को अपने अनुमानों को लगातार परिष्कृत करने में मदद करती है, जिससे सीखने की प्रक्रिया इष्टतम नीति की ओर अग्रसर होती है।

हाइपरपैरामीटर्स की भूमिका

1. लर्निंग रेट (α):

  • सीखने की गति को नियंत्रित करता है।
  • उच्च α: तेज़ सीखना, पर अस्थिर हो सकता है।
  • निम्न α: धीमा, पर अधिक स्थिर सीखना।

2. डिस्काउंट फैक्टर (γ):

  • तत्काल और भविष्य के रिवॉर्ड्स के बीच संतुलन बनाता है।
  • γ जो 1 के करीब हो: एजेंट भविष्य के रिवॉर्ड्स को लगभग तत्काल रिवॉर्ड्स जितना महत्व देता है।
  • कम γ: एजेंट अधिक तत्काल रिवॉर्ड्स पर ध्यान केंद्रित करता है।

3. एक्सप्लोरेशन रेट (ε):

  • हालाँकि यह खुद अपडेट नियम में नहीं है, पर यह एप्सिलॉन-ग्रीडी नीति के लिए अत्यंत महत्वपूर्ण है।
  • एक्सप्लोरेशन (नए एक्शन आज़माना) और एक्सप्लॉइटेशन (ज्ञात अच्छे एक्शन का उपयोग) के बीच संतुलन बनाता है।
  • उच्च ε: अधिक एक्सप्लोरेशन, जो अल्पकालिक परफॉर्मेंस की कीमत पर बेहतर रणनीतियाँ खोज सकता है।

बड़ी तस्वीर

SARSA का अपडेट नियम एजेंट को अपने अनुभवों से सीखने देता है, स्टेट-एक्शन वैल्यू के अनुमानों को लगातार समायोजित करके। हर इंटरैक्शन के साथ, एजेंट अपने एनवायरनमेंट के बारे में थोड़ा और समझदार हो जाता है। कई एपिसोड्स में, यह प्रक्रिया एनवायरनमेंट में नेविगेट करने के लिए एक इष्टतम नीति के विकास की ओर ले जाती है।

हाइपरपैरामीटर्स को ट्यून करके, हम सीखने की प्रक्रिया के विभिन्न पहलुओं को नियंत्रित कर सकते हैं, जिससे SARSA अलग-अलग प्रकार की समस्याओं और एनवायरनमेंट्स के अनुसार अनुकूल हो सकता है। यह लचीलापन, अपने सहज अपडेट नियम के साथ मिलकर, SARSA को एक शक्तिशाली और व्यापक रूप से उपयोग किया जाने वाला रिइनफोर्समेंट लर्निंग एल्गोरिदम बनाता है।

SARSA बनाम Q-learning: प्रमुख अंतर

हालाँकि SARSA और Q-learning दोनों व्यापक रूप से उपयोग किए जाने वाले रिइनफोर्समेंट लर्निंग एल्गोरिदम हैं, उनमें कुछ महत्वपूर्ण अंतर हैं। और ये अंतर यह समझने के लिए महत्वपूर्ण हैं कि प्रत्येक एल्गोरिदम का उपयोग कब और कैसे किया जाए।

1. ऑन-पॉलिसी बनाम ऑफ-पॉलिसी

एक ऑन-पॉलिसी एल्गोरिदम होने के नाते, SARSA उसी नीति का मूल्य सीखता है जिसका वह अनुसरण करता है—यहाँ तक कि एक्सप्लोरेशन के दौरान उठाए गए कदमों का भी। Q-learning ऑफ-पॉलिसी है; यह इष्टतम नीति का मूल्य सीखता है—भले ही वह उस नीति का पालन न कर रहा हो, यह फिर भी एपिसोड के अंत में पहुँचने पर इष्टतम नीति का मूल्य सीखता है। इसलिए हमने शुरुआत में कहा था कि SARSA तब उपयोग करना चाहिए जब सीखने की यात्रा परिणाम जितनी ही महत्वपूर्ण हो। Q-learning को सीखने की यात्रा से अधिक मतलब नहीं होता।

2. अपडेट नियम

  • SARSA: Q(s, a) = Q(s, a) + α * [R + γ * Q(s’, a’) — Q(s, a)]
  • Q-learning: Q(s, a) = Q(s, a) + α * [R + γ * max(Q(s’, a’)) — Q(s, a)]

मुख्य अंतर यह है कि SARSA अगले लिए गए वास्तविक एक्शन (a’) के Q-वैल्यू का उपयोग करता है, जबकि Q-learning अगले स्टेट के अधिकतम Q-वैल्यू (max(Q(s’, a’))) का उपयोग करता है।

3. एक्सप्लोरेशन पर विचार

Q-वैल्यू अपडेट करते समय, SARSA एक्सप्लोरेशन नीति की अनदेखी नहीं करता और इस प्रकार अधिक सतर्क होता है। तुलना में, Q-learning हमेशा मानता है कि एजेंट भविष्य में इष्टतम एक्शन लेगा और इसलिए अधिक आक्रामक होता है।

4. अभिसरण (Convergence)

हालाँकि दोनों एल्गोरिदम अंततः इष्टतम नीति तक पहुँचते हैं, Q-learning अक्सर तेज़ी से सीख सकता है, विशेषकर निर्धारक (deterministic) एनवायरनमेंट्स में।

5. सुरक्षा

ऐसे एनवायरनमेंट्स में जहाँ एक्सप्लोरेशन के बुरे परिणाम हो सकते हैं, SARSA आमतौर पर अधिक सुरक्षित नीतियाँ सीखता है क्योंकि यह वास्तविक अपनाई गई नीति को ध्यान में रखता है।

क्लासिक “cliff walking” समस्या में, SARSA आमतौर पर चट्टान के किनारे से दूर रहने वाला अधिक सुरक्षित मार्ग सीखता है, जबकि Q-learning किनारे के साथ चलने वाला अधिक जोखिम भरा मार्ग सीख सकता है।

6. स्थिरता

कुछ यादृच्छिक (stochastic) एनवायरनमेंट्स में, SARSA अधिक स्थिर हो सकता है क्योंकि यह वास्तविक अगले एक्शन को ध्यान में रखता है, भले ही वह उप-इष्टतम एक्सप्लोरेटरी एक्शन ही क्यों न हो।

7. हाइपरपैरामीटर संवेदनशीलता

Q-learning, विशेषकर अधिक स्टोकेस्टिक एनवायरनमेंट्स में, लर्निंग रेट और एक्सप्लोरेशन रेट के चुनाव के प्रति अधिक संवेदनशील हो सकता है।

8. वास्तविक दुनिया के अनुप्रयोग

जब बात रोबोटिक्स या अन्य भौतिक प्रणालियों की आती है जहाँ एनवायरनमेंट का एक्सप्लोरेशन महँगा है और जहाँ हम अधिक सुरक्षित नीतियाँ लागू करना चाहते हैं, तो हम ऑन-पॉलिसी एल्गोरिदम SARSA को प्राथमिकता दे सकते हैं। जब हम सिम्युलेटेड दुनिया, गेम्स या अन्य ऐसे एनवायरनमेंट्स में होते हैं जहाँ हमें बहुत सा फीडबैक मिल सकता है और जहाँ हम इष्टतम नीति को तेज़ और अपेक्षाकृत सुरक्षित तरीके से पाना चाहते हैं, वहाँ हमें Q-learning अधिक पसंद आ सकता है।

तो आप सोच सकते हैं कि SARSA कुछ हद तक सुरक्षित क्षेत्र है, और Q-learning तेज़, अधिक जोखिम लेने वाला तरीका। व्यवहार में, यह अक्सर विशिष्ट समस्या पर निर्भर करता है। दोनों एल्गोरिदम बहुत मजबूत हैं, और उनके बीच के अंतर जानना हमेशा समझदारी है।

निष्कर्ष

इस व्यापक मार्गदर्शिका में, हमने SARSA एल्गोरिदम का अध्ययन किया—इसके कोर कॉन्सेप्ट्स, इम्प्लीमेंटेशन डिटेल्स, और Taxi-v3 एनवायरनमेंट का उपयोग करते हुए व्यावहारिक अनुप्रयोग।

मुख्य बातें:

  1. SARSA की ऑन-पॉलिसी प्रकृति और उसके अपडेट नियम की सहज समझ
  2. Python इम्प्लीमेंटेशन और विज़ुअलाइज़ेशन तकनीकें
  3. Q-learning से तुलना, उसकी ताकतें और उपयोग के मामले उजागर करना

SARSA की अधिक सुरक्षित नीतियाँ सीखने की क्षमता इसे वास्तविक दुनिया के अनुप्रयोगों के लिए उपयुक्त बनाती है, जहाँ एक्सप्लोरेशन की लागतें अधिक होती हैं—हालाँकि कुछ परिदृश्यों में यह Q-learning जैसे ऑफ-पॉलिसी एल्गोरिदम की तुलना में धीरे अभिसरित हो सकता है।

ध्यान रखें, SARSA और अन्य एल्गोरिदम के बीच चुनाव आपकी विशिष्ट समस्या और एनवायरनमेंट पर निर्भर करता है। सर्वोत्तम परिणामों के लिए प्रयोग और फाइन-ट्यूनिंग अत्यंत महत्वपूर्ण हैं।

हम आपको इस नींव पर आगे निर्माण करने के लिए प्रोत्साहित करते हैं—अधिक जटिल एनवायरनमेंट्स का अन्वेषण करें, फंक्शन एप्रॉक्सिमेशन के साथ SARSA लागू करें, या अन्य रिइनफोर्समेंट लर्निंग एल्गोरिदम में गहराई से उतरें।

यहाँ कुछ संबंधित संसाधन हैं जो आपकी मदद करेंगे:

SARSA FAQs

What is the SARSA algorithm in reinforcement learning?

SARSA (State-Action-Reward-State-Action) एक ऑन-पॉलिसी रिइनफोर्समेंट लर्निंग एल्गोरिदम है जो एजेंट के वास्तविक अनुभवों—एक्सप्लोरेटरी एक्शन्स सहित—के आधार पर Q-वैल्यूज़ को अपडेट करता है।

How does SARSA differ from Q-learning?

SARSA ऑन-पॉलिसी है और अगले लिए गए वास्तविक एक्शन का उपयोग करके Q-वैल्यू अपडेट करता है, जबकि Q-learning ऑफ-पॉलिसी है और अगले स्टेट के अधिकतम Q-वैल्यू का उपयोग करता है—इससे सीखने का व्यवहार अलग होता है।

What are the key hyperparameters in SARSA, and how do they affect learning?

मुख्य हाइपरपैरामीटर्स हैं लर्निंग रेट (α), डिस्काउंट फैक्टर (γ), और एक्सप्लोरेशन रेट (ε)। ये क्रमशः सीखने की गति, भविष्य के रिवॉर्ड्स के महत्व, और एक्सप्लोरेशन व एक्सप्लॉइटेशन के संतुलन को नियंत्रित करते हैं।

How can I implement the SARSA algorithm in Python?

लेख Python में SARSA इम्प्लीमेंट करने की चरण-दर-चरण मार्गदर्शिका प्रदान करता है—जिसमें एनवायरनमेंट सेटअप, Q-टेबल इनिशियलाइज़ेशन, और ट्रेनिंग लूप लिखना शामिल है।

What are the practical applications of SARSA in real-world scenarios?

SARSA उन अनुप्रयोगों के लिए उपयुक्त है जहाँ एक्सप्लोरेशन महँगा होता है, जैसे रोबोटिक्स और भौतिक प्रणालियाँ, क्योंकि यह Q-learning जैसे ऑफ-पॉलिसी एल्गोरिदम की तुलना में आमतौर पर अधिक सुरक्षित नीतियाँ सीखता है।

Bexruz (Bex) Tuychiev

लेखक

Bexruz (Bex) Tuychiev

मैं 2 से अधिक वर्षों के अनुभव वाला डेटा साइंस कंटेंट क्रिएटर हूँ और Medium पर सबसे बड़े फॉलोइंग्स में से एक रखता हूँ। मुझे एआई और एमएल पर विस्तार से लेख लिखना पसंद है, जिसमें हल्का-सा व्यंग्यात्मक अंदाज रहता है—क्योंकि कुछ तो करना पड़ता है ताकि वे कम उबाऊ लगें। मैंने 130 से अधिक लेख और एक DataCamp कोर्स तैयार किया है, और एक और बन रहा है। मेरा कंटेंट 50 लाख से अधिक लोगों ने देखा है, जिनमें से 20 हज़ार लोग Medium और LinkedIn पर फॉलोअर्स बन गए। 

विषय