├── DQN ├── .ipynb_checkpoints │ ├── Deep_Q_network-checkpoint.ipynb │ ├── dqn_cartpole-checkpoint.ipynb │ └── dqn_cnn-checkpoint.ipynb ├── dqn_cnn.ipynb ├── dqn_low_state.ipynb ├── models │ └── CartPole-v0.pth ├── rewards.npy └── testing.py ├── Model-Based-Learn ├── Makefile ├── __pycache__ │ └── lake_envs.cpython-36.pyc ├── collect_submission.sh ├── discrete_env.py ├── frozen_lake.py ├── lake_envs.py ├── requirements.txt └── vi_and_pi.py ├── Model-Free-Learn ├── custom_environment.py └── q_learning.py └── README.md /DQN/.ipynb_checkpoints/Deep_Q_network-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "import numpy as np\n", 11 | "import gym\n", 12 | "import torch.nn as nn\n", 13 | "import time\n", 14 | "import random\n", 15 | "import torch.optim as optim\n", 16 | "import math\n", 17 | "\n", 18 | "\n", 19 | "from IPython.display import clear_output\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "%matplotlib inline\n", 22 | "\n", 23 | "\n", 24 | "if torch.cuda.is_available():\n", 25 | " device = 'cuda'\n", 26 | "else:\n", 27 | " device = 'cpu'" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "# Network architecture for DQN\n", 37 | "class q_network(nn.Module):\n", 38 | " def __init__(self, observations, actions):\n", 39 | " super(q_network, self).__init__()\n", 40 | " self.network = nn.Sequential(\n", 41 | " nn.Linear(observations, 64),\n", 42 | " nn.ReLU(),\n", 43 | " nn.Linear(64, 32),\n", 44 | " nn.ReLU(),\n", 45 | " nn.Linear(32, actions),\n", 46 | " )\n", 47 | " def forward(self, x):\n", 48 | " return self.network(x)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "name": "stdout", 58 | "output_type": "stream", 59 | "text": [ 60 | "0.95\n" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "done = False\n", 66 | "learning_rate = 0.0001\n", 67 | "discount= 0.99\n", 68 | "epsilon = 0.95\n", 69 | "epsilon_decay = 0.9999\n", 70 | "min_epsilon = 0.1\n", 71 | "n_episodes = 1000\n", 72 | "batch_size = 128\n", 73 | "Reward_Path = 'rewards.npy'\n", 74 | "env_name = 'CartPole-v0'\n", 75 | "model_path = './models/' + env_name + '.pth'\n", 76 | "\n", 77 | "print(epsilon)" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 4, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "data": { 87 | "text/plain": [ 88 | "array([-0.00270691, -0.01540017, 0.0037088 , 0.01664034])" 89 | ] 90 | }, 91 | "execution_count": 4, 92 | "metadata": {}, 93 | "output_type": "execute_result" 94 | } 95 | ], 96 | "source": [ 97 | "# creating a cartpole environment\n", 98 | "env = gym.make(env_name)\n", 99 | "env.reset()" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 5, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/plain": [ 110 | "'\\n# Testing the environment with random actions\\nfor _ in range(1000):\\n env.render(100)\\n time.sleep(0.05)\\n env.step(env.action_space.sample())\\nenv.close()\\n'" 111 | ] 112 | }, 113 | "execution_count": 5, 114 | "metadata": {}, 115 | "output_type": "execute_result" 116 | } 117 | ], 118 | "source": [ 119 | "'''\n", 120 | "# Testing the environment with random actions\n", 121 | "for _ in range(1000):\n", 122 | " env.render(100)\n", 123 | " time.sleep(0.05)\n", 124 | " env.step(env.action_space.sample())\n", 125 | "env.close()\n", 126 | "'''" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 6, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "# for experience replay\n", 136 | "from collections import deque\n", 137 | "\n", 138 | "class Exp_Replay:\n", 139 | " def __init__(self, limit):\n", 140 | " self.memory = deque(maxlen=limit) \n", 141 | " \n", 142 | " def push(self, state, action, reward, next_state, done):\n", 143 | " state = np.expand_dims(state,0)\n", 144 | " next_state = np.expand_dims(next_state,0)\n", 145 | "\n", 146 | " self.memory.append((state, action, reward, next_state, done))\n", 147 | " \n", 148 | " def sample(self, batch_size):\n", 149 | " state, action, reward, next_state, done = zip(*random.sample(self.memory, batch_size))\n", 150 | " return np.concatenate(state), action, reward, np.concatenate(next_state), done\n", 151 | " \n", 152 | " def __len__(self):\n", 153 | " return len(self.memory)" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 7, 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "" 165 | ] 166 | }, 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "# creating object for network\n", 174 | "q_hat = q_network(env.observation_space.shape[0], env.action_space.n).to(device)\n", 175 | "q_hat_target = q_network(env.observation_space.shape[0], env.action_space.n).to(device)\n", 176 | "\n", 177 | "q_hat_target.load_state_dict(q_hat.state_dict())" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 8, 183 | "metadata": {}, 184 | "outputs": [], 185 | "source": [ 186 | "criterion = nn.MSELoss().to(device)\n", 187 | "optimizer = optim.RMSprop(q_hat.parameters(), lr = learning_rate)\n", 188 | "\n", 189 | "memory = Exp_Replay(10000)" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 9, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "def plot(episode, avg_loss, eps, eps_rewards):\n", 199 | " clear_output(True)\n", 200 | " plt.figure(figsize=(20,5))\n", 201 | " plt.subplot(131)\n", 202 | " plt.title('Episode: %5d | Epsilon: %4.2f | Avg. Reward: %5.2f'%(episode, eps, np.mean(ep_rewards[-50:])))\n", 203 | " plt.plot(eps_rewards)\n", 204 | " plt.subplot(132)\n", 205 | " plt.title('loss | Average Loss: %5.2f'%np.mean(ep_loss[-50:]))\n", 206 | " plt.plot(ep_loss)\n", 207 | " plt.show()" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 10, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "def action_select(state, epsilon):\n", 217 | " \n", 218 | " if random.random() < epsilon:\n", 219 | " action = env.action_space.sample()\n", 220 | " else:\n", 221 | " state = torch.FloatTensor(state).unsqueeze(0).to(device) \n", 222 | " action = torch.argmax(q_hat(state)).item()\n", 223 | " \n", 224 | " return action" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 11, 230 | "metadata": {}, 231 | "outputs": [], 232 | "source": [ 233 | "def compute_td_loss(batch_size,criterion, optimizer, target_net, loss, limit):\n", 234 | " if limit< batch_size:\n", 235 | " return 0\n", 236 | " \n", 237 | " state, action, reward, next_state, done = memory.sample(batch_size)\n", 238 | "\n", 239 | " state = torch.FloatTensor(np.float32(state)).to(device)\n", 240 | " next_state = torch.FloatTensor(np.float32(next_state)).to(device)\n", 241 | " action = torch.LongTensor(action).to(device)\n", 242 | " reward = torch.FloatTensor(reward).to(device)\n", 243 | " done = torch.FloatTensor(done).to(device)\n", 244 | " \n", 245 | " current_q = q_hat(state).gather(1, action.unsqueeze(1)).squeeze(1)\n", 246 | " \n", 247 | " \n", 248 | " next_q = target_net(next_state).max(dim=1)[0]\n", 249 | " q_target = reward + discount*next_q*(1 - done)\n", 250 | " \n", 251 | " tdloss = criterion(current_q, q_target.detach())\n", 252 | " loss += tdloss.item()\n", 253 | " \n", 254 | " optimizer.zero_grad()\n", 255 | " tdloss.backward()\n", 256 | " optimizer.step()\n", 257 | " \n", 258 | " return loss" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 12, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "data": { 268 | "image/png": "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\n", 269 | "text/plain": [ 270 | "
" 271 | ] 272 | }, 273 | "metadata": { 274 | "needs_background": "light" 275 | }, 276 | "output_type": "display_data" 277 | } 278 | ], 279 | "source": [ 280 | "avg_loss = 0\n", 281 | "steps = 200\n", 282 | "ep_rewards = np.array([])\n", 283 | "ep_loss = np.array([])\n", 284 | "\n", 285 | "# Training the agent\n", 286 | "for episode in range(n_episodes):\n", 287 | " state = env.reset()\n", 288 | " ep_reward = 0\n", 289 | " running_loss = 0\n", 290 | " done = False\n", 291 | " \n", 292 | " while not done:\n", 293 | " \n", 294 | " action = action_select(state, epsilon)\n", 295 | " epsilon = max(epsilon*epsilon_decay, min_epsilon)\n", 296 | " \n", 297 | " \n", 298 | " next_state, reward, done, _ = env.step(action)\n", 299 | " \n", 300 | " ep_reward += reward\n", 301 | " memory.push(state, action, reward, next_state, done)\n", 302 | " \n", 303 | " state = next_state\n", 304 | " \n", 305 | " running_loss = compute_td_loss(batch_size,criterion, optimizer, q_hat_target, running_loss, len(memory))\n", 306 | " \n", 307 | " ep_rewards = np.append(ep_rewards, ep_reward)\n", 308 | " ep_loss = np.append(ep_loss, running_loss)\n", 309 | " q_hat_target.load_state_dict(q_hat.state_dict())\n", 310 | " \n", 311 | " if episode%50==0:\n", 312 | " plot(episode, ep_loss, epsilon, ep_rewards)\n", 313 | " avg_loss = 0\n", 314 | " ep_reward =0\n", 315 | " np.save(Reward_Path, ep_rewards)\n", 316 | " \n", 317 | "env.close()" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": 14, 323 | "metadata": {}, 324 | "outputs": [ 325 | { 326 | "data": { 327 | "text/plain": [ 328 | "" 329 | ] 330 | }, 331 | "execution_count": 14, 332 | "metadata": {}, 333 | "output_type": "execute_result" 334 | } 335 | ], 336 | "source": [ 337 | "# Save model\n", 338 | "torch.save(q_hat_target.state_dict(),model_path)\n", 339 | "\n", 340 | "q_hat_target = q_network(env.observation_space.shape[0], env.action_space.n).to(device)\n", 341 | "q_hat_target.load_state_dict(torch.load(model_path))" 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": 16, 347 | "metadata": {}, 348 | "outputs": [ 349 | { 350 | "name": "stdout", 351 | "output_type": "stream", 352 | "text": [ 353 | "Total Reward: 200.0\n" 354 | ] 355 | } 356 | ], 357 | "source": [ 358 | "import gym\n", 359 | "import time\n", 360 | "\n", 361 | "env = gym.make(env_name)\n", 362 | "# env.reset()\n", 363 | "state = env.reset()\n", 364 | "done = False\n", 365 | "testing_epsilon = 0.05\n", 366 | "tot_reward = 0\n", 367 | "\n", 368 | "for step in range(2000):\n", 369 | " state = torch.from_numpy(state).float().to(device)\n", 370 | " env.render()\n", 371 | " action = torch.argmax(q_hat_target(state)).item()\n", 372 | " state, reward, done, _ = env.step(action)\n", 373 | " tot_reward += reward\n", 374 | " if done:\n", 375 | "# print('DONE')\n", 376 | " break\n", 377 | " time.sleep(.05)\n", 378 | " \n", 379 | "print('Total Reward:', tot_reward)\n", 380 | " \n", 381 | "env.close()" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": null, 387 | "metadata": {}, 388 | "outputs": [], 389 | "source": [] 390 | } 391 | ], 392 | "metadata": { 393 | "kernelspec": { 394 | "display_name": "Python 3", 395 | "language": "python", 396 | "name": "python3" 397 | }, 398 | "language_info": { 399 | "codemirror_mode": { 400 | "name": "ipython", 401 | "version": 3 402 | }, 403 | "file_extension": ".py", 404 | "mimetype": "text/x-python", 405 | "name": "python", 406 | "nbconvert_exporter": "python", 407 | "pygments_lexer": "ipython3", 408 | "version": "3.6.9" 409 | } 410 | }, 411 | "nbformat": 4, 412 | "nbformat_minor": 2 413 | } 414 | -------------------------------------------------------------------------------- /DQN/dqn_cnn.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "import torch.nn as nn\n", 11 | "import torch.optim as optim\n", 12 | "import torch.autograd as autograd\n", 13 | "import torch.nn.functional as F\n", 14 | "import torchvision.transforms as T\n", 15 | "from collections import namedtuple\n", 16 | "\n", 17 | "import gym\n", 18 | "import numpy as np\n", 19 | "import time\n", 20 | "import cv2\n", 21 | "\n", 22 | "import random\n", 23 | "import math\n", 24 | "from itertools import count\n", 25 | "\n", 26 | "\n", 27 | "from PIL import Image\n", 28 | "import matplotlib\n", 29 | "import matplotlib.pyplot as plt\n", 30 | "\n", 31 | "%matplotlib inline\n", 32 | "is_ipython = 'inline' in matplotlib.get_backend()\n", 33 | "if is_ipython:\n", 34 | " from IPython import display\n", 35 | "\n", 36 | "plt.ion()" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "Checking the Environment" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 2, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "data": { 53 | "text/plain": [ 54 | "array([-0.01334107, -0.03290919, 0.02486646, -0.02966823])" 55 | ] 56 | }, 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "output_type": "execute_result" 60 | } 61 | ], 62 | "source": [ 63 | "env_id = 'CartPole-v0'\n", 64 | "\n", 65 | "env = gym.make(env_id)\n", 66 | "env.reset()\n", 67 | "# for _ in range(400):\n", 68 | "# env.render()\n", 69 | "# time.sleep(0.01)\n", 70 | "# env.step(env.action_space.sample()) # take random actions\n", 71 | "# env.close()" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "Checking and using if CUDA is available()" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 3, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "name": "stdout", 88 | "output_type": "stream", 89 | "text": [ 90 | "cuda\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "\n", 96 | "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", 97 | "print(device)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "Experience Replay to have memory for model" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 4, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "from collections import deque\n", 114 | "\n", 115 | "class exp_replay(object):\n", 116 | " def __init__(self, capacity):\n", 117 | " self.buffer = deque(maxlen=capacity)\n", 118 | "\n", 119 | " def push(self, state, action, reward, next_state, done):\n", 120 | " self.buffer.append((state, action, reward, next_state, done))\n", 121 | "\n", 122 | " def sample(self, batch_size):\n", 123 | " state, action, reward, next_state, done = zip(*random.sample(self.buffer, batch_size))\n", 124 | " return np.concatenate(state), action, reward, np.concatenate(next_state), done\n", 125 | "\n", 126 | " def __len__(self):\n", 127 | " return len(self.buffer)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 5, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "epsilon = 1\n", 137 | "epsilon_min = 0.01\n", 138 | "epsilon_decay = 3000\n", 139 | "gamma = 0.999\n", 140 | "batch_size = 128\n", 141 | "\n", 142 | "replay_buffer_size = 10000\n", 143 | "learning_rate = 0.0001\n", 144 | "num_episodes = 500\n", 145 | "target_update_freq = 10\n" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 6, 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [ 154 | "def get_cart_loc(screen_width):\n", 155 | " world_width = env.x_threshold*2\n", 156 | " scale = screen_width/world_width\n", 157 | "# print(scale)\n", 158 | "# print(int(env.state[0]*scale + screen_width/2.0))\n", 159 | " return int(env.state[0]*scale + screen_width/2.0)" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 7, 165 | "metadata": {}, 166 | "outputs": [], 167 | "source": [ 168 | "# def get_screen():\n", 169 | "# screen = env.render(mode='rgb_array')\n", 170 | "# screen_1 = cv2.cvtColor(screen, cv2.COLOR_RGB2GRAY)\n", 171 | "# r_screen = cv2.resize(screen_1, (84,84), interpolation=cv2.INTER_AREA)\n", 172 | "# r_screen = np.array(r_screen)\n", 173 | "# r_screen = np.expand_dims(r_screen,axis=0)\n", 174 | "# r_screen = torch.Tensor(r_screen)\n", 175 | "# return r_screen.unsqueeze(0).to(device)\n" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 8, 181 | "metadata": {}, 182 | "outputs": [ 183 | { 184 | "data": { 185 | "image/png": "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\n", 186 | "text/plain": [ 187 | "
" 188 | ] 189 | }, 190 | "metadata": { 191 | "needs_background": "light" 192 | }, 193 | "output_type": "display_data" 194 | } 195 | ], 196 | "source": [ 197 | "def get_screen():\n", 198 | " screen = env.render(mode = 'rgb_array')\n", 199 | " ### Capture screen return in shape (H,W,C) = (400,600,3)\n", 200 | " \n", 201 | " ### Cart is in lower half of screen. We remove the unuseful part of environment\n", 202 | " screen_height, screen_width, _ = screen.shape\n", 203 | " screen = screen[int(screen_height*0.4):int(screen_height*0.8),:] # Screen Shape is now (160,600,3)\n", 204 | "# print(screen.shape)\n", 205 | "\n", 206 | " view_width = int(screen_width*0.6) # width required when pole becomes horizontal. \n", 207 | "# print(view_width//2)\n", 208 | " cart_loc = get_cart_loc(screen_width)\n", 209 | "\n", 210 | " ### Extract screen where cart is locaed and discard the remaining part\n", 211 | " if cart_loc < view_width//2:\n", 212 | " slice_range = slice(view_width)\n", 213 | " elif cart_loc > (screen_width - view_width//2):\n", 214 | " slice_range = slice(-view_width, None)\n", 215 | " else:\n", 216 | " slice_range = slice(cart_loc - view_width//2, cart_loc + view_width//2)\n", 217 | "# print(slice_range)\n", 218 | " screen = screen[:,slice_range,:]\n", 219 | "# print(screen.shape)\n", 220 | " \n", 221 | " width = int(screen.shape[1] * 30 / 100)\n", 222 | " height = int(screen.shape[0] * 30 / 100)\n", 223 | " dim = (width, height)\n", 224 | "# print(dim)\n", 225 | " # resize image\n", 226 | " screen = cv2.resize(screen, dim, interpolation = cv2.INTER_AREA)\n", 227 | "# print(screen.shape)\n", 228 | " ### Pytorch work wwith format (C,H,W). So we take transpose\n", 229 | " screen = screen.transpose((2,0,1))\n", 230 | "# \n", 231 | " \n", 232 | " ### Convert ot float and normalize\n", 233 | " screen = np.ascontiguousarray(screen, dtype = np.float32)/255\n", 234 | " screen=np.expand_dims(screen,0)\n", 235 | " \n", 236 | " ### Convert to tensor\n", 237 | " screen = torch.from_numpy(screen)\n", 238 | "# print(screen.shape)\n", 239 | " return screen\n", 240 | " \n", 241 | "\n", 242 | "### Image appears to be blur due to interpolation\n", 243 | "plt.figure()\n", 244 | "plt.imshow(get_screen().cpu().squeeze(0).permute(1, 2, 0).numpy())\n", 245 | "plt.title('Extracted screen')\n", 246 | "plt.show()" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "Deep Q-Network" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 9, 259 | "metadata": {}, 260 | "outputs": [], 261 | "source": [ 262 | "class dqn(nn.Module):\n", 263 | " def __init__(self, input_shape, num_actions):\n", 264 | " super(dqn, self).__init__()\n", 265 | " self.device='cuda' if torch.cuda.is_available() else 'cpu'\n", 266 | " self.input_shape = input_shape\n", 267 | " self.num_actions = num_actions\n", 268 | " \n", 269 | " self.features = nn.Sequential(\n", 270 | " nn.Conv2d(input_shape[0], 32, kernel_size=8, stride=4),\n", 271 | " nn.ReLU(),\n", 272 | " nn.Conv2d(32, 64, kernel_size=4, stride=2),\n", 273 | " nn.ReLU(),\n", 274 | " nn.Conv2d(64, 64, kernel_size=3, stride=1),\n", 275 | " nn.ReLU()\n", 276 | " )\n", 277 | " \n", 278 | " self.fc = nn.Sequential(\n", 279 | " nn.Linear(self.feature_size(), 512),\n", 280 | " nn.ReLU(),\n", 281 | " nn.Linear(512, self.num_actions)\n", 282 | " )\n", 283 | " def forward(self, x):\n", 284 | " x=x.to(self.device)\n", 285 | " x = self.features(x)\n", 286 | " x = x.view(x.size(0), -1)\n", 287 | " x = self.fc(x)\n", 288 | " return x\n", 289 | " \n", 290 | " def feature_size(self):\n", 291 | " return self.features(torch.zeros(1, *self.input_shape)).view(1, -1).size(1)" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 10, 297 | "metadata": {}, 298 | "outputs": [], 299 | "source": [ 300 | "init_screen = get_screen()\n", 301 | "init_screen = init_screen.squeeze(0)\n", 302 | "# print(init_screen.shape[2])\n", 303 | "\n", 304 | "\n", 305 | "num_actions = env.action_space.n\n", 306 | "policy_net = dqn(init_screen.shape, num_actions).to(device)\n", 307 | "target_net = dqn(init_screen.shape, num_actions).to(device)\n", 308 | "\n", 309 | "target_net.load_state_dict(policy_net.state_dict())\n", 310 | "target_net.eval()\n", 311 | "\n", 312 | "criterion = nn.MSELoss()\n", 313 | "optimizer = optim.Adam(policy_net.parameters())\n", 314 | "\n", 315 | "memory = exp_replay(10000)" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 11, 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [ 324 | "steps_done = 0\n", 325 | "def select_action(state, epsilon):\n", 326 | " global steps_done\n", 327 | " sample = random.random()\n", 328 | "\n", 329 | " if sample < epsilon:\n", 330 | " action = random.randrange(env.action_space.n) \n", 331 | " else:\n", 332 | " q_val = policy_net(state)\n", 333 | " action = torch.argmax(q_val).item()\n", 334 | " \n", 335 | " return action\n", 336 | "\n", 337 | "\n", 338 | "def plot_durations(scores,pause):\n", 339 | " plt.ion()\n", 340 | " plt.figure(2)\n", 341 | " plt.clf()\n", 342 | "\n", 343 | " durations_t = torch.tensor(scores, dtype=torch.float)\n", 344 | " plt.title('Training...')\n", 345 | " plt.xlabel('Episode')\n", 346 | " plt.ylabel('Scores')\n", 347 | " plt.plot(durations_t.numpy())\n", 348 | " # Take 20 episode averages and plot them too\n", 349 | " if len(durations_t) >= 20:\n", 350 | " means = durations_t.unfold(0, 20, 1).mean(1).view(-1)\n", 351 | " means = torch.cat((torch.zeros(19), means))\n", 352 | " plt.plot(means.numpy())\n", 353 | " if pause< 25:\n", 354 | " plt.pause(pause) # pause a bit so that plots are updated\n", 355 | " if is_ipython:\n", 356 | " display.clear_output(wait=True)\n", 357 | " display.display(plt.gcf())" 358 | ] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "execution_count": 12, 363 | "metadata": {}, 364 | "outputs": [], 365 | "source": [ 366 | "def learn():\n", 367 | " if len(memory) < batch_size:\n", 368 | " return\n", 369 | " \n", 370 | " \n", 371 | " state, action, reward, next_state, done = memory.sample(batch_size)\n", 372 | " \n", 373 | " \n", 374 | " state=torch.FloatTensor(state)\n", 375 | " action=torch.tensor(action).to(device)\n", 376 | " reward=torch.tensor(reward).to(device)\n", 377 | " next_state=torch.FloatTensor(next_state)\n", 378 | " done=torch.tensor(done).float().to(device)\n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | "# state_batch, action_batch, reward_batch, next_state_batch, done_batch = memory.sample(batch_size)\n", 383 | "# reward_batch = torch.tensor(reward_batch, device = device)\n", 384 | "# done_batch = torch.tensor(done_batch, device = device)\n", 385 | "# # print(done_batch)\n", 386 | "# action_batch = torch.tensor(action_batch,device = device)\n", 387 | "# # print(action_batch.size())\n", 388 | "# done_batch = torch.tensor(done, device = device, dtype = torch.float)\n", 389 | "# # print(done_batch)\n", 390 | "\n", 391 | " q_vals = policy_net(state)\n", 392 | " q_next = target_net(next_state).detach()\n", 393 | "# # print(q_val.size, q_target.size)\n", 394 | "# batch_index = np.arange(batch_size)\n", 395 | " q_val = q_vals.gather(1, action.unsqueeze(1)).squeeze(1)\n", 396 | " q_next_val = q_next.max(1)[0]\n", 397 | " \n", 398 | "\n", 399 | " expected_q_val = reward + gamma*q_next_val*(1-done)\n", 400 | " \n", 401 | " loss = criterion(q_val, expected_q_val)\n", 402 | " optimizer.zero_grad()\n", 403 | " loss.backward()\n", 404 | " optimizer.step()\n", 405 | " \n", 406 | " return loss" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 13, 412 | "metadata": { 413 | "scrolled": true 414 | }, 415 | "outputs": [ 416 | { 417 | "data": { 418 | "text/plain": [ 419 | "
" 420 | ] 421 | }, 422 | "metadata": {}, 423 | "output_type": "display_data" 424 | }, 425 | { 426 | "name": "stdout", 427 | "output_type": "stream", 428 | "text": [ 429 | "Complete\n" 430 | ] 431 | }, 432 | { 433 | "data": { 434 | "text/plain": [ 435 | "
" 436 | ] 437 | }, 438 | "metadata": {}, 439 | "output_type": "display_data" 440 | } 441 | ], 442 | "source": [ 443 | "ep_reward = []\n", 444 | "num_frame = 120\n", 445 | "\n", 446 | "\n", 447 | "epsilon_by_frame = lambda frame_idx: epsilon_min + (epsilon - epsilon_min) * math.exp(-1. * frame_idx / epsilon_decay)\n", 448 | "\n", 449 | "\n", 450 | "\n", 451 | "steps = 0\n", 452 | "for ep in range(1, num_frame+1):\n", 453 | " env.reset()\n", 454 | " last_screen = get_screen()\n", 455 | " current_screen = get_screen()\n", 456 | " state = current_screen - last_screen\n", 457 | " done = 0\n", 458 | " total_reward = 0\n", 459 | " while not done:\n", 460 | " \n", 461 | " epsilon = epsilon_by_frame(steps)\n", 462 | " steps += 1\n", 463 | " \n", 464 | " action = select_action(state, epsilon)\n", 465 | " \n", 466 | " _, reward, done, _ = env.step(action)\n", 467 | "# next_state = torch.tensor(next_state, device = device, dtype = torch.float)\n", 468 | " # Observe new state\n", 469 | " last_screen = current_screen\n", 470 | " current_screen = get_screen()\n", 471 | " next_state = current_screen - last_screen\n", 472 | " \n", 473 | " \n", 474 | " memory.push(state, action, reward, next_state, done)\n", 475 | " loss = learn() # Learning of model with help of experience replay\n", 476 | " \n", 477 | " total_reward += reward\n", 478 | " state = next_state\n", 479 | "\n", 480 | " \n", 481 | " ep_reward.append(total_reward)\n", 482 | " # Update the target network, copying all weights and biases in DQN\n", 483 | " if ep % target_update_freq == 0:\n", 484 | " target_net.load_state_dict(policy_net.state_dict())\n", 485 | " plot_durations(ep_reward,2)\n", 486 | "print('Complete')\n", 487 | "env.close()" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": 14, 493 | "metadata": {}, 494 | "outputs": [ 495 | { 496 | "data": { 497 | "image/png": "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\n", 498 | "text/plain": [ 499 | "
" 500 | ] 501 | }, 502 | "metadata": { 503 | "needs_background": "light" 504 | }, 505 | "output_type": "display_data" 506 | } 507 | ], 508 | "source": [ 509 | "plot_durations(ep_reward,25)" 510 | ] 511 | }, 512 | { 513 | "cell_type": "code", 514 | "execution_count": null, 515 | "metadata": {}, 516 | "outputs": [], 517 | "source": [] 518 | }, 519 | { 520 | "cell_type": "code", 521 | "execution_count": null, 522 | "metadata": {}, 523 | "outputs": [], 524 | "source": [] 525 | }, 526 | { 527 | "cell_type": "code", 528 | "execution_count": null, 529 | "metadata": {}, 530 | "outputs": [], 531 | "source": [] 532 | } 533 | ], 534 | "metadata": { 535 | "kernelspec": { 536 | "display_name": "Python 3", 537 | "language": "python", 538 | "name": "python3" 539 | }, 540 | "language_info": { 541 | "codemirror_mode": { 542 | "name": "ipython", 543 | "version": 3 544 | }, 545 | "file_extension": ".py", 546 | "mimetype": "text/x-python", 547 | "name": "python", 548 | "nbconvert_exporter": "python", 549 | "pygments_lexer": "ipython3", 550 | "version": "3.6.9" 551 | } 552 | }, 553 | "nbformat": 4, 554 | "nbformat_minor": 2 555 | } 556 | -------------------------------------------------------------------------------- /DQN/dqn_low_state.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import torch\n", 10 | "import numpy as np\n", 11 | "import gym\n", 12 | "import torch.nn as nn\n", 13 | "import time\n", 14 | "import random\n", 15 | "import torch.optim as optim\n", 16 | "import math\n", 17 | "\n", 18 | "\n", 19 | "from IPython.display import clear_output\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "%matplotlib inline\n", 22 | "\n", 23 | "\n", 24 | "if torch.cuda.is_available():\n", 25 | " device = 'cuda'\n", 26 | "else:\n", 27 | " device = 'cpu'" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "# Network architecture for DQN\n", 37 | "class q_network(nn.Module):\n", 38 | " def __init__(self, observations, actions):\n", 39 | " super(q_network, self).__init__()\n", 40 | " self.network = nn.Sequential(\n", 41 | " nn.Linear(observations, 64),\n", 42 | " nn.ReLU(),\n", 43 | " nn.Linear(64, 32),\n", 44 | " nn.ReLU(),\n", 45 | " nn.Linear(32, actions),\n", 46 | " )\n", 47 | " def forward(self, x):\n", 48 | " return self.network(x)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "name": "stdout", 58 | "output_type": "stream", 59 | "text": [ 60 | "0.95\n" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "done = False\n", 66 | "learning_rate = 0.0001\n", 67 | "discount= 0.99\n", 68 | "epsilon = 0.95\n", 69 | "epsilon_decay = 0.9999\n", 70 | "min_epsilon = 0.1\n", 71 | "n_episodes = 1000\n", 72 | "batch_size = 128\n", 73 | "Reward_Path = 'rewards.npy'\n", 74 | "env_name = 'CartPole-v0'\n", 75 | "model_path = './models/' + env_name + '.pth'\n", 76 | "\n", 77 | "print(epsilon)" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 4, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "data": { 87 | "text/plain": [ 88 | "array([-0.00270691, -0.01540017, 0.0037088 , 0.01664034])" 89 | ] 90 | }, 91 | "execution_count": 4, 92 | "metadata": {}, 93 | "output_type": "execute_result" 94 | } 95 | ], 96 | "source": [ 97 | "# creating a cartpole environment\n", 98 | "env = gym.make(env_name)\n", 99 | "env.reset()" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 5, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/plain": [ 110 | "'\\n# Testing the environment with random actions\\nfor _ in range(1000):\\n env.render(100)\\n time.sleep(0.05)\\n env.step(env.action_space.sample())\\nenv.close()\\n'" 111 | ] 112 | }, 113 | "execution_count": 5, 114 | "metadata": {}, 115 | "output_type": "execute_result" 116 | } 117 | ], 118 | "source": [ 119 | "'''\n", 120 | "# Testing the environment with random actions\n", 121 | "for _ in range(1000):\n", 122 | " env.render(100)\n", 123 | " time.sleep(0.05)\n", 124 | " env.step(env.action_space.sample())\n", 125 | "env.close()\n", 126 | "'''" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 6, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "# for experience replay\n", 136 | "from collections import deque\n", 137 | "\n", 138 | "class Exp_Replay:\n", 139 | " def __init__(self, limit):\n", 140 | " self.memory = deque(maxlen=limit) \n", 141 | " \n", 142 | " def push(self, state, action, reward, next_state, done):\n", 143 | " state = np.expand_dims(state,0)\n", 144 | " next_state = np.expand_dims(next_state,0)\n", 145 | "\n", 146 | " self.memory.append((state, action, reward, next_state, done))\n", 147 | " \n", 148 | " def sample(self, batch_size):\n", 149 | " state, action, reward, next_state, done = zip(*random.sample(self.memory, batch_size))\n", 150 | " return np.concatenate(state), action, reward, np.concatenate(next_state), done\n", 151 | " \n", 152 | " def __len__(self):\n", 153 | " return len(self.memory)" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 7, 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "" 165 | ] 166 | }, 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "# creating object for network\n", 174 | "q_hat = q_network(env.observation_space.shape[0], env.action_space.n).to(device)\n", 175 | "q_hat_target = q_network(env.observation_space.shape[0], env.action_space.n).to(device)\n", 176 | "\n", 177 | "q_hat_target.load_state_dict(q_hat.state_dict())" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 8, 183 | "metadata": {}, 184 | "outputs": [], 185 | "source": [ 186 | "criterion = nn.MSELoss().to(device)\n", 187 | "optimizer = optim.RMSprop(q_hat.parameters(), lr = learning_rate)\n", 188 | "\n", 189 | "memory = Exp_Replay(10000)" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 9, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "def plot(episode, avg_loss, eps, eps_rewards):\n", 199 | " clear_output(True)\n", 200 | " plt.figure(figsize=(20,5))\n", 201 | " plt.subplot(131)\n", 202 | " plt.title('Episode: %5d | Epsilon: %4.2f | Avg. Reward: %5.2f'%(episode, eps, np.mean(ep_rewards[-50:])))\n", 203 | " plt.plot(eps_rewards)\n", 204 | " plt.subplot(132)\n", 205 | " plt.title('loss | Average Loss: %5.2f'%np.mean(ep_loss[-50:]))\n", 206 | " plt.plot(ep_loss)\n", 207 | " plt.show()" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 10, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "def action_select(state, epsilon):\n", 217 | " \n", 218 | " if random.random() < epsilon:\n", 219 | " action = env.action_space.sample()\n", 220 | " else:\n", 221 | " state = torch.FloatTensor(state).unsqueeze(0).to(device) \n", 222 | " action = torch.argmax(q_hat(state)).item()\n", 223 | " \n", 224 | " return action" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 11, 230 | "metadata": {}, 231 | "outputs": [], 232 | "source": [ 233 | "def compute_td_loss(batch_size,criterion, optimizer, target_net, loss, limit):\n", 234 | " if limit< batch_size:\n", 235 | " return 0\n", 236 | " \n", 237 | " state, action, reward, next_state, done = memory.sample(batch_size)\n", 238 | "\n", 239 | " state = torch.FloatTensor(np.float32(state)).to(device)\n", 240 | " next_state = torch.FloatTensor(np.float32(next_state)).to(device)\n", 241 | " action = torch.LongTensor(action).to(device)\n", 242 | " reward = torch.FloatTensor(reward).to(device)\n", 243 | " done = torch.FloatTensor(done).to(device)\n", 244 | " \n", 245 | " current_q = q_hat(state).gather(1, action.unsqueeze(1)).squeeze(1)\n", 246 | " \n", 247 | " \n", 248 | " next_q = target_net(next_state).max(dim=1)[0]\n", 249 | " q_target = reward + discount*next_q*(1 - done)\n", 250 | " \n", 251 | " tdloss = criterion(current_q, q_target.detach())\n", 252 | " loss += tdloss.item()\n", 253 | " \n", 254 | " optimizer.zero_grad()\n", 255 | " tdloss.backward()\n", 256 | " optimizer.step()\n", 257 | " \n", 258 | " return loss" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": 12, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "data": { 268 | "image/png": "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\n", 269 | "text/plain": [ 270 | "
" 271 | ] 272 | }, 273 | "metadata": { 274 | "needs_background": "light" 275 | }, 276 | "output_type": "display_data" 277 | } 278 | ], 279 | "source": [ 280 | "avg_loss = 0\n", 281 | "steps = 200\n", 282 | "ep_rewards = np.array([])\n", 283 | "ep_loss = np.array([])\n", 284 | "\n", 285 | "# Training the agent\n", 286 | "for episode in range(n_episodes):\n", 287 | " state = env.reset()\n", 288 | " ep_reward = 0\n", 289 | " running_loss = 0\n", 290 | " done = False\n", 291 | " \n", 292 | " while not done:\n", 293 | " \n", 294 | " action = action_select(state, epsilon)\n", 295 | " epsilon = max(epsilon*epsilon_decay, min_epsilon)\n", 296 | " \n", 297 | " \n", 298 | " next_state, reward, done, _ = env.step(action)\n", 299 | " \n", 300 | " ep_reward += reward\n", 301 | " memory.push(state, action, reward, next_state, done)\n", 302 | " \n", 303 | " state = next_state\n", 304 | " \n", 305 | " running_loss = compute_td_loss(batch_size,criterion, optimizer, q_hat_target, running_loss, len(memory))\n", 306 | " \n", 307 | " ep_rewards = np.append(ep_rewards, ep_reward)\n", 308 | " ep_loss = np.append(ep_loss, running_loss)\n", 309 | " q_hat_target.load_state_dict(q_hat.state_dict())\n", 310 | " \n", 311 | " if episode%50==0:\n", 312 | " plot(episode, ep_loss, epsilon, ep_rewards)\n", 313 | " avg_loss = 0\n", 314 | " ep_reward =0\n", 315 | " np.save(Reward_Path, ep_rewards)\n", 316 | " \n", 317 | "env.close()" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": 14, 323 | "metadata": {}, 324 | "outputs": [ 325 | { 326 | "data": { 327 | "text/plain": [ 328 | "" 329 | ] 330 | }, 331 | "execution_count": 14, 332 | "metadata": {}, 333 | "output_type": "execute_result" 334 | } 335 | ], 336 | "source": [ 337 | "# Save model\n", 338 | "torch.save(q_hat_target.state_dict(),model_path)\n", 339 | "\n", 340 | "q_hat_target = q_network(env.observation_space.shape[0], env.action_space.n).to(device)\n", 341 | "q_hat_target.load_state_dict(torch.load(model_path))" 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": 16, 347 | "metadata": {}, 348 | "outputs": [ 349 | { 350 | "name": "stdout", 351 | "output_type": "stream", 352 | "text": [ 353 | "Total Reward: 200.0\n" 354 | ] 355 | } 356 | ], 357 | "source": [ 358 | "import gym\n", 359 | "import time\n", 360 | "\n", 361 | "env = gym.make(env_name)\n", 362 | "# env.reset()\n", 363 | "state = env.reset()\n", 364 | "done = False\n", 365 | "testing_epsilon = 0.05\n", 366 | "tot_reward = 0\n", 367 | "\n", 368 | "for step in range(2000):\n", 369 | " state = torch.from_numpy(state).float().to(device)\n", 370 | " env.render()\n", 371 | " action = torch.argmax(q_hat_target(state)).item()\n", 372 | " state, reward, done, _ = env.step(action)\n", 373 | " tot_reward += reward\n", 374 | " if done:\n", 375 | "# print('DONE')\n", 376 | " break\n", 377 | " time.sleep(.05)\n", 378 | " \n", 379 | "print('Total Reward:', tot_reward)\n", 380 | " \n", 381 | "env.close()" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": null, 387 | "metadata": {}, 388 | "outputs": [], 389 | "source": [] 390 | } 391 | ], 392 | "metadata": { 393 | "kernelspec": { 394 | "display_name": "Python 3", 395 | "language": "python", 396 | "name": "python3" 397 | }, 398 | "language_info": { 399 | "codemirror_mode": { 400 | "name": "ipython", 401 | "version": 3 402 | }, 403 | "file_extension": ".py", 404 | "mimetype": "text/x-python", 405 | "name": "python", 406 | "nbconvert_exporter": "python", 407 | "pygments_lexer": "ipython3", 408 | "version": "3.6.9" 409 | } 410 | }, 411 | "nbformat": 4, 412 | "nbformat_minor": 2 413 | } 414 | -------------------------------------------------------------------------------- /DQN/models/CartPole-v0.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiPatil/Value-based-RL/a4421c816572162740fbda2798e12ad787e1617c/DQN/models/CartPole-v0.pth -------------------------------------------------------------------------------- /DQN/rewards.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiPatil/Value-based-RL/a4421c816572162740fbda2798e12ad787e1617c/DQN/rewards.npy -------------------------------------------------------------------------------- /DQN/testing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # In[1]: 5 | 6 | 7 | 8 | import math, random 9 | 10 | import gym 11 | import numpy as np 12 | 13 | import torch 14 | import torch.nn as nn 15 | import torch.optim as optim 16 | import torch.autograd as autograd 17 | import torch.nn.functional as F 18 | 19 | 20 | # In[2]: 21 | 22 | 23 | # from IPython.display import clear_output 24 | # import matplotlib.pyplot as plt 25 | # get_ipython().run_line_magic('matplotlib', 'inline') 26 | 27 | 28 | # In[3]: 29 | 30 | 31 | USE_CUDA = torch.cuda.is_available() 32 | Variable = lambda *args, **kwargs: autograd.Variable(*args, **kwargs).cuda() if USE_CUDA else autograd.Variable(*args, **kwargs) 33 | 34 | 35 | # In[4]: 36 | 37 | 38 | from collections import deque 39 | 40 | class ReplayBuffer(object): 41 | def __init__(self, capacity): 42 | self.buffer = deque(maxlen=capacity) 43 | 44 | def push(self, state, action, reward, next_state, done): 45 | state = np.expand_dims(state, 0) 46 | next_state = np.expand_dims(next_state, 0) 47 | 48 | self.buffer.append((state, action, reward, next_state, done)) 49 | 50 | def sample(self, batch_size): 51 | state, action, reward, next_state, done = zip(*random.sample(self.buffer, batch_size)) 52 | return np.concatenate(state), action, reward, np.concatenate(next_state), done 53 | 54 | def __len__(self): 55 | return len(self.buffer) 56 | 57 | 58 | # In[5]: 59 | 60 | 61 | env_id = "CartPole-v0" 62 | env = gym.make(env_id) 63 | 64 | 65 | # In[6]: 66 | 67 | 68 | epsilon_start = 1.0 69 | epsilon_final = 0.01 70 | epsilon_decay = 500 71 | 72 | epsilon_by_frame = lambda frame_idx: epsilon_final + (epsilon_start - epsilon_final) * math.exp(-1. * frame_idx / epsilon_decay) 73 | 74 | 75 | # In[7]: 76 | 77 | 78 | # plt.plot([epsilon_by_frame(i) for i in range(10000)]) 79 | 80 | 81 | # In[8]: 82 | 83 | 84 | class DQN(nn.Module): 85 | def __init__(self, num_inputs, num_actions): 86 | super(DQN, self).__init__() 87 | 88 | self.layers = nn.Sequential( 89 | nn.Linear(env.observation_space.shape[0], 128), 90 | nn.ReLU(), 91 | nn.Linear(128, 128), 92 | nn.ReLU(), 93 | nn.Linear(128, env.action_space.n) 94 | ) 95 | 96 | def forward(self, x): 97 | return self.layers(x) 98 | 99 | def act(self, state, epsilon): 100 | if random.random() > epsilon: 101 | state = Variable(torch.FloatTensor(state).unsqueeze(0), volatile=True) 102 | q_value = self.forward(state) 103 | action = q_value.max(1)[1].data[0] 104 | else: 105 | action = random.randrange(env.action_space.n) 106 | return action 107 | 108 | 109 | # In[9]: 110 | 111 | 112 | model = DQN(env.observation_space.shape[0], env.action_space.n) 113 | 114 | if USE_CUDA: 115 | model = model.cuda() 116 | 117 | optimizer = optim.Adam(model.parameters()) 118 | 119 | replay_buffer = ReplayBuffer(1000) 120 | 121 | 122 | # In[10]: 123 | 124 | 125 | def compute_td_loss(batch_size): 126 | state, action, reward, next_state, done = replay_buffer.sample(batch_size) 127 | 128 | state = Variable(torch.FloatTensor(np.float32(state))) 129 | next_state = Variable(torch.FloatTensor(np.float32(next_state)), volatile=True) 130 | action = Variable(torch.LongTensor(action)) 131 | reward = Variable(torch.FloatTensor(reward)) 132 | done = Variable(torch.FloatTensor(done)) 133 | 134 | q_values = model(state) 135 | next_q_values = model(next_state) 136 | 137 | q_value = q_values.gather(1, action.unsqueeze(1)).squeeze(1) 138 | next_q_value = next_q_values.max(1)[0] 139 | expected_q_value = reward + gamma * next_q_value * (1 - done) 140 | 141 | loss = (q_value - Variable(expected_q_value.data)).pow(2).mean() 142 | 143 | optimizer.zero_grad() 144 | loss.backward() 145 | optimizer.step() 146 | 147 | return loss 148 | 149 | 150 | # In[11]: 151 | 152 | 153 | # def plot(frame_idx, rewards, losses): 154 | # clear_output(True) 155 | # plt.figure(figsize=(20,5)) 156 | # plt.subplot(131) 157 | # plt.title('frame %s. reward: %s' % (frame_idx, np.mean(rewards[-10:]))) 158 | # plt.plot(rewards) 159 | # plt.subplot(132) 160 | # plt.title('loss') 161 | # plt.plot(losses) 162 | # plt.show() 163 | 164 | 165 | # In[12]: 166 | 167 | 168 | num_frames = 10000 169 | batch_size = 32 170 | gamma = 0.99 171 | 172 | losses = [] 173 | all_rewards = [] 174 | episode_reward = 0 175 | 176 | state = env.reset() 177 | for frame_idx in range(1, num_frames + 1): 178 | epsilon = epsilon_by_frame(frame_idx) 179 | action = model.act(state, epsilon) 180 | 181 | next_state, reward, done, _ = env.step(action) 182 | replay_buffer.push(state, action, reward, next_state, done) 183 | 184 | state = next_state 185 | episode_reward += reward 186 | 187 | if done: 188 | state = env.reset() 189 | all_rewards.append(episode_reward) 190 | episode_reward = 0 191 | 192 | if len(replay_buffer) > batch_size: 193 | loss = compute_td_loss(batch_size) 194 | losses.append(loss.item()) 195 | 196 | # if frame_idx % 200 == 0: 197 | # plot(frame_idx, all_rewards, losses) 198 | 199 | 200 | # In[ ]: 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /Model-Based-Learn/Makefile: -------------------------------------------------------------------------------- 1 | submit: 2 | sh collect_submission.sh 3 | 4 | clean: 5 | rm -f assignment1.zip 6 | rm -f *.pyc *.png *.npy utils/*.pyc 7 | 8 | -------------------------------------------------------------------------------- /Model-Based-Learn/__pycache__/lake_envs.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiPatil/Value-based-RL/a4421c816572162740fbda2798e12ad787e1617c/Model-Based-Learn/__pycache__/lake_envs.cpython-36.pyc -------------------------------------------------------------------------------- /Model-Based-Learn/collect_submission.sh: -------------------------------------------------------------------------------- 1 | rm -f assignment1.zip 2 | zip -r assignment1.zip vi_and_pi.py 3 | -------------------------------------------------------------------------------- /Model-Based-Learn/discrete_env.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from gym import Env, spaces 4 | from gym.utils import seeding 5 | 6 | def categorical_sample(prob_n, np_random): 7 | """ 8 | Sample from categorical distribution 9 | Each row specifies class probabilities 10 | """ 11 | prob_n = np.asarray(prob_n) 12 | csprob_n = np.cumsum(prob_n) 13 | return (csprob_n > np_random.rand()).argmax() 14 | 15 | 16 | class DiscreteEnv(Env): 17 | 18 | """ 19 | Has the following members 20 | - nS: number of states 21 | - nA: number of actions 22 | - P: transitions (*) 23 | - isd: initial state distribution (**) 24 | 25 | (*) dictionary dict of dicts of lists, where 26 | P[s][a] == [(probability, nextstate, reward, done), ...] 27 | (**) list or array of length nS 28 | 29 | 30 | """ 31 | def __init__(self, nS, nA, P, isd): 32 | self.P = P 33 | self.isd = isd 34 | self.lastaction=None # for rendering 35 | self.nS = nS 36 | self.nA = nA 37 | 38 | self.action_space = spaces.Discrete(self.nA) 39 | self.observation_space = spaces.Discrete(self.nS) 40 | 41 | self._seed() 42 | self._reset() 43 | 44 | def _seed(self, seed=None): 45 | self.np_random, seed = seeding.np_random(seed) 46 | return [seed] 47 | 48 | def _reset(self): 49 | self.s = categorical_sample(self.isd, self.np_random) 50 | self.lastaction=None 51 | return self.s 52 | 53 | def _step(self, a): 54 | transitions = self.P[self.s][a] 55 | i = categorical_sample([t[0] for t in transitions], self.np_random) 56 | p, s, r, d= transitions[i] 57 | self.s = s 58 | self.lastaction=a 59 | return (s, r, d, {"prob" : p}) 60 | -------------------------------------------------------------------------------- /Model-Based-Learn/frozen_lake.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import sys 3 | from six import StringIO, b 4 | from gym import utils 5 | import discrete_env 6 | 7 | # Mapping between directions and index number 8 | LEFT = 0 9 | DOWN = 1 10 | RIGHT = 2 11 | UP = 3 12 | 13 | # Maps for the two different environments 14 | MAPS = { 15 | "4x4": [ 16 | "SFFF", 17 | "FHFH", 18 | "FFFH", 19 | "HFFG" 20 | ], 21 | "8x8": [ 22 | "SFFFFFFF", 23 | "FFFFFFFF", 24 | "FFFHFFFF", 25 | "FHFFFHFF", 26 | "FFFHFFFF", 27 | "FFHFFFHF", 28 | "FHFFHFHF", 29 | "FFFHFFFG" 30 | ], 31 | } 32 | 33 | class FrozenLakeEnv(discrete_env.DiscreteEnv): 34 | """ 35 | Winter is here. You and your friends were tossing around a frisbee at the park 36 | when you made a wild throw that left the frisbee out in the middle of the lake. 37 | The water is mostly frozen, but there are a few holes where the ice has melted. 38 | If you step into one of those holes, you'll fall into the freezing water. 39 | At this time, there's an international frisbee shortage, so it's absolutely imperative that 40 | you navigate across the lake and retrieve the disc. 41 | However, the ice is slippery, so you won't always move in the direction you intend. 42 | The surface is described using a grid like the following 43 | 44 | SFFF 45 | FHFH 46 | FFFH 47 | HFFG 48 | 49 | S : starting point, safe 50 | F : frozen surface, safe 51 | H : hole, fall to your doom 52 | G : goal, where the frisbee is located 53 | 54 | The episode ends when you reach the goal or fall in a hole. 55 | You receive a reward of 1 if you reach the goal, and zero otherwise. 56 | 57 | """ 58 | 59 | metadata = {'render.modes': ['human', 'ansi']} 60 | 61 | def __init__(self, desc=None, map_name="4x4",is_slippery=True): 62 | if desc is None and map_name is None: 63 | raise ValueError('Must provide either desc or map_name') 64 | elif desc is None: 65 | desc = MAPS[map_name] 66 | self.desc = desc = np.asarray(desc,dtype='c') 67 | self.nrow, self.ncol = nrow, ncol = desc.shape 68 | 69 | nA = 4 # number of actions 70 | nS = nrow * ncol # number of states 71 | 72 | isd = np.array(desc == b'S').astype('float64').ravel() 73 | isd /= isd.sum() 74 | 75 | P = {s : {a : [] for a in range(nA)} for s in range(nS)} 76 | 77 | def to_s(row, col): 78 | return row*ncol + col 79 | def inc(row, col, a): 80 | if a==0: # left 81 | col = max(col-1,0) 82 | elif a==1: # down 83 | row = min(row+1,nrow-1) 84 | elif a==2: # right 85 | col = min(col+1,ncol-1) 86 | elif a==3: # up 87 | row = max(row-1,0) 88 | return (row, col) 89 | 90 | for row in range(nrow): 91 | for col in range(ncol): 92 | s = to_s(row, col) 93 | for a in range(4): 94 | li = P[s][a] 95 | letter = desc[row, col] 96 | if letter in b'GH': 97 | li.append((1.0, s, 0, True)) 98 | else: 99 | if is_slippery: 100 | for b in [(a-1)%4, a, (a+1)%4]: 101 | newrow, newcol = inc(row, col, b) 102 | newstate = to_s(newrow, newcol) 103 | newletter = desc[newrow, newcol] 104 | done = bytes(newletter) in b'GH' 105 | rew = float(newletter == b'G') 106 | li.append((0.8 if b==a else 0.1, newstate, rew, done)) 107 | else: 108 | newrow, newcol = inc(row, col, a) 109 | newstate = to_s(newrow, newcol) 110 | newletter = desc[newrow, newcol] 111 | done = bytes(newletter) in b'GH' 112 | rew = float(newletter == b'G') 113 | li.append((1.0, newstate, rew, done)) 114 | 115 | super(FrozenLakeEnv, self).__init__(nS, nA, P, isd) 116 | 117 | def _render(self, mode='human', close=False): 118 | if close: 119 | return 120 | outfile = StringIO() if mode == 'ansi' else sys.stdout 121 | 122 | row, col = self.s // self.ncol, self.s % self.ncol 123 | desc = self.desc.tolist() 124 | desc = [[c.decode('utf-8') for c in line] for line in desc] 125 | desc[row][col] = utils.colorize(desc[row][col], "red", highlight=True) 126 | if self.lastaction is not None: 127 | outfile.write(" ({})\n".format(["Left","Down","Right","Up"][self.lastaction])) 128 | else: 129 | outfile.write("\n") 130 | outfile.write("\n".join(''.join(line) for line in desc)+"\n") 131 | 132 | return outfile 133 | -------------------------------------------------------------------------------- /Model-Based-Learn/lake_envs.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """Defines some frozen lake maps.""" 3 | from gym.envs.toy_text import frozen_lake, discrete 4 | from gym.envs.registration import register 5 | 6 | 7 | register( 8 | id='Deterministic-4x4-FrozenLake-v0', 9 | entry_point='gym.envs.toy_text.frozen_lake:FrozenLakeEnv', 10 | kwargs={'map_name': '4x4', 11 | 'is_slippery': False}) 12 | 13 | register( 14 | id='Deterministic-8x8-FrozenLake-v0', 15 | entry_point='gym.envs.toy_text.frozen_lake:FrozenLakeEnv', 16 | kwargs={'map_name': '8x8', 17 | 'is_slippery': False}) 18 | 19 | register( 20 | id='Stochastic-4x4-FrozenLake-v0', 21 | entry_point='gym.envs.toy_text.frozen_lake:FrozenLakeEnv', 22 | kwargs={'map_name': '4x4', 23 | 'is_slippery': True}) 24 | -------------------------------------------------------------------------------- /Model-Based-Learn/requirements.txt: -------------------------------------------------------------------------------- 1 | gym==0.10.9 2 | matplotlib 3 | numpy 4 | scipy 5 | -------------------------------------------------------------------------------- /Model-Based-Learn/vi_and_pi.py: -------------------------------------------------------------------------------- 1 | ### MDP Value Iteration and Policy Iteration 2 | 3 | import numpy as np 4 | import gym 5 | import time 6 | from lake_envs import * 7 | import random 8 | 9 | np.set_printoptions(precision=3) 10 | 11 | """ 12 | For policy_evaluation, policy_improvement, policy_iteration and value_iteration, 13 | the parameters P, nS, nA, gamma are defined as follows: 14 | 15 | P: nested dictionary 16 | From gym.core.Environment 17 | For each pair of states in [1, nS] and actions in [1, nA], P[state][action] is a 18 | tuple of the form (probability, nextstate, reward, terminal) where 19 | - probability: float 20 | the probability of transitioning from "state" to "nextstate" with "action" 21 | - nextstate: int 22 | denotes the state we transition to (in range [0, nS - 1]) 23 | - reward: int 24 | either 0 or 1, the reward for transitioning from "state" to 25 | "nextstate" with "action" 26 | - terminal: bool 27 | True when "nextstate" is a terminal state (hole or goal), False otherwise 28 | nS: int 29 | number of states in the environment 30 | nA: int 31 | number of actions in the environment 32 | gamma: float 33 | Discount factor. Number in range [0, 1) 34 | """ 35 | 36 | def policy_evaluation(P, nS, nA, policy, gamma=0.9, tol=1e-3): 37 | """Evaluate the value function from a given policy. 38 | 39 | Parameters 40 | ---------- 41 | P, nS, nA, gamma: 42 | defined at beginning of file 43 | policy: np.array[nS] 44 | The policy to evaluate. Maps states to actions. 45 | tol: float 46 | Terminate policy evaluation when 47 | max |value_function(s) - prev_value_function(s)| < tol 48 | Returns 49 | ------- 50 | value_function: np.ndarray[nS] 51 | The value function of the given policy, where value_function[s] is 52 | the value of state s 53 | """ 54 | # print(nA) 55 | v_new = np.zeros(nS, dtype=float) 56 | ############################ 57 | # YOUR IMPLEMENTATION HERE # 58 | for i in range(1000): 59 | value=v_new.copy() 60 | for state in range(nS): 61 | # for action in range(nA): 62 | # print(P[state][policy[state]]) 63 | for probability, nextstate, reward, terminal in P[state][policy[state]]: 64 | v_new[state] = probability*(reward+gamma*v_new[nextstate]) 65 | 66 | if terminal: 67 | v_new[state] = reward 68 | 69 | if(np.all(np.abs(value-v_new) valMax: 105 | new_policy[state] = action 106 | valMax = Qval 107 | elif Qval == valMax: 108 | if random.random()<0.5: 109 | new_policy[state]=action 110 | 111 | return new_policy 112 | ############################ 113 | 114 | 115 | 116 | def policy_iteration(P, nS, nA, gamma=0.9, tol=10e-3): 117 | """Runs policy iteration. 118 | 119 | You should call the policy_evaluation() and policy_improvement() methods to 120 | implement this method. 121 | 122 | Parameters 123 | ---------- 124 | P, nS, nA, gamma: 125 | defined at beginning of file 126 | tol: float 127 | tol parameter used in policy_evaluation() 128 | Returns: 129 | ---------- 130 | value_function: np.ndarray[nS] 131 | policy: np.ndarray[nS] 132 | """ 133 | 134 | value_function = np.zeros(nS) 135 | policy = np.zeros(nS, dtype=int) 136 | 137 | ############################ 138 | # YOUR IMPLEMENTATION HERE # 139 | for s in range(nS): 140 | policy[s] = 1#s%nA 141 | for i in range(1000): 142 | v_new = policy_evaluation(P, nS, nA, policy, gamma) 143 | policy_new = policy_improvement(P, nS, nA, v_new, policy, gamma) 144 | # if np.all(np.abs(value_function - v_new) < tol): 145 | # print('tatti') 146 | # break 147 | 148 | value_function = v_new.copy() 149 | policy = policy_new.copy() 150 | 151 | print(value_function) 152 | 153 | 154 | ############################ 155 | return value_function, policy 156 | 157 | def value_iteration(P, nS, nA, gamma=0.9, tol=1e-3): 158 | """ 159 | Learn value function and policy by using value iteration method for a given 160 | gamma and environment. 161 | 162 | Parameters: 163 | ---------- 164 | P, nS, nA, gamma: 165 | defined at beginning of file 166 | tol: float 167 | Terminate value iteration when 168 | max |value_function(s) - prev_value_function(s)| < tol 169 | Returns: 170 | ---------- 171 | value_function: np.ndarray[nS] 172 | policy: np.ndarray[nS] 173 | """ 174 | # print(P) 175 | value_function = np.zeros(nS,dtype='double') 176 | policy = np.zeros(nS, dtype=int) 177 | 178 | ############################ 179 | # YOUR IMPLEMENTATION HERE # 180 | for i in range(1000): 181 | v_new=value_function.copy() 182 | for s in range(nS): 183 | 184 | action_reward=[] 185 | for a in range(nA): 186 | q=0 187 | for probability, nextstate, reward, terminal in P[s][a]: 188 | q += probability*(reward+gamma*value_function[nextstate]) 189 | action_reward.append(q) 190 | v_new[s]= np.max(action_reward) 191 | policy[s]=np.argmax(action_reward) 192 | # if value_change self.size-1: 68 | self.x = self.size-1 69 | if self.y < 0: 70 | self.y = 0 71 | elif self.y > self.size-1: 72 | self.y = self.size-1 73 | 74 | 75 | class ENVIRONMENT(): 76 | 77 | 78 | 79 | def __init__(self, num_player=1, num_enemy=1, num_food=1, size = 10, diagonal = False): 80 | self.size = size 81 | self.naction = 4 82 | self.diagonal = diagonal 83 | self.num_enemy = num_enemy 84 | self.num_food = num_food 85 | self.player = Blob(size) 86 | self.enemy = [Blob() for _ in range(self.num_enemy)] 87 | self.food = [Blob() for _ in range(self.num_food)] 88 | self.reward = 0 89 | self.colors = {1: (255, 0, 0), 90 | 2: (0, 255, 0), 91 | 3: (0, 0, 255)} 92 | self.px,self.py = self.player.x,self.player.y 93 | self.ex,self.ey = [self.enemy[iter].x for iter in range(self.num_enemy)], [self.enemy[iter].y for iter in range(self.num_enemy)] 94 | self.fx,self.fy = [self.food[iter].x for iter in range(self.num_food)], [self.food[iter].y for iter in range(self.num_food)] 95 | 96 | 97 | def startover(self, newpos=False): 98 | 99 | self.player.x, self.player.y = self.px, self.py 100 | for iter in range(self.num_enemy): 101 | self.enemy[iter].x, self.enemy[iter].y = self.ex[iter], self.ey[iter] 102 | for iter in range(self.num_food): 103 | self.food[iter].x, self.food[iter].y = self.fx[iter], self.fy[iter] 104 | if newpos == True: 105 | self.player = Blob(self.size) 106 | self.reward = 0 107 | 108 | return (self.player.x, self.player.y), self.reward, False 109 | 110 | def step(self, action): 111 | 112 | self.player.act(action, self.diagonal) 113 | self.reward = self.calculate_reward() 114 | return (self.player.x, self.player.y), self.reward 115 | 116 | def calculate_reward(self): 117 | 118 | if self.player.x in [self.enemy[iter].x for iter in range(self.num_enemy)] and self.player.y in [self.enemy[iter].y for iter in range(self.num_enemy)]: 119 | return -100, True 120 | 121 | if self.player.x in [self.food[iter].x for iter in range(self.num_food)] and self.player.y in [self.food[iter].y for iter in range(self.num_food)]: 122 | return 100, True 123 | 124 | else: 125 | return -1, False 126 | 127 | 128 | def render(self,renderTime=100): 129 | 130 | env = np.zeros((self.size, self.size, 3), dtype=np.uint8) 131 | for iter in range(self.num_food): 132 | env[self.food[iter].x][self.food[iter].y] = self.colors[2] 133 | for iter in range(self.num_enemy): 134 | env[self.enemy[iter].x][self.enemy[iter].y] = self.colors[3] 135 | env[self.player.x][self.player.y] = self.colors[1] 136 | img = Image.fromarray(env, 'RGB') 137 | img = img.resize((300, 300)) 138 | cv2.imshow("image", np.array(img)) 139 | cv2.waitKey(renderTime) 140 | # cv2.destroyAllWindows() 141 | 142 | def sample_action(self): 143 | return np.random.randint(0, self.naction) 144 | -------------------------------------------------------------------------------- /Model-Free-Learn/q_learning.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # In[1]: 5 | 6 | 7 | import gym 8 | import numpy as np 9 | from custom_environment import ENVIRONMENT 10 | import cv2 11 | import pickle 12 | import random 13 | 14 | 15 | # In[2]: 16 | 17 | 18 | size=10 19 | episodes = 25000 20 | epsilon=0.9 21 | discount = 0.95 22 | learning_rate=0.1 23 | total_reward=0 24 | display_every = 500 25 | render_every = 500 26 | EPS_DECAY=0.998 27 | 28 | 29 | # In[3]: 30 | 31 | 32 | env = ENVIRONMENT(diagonal=False, size=10, num_enemy=3, num_food=1) 33 | 34 | 35 | # In[4]: 36 | 37 | 38 | class parameter(): 39 | def __init__(self, size, episode, discount, epsilon, learning_rate, render_every=500, verbose_every=500, EPS_DECAY=0.998, random_start=True): 40 | self.episode = episodes 41 | self.discount= discount 42 | self.size = size 43 | self. learning_rate = learning_rate 44 | self.epsilon = epsilon 45 | self.render_every=render_every 46 | self.random_start = random_start 47 | self.verbose_every = display_every 48 | self.EPS_DECAY = EPS_DECAY 49 | 50 | def decay_epsilon(self): 51 | self.epsilon *= self.EPS_DECAY 52 | 53 | # In[5]: 54 | 55 | 56 | def q_table(size, action): 57 | q_table = np.random.randn(size,size,action) 58 | return q_table 59 | 60 | 61 | # In[8]: 62 | 63 | 64 | def q_improve(env, q, parameter, verbose=True): 65 | total_reward = 0 66 | for episode in range(parameter.episode): 67 | state, reward, terminal = env.startover(newpos=parameter.random_start) 68 | while not terminal: 69 | current_q = q[state[0],state[1],:] 70 | # to make policy e-greedy 71 | if random.random() > parameter.epsilon: 72 | action = np.argmax(current_q) 73 | else: 74 | action=env.sample_action() 75 | #Now take a step and see what happens 76 | next_state, (next_reward, terminal) = env.step(action) 77 | total_reward += next_reward 78 | future_q = q[next_state[0],next_state[1],:] 79 | 80 | q[state[0],state[1],action] =current_q[action] + parameter.learning_rate*(next_reward + parameter.discount*np.max(future_q) - current_q[action]) 81 | 82 | if terminal and next_reward == 100: 83 | q[state[0],state[1],:]=0 84 | if episode%parameter.render_every == 0: 85 | env.render(100) 86 | state = next_state 87 | parameter.decay_epsilon() 88 | cv2.destroyAllWindows() 89 | if episode%parameter.verbose_every == 0 and verbose: 90 | print('Episode: ',episode,'state:',state,'| Total Average Reward:', total_reward/500,'| Epsilon:', parameter.epsilon) 91 | total_reward= 0 92 | return q 93 | 94 | 95 | 96 | # In[9]: 97 | 98 | 99 | env = ENVIRONMENT(diagonal=True, size=10, num_enemy = 3, num_food = 1) 100 | q = q_table(size=10, action=4) 101 | parameters = parameter(size, episodes, discount, epsilon, learning_rate) 102 | 103 | # Test Environment 104 | # print(env.startover()) 105 | 106 | # for i in range(10): 107 | # print(env.step(np.random.randint(0,4))) 108 | # env.render(100) 109 | 110 | # cv2.destroyAllWindows() 111 | 112 | # print(env.startover()) 113 | 114 | 115 | # Improve the Q-value table 116 | q = q_improve(env, q, parameter=parameters) 117 | 118 | 119 | # In[ ]: 120 | 121 | 122 | 123 | 124 | 125 | # In[ ]: 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Value-based RL 2 | 3 | Implementation of Reinforcement Learning Algorithms based on value function. 4 | - Deep Q-Network 5 | - Q-learning 6 | - SARSA 7 | - Policy iteration 8 | - Value iteration 9 | 10 | --------------------------------------------------------------------------------