MohamedMaged262
commited on
Delete Mohamed Maged (221101329) (Ais) Task 7 Advanced machine.ipynb
Browse files
Mohamed Maged (221101329) (Ais) Task 7 Advanced machine.ipynb
DELETED
@@ -1,454 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"cells": [
|
3 |
-
{
|
4 |
-
"cell_type": "code",
|
5 |
-
"execution_count": 1,
|
6 |
-
"metadata": {},
|
7 |
-
"outputs": [
|
8 |
-
{
|
9 |
-
"name": "stdout",
|
10 |
-
"output_type": "stream",
|
11 |
-
"text": [
|
12 |
-
"Initial State: (0, 0)\n"
|
13 |
-
]
|
14 |
-
}
|
15 |
-
],
|
16 |
-
"source": [
|
17 |
-
"import numpy as np\n",
|
18 |
-
"\n",
|
19 |
-
"# Create a grid environment\n",
|
20 |
-
"class Gridworld:\n",
|
21 |
-
" def __init__(self):\n",
|
22 |
-
" self.grid_size = 5\n",
|
23 |
-
" self.start_state = (0, 0)\n",
|
24 |
-
" self.goal_state = (4, 4)\n",
|
25 |
-
" self.obstacles = [(2, 2), (3, 3)]\n",
|
26 |
-
" self.state = self.start_state\n",
|
27 |
-
"\n",
|
28 |
-
" def reset(self):\n",
|
29 |
-
" self.state = self.start_state\n",
|
30 |
-
" return self.state\n",
|
31 |
-
"\n",
|
32 |
-
" def step(self, action):\n",
|
33 |
-
" actions = {\n",
|
34 |
-
" 0: (-1, 0), # Up\n",
|
35 |
-
" 1: (1, 0), # Down\n",
|
36 |
-
" 2: (0, -1), # Left\n",
|
37 |
-
" 3: (0, 1) # Right\n",
|
38 |
-
" }\n",
|
39 |
-
" next_state = (self.state[0] + actions[action][0],\n",
|
40 |
-
" self.state[1] + actions[action][1])\n",
|
41 |
-
"\n",
|
42 |
-
" # Ensure the agent doesn't move out of bounds\n",
|
43 |
-
" if 0 <= next_state[0] < self.grid_size and 0 <= next_state[1] < self.grid_size:\n",
|
44 |
-
" self.state = next_state\n",
|
45 |
-
"\n",
|
46 |
-
" # Check for rewards or penalties\n",
|
47 |
-
" if self.state == self.goal_state:\n",
|
48 |
-
" return self.state, 100, True # Goal reached\n",
|
49 |
-
" elif self.state in self.obstacles:\n",
|
50 |
-
" return self.state, -10, False # Hit obstacle\n",
|
51 |
-
" else:\n",
|
52 |
-
" return self.state, -1, False # Normal step\n",
|
53 |
-
"\n",
|
54 |
-
"# Test environment\n",
|
55 |
-
"env = Gridworld()\n",
|
56 |
-
"print(\"Initial State:\", env.reset())\n"
|
57 |
-
]
|
58 |
-
},
|
59 |
-
{
|
60 |
-
"cell_type": "code",
|
61 |
-
"execution_count": 2,
|
62 |
-
"metadata": {},
|
63 |
-
"outputs": [],
|
64 |
-
"source": [
|
65 |
-
"# Q-Learning parameters\n",
|
66 |
-
"episodes = 500\n",
|
67 |
-
"alpha = 0.1 # Learning rate\n",
|
68 |
-
"gamma = 0.9 # Discount factor\n",
|
69 |
-
"epsilon = 0.2 # Exploration rate\n",
|
70 |
-
"actions = [0, 1, 2, 3] # Up, Down, Left, Right\n",
|
71 |
-
"\n",
|
72 |
-
"# Initialize Q-table\n",
|
73 |
-
"Q_table = np.zeros((5, 5, len(actions)))\n",
|
74 |
-
"\n",
|
75 |
-
"# Q-Learning function\n",
|
76 |
-
"def train_gridworld(env):\n",
|
77 |
-
" for episode in range(episodes):\n",
|
78 |
-
" state = env.reset()\n",
|
79 |
-
" done = False\n",
|
80 |
-
"\n",
|
81 |
-
" while not done:\n",
|
82 |
-
" # Epsilon-greedy action selection\n",
|
83 |
-
" if np.random.uniform(0, 1) < epsilon:\n",
|
84 |
-
" action = np.random.choice(actions)\n",
|
85 |
-
" else:\n",
|
86 |
-
" action = np.argmax(Q_table[state[0], state[1], :])\n",
|
87 |
-
"\n",
|
88 |
-
" # Take action\n",
|
89 |
-
" next_state, reward, done = env.step(action)\n",
|
90 |
-
"\n",
|
91 |
-
" # Update Q-value\n",
|
92 |
-
" Q_table[state[0], state[1], action] = Q_table[state[0], state[1], action] + \\\n",
|
93 |
-
" alpha * (reward + gamma * np.max(Q_table[next_state[0], next_state[1], :]) -\n",
|
94 |
-
" Q_table[state[0], state[1], action])\n",
|
95 |
-
"\n",
|
96 |
-
" state = next_state\n",
|
97 |
-
"\n",
|
98 |
-
"train_gridworld(env)\n"
|
99 |
-
]
|
100 |
-
},
|
101 |
-
{
|
102 |
-
"cell_type": "code",
|
103 |
-
"execution_count": 3,
|
104 |
-
"metadata": {},
|
105 |
-
"outputs": [
|
106 |
-
{
|
107 |
-
"name": "stdout",
|
108 |
-
"output_type": "stream",
|
109 |
-
"text": [
|
110 |
-
"['↓', '↓', '↓', '↓', '↓']\n",
|
111 |
-
"['→', '↓', '→', '→', '↓']\n",
|
112 |
-
"['→', '↓', '←', '→', '↓']\n",
|
113 |
-
"['→', '→', '↓', '→', '↓']\n",
|
114 |
-
"['→', '→', '→', '→', '↑']\n"
|
115 |
-
]
|
116 |
-
}
|
117 |
-
],
|
118 |
-
"source": [
|
119 |
-
"# Display optimal policy\n",
|
120 |
-
"policy = np.argmax(Q_table, axis=2)\n",
|
121 |
-
"actions_mapping = {0: '↑', 1: '↓', 2: '←', 3: '→'}\n",
|
122 |
-
"\n",
|
123 |
-
"for row in policy:\n",
|
124 |
-
" print([actions_mapping[action] for action in row])\n"
|
125 |
-
]
|
126 |
-
},
|
127 |
-
{
|
128 |
-
"cell_type": "code",
|
129 |
-
"execution_count": 4,
|
130 |
-
"metadata": {},
|
131 |
-
"outputs": [
|
132 |
-
{
|
133 |
-
"name": "stdout",
|
134 |
-
"output_type": "stream",
|
135 |
-
"text": [
|
136 |
-
"State space: Box([-1.2 -0.07], [0.6 0.07], (2,), float32)\n",
|
137 |
-
"Action space: Discrete(3)\n"
|
138 |
-
]
|
139 |
-
},
|
140 |
-
{
|
141 |
-
"data": {
|
142 |
-
"text/plain": [
|
143 |
-
"array([[[255, 255, 255],\n",
|
144 |
-
" [255, 255, 255],\n",
|
145 |
-
" [255, 255, 255],\n",
|
146 |
-
" ...,\n",
|
147 |
-
" [255, 255, 255],\n",
|
148 |
-
" [255, 255, 255],\n",
|
149 |
-
" [255, 255, 255]],\n",
|
150 |
-
"\n",
|
151 |
-
" [[255, 255, 255],\n",
|
152 |
-
" [255, 255, 255],\n",
|
153 |
-
" [255, 255, 255],\n",
|
154 |
-
" ...,\n",
|
155 |
-
" [255, 255, 255],\n",
|
156 |
-
" [255, 255, 255],\n",
|
157 |
-
" [255, 255, 255]],\n",
|
158 |
-
"\n",
|
159 |
-
" [[255, 255, 255],\n",
|
160 |
-
" [255, 255, 255],\n",
|
161 |
-
" [255, 255, 255],\n",
|
162 |
-
" ...,\n",
|
163 |
-
" [255, 255, 255],\n",
|
164 |
-
" [255, 255, 255],\n",
|
165 |
-
" [255, 255, 255]],\n",
|
166 |
-
"\n",
|
167 |
-
" ...,\n",
|
168 |
-
"\n",
|
169 |
-
" [[255, 255, 255],\n",
|
170 |
-
" [255, 255, 255],\n",
|
171 |
-
" [255, 255, 255],\n",
|
172 |
-
" ...,\n",
|
173 |
-
" [255, 255, 255],\n",
|
174 |
-
" [255, 255, 255],\n",
|
175 |
-
" [255, 255, 255]],\n",
|
176 |
-
"\n",
|
177 |
-
" [[255, 255, 255],\n",
|
178 |
-
" [255, 255, 255],\n",
|
179 |
-
" [255, 255, 255],\n",
|
180 |
-
" ...,\n",
|
181 |
-
" [255, 255, 255],\n",
|
182 |
-
" [255, 255, 255],\n",
|
183 |
-
" [255, 255, 255]],\n",
|
184 |
-
"\n",
|
185 |
-
" [[255, 255, 255],\n",
|
186 |
-
" [255, 255, 255],\n",
|
187 |
-
" [255, 255, 255],\n",
|
188 |
-
" ...,\n",
|
189 |
-
" [255, 255, 255],\n",
|
190 |
-
" [255, 255, 255],\n",
|
191 |
-
" [255, 255, 255]]], dtype=uint8)"
|
192 |
-
]
|
193 |
-
},
|
194 |
-
"execution_count": 4,
|
195 |
-
"metadata": {},
|
196 |
-
"output_type": "execute_result"
|
197 |
-
}
|
198 |
-
],
|
199 |
-
"source": [
|
200 |
-
"import gym\n",
|
201 |
-
"import matplotlib.pyplot as plt\n",
|
202 |
-
"\n",
|
203 |
-
"# Initialize environment\n",
|
204 |
-
"env = gym.make(\"MountainCar-v0\", render_mode=\"rgb_array\")\n",
|
205 |
-
"\n",
|
206 |
-
"# Inspect state and action spaces\n",
|
207 |
-
"print(\"State space:\", env.observation_space)\n",
|
208 |
-
"print(\"Action space:\", env.action_space)\n",
|
209 |
-
"\n",
|
210 |
-
"# Visualize environment\n",
|
211 |
-
"state = env.reset()\n",
|
212 |
-
"env.render()\n"
|
213 |
-
]
|
214 |
-
},
|
215 |
-
{
|
216 |
-
"cell_type": "code",
|
217 |
-
"execution_count": 5,
|
218 |
-
"metadata": {},
|
219 |
-
"outputs": [
|
220 |
-
{
|
221 |
-
"name": "stderr",
|
222 |
-
"output_type": "stream",
|
223 |
-
"text": [
|
224 |
-
"C:\\Users\\moham\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\gym\\utils\\passive_env_checker.py:233: DeprecationWarning: `np.bool8` is a deprecated alias for `np.bool_`. (Deprecated NumPy 1.24)\n",
|
225 |
-
" if not isinstance(terminated, (bool, np.bool8)):\n"
|
226 |
-
]
|
227 |
-
},
|
228 |
-
{
|
229 |
-
"name": "stdout",
|
230 |
-
"output_type": "stream",
|
231 |
-
"text": [
|
232 |
-
"Model saved as 'q_learning_model.pkl'\n"
|
233 |
-
]
|
234 |
-
}
|
235 |
-
],
|
236 |
-
"source": [
|
237 |
-
"import pickle\n",
|
238 |
-
"\n",
|
239 |
-
"# Initialize Q-table\n",
|
240 |
-
"state_bins = [20, 20] # Number of bins for discretizing the state space\n",
|
241 |
-
"action_space = env.action_space.n\n",
|
242 |
-
"Q_table = np.random.uniform(low=-1, high=1, size=(state_bins[0], state_bins[1], action_space))\n",
|
243 |
-
"\n",
|
244 |
-
"# Helper to discretize state space\n",
|
245 |
-
"def discretize_state(state):\n",
|
246 |
-
" state_low = env.observation_space.low\n",
|
247 |
-
" state_high = env.observation_space.high\n",
|
248 |
-
" bins = [np.linspace(state_low[i], state_high[i], state_bins[i]) for i in range(len(state))]\n",
|
249 |
-
" state_indices = [np.digitize(state[i], bins[i]) - 1 for i in range(len(state))]\n",
|
250 |
-
" return tuple(state_indices)\n",
|
251 |
-
"\n",
|
252 |
-
"# Initialize Q-learning parameters\n",
|
253 |
-
"alpha = 0.1\n",
|
254 |
-
"gamma = 0.99\n",
|
255 |
-
"epsilon = 0.2\n",
|
256 |
-
"episodes = 5000\n",
|
257 |
-
"epsilon_decay = 0.995\n",
|
258 |
-
"\n",
|
259 |
-
"# Track total rewards for plotting\n",
|
260 |
-
"total_rewards = []\n",
|
261 |
-
"\n",
|
262 |
-
"# Train the agent\n",
|
263 |
-
"for episode in range(episodes):\n",
|
264 |
-
" state, _ = env.reset()\n",
|
265 |
-
" state = discretize_state(state)\n",
|
266 |
-
" done = False\n",
|
267 |
-
" total_reward = 0\n",
|
268 |
-
"\n",
|
269 |
-
" while not done:\n",
|
270 |
-
" # Epsilon-greedy action selection\n",
|
271 |
-
" if np.random.uniform(0, 1) < epsilon:\n",
|
272 |
-
" action = np.random.choice(action_space)\n",
|
273 |
-
" else:\n",
|
274 |
-
" action = np.argmax(Q_table[state])\n",
|
275 |
-
"\n",
|
276 |
-
" # Take action\n",
|
277 |
-
" next_state, reward, done, _, _ = env.step(action)\n",
|
278 |
-
" next_state = discretize_state(next_state)\n",
|
279 |
-
" total_reward += reward\n",
|
280 |
-
"\n",
|
281 |
-
" # Update Q-value\n",
|
282 |
-
" Q_table[state + (action,)] += alpha * (\n",
|
283 |
-
" reward + gamma * np.max(Q_table[next_state]) - Q_table[state + (action,)]\n",
|
284 |
-
" )\n",
|
285 |
-
" state = next_state\n",
|
286 |
-
"\n",
|
287 |
-
" # Decay epsilon\n",
|
288 |
-
" epsilon = max(0.01, epsilon * epsilon_decay)\n",
|
289 |
-
"\n",
|
290 |
-
" # Log total reward\n",
|
291 |
-
" total_rewards.append(total_reward)\n",
|
292 |
-
"\n",
|
293 |
-
"# Save the model as a .pkl file\n",
|
294 |
-
"model_data = {\n",
|
295 |
-
" \"Q_table\": Q_table,\n",
|
296 |
-
" \"state_bins\": state_bins,\n",
|
297 |
-
" \"alpha\": alpha,\n",
|
298 |
-
" \"gamma\": gamma,\n",
|
299 |
-
" \"epsilon_decay\": epsilon_decay,\n",
|
300 |
-
"}\n",
|
301 |
-
"with open(\"q_learning_model.pkl\", \"wb\") as f:\n",
|
302 |
-
" pickle.dump(model_data, f)\n",
|
303 |
-
"\n",
|
304 |
-
"print(\"Model saved as 'q_learning_model.pkl'\")\n"
|
305 |
-
]
|
306 |
-
},
|
307 |
-
{
|
308 |
-
"cell_type": "code",
|
309 |
-
"execution_count": 7,
|
310 |
-
"metadata": {},
|
311 |
-
"outputs": [
|
312 |
-
{
|
313 |
-
"name": "stdout",
|
314 |
-
"output_type": "stream",
|
315 |
-
"text": [
|
316 |
-
"Total reward: -140.0\n"
|
317 |
-
]
|
318 |
-
},
|
319 |
-
{
|
320 |
-
"data": {
|
321 |
-
"image/png": "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",
|
322 |
-
"text/plain": [
|
323 |
-
"<Figure size 640x480 with 1 Axes>"
|
324 |
-
]
|
325 |
-
},
|
326 |
-
"metadata": {},
|
327 |
-
"output_type": "display_data"
|
328 |
-
}
|
329 |
-
],
|
330 |
-
"source": [
|
331 |
-
"from IPython.display import display, clear_output\n",
|
332 |
-
"import time\n",
|
333 |
-
"\n",
|
334 |
-
"# Initialize environment\n",
|
335 |
-
"state, _ = env.reset()\n",
|
336 |
-
"state = discretize_state(state)\n",
|
337 |
-
"done = False\n",
|
338 |
-
"total_reward = 0\n",
|
339 |
-
"\n",
|
340 |
-
"# Test the policy\n",
|
341 |
-
"while not done:\n",
|
342 |
-
" action = np.argmax(Q_table[state])\n",
|
343 |
-
" next_state, reward, done, truncated, _ = env.step(action)\n",
|
344 |
-
" state = discretize_state(next_state)\n",
|
345 |
-
" total_reward += reward\n",
|
346 |
-
"\n",
|
347 |
-
" # Render frame\n",
|
348 |
-
" frame = env.render()\n",
|
349 |
-
" plt.imshow(frame)\n",
|
350 |
-
" plt.axis(\"off\")\n",
|
351 |
-
" display(plt.gcf())\n",
|
352 |
-
" clear_output(wait=True)\n",
|
353 |
-
" time.sleep(0.3) # Add delay for smoother animation\n",
|
354 |
-
"\n",
|
355 |
-
"print(\"Total reward:\", total_reward)\n",
|
356 |
-
"env.close()\n"
|
357 |
-
]
|
358 |
-
},
|
359 |
-
{
|
360 |
-
"cell_type": "code",
|
361 |
-
"execution_count": 8,
|
362 |
-
"metadata": {},
|
363 |
-
"outputs": [
|
364 |
-
{
|
365 |
-
"name": "stdout",
|
366 |
-
"output_type": "stream",
|
367 |
-
"text": [
|
368 |
-
"Testing Episode 1\n"
|
369 |
-
]
|
370 |
-
},
|
371 |
-
{
|
372 |
-
"ename": "TypeError",
|
373 |
-
"evalue": "MountainCarEnv.render() got an unexpected keyword argument 'mode'",
|
374 |
-
"output_type": "error",
|
375 |
-
"traceback": [
|
376 |
-
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
|
377 |
-
"\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)",
|
378 |
-
"Cell \u001b[1;32mIn[8], line 38\u001b[0m\n\u001b[0;32m 35\u001b[0m total_reward \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m reward\n\u001b[0;32m 37\u001b[0m \u001b[38;5;66;03m# Native rendering\u001b[39;00m\n\u001b[1;32m---> 38\u001b[0m \u001b[43menv\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrender\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mhuman\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m 39\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;241m0.03\u001b[39m) \u001b[38;5;66;03m# Delay for smooth rendering\u001b[39;00m\n\u001b[0;32m 41\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTotal reward for Episode \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mepisode\u001b[38;5;250m \u001b[39m\u001b[38;5;241m+\u001b[39m\u001b[38;5;250m \u001b[39m\u001b[38;5;241m1\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtotal_reward\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
|
379 |
-
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\gym\\core.py:329\u001b[0m, in \u001b[0;36mWrapper.render\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 325\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrender\u001b[39m(\n\u001b[0;32m 326\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs\n\u001b[0;32m 327\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Optional[Union[RenderFrame, List[RenderFrame]]]:\n\u001b[0;32m 328\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Renders the environment.\"\"\"\u001b[39;00m\n\u001b[1;32m--> 329\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43menv\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrender\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
380 |
-
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\gym\\wrappers\\order_enforcing.py:51\u001b[0m, in \u001b[0;36mOrderEnforcing.render\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 46\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_disable_render_order_enforcing \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_has_reset:\n\u001b[0;32m 47\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m ResetNeeded(\n\u001b[0;32m 48\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCannot call `env.render()` before calling `env.reset()`, if this is a intended action, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 49\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mset `disable_render_order_enforcing=True` on the OrderEnforcer wrapper.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 50\u001b[0m )\n\u001b[1;32m---> 51\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43menv\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrender\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
381 |
-
"File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\gym\\wrappers\\env_checker.py:55\u001b[0m, in \u001b[0;36mPassiveEnvChecker.render\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m env_render_passive_checker(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39menv, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 54\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 55\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43menv\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrender\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
382 |
-
"\u001b[1;31mTypeError\u001b[0m: MountainCarEnv.render() got an unexpected keyword argument 'mode'"
|
383 |
-
]
|
384 |
-
}
|
385 |
-
],
|
386 |
-
"source": [
|
387 |
-
"import pickle\n",
|
388 |
-
"import time\n",
|
389 |
-
"\n",
|
390 |
-
"# Load the saved model\n",
|
391 |
-
"with open(\"q_learning_model.pkl\", \"rb\") as f:\n",
|
392 |
-
" model_data = pickle.load(f)\n",
|
393 |
-
"\n",
|
394 |
-
"# Extract the Q-table and state bins\n",
|
395 |
-
"Q_table = model_data[\"Q_table\"]\n",
|
396 |
-
"state_bins = model_data[\"state_bins\"]\n",
|
397 |
-
"\n",
|
398 |
-
"# Helper to discretize state space\n",
|
399 |
-
"def discretize_state(state):\n",
|
400 |
-
" state_low = env.observation_space.low\n",
|
401 |
-
" state_high = env.observation_space.high\n",
|
402 |
-
" bins = [np.linspace(state_low[i], state_high[i], state_bins[i]) for i in range(len(state))]\n",
|
403 |
-
" state_indices = [np.digitize(state[i], bins[i]) - 1 for i in range(len(state))]\n",
|
404 |
-
" return tuple(state_indices)\n",
|
405 |
-
"\n",
|
406 |
-
"# Number of episodes to test\n",
|
407 |
-
"test_episodes = 10\n",
|
408 |
-
"\n",
|
409 |
-
"for episode in range(test_episodes):\n",
|
410 |
-
" state, _ = env.reset()\n",
|
411 |
-
" state = discretize_state(state)\n",
|
412 |
-
" done = False\n",
|
413 |
-
" total_reward = 0\n",
|
414 |
-
"\n",
|
415 |
-
" print(f\"Testing Episode {episode + 1}\")\n",
|
416 |
-
"\n",
|
417 |
-
" while not done:\n",
|
418 |
-
" action = np.argmax(Q_table[state]) # Choose best action\n",
|
419 |
-
" next_state, reward, done, truncated, _ = env.step(action)\n",
|
420 |
-
" state = discretize_state(next_state)\n",
|
421 |
-
" total_reward += reward\n",
|
422 |
-
"\n",
|
423 |
-
" # Native rendering\n",
|
424 |
-
" env.render(mode=\"human\")\n",
|
425 |
-
" time.sleep(0.03) # Delay for smooth rendering\n",
|
426 |
-
"\n",
|
427 |
-
" print(f\"Total reward for Episode {episode + 1}: {total_reward}\")\n",
|
428 |
-
"\n",
|
429 |
-
"env.close()\n"
|
430 |
-
]
|
431 |
-
}
|
432 |
-
],
|
433 |
-
"metadata": {
|
434 |
-
"kernelspec": {
|
435 |
-
"display_name": "Python 3",
|
436 |
-
"language": "python",
|
437 |
-
"name": "python3"
|
438 |
-
},
|
439 |
-
"language_info": {
|
440 |
-
"codemirror_mode": {
|
441 |
-
"name": "ipython",
|
442 |
-
"version": 3
|
443 |
-
},
|
444 |
-
"file_extension": ".py",
|
445 |
-
"mimetype": "text/x-python",
|
446 |
-
"name": "python",
|
447 |
-
"nbconvert_exporter": "python",
|
448 |
-
"pygments_lexer": "ipython3",
|
449 |
-
"version": "3.11.9"
|
450 |
-
}
|
451 |
-
},
|
452 |
-
"nbformat": 4,
|
453 |
-
"nbformat_minor": 2
|
454 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|