{"cells": [{"cell_type": "markdown", "id": "ef8a43a5", "metadata": {"papermill": {"duration": 0.039794, "end_time": "2021-08-31T12:37:17.276676", "exception": false, "start_time": "2021-08-31T12:37:17.236882", "status": "completed"}, "tags": []}, "source": ["\n", "# How to train a Deep Q Network\n", "\n", "* **Author:** PL team\n", "* **License:** CC BY-SA\n", "* **Generated:** 2021-08-31T13:56:11.349578\n", "\n", "Main takeaways:\n", "\n", "1. RL has the same flow as previous models we have seen, with a few additions\n", "2. Handle unsupervised learning by using an IterableDataset where the dataset itself is constantly updated during training\n", "3. Each training step carries has the agent taking an action in the environment and storing the experience in the IterableDataset\n", "\n", "\n", "---\n", "Open in [![Open In Colab](data:image/png;base64,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){height=\"20px\" width=\"117px\"}](https://colab.research.google.com/github/PytorchLightning/lightning-tutorials/blob/publication/.notebooks/lightning_examples/reinforce-learning-DQN.ipynb)\n", "\n", "Give us a \u2b50 [on Github](https://www.github.com/PytorchLightning/pytorch-lightning/)\n", "| Check out [the documentation](https://pytorch-lightning.readthedocs.io/en/latest/)\n", "| Join us [on Slack](https://join.slack.com/t/pytorch-lightning/shared_invite/zt-pw5v393p-qRaDgEk24~EjiZNBpSQFgQ)"]}, {"cell_type": "markdown", "id": "a4f9cec5", "metadata": {"papermill": {"duration": 0.007549, "end_time": "2021-08-31T12:37:17.292223", "exception": false, "start_time": "2021-08-31T12:37:17.284674", "status": "completed"}, "tags": []}, "source": ["## Setup\n", "This notebook requires some packages besides pytorch-lightning."]}, {"cell_type": "code", "execution_count": 1, "id": "f96d7041", "metadata": {"colab": {}, "colab_type": "code", "execution": {"iopub.execute_input": "2021-08-31T12:37:17.314301Z", "iopub.status.busy": "2021-08-31T12:37:17.313817Z", "iopub.status.idle": "2021-08-31T12:37:19.681259Z", "shell.execute_reply": "2021-08-31T12:37:19.680722Z"}, "id": "LfrJLKPFyhsK", "lines_to_next_cell": 0, "papermill": {"duration": 2.381402, "end_time": "2021-08-31T12:37:19.681392", "exception": false, "start_time": "2021-08-31T12:37:17.299990", "status": "completed"}, "tags": []}, "outputs": [], "source": ["! pip install --quiet \"torchmetrics>=0.3\" \"torch>=1.6, <1.9\" \"pytorch-lightning>=1.3\" \"gym\""]}, {"cell_type": "code", "execution_count": 2, "id": "8447fac2", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:19.702696Z", "iopub.status.busy": "2021-08-31T12:37:19.702216Z", "iopub.status.idle": "2021-08-31T12:37:22.180422Z", "shell.execute_reply": "2021-08-31T12:37:22.179976Z"}, "papermill": {"duration": 2.4905, "end_time": "2021-08-31T12:37:22.180549", "exception": false, "start_time": "2021-08-31T12:37:19.690049", "status": "completed"}, "tags": []}, "outputs": [], "source": ["import os\n", "from collections import OrderedDict, deque, namedtuple\n", "from typing import List, Tuple\n", "\n", "import gym\n", "import numpy as np\n", "import torch\n", "from pytorch_lightning import LightningModule, Trainer\n", "from pytorch_lightning.utilities import DistributedType\n", "from torch import Tensor, nn\n", "from torch.optim import Adam, Optimizer\n", "from torch.utils.data import DataLoader\n", "from torch.utils.data.dataset import IterableDataset\n", "\n", "PATH_DATASETS = os.environ.get(\"PATH_DATASETS\", \".\")\n", "AVAIL_GPUS = min(1, torch.cuda.device_count())"]}, {"cell_type": "code", "execution_count": 3, "id": "eb2c666d", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.201758Z", "iopub.status.busy": "2021-08-31T12:37:22.201258Z", "iopub.status.idle": "2021-08-31T12:37:22.203391Z", "shell.execute_reply": "2021-08-31T12:37:22.202923Z"}, "papermill": {"duration": 0.014583, "end_time": "2021-08-31T12:37:22.203491", "exception": false, "start_time": "2021-08-31T12:37:22.188908", "status": "completed"}, "tags": []}, "outputs": [], "source": ["class DQN(nn.Module):\n", " \"\"\"Simple MLP network.\"\"\"\n", "\n", " def __init__(self, obs_size: int, n_actions: int, hidden_size: int = 128):\n", " \"\"\"\n", " Args:\n", " obs_size: observation/state size of the environment\n", " n_actions: number of discrete actions available in the environment\n", " hidden_size: size of hidden layers\n", " \"\"\"\n", " super().__init__()\n", " self.net = nn.Sequential(\n", " nn.Linear(obs_size, hidden_size),\n", " nn.ReLU(),\n", " nn.Linear(hidden_size, n_actions),\n", " )\n", "\n", " def forward(self, x):\n", " return self.net(x.float())"]}, {"cell_type": "markdown", "id": "395cefea", "metadata": {"papermill": {"duration": 0.007826, "end_time": "2021-08-31T12:37:22.219352", "exception": false, "start_time": "2021-08-31T12:37:22.211526", "status": "completed"}, "tags": []}, "source": ["### Memory"]}, {"cell_type": "code", "execution_count": 4, "id": "8491d2e4", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.239138Z", "iopub.status.busy": "2021-08-31T12:37:22.238662Z", "iopub.status.idle": "2021-08-31T12:37:22.240820Z", "shell.execute_reply": "2021-08-31T12:37:22.240330Z"}, "papermill": {"duration": 0.013722, "end_time": "2021-08-31T12:37:22.240922", "exception": false, "start_time": "2021-08-31T12:37:22.227200", "status": "completed"}, "tags": []}, "outputs": [], "source": ["\n", "# Named tuple for storing experience steps gathered in training\n", "Experience = namedtuple(\n", " \"Experience\",\n", " field_names=[\"state\", \"action\", \"reward\", \"done\", \"new_state\"],\n", ")"]}, {"cell_type": "code", "execution_count": 5, "id": "dba6653a", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.263599Z", "iopub.status.busy": "2021-08-31T12:37:22.263108Z", "iopub.status.idle": "2021-08-31T12:37:22.265253Z", "shell.execute_reply": "2021-08-31T12:37:22.264753Z"}, "papermill": {"duration": 0.016357, "end_time": "2021-08-31T12:37:22.265353", "exception": false, "start_time": "2021-08-31T12:37:22.248996", "status": "completed"}, "tags": []}, "outputs": [], "source": ["class ReplayBuffer:\n", " \"\"\"Replay Buffer for storing past experiences allowing the agent to learn from them.\n", "\n", " Args:\n", " capacity: size of the buffer\n", " \"\"\"\n", "\n", " def __init__(self, capacity: int) -> None:\n", " self.buffer = deque(maxlen=capacity)\n", "\n", " def __len__(self) -> None:\n", " return len(self.buffer)\n", "\n", " def append(self, experience: Experience) -> None:\n", " \"\"\"Add experience to the buffer.\n", "\n", " Args:\n", " experience: tuple (state, action, reward, done, new_state)\n", " \"\"\"\n", " self.buffer.append(experience)\n", "\n", " def sample(self, batch_size: int) -> Tuple:\n", " indices = np.random.choice(len(self.buffer), batch_size, replace=False)\n", " states, actions, rewards, dones, next_states = zip(*(self.buffer[idx] for idx in indices))\n", "\n", " return (\n", " np.array(states),\n", " np.array(actions),\n", " np.array(rewards, dtype=np.float32),\n", " np.array(dones, dtype=np.bool),\n", " np.array(next_states),\n", " )"]}, {"cell_type": "code", "execution_count": 6, "id": "d4d0109b", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.285666Z", "iopub.status.busy": "2021-08-31T12:37:22.285190Z", "iopub.status.idle": "2021-08-31T12:37:22.286884Z", "shell.execute_reply": "2021-08-31T12:37:22.287257Z"}, "lines_to_next_cell": 2, "papermill": {"duration": 0.014122, "end_time": "2021-08-31T12:37:22.287372", "exception": false, "start_time": "2021-08-31T12:37:22.273250", "status": "completed"}, "tags": []}, "outputs": [], "source": ["class RLDataset(IterableDataset):\n", " \"\"\"Iterable Dataset containing the ExperienceBuffer which will be updated with new experiences during training.\n", "\n", " Args:\n", " buffer: replay buffer\n", " sample_size: number of experiences to sample at a time\n", " \"\"\"\n", "\n", " def __init__(self, buffer: ReplayBuffer, sample_size: int = 200) -> None:\n", " self.buffer = buffer\n", " self.sample_size = sample_size\n", "\n", " def __iter__(self) -> Tuple:\n", " states, actions, rewards, dones, new_states = self.buffer.sample(self.sample_size)\n", " for i in range(len(dones)):\n", " yield states[i], actions[i], rewards[i], dones[i], new_states[i]"]}, {"cell_type": "markdown", "id": "a0b14f16", "metadata": {"lines_to_next_cell": 2, "papermill": {"duration": 0.007984, "end_time": "2021-08-31T12:37:22.303700", "exception": false, "start_time": "2021-08-31T12:37:22.295716", "status": "completed"}, "tags": []}, "source": ["### Agent"]}, {"cell_type": "code", "execution_count": 7, "id": "fe9a42c1", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.328705Z", "iopub.status.busy": "2021-08-31T12:37:22.328223Z", "iopub.status.idle": "2021-08-31T12:37:22.330404Z", "shell.execute_reply": "2021-08-31T12:37:22.329938Z"}, "lines_to_next_cell": 2, "papermill": {"duration": 0.018735, "end_time": "2021-08-31T12:37:22.330502", "exception": false, "start_time": "2021-08-31T12:37:22.311767", "status": "completed"}, "tags": []}, "outputs": [], "source": ["class Agent:\n", " \"\"\"Base Agent class handeling the interaction with the environment.\"\"\"\n", "\n", " def __init__(self, env: gym.Env, replay_buffer: ReplayBuffer) -> None:\n", " \"\"\"\n", " Args:\n", " env: training environment\n", " replay_buffer: replay buffer storing experiences\n", " \"\"\"\n", " self.env = env\n", " self.replay_buffer = replay_buffer\n", " self.reset()\n", " self.state = self.env.reset()\n", "\n", " def reset(self) -> None:\n", " \"\"\"Resents the environment and updates the state.\"\"\"\n", " self.state = self.env.reset()\n", "\n", " def get_action(self, net: nn.Module, epsilon: float, device: str) -> int:\n", " \"\"\"Using the given network, decide what action to carry out using an epsilon-greedy policy.\n", "\n", " Args:\n", " net: DQN network\n", " epsilon: value to determine likelihood of taking a random action\n", " device: current device\n", "\n", " Returns:\n", " action\n", " \"\"\"\n", " if np.random.random() < epsilon:\n", " action = self.env.action_space.sample()\n", " else:\n", " state = torch.tensor([self.state])\n", "\n", " if device not in [\"cpu\"]:\n", " state = state.cuda(device)\n", "\n", " q_values = net(state)\n", " _, action = torch.max(q_values, dim=1)\n", " action = int(action.item())\n", "\n", " return action\n", "\n", " @torch.no_grad()\n", " def play_step(\n", " self,\n", " net: nn.Module,\n", " epsilon: float = 0.0,\n", " device: str = \"cpu\",\n", " ) -> Tuple[float, bool]:\n", " \"\"\"Carries out a single interaction step between the agent and the environment.\n", "\n", " Args:\n", " net: DQN network\n", " epsilon: value to determine likelihood of taking a random action\n", " device: current device\n", "\n", " Returns:\n", " reward, done\n", " \"\"\"\n", "\n", " action = self.get_action(net, epsilon, device)\n", "\n", " # do step in the environment\n", " new_state, reward, done, _ = self.env.step(action)\n", "\n", " exp = Experience(self.state, action, reward, done, new_state)\n", "\n", " self.replay_buffer.append(exp)\n", "\n", " self.state = new_state\n", " if done:\n", " self.reset()\n", " return reward, done"]}, {"cell_type": "markdown", "id": "87c06ab2", "metadata": {"lines_to_next_cell": 2, "papermill": {"duration": 0.008003, "end_time": "2021-08-31T12:37:22.346701", "exception": false, "start_time": "2021-08-31T12:37:22.338698", "status": "completed"}, "tags": []}, "source": ["### DQN Lightning Module"]}, {"cell_type": "code", "execution_count": 8, "id": "2674d9e4", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.378167Z", "iopub.status.busy": "2021-08-31T12:37:22.369838Z", "iopub.status.idle": "2021-08-31T12:37:22.379784Z", "shell.execute_reply": "2021-08-31T12:37:22.380160Z"}, "papermill": {"duration": 0.025499, "end_time": "2021-08-31T12:37:22.380273", "exception": false, "start_time": "2021-08-31T12:37:22.354774", "status": "completed"}, "tags": []}, "outputs": [], "source": ["class DQNLightning(LightningModule):\n", " \"\"\"Basic DQN Model.\"\"\"\n", "\n", " def __init__(\n", " self,\n", " batch_size: int = 16,\n", " lr: float = 1e-2,\n", " env: str = \"CartPole-v0\",\n", " gamma: float = 0.99,\n", " sync_rate: int = 10,\n", " replay_size: int = 1000,\n", " warm_start_size: int = 1000,\n", " eps_last_frame: int = 1000,\n", " eps_start: float = 1.0,\n", " eps_end: float = 0.01,\n", " episode_length: int = 200,\n", " warm_start_steps: int = 1000,\n", " ) -> None:\n", " \"\"\"\n", " Args:\n", " batch_size: size of the batches\")\n", " lr: learning rate\n", " env: gym environment tag\n", " gamma: discount factor\n", " sync_rate: how many frames do we update the target network\n", " replay_size: capacity of the replay buffer\n", " warm_start_size: how many samples do we use to fill our buffer at the start of training\n", " eps_last_frame: what frame should epsilon stop decaying\n", " eps_start: starting value of epsilon\n", " eps_end: final value of epsilon\n", " episode_length: max length of an episode\n", " warm_start_steps: max episode reward in the environment\n", " \"\"\"\n", " super().__init__()\n", " self.save_hyperparameters()\n", "\n", " self.env = gym.make(self.hparams.env)\n", " obs_size = self.env.observation_space.shape[0]\n", " n_actions = self.env.action_space.n\n", "\n", " self.net = DQN(obs_size, n_actions)\n", " self.target_net = DQN(obs_size, n_actions)\n", "\n", " self.buffer = ReplayBuffer(self.hparams.replay_size)\n", " self.agent = Agent(self.env, self.buffer)\n", " self.total_reward = 0\n", " self.episode_reward = 0\n", " self.populate(self.hparams.warm_start_steps)\n", "\n", " def populate(self, steps: int = 1000) -> None:\n", " \"\"\"Carries out several random steps through the environment to initially fill up the replay buffer with\n", " experiences.\n", "\n", " Args:\n", " steps: number of random steps to populate the buffer with\n", " \"\"\"\n", " for i in range(steps):\n", " self.agent.play_step(self.net, epsilon=1.0)\n", "\n", " def forward(self, x: Tensor) -> Tensor:\n", " \"\"\"Passes in a state x through the network and gets the q_values of each action as an output.\n", "\n", " Args:\n", " x: environment state\n", "\n", " Returns:\n", " q values\n", " \"\"\"\n", " output = self.net(x)\n", " return output\n", "\n", " def dqn_mse_loss(self, batch: Tuple[Tensor, Tensor]) -> Tensor:\n", " \"\"\"Calculates the mse loss using a mini batch from the replay buffer.\n", "\n", " Args:\n", " batch: current mini batch of replay data\n", "\n", " Returns:\n", " loss\n", " \"\"\"\n", " states, actions, rewards, dones, next_states = batch\n", "\n", " state_action_values = self.net(states).gather(1, actions.unsqueeze(-1)).squeeze(-1)\n", "\n", " with torch.no_grad():\n", " next_state_values = self.target_net(next_states).max(1)[0]\n", " next_state_values[dones] = 0.0\n", " next_state_values = next_state_values.detach()\n", "\n", " expected_state_action_values = next_state_values * self.hparams.gamma + rewards\n", "\n", " return nn.MSELoss()(state_action_values, expected_state_action_values)\n", "\n", " def training_step(self, batch: Tuple[Tensor, Tensor], nb_batch) -> OrderedDict:\n", " \"\"\"Carries out a single step through the environment to update the replay buffer. Then calculates loss\n", " based on the minibatch recieved.\n", "\n", " Args:\n", " batch: current mini batch of replay data\n", " nb_batch: batch number\n", "\n", " Returns:\n", " Training loss and log metrics\n", " \"\"\"\n", " device = self.get_device(batch)\n", " epsilon = max(\n", " self.hparams.eps_end,\n", " self.hparams.eps_start - self.global_step + 1 / self.hparams.eps_last_frame,\n", " )\n", "\n", " # step through environment with agent\n", " reward, done = self.agent.play_step(self.net, epsilon, device)\n", " self.episode_reward += reward\n", "\n", " # calculates training loss\n", " loss = self.dqn_mse_loss(batch)\n", "\n", " if self.trainer._distrib_type in {DistributedType.DP, DistributedType.DDP2}:\n", " loss = loss.unsqueeze(0)\n", "\n", " if done:\n", " self.total_reward = self.episode_reward\n", " self.episode_reward = 0\n", "\n", " # Soft update of target network\n", " if self.global_step % self.hparams.sync_rate == 0:\n", " self.target_net.load_state_dict(self.net.state_dict())\n", "\n", " log = {\n", " \"total_reward\": torch.tensor(self.total_reward).to(device),\n", " \"reward\": torch.tensor(reward).to(device),\n", " \"train_loss\": loss,\n", " }\n", " status = {\n", " \"steps\": torch.tensor(self.global_step).to(device),\n", " \"total_reward\": torch.tensor(self.total_reward).to(device),\n", " }\n", "\n", " return OrderedDict({\"loss\": loss, \"log\": log, \"progress_bar\": status})\n", "\n", " def configure_optimizers(self) -> List[Optimizer]:\n", " \"\"\"Initialize Adam optimizer.\"\"\"\n", " optimizer = Adam(self.net.parameters(), lr=self.hparams.lr)\n", " return [optimizer]\n", "\n", " def __dataloader(self) -> DataLoader:\n", " \"\"\"Initialize the Replay Buffer dataset used for retrieving experiences.\"\"\"\n", " dataset = RLDataset(self.buffer, self.hparams.episode_length)\n", " dataloader = DataLoader(\n", " dataset=dataset,\n", " batch_size=self.hparams.batch_size,\n", " )\n", " return dataloader\n", "\n", " def train_dataloader(self) -> DataLoader:\n", " \"\"\"Get train loader.\"\"\"\n", " return self.__dataloader()\n", "\n", " def get_device(self, batch) -> str:\n", " \"\"\"Retrieve device currently being used by minibatch.\"\"\"\n", " return batch[0].device.index if self.on_gpu else \"cpu\""]}, {"cell_type": "markdown", "id": "34468e32", "metadata": {"papermill": {"duration": 0.008184, "end_time": "2021-08-31T12:37:22.396696", "exception": false, "start_time": "2021-08-31T12:37:22.388512", "status": "completed"}, "tags": []}, "source": ["### Trainer"]}, {"cell_type": "code", "execution_count": 9, "id": "d99173d5", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:22.416827Z", "iopub.status.busy": "2021-08-31T12:37:22.416355Z", "iopub.status.idle": "2021-08-31T12:37:37.151109Z", "shell.execute_reply": "2021-08-31T12:37:37.151493Z"}, "papermill": {"duration": 14.746762, "end_time": "2021-08-31T12:37:37.151642", "exception": false, "start_time": "2021-08-31T12:37:22.404880", "status": "completed"}, "tags": []}, "outputs": [{"name": "stderr", "output_type": "stream", "text": ["GPU available: True, used: True\n"]}, {"name": "stderr", "output_type": "stream", "text": ["TPU available: False, using: 0 TPU cores\n"]}, {"name": "stderr", "output_type": "stream", "text": ["IPU available: False, using: 0 IPUs\n"]}, {"name": "stderr", "output_type": "stream", "text": ["LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n"]}, {"name": "stderr", "output_type": "stream", "text": ["\n", " | Name | Type | Params\n", "------------------------------------\n", "0 | net | DQN | 898 \n", "1 | target_net | DQN | 898 \n", "------------------------------------\n", "1.8 K Trainable params\n", "0 Non-trainable params\n", "1.8 K Total params\n", "0.007 Total estimated model params size (MB)\n"]}, {"name": "stderr", "output_type": "stream", "text": ["/home/AzDevOps_azpcontainer/.local/lib/python3.9/site-packages/pytorch_lightning/trainer/data_loading.py:105: UserWarning: The dataloader, train dataloader, does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` (try 12 which is the number of cpus on this machine) in the `DataLoader` init to improve performance.\n", " rank_zero_warn(\n"]}, {"data": {"application/vnd.jupyter.widget-view+json": {"model_id": "f962e76bc6bd4477847f5dedbf4d5f6d", "version_major": 2, "version_minor": 0}, "text/plain": ["Training: -1it [00:00, ?it/s]"]}, "metadata": {}, "output_type": "display_data"}, {"name": "stderr", "output_type": "stream", "text": ["/tmp/ipykernel_13751/3638216480.py:30: DeprecationWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence this warning, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.\n", "Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations\n", " np.array(dones, dtype=np.bool),\n", "/home/AzDevOps_azpcontainer/.local/lib/python3.9/site-packages/pytorch_lightning/trainer/connectors/logger_connector/result.py:397: LightningDeprecationWarning: One of the returned values {'progress_bar', 'log'} has a `grad_fn`. We will detach it automatically but this behaviour will change in v1.6. Please detach it manually: `return {'loss': ..., 'something': something.detach()}`\n", " warning_cache.deprecation(\n"]}], "source": ["\n", "model = DQNLightning()\n", "\n", "trainer = Trainer(\n", " gpus=AVAIL_GPUS,\n", " max_epochs=200,\n", " val_check_interval=100,\n", ")\n", "\n", "trainer.fit(model)"]}, {"cell_type": "code", "execution_count": 10, "id": "4d7a7f5b", "metadata": {"execution": {"iopub.execute_input": "2021-08-31T12:37:37.176779Z", "iopub.status.busy": "2021-08-31T12:37:37.176322Z", "iopub.status.idle": "2021-08-31T12:37:38.234163Z", "shell.execute_reply": "2021-08-31T12:37:38.234540Z"}, "papermill": {"duration": 1.071924, "end_time": "2021-08-31T12:37:38.234673", "exception": false, "start_time": "2021-08-31T12:37:37.162749", "status": "completed"}, "tags": []}, "outputs": [{"data": {"text/html": ["\n", " \n", " \n", " "], "text/plain": [""]}, "metadata": {}, "output_type": "display_data"}], "source": ["# Start tensorboard.\n", "%load_ext tensorboard\n", "%tensorboard --logdir lightning_logs/"]}, {"cell_type": "markdown", "id": "f022a7f9", "metadata": {"papermill": {"duration": 0.010581, "end_time": "2021-08-31T12:37:38.256184", "exception": false, "start_time": "2021-08-31T12:37:38.245603", "status": "completed"}, "tags": []}, "source": ["## Congratulations - Time to Join the Community!\n", "\n", "Congratulations on completing this notebook tutorial! If you enjoyed this and would like to join the Lightning\n", "movement, you can do so in the following ways!\n", "\n", "### Star [Lightning](https://github.com/PyTorchLightning/pytorch-lightning) on GitHub\n", "The easiest way to help our community is just by starring the GitHub repos! This helps raise awareness of the cool\n", "tools we're building.\n", "\n", "### Join our [Slack](https://join.slack.com/t/pytorch-lightning/shared_invite/zt-pw5v393p-qRaDgEk24~EjiZNBpSQFgQ)!\n", "The best way to keep up to date on the latest advancements is to join our community! Make sure to introduce yourself\n", "and share your interests in `#general` channel\n", "\n", "\n", "### Contributions !\n", "The best way to contribute to our community is to become a code contributor! At any time you can go to\n", "[Lightning](https://github.com/PyTorchLightning/pytorch-lightning) or [Bolt](https://github.com/PyTorchLightning/lightning-bolts)\n", "GitHub Issues page and filter for \"good first issue\".\n", "\n", "* [Lightning good first issue](https://github.com/PyTorchLightning/pytorch-lightning/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n", "* [Bolt good first issue](https://github.com/PyTorchLightning/lightning-bolts/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n", "* You can also contribute your own notebooks with useful examples !\n", "\n", "### Great thanks from the entire Pytorch Lightning Team for your interest !\n", "\n", "![Pytorch Lightning](data:image/png;base64,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MDY6NUFBNzoyRjVDOUEzOjU4MDQ4MjQ6NjEyRTE4REIiIGRhdGEtcGpheC10cmFuc2llbnQ9InRydWUiLz48bWV0YSBuYW1lPSJodG1sLXNhZmUtbm9uY2UiIGNvbnRlbnQ9IjRlZmVjM2QwZGU1MGZmYjdmZDJkZTM3ODJkNTI1MmMzNDY2ODBkNzljZjNiYWRlNjhiMjBjNTZkZGY3OTRhNWQiIGRhdGEtcGpheC10cmFuc2llbnQ9InRydWUiLz48bWV0YSBuYW1lPSJ2aXNpdG9yLXBheWxvYWQiIGNvbnRlbnQ9ImV5SnlaV1psY25KbGNpSTZJaUlzSW5KbGNYVmxjM1JmYVdRaU9pSXdPREEyT2pWQlFUYzZNa1kxUXpsQk16bzFPREEwT0RJME9qWXhNa1V4T0VSQ0lpd2lkbWx6YVhSdmNsOXBaQ0k2SWpjNE1UWTRNRFkzTmpBMU5qSXhOekF3TnpVaUxDSnlaV2RwYjI1ZlpXUm5aU0k2SW1saFpDSXNJbkpsWjJsdmJsOXlaVzVrWlhJaU9pSnBZV1FpZlE9PSIgZGF0YS1wamF4LXRyYW5zaWVudD0idHJ1ZSIvPjxtZXRhIG5hbWU9InZpc2l0b3ItaG1hYyIgY29udGVudD0iZDIwMWNjMTJlMmFhNWI2OTYxOThiODJiYzg3MTM5ZjRkNDM4MTgyMjYzYTQ1ZTdiZTQ2ZjJjNDFmZmQ0OGVjZSIgZGF0YS1wamF4LXRyYW5zaWVudD0idHJ1ZSIvPuw9aZfbNpLf/Su4yia7+2xKvA+7u+d1fE98rdtxspmZx6VISKKbIhge3S3n5b9vFUCKh6Qmddnu2Zl4miQIFAqFuglA9+4J8L+TOclcIXLn5HQwo1ck8dzEF9N8/Il4mZi504Hg0SgjUXY6SEhM0yCjyeKhbFqGYpiKNBB8N3PF+JN7I2aJG6UBVD27d+9eE/Q0yGb5WLwkizFlHcxoknl5lq4F/yCleeIR0aM+WdvB6SBLcng1OsOO2p2lJATkiS+GQXQ5EK7cMCccvMMBb0K6TZAppdOQiIAUEYE0wSTw3CygUQ1pT77Mn4g/KS9efnxmqHq4iL30l3f0iXYZhFQXP5071z8+W3zQ8tf/MzhrE6Ub/E8f9GlqzaTrK9edvvrp/OMvv1vjMXlzHf32209yIv/634v0V/UmT179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){height=\"60px\" width=\"240px\"}"]}, {"cell_type": "raw", "metadata": {"raw_mimetype": "text/restructuredtext"}, "source": [".. customcarditem::\n", " :header: How to train a Deep Q Network\n", " :card_description: Main takeaways: 1. RL has the same flow as previous models we have seen, with a few additions 2. Handle unsupervised learning by using an IterableDataset where the dataset...\n", " :tags: RL,GPU/TPU,Lightning-Examples"]}], "metadata": {"jupytext": {"cell_metadata_filter": "colab_type,colab,id,-all", "formats": "ipynb,py:percent", "main_language": "python"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6"}, "papermill": {"default_parameters": {}, "duration": 23.186754, "end_time": "2021-08-31T12:37:39.374766", "environment_variables": {}, "exception": null, "input_path": "lightning_examples/reinforce-learning-DQN/dqn.ipynb", "output_path": ".notebooks/lightning_examples/reinforce-learning-DQN.ipynb", "parameters": {}, "start_time": "2021-08-31T12:37:16.188012", "version": "2.3.3"}, "widgets": {"application/vnd.jupyter.widget-state+json": {"state": {"4c55a94d1d6e4fd7a0df1813d82588a3": {"model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null}}, "6d83ec49723d45a6931b6ba9dbd64ec4": {"model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": "2", "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null}}, "943f4388dd7b46e68aba0643420fc6ce": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": {"_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": ""}}, "aade554e920a484b943345379a01cf83": {"model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": "inline-flex", "flex": null, "flex_flow": "row wrap", "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": "100%"}}, "d0caef34ba7f48a3a5a32083a7622c04": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": {"_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_e8087a4edab0420cbecaba04e73c4cfb", "placeholder": "\u200b", "style": "IPY_MODEL_f3ddb52ac2e24d3db75c8fb658d94a41", "value": " 13/? [00:00<00:00, 238.76it/s, loss=7.33, v_num=6]"}}, "d514fe7f72904e5fb9f4727b9a0d1e5b": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "FloatProgressModel", "state": {"_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "FloatProgressModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "ProgressView", "bar_style": "success", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_6d83ec49723d45a6931b6ba9dbd64ec4", "max": 1.0, "min": 0.0, "orientation": "horizontal", "style": "IPY_MODEL_eb85619e8c9f4ae7bb3ad91dd9896fb3", "value": 1.0}}, "e8087a4edab0420cbecaba04e73c4cfb": {"model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", "model_name": "LayoutModel", "state": {"_model_module": "@jupyter-widgets/base", "_model_module_version": "1.2.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "overflow_x": null, "overflow_y": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null}}, "eb85619e8c9f4ae7bb3ad91dd9896fb3": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "ProgressStyleModel", "state": {"_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "ProgressStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "bar_color": null, "description_width": ""}}, "f3ddb52ac2e24d3db75c8fb658d94a41": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "DescriptionStyleModel", "state": {"_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "DescriptionStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "1.2.0", "_view_name": "StyleView", "description_width": ""}}, "f962e76bc6bd4477847f5dedbf4d5f6d": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HBoxModel", "state": {"_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HBoxModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HBoxView", "box_style": "", "children": ["IPY_MODEL_ffed8dbcdc9d4bd8ab6c5c4411ccf6af", "IPY_MODEL_d514fe7f72904e5fb9f4727b9a0d1e5b", "IPY_MODEL_d0caef34ba7f48a3a5a32083a7622c04"], "layout": "IPY_MODEL_aade554e920a484b943345379a01cf83"}}, "ffed8dbcdc9d4bd8ab6c5c4411ccf6af": {"model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", "model_name": "HTMLModel", "state": {"_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "1.5.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "1.5.0", "_view_name": "HTMLView", "description": "", "description_tooltip": null, "layout": "IPY_MODEL_4c55a94d1d6e4fd7a0df1813d82588a3", "placeholder": "\u200b", "style": "IPY_MODEL_943f4388dd7b46e68aba0643420fc6ce", "value": "Epoch 199: "}}}, "version_major": 2, "version_minor": 0}}}, "nbformat": 4, "nbformat_minor": 5}