{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "k7xBVPzoXxOg" }, "source": [ "# Unit 3: Deep Q-Learning with Atari Games ๐Ÿ‘พ using RL Baselines3 Zoo\n", "\n", "\"Unit\n", "\n", "In this notebook, **you'll train a Deep Q-Learning agent** playing Space Invaders using [RL Baselines3 Zoo](https://github.com/DLR-RM/rl-baselines3-zoo), a training framework based on [Stable-Baselines3](https://stable-baselines3.readthedocs.io/en/master/) that provides scripts for training, evaluating agents, tuning hyperparameters, plotting results and recording videos.\n", "\n", "We're using the [RL-Baselines-3 Zoo integration, a vanilla version of Deep Q-Learning](https://stable-baselines3.readthedocs.io/en/master/modules/dqn.html) with no extensions such as Double-DQN, Dueling-DQN, and Prioritized Experience Replay.\n", "\n", "โฌ‡๏ธ Here is an example of what **you will achieve** โฌ‡๏ธ" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "J9S713biXntc" }, "outputs": [], "source": [ "%%html\n", "" ] }, { "cell_type": "markdown", "source": [ "TODO: ADD TEXT LIVE INFO\n", "\n", "TODO: ADD IF YOU HAVE QUESTIONS\n", "\n", "\n", "###๐ŸŽฎ Environments: \n", "- SpacesInvadersNoFrameskip-v4 \n", "\n", "###๐Ÿ“š RL-Library: \n", "- [RL-Baselines3-Zoo](https://github.com/DLR-RM/rl-baselines3-zoo)" ], "metadata": { "id": "ykJiGevCMVc5" } }, { "cell_type": "markdown", "metadata": { "id": "wciHGjrFYz9m" }, "source": [ "## Objectives of this notebook ๐Ÿ†\n", "At the end of the notebook, you will:\n", "- Be able to understand deeper **how RL Baselines3 Zoo works**.\n", "- Be able to **push your trained agent and the code to the Hub** with a nice video replay and an evaluation score ๐Ÿ”ฅ.\n", "\n", "\n" ] }, { "cell_type": "markdown", "source": [ "## This notebook is from Deep Reinforcement Learning Course\n", "\"Deep" ], "metadata": { "id": "TsnP0rjxMn1e" } }, { "cell_type": "markdown", "metadata": { "id": "nw6fJHIAZd-J" }, "source": [ "In this free course, you will:\n", "\n", "- ๐Ÿ“– Study Deep Reinforcement Learning in **theory and practice**.\n", "- ๐Ÿง‘โ€๐Ÿ’ป Learn to **use famous Deep RL libraries** such as Stable Baselines3, RL Baselines3 Zoo, CleanRL and Sample Factory 2.0.\n", "- ๐Ÿค– Train **agents in unique environments** \n", "\n", "And more check ๐Ÿ“š the syllabus ๐Ÿ‘‰ https://simoninithomas.github.io/deep-rl-course\n", "\n", "Donโ€™t forget to **sign up to the course** (we are collecting your email to be able toย **send you the links when each Unit is published and give you information about the challenges and updates).**\n", "\n", "\n", "The best way to keep in touch is to join our discord server to exchange with the community and with us ๐Ÿ‘‰๐Ÿป https://discord.gg/ydHrjt3WP5" ] }, { "cell_type": "markdown", "metadata": { "id": "0vgANIBBZg1p" }, "source": [ "## Prerequisites ๐Ÿ—๏ธ\n", "Before diving into the notebook, you need to:\n", "\n", "๐Ÿ”ฒ ๐Ÿ“š **Study Deep Q-Learning by reading Unit 3** ๐Ÿค— ADD LINK " ] }, { "cell_type": "markdown", "source": [ "We're constantly trying to improve our tutorials, so **if you find some issues in this notebook**, please [open an issue on the Github Repo](https://github.com/huggingface/deep-rl-class/issues)." ], "metadata": { "id": "7kszpGFaRVhq" } }, { "cell_type": "markdown", "metadata": { "id": "QR0jZtYreSI5" }, "source": [ "# Let's train a Deep Q-Learning agent playing Atari' Space Invaders ๐Ÿ‘พ and upload it to the Hub." ] }, { "cell_type": "markdown", "source": [ "## Set the GPU ๐Ÿ’ช\n", "- To **accelerate the agent's training, we'll use a GPU**. To do that, go to `Runtime > Change Runtime type`\n", "\n", "\"GPU" ], "metadata": { "id": "PU4FVzaoM6fC" } }, { "cell_type": "markdown", "source": [ "- `Hardware Accelerator > GPU`\n", "\n", "\"GPU" ], "metadata": { "id": "KV0NyFdQM9ZG" } }, { "cell_type": "markdown", "source": [ "## Create a virtual display ๐Ÿ”ฝ\n", "\n", "During the notebook, we'll need to generate a replay video. To do so, with colab, **we need to have a virtual screen to be able to render the environment** (and thus record the frames). \n", "\n", "Hence the following cell will install the librairies and create and run a virtual screen ๐Ÿ–ฅ" ], "metadata": { "id": "bTpYcVZVMzUI" } }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "jV6wjQ7Be7p5" }, "outputs": [], "source": [ "%%capture\n", "!apt install python-opengl\n", "!apt install ffmpeg\n", "!apt install xvfb\n", "!pip3 install pyvirtualdisplay" ] }, { "cell_type": "code", "source": [ "# Additional dependencies for RL Baselines3 Zoo\n", "!apt-get install swig cmake freeglut3-dev " ], "metadata": { "id": "fWyKJCy_NJBX" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "!pip install pyglet==1.5.1" ], "metadata": { "id": "C5LwHrISW7Q5" }, "execution_count": null, "outputs": [] }, { "cell_type": "code", "source": [ "# Virtual display\n", "from pyvirtualdisplay import Display\n", "\n", "virtual_display = Display(visible=0, size=(1400, 900))\n", "virtual_display.start()" ], "metadata": { "id": "ww5PQH1gNLI4" }, "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "mYIMvl5X9NAu" }, "source": [ "## Clone RL-Baselines3 Zoo Repo ๐Ÿ“š\n", "You can now directly install from python package `pip install rl_zoo3` but since we want **the full installation with extra environments and dependencies** we're going to clone `RL-Baselines3-Zoo` repository and install from source." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "eu5ZDPZ09VNQ" }, "outputs": [], "source": [ "!git clone https://github.com/DLR-RM/rl-baselines3-zoo" ] }, { "cell_type": "markdown", "metadata": { "id": "HCIoSbvbfAQh" }, "source": [ "## Install dependencies ๐Ÿ”ฝ\n", "We can now install the dependencies RL-Baselines3 Zoo needs (this can take 5min โฒ)\n", "\n", "But we'll also install:\n", "- `huggingface_sb3`: Additional code for Stable-baselines3 to load and upload models from the Hugging Face ๐Ÿค— Hub." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "s2QsFAk29h-D" }, "outputs": [], "source": [ "%cd /content/rl-baselines3-zoo/" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "3QaOS7Xj9j1s" }, "outputs": [], "source": [ "!pip install -r requirements.txt" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "RLRGKFR39l9s" }, "outputs": [], "source": [ "%%capture\n", "!pip install huggingface_sb3" ] }, { "cell_type": "markdown", "metadata": { "id": "5iPgzluo9z-u" }, "source": [ "## Train our Deep Q-Learning Agent to Play Space Invaders ๐Ÿ‘พ\n", "\n", "To train an agent with RL-Baselines3-Zoo, we just need to do two things:\n", "1. We define the hyperparameters in `rl-baselines3-zoo/hyperparams/dqn.yml`\n", "\n", "\"DQN\n" ] }, { "cell_type": "markdown", "metadata": { "id": "_VjblFSVDQOj" }, "source": [ "Here we see that:\n", "- We use the `Atari Wrapper` that preprocess the input (Frame reduction ,grayscale, stack 4 frames)\n", "- We use `CnnPolicy`, since we use Convolutional layers to process the frames\n", "- We train it for 10 million `n_timesteps` \n", "- Memory (Experience Replay) size is 100000, aka the amount of experience steps you saved to train again your agent with.\n", "\n", "๐Ÿ’ก My advice is to **reduce the training timesteps to 1M,** which will take about 90 minutes on a P100. `!nvidia-smi` will tell you what GPU you're using. At 10 million steps, this will take about 9 hours, which could likely result in Colab timing out. I recommend running this on your local computer (or somewhere else). Just click on: `File>Download`. " ] }, { "cell_type": "markdown", "metadata": { "id": "5qTkbWrkECOJ" }, "source": [ "In terms of hyperparameters optimization, my advice is to focus on these 3 hyperparameters:\n", "- `learning_rate`\n", "- `buffer_size (Experience Memory size)`\n", "- `batch_size`\n", "\n", "As a good practice, you need to **check the documentation to understand what each hyperparameters does**: https://stable-baselines3.readthedocs.io/en/master/modules/dqn.html#parameters\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "Hn8bRTHvERRL" }, "source": [ "2. We run `train.py` and save the models on `logs` folder ๐Ÿ“" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Xr1TVW4xfbz3" }, "outputs": [], "source": [ "!python train.py --algo ________ --env SpaceInvadersNoFrameskip-v4 -f _________" ] }, { "cell_type": "markdown", "metadata": { "id": "SeChoX-3SZfP" }, "source": [ "#### Solution" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "PuocgdokSab9" }, "outputs": [], "source": [ "!python train.py --algo dqn --env SpaceInvadersNoFrameskip-v4 -f logs/" ] }, { "cell_type": "markdown", "metadata": { "id": "_dLomIiMKQaf" }, "source": [ "## Let's evaluate our agent ๐Ÿ‘€\n", "- RL-Baselines3-Zoo provides `enjoy.py` to evaluate our agent.\n", "- Let's evaluate it for 5000 timesteps ๐Ÿ”ฅ" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "co5um_KeKbBJ" }, "outputs": [], "source": [ "!python enjoy.py --algo dqn --env SpaceInvadersNoFrameskip-v4 --no-render --n-timesteps _________ --folder logs/" ] }, { "cell_type": "markdown", "metadata": { "id": "Q24K1tyWSj7t" }, "source": [ "#### Solution" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "P_uSmwGRSk0z" }, "outputs": [], "source": [ "!python enjoy.py --algo dqn --env SpaceInvadersNoFrameskip-v4 --no-render --n-timesteps 5000 --folder logs/" ] }, { "cell_type": "markdown", "metadata": { "id": "liBeTltiHJtr" }, "source": [ "## Publish our trained model on the Hub ๐Ÿš€\n", "Now that we saw we got good results after the training, we can publish our trained model on the hub ๐Ÿค— with one line of code.\n", "\n", "\"Space" ] }, { "cell_type": "markdown", "metadata": { "id": "ezbHS1q3HYVV" }, "source": [ "By using `rl_zoo3.push_to_hub.py` **you evaluate, record a replay, generate a model card of your agent and push it to the hub**.\n", "\n", "This way:\n", "- You can **showcase our work** ๐Ÿ”ฅ\n", "- You can **visualize your agent playing** ๐Ÿ‘€\n", "- You can **share with the community an agent that others can use** ๐Ÿ’พ\n", "- You can **access a leaderboard ๐Ÿ† to see how well your agent is performing compared to your classmates** ๐Ÿ‘‰ https://huggingface.co/spaces/chrisjay/Deep-Reinforcement-Learning-Leaderboard" ] }, { "cell_type": "markdown", "metadata": { "id": "XMSeZRBiHk6X" }, "source": [ "To be able to share your model with the community there are three more steps to follow:\n", "\n", "1๏ธโƒฃ (If it's not already done) create an account to HF โžก https://huggingface.co/join\n", "\n", "2๏ธโƒฃ Sign in and then, you need to store your authentication token from the Hugging Face website.\n", "- Create a new token (https://huggingface.co/settings/tokens) **with write role**" ] }, { "cell_type": "markdown", "metadata": { "id": "9ToyuaYwHmxG" }, "source": [ "![image.png](data:image/png;base64,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T2/HkCE5rF+/juefe565c+fSvn372tPEiedpUxvYuXzlsTyw7xV5ed0rBxr11PCM4Xzv9AngOwMKr/eg6otYg7VeDeMZGTkX15YgzOTxSp6a5D39oKxyT86n/eu1gZ40BQiR6t3cZ3dnf+XlO2tQExF5+2haTeQEubm5AEyZMgVN05gzxxE5zZ49hwkTJrhFRs7dQ38PiqqqamVx+6uqttZYb9/X7ti5S1144YXq6quvVkeOHlNVXuurqmtsVbVavmKlAtR5XbqoJUuXurYpPl2i7ho/XmVlZaut27a59p8+Y4bq3qOHytu0WVVVW9WRo8fUseMnatK1qjVrv1ft27dX99//gCotK1dV1VY1b958Bah58+a7tmto+t5/zvyqA+TnXO60paVl6t5771PJycnqjVmzlMlkVpaqajVjxgwFqBdeeEFVV1vVofx8dfXVV6uRI0eq/PzDqtpqVSaTWT3+xBPq8ssvVwcPHVJ79+5VF110kbrjjjtUUXGxOnWqUI0ZM0bdcsstKis7W/3000+q2mpVL730kmrfvr1av2GDqrbaVLXV6mFPFRaq/MNHXP6ePXvU4MFD1MiRI1XByVOq2mpVs2b9WwHq/gceUKdLSlS11abMFosyW6rU6ZISNX78eJWcnKzmv/2Oo75Wm6o0mVRVtVWdLilV48ePV1nZ2Wrbtu2OvKutasaMV1WPHj3Ups2b1YkTBWrYsOFqwoQJ6nRJqbJabcpktiiTyayqrTb10087VFZ2tnr66adVVVW1slptqtJkVmazRVmtNp+/EwWO9IYNG65OnChQVptj+dJly1RycrK68847VVFRsbLabOrw4SNq5MiRqkuXLiovL09ZrTa1cqXjPMzNzVUlJaXqgQceUF26dFH//e47R1o2m6tN5s2fr6qtVmW12dTGjRtVjx491Guvv66sNpv6accOlZ2drQYPGaI2bNigrDabKiwqUrfddptKTk5Wa9asUVabTdlsdle67r7Nx6/f2gL4tdYewA/izx7Aj4S1+/r2CFp7AD+4PxXAj5BV7lbV66u6rArgB7CRYsqUKQpQU6ZMUXPmzFGAmjNnToRzcWDweTbppcwqQESklMJms2G1WtHp9S6FxGs71x1djf8///M/XHTRxa5lx44dY/u2beTkDCE1NZVTp04BkNElg1/27OHAgf1kZmbSunVr7HY7R48e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vffdx7hbb0Nv0HM4P585c+Zw3fXXc/XVV9OqZStA8dJLL9GmTWuGDMmhQ4f2bNyYxzvvvI3ZbMZmt7N2zVpmzJjOhRcOJDk5mcJThSxevJhOnToxbNhwYgwxAKxatdL1zkjnzucFf0G5lN3Lj4R1UsctaySz959dY1awASUIM9nwI6y6I4boo/Z4OcVp9uzZTJhwN84GueLyy4Fakbr88stdDRXue1BYvGbx1ffnmt3nNuuvtKxcvf322yozM1PV1Ea1atVKvfDCn1VhUbGyuM3imzo1t3aWn3PWn6VKLVm6TA0aNMi1/3lduqi/v/SSKj5doipNJjV9xgzVqlUrBahBgwapjz76WE2cNEkNGzbMNbuvpLRMPfXUH1xpjBw5Up0oOKksVdV1pu89g6/SZG5Qfu5/JTWz+LKystX2n35yze5b4VZv56y/SpNZvf32O6pnz16u8mRm9lPz5s13zZCrrraq1157TQHqoosuUnv37lXV1VZVcPKkGjlypALU73//lDJbLKq62uqYqedmq6qr1cJFi1TPXo48evbqpea//bb6/VNPecwErLba1Pbt29UNN9zgcexeeullVVpWpixV1erDhQtVZr9+rvWDBg1SS5d945qluXTZMjVo0K9c67t06aJeeulldbqkVB09dlzlPvecqy0BddVVV6sffvhBVVtt6pdf9qrfPvigSk5Odq2/+eab1d69+1R1zcy9aq+ZfN+vW6eys7Nd2y9Y8J6yWm2qoOCkevLJJ11ptWrVSv3pT39SxcWnXfu6z+KzWh0z6U6ePKXGjh2runTpotauXausVpvaf+CAuvPOO115JCcnqwkTJqg9v/yirNbaWXz33XefKisvd83Sy83NVYBauXKlx+y9QH82Hz/QLL/6Z/3VP8uvPtuAWYDNNMsvErP+IjPLr5FnAargZv0pj+W1vl+rAvheM+f8zfrbv3+/grpn6zln93333XcBtwmWiH7N3G63U1JSgt1uJzk5mdjY2KD3Ly0pQeEY3zIYDB53HJUmExaLmaSkZGIMBmfA4xPqlpWVU1VlITkpmVij0TVpw26zU1JaimP2WAoGvd5zR2dONb7JVInZbCE5OQmDIcatJGHcorphtVopKysDIDU1FZ2u/vemg73/rK6qorSsjJTkZGJiY+u8gysvL8fibDfnsavZwa7slJwuAc0xW02n13lk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)" ] }, { "cell_type": "markdown", "metadata": { "id": "9O6FI0F8HnzE" }, "source": [ "- Copy the token \n", "- Run the cell below and past the token" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Ppu9yePwHrZX" }, "outputs": [], "source": [ "from huggingface_hub import notebook_login # To log to our Hugging Face account to be able to upload models to the Hub.\n", "notebook_login()\n", "!git config --global credential.helper store" ] }, { "cell_type": "markdown", "metadata": { "id": "2RVEdunPHs8B" }, "source": [ "If you don't want to use a Google Colab or a Jupyter Notebook, you need to use this command instead: `huggingface-cli login`" ] }, { "cell_type": "markdown", "metadata": { "id": "dSLwdmvhHvjw" }, "source": [ "3๏ธโƒฃ We're now ready to push our trained agent to the ๐Ÿค— Hub ๐Ÿ”ฅ" ] }, { "cell_type": "markdown", "metadata": { "id": "PW436XnhHw1H" }, "source": [ "Let's run push_to_hub.py file to upload our trained agent to the Hub.\n", "\n", "`--repo-name `: The name of the repo\n", "\n", "`-orga`: Your Hugging Face username\n", "\n", "\"Select" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Ygk2sEktTDEw" }, "outputs": [], "source": [ "!python -m rl_zoo3.push_to_hub --algo dqn --env SpaceInvadersNoFrameskip-v4 --repo-name _____________________ -orga _____________________ -f logs/" ] }, { "cell_type": "markdown", "metadata": { "id": "otgpa0rhS9wR" }, "source": [ "#### Solution" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "_HQNlAXuEhci" }, "outputs": [], "source": [ "!python -m rl_zoo3.push_to_hub --algo dqn --env SpaceInvadersNoFrameskip-v4 --repo-name dqn-SpaceInvadersNoFrameskip-v4 -orga ThomasSimonini -f logs/" ] }, { "cell_type": "markdown", "metadata": { "id": "0D4F5zsTTJ-L" }, "source": [ "###." ] }, { "cell_type": "markdown", "metadata": { "id": "ff89kd2HL1_s" }, "source": [ "Congrats ๐Ÿฅณ you've just trained and uploaded your first Deep Q-Learning agent using RL-Baselines-3 Zoo. The script above should have displayed a link to a model repository such as https://huggingface.co/ThomasSimonini/dqn-SpaceInvadersNoFrameskip-v4. When you go to this link, you can:\n", "\n", "- See a **video preview of your agent** at the right. \n", "- Click \"Files and versions\" to see all the files in the repository.\n", "- Click \"Use in stable-baselines3\" to get a code snippet that shows how to load the model.\n", "- A model card (`README.md` file) which gives a description of the model and the hyperparameters you used.\n", "\n", "Under the hood, the Hub uses git-based repositories (don't worry if you don't know what git is), which means you can update the model with new versions as you experiment and improve your agent.\n", "\n", "**Compare the results of your agents with your classmates** using the [leaderboard](https://huggingface.co/spaces/huggingface-projects/Deep-Reinforcement-Learning-Leaderboard) ๐Ÿ†" ] }, { "cell_type": "markdown", "metadata": { "id": "fyRKcCYY-dIo" }, "source": [ "## Load a powerful trained model ๐Ÿ”ฅ\n", "- The Stable-Baselines3 team uploaded **more than 150 trained Deep Reinforcement Learning agents on the Hub**.\n", "\n", "You can find them here: ๐Ÿ‘‰ https://huggingface.co/sb3\n", "\n", "Some examples:\n", "- Asteroids: https://huggingface.co/sb3/dqn-AsteroidsNoFrameskip-v4\n", "- Beam Rider: https://huggingface.co/sb3/dqn-BeamRiderNoFrameskip-v4\n", "- Breakout: https://huggingface.co/sb3/dqn-BreakoutNoFrameskip-v4\n", "- Road Runner: https://huggingface.co/sb3/dqn-RoadRunnerNoFrameskip-v4\n", "\n", "Let's load an agent playing Beam Rider: https://huggingface.co/sb3/dqn-BeamRiderNoFrameskip-v4" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "B-9QVFIROI5Y" }, "outputs": [], "source": [ "%%html\n", "" ] }, { "cell_type": "markdown", "metadata": { "id": "7ZQNY_r6NJtC" }, "source": [ "1. We download the model using `rl_zoo3.load_from_hub`, and place it in a new folder that we can call `rl_trained`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "OdBNZHy0NGTR" }, "outputs": [], "source": [ "# Download model and save it into the logs/ folder\n", "!python -m rl_zoo3.load_from_hub --algo dqn --env BeamRiderNoFrameskip-v4 -orga sb3 -f rl_trained/" ] }, { "cell_type": "markdown", "metadata": { "id": "LFt6hmWsNdBo" }, "source": [ "2. Let's evaluate if for 5000 timesteps" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "aOxs0rNuN0uS" }, "outputs": [], "source": [ "!python enjoy.py --algo dqn --env BeamRiderNoFrameskip-v4 -n 5000 -f rl_trained/" ] }, { "cell_type": "markdown", "metadata": { "id": "kxMDuDfPON57" }, "source": [ "Why not trying to train your own **Deep Q-Learning Agent playing BeamRiderNoFrameskip-v4? ๐Ÿ†.**\n", "\n", "If you want to try, check https://huggingface.co/sb3/dqn-BeamRiderNoFrameskip-v4#hyperparameters **in the model card, you have the hyperparameters of the trained agent.**" ] }, { "cell_type": "markdown", "metadata": { "id": "xL_ZtUgpOuY6" }, "source": [ "But finding hyperparameters can be a daunting task. Fortunately, we'll see in the next Unit, how we can **use Optuna for optimizing the Hyperparameters ๐Ÿ”ฅ.**\n" ] }, { "cell_type": "markdown", "metadata": { "id": "-pqaco8W-huW" }, "source": [ "## Some additional challenges ๐Ÿ†\n", "The best way to learn **is to try things by your own**!\n", "\n", "In the [Leaderboard](https://huggingface.co/spaces/chrisjay/Deep-Reinforcement-Learning-Leaderboard) you will find your agents. Can you get to the top?\n", "\n", "Here's a list of environments you can try to train your agent with:\n", "- BeamRiderNoFrameskip-v4\n", "- BreakoutNoFrameskip-v4 \n", "- EnduroNoFrameskip-v4\n", "- PongNoFrameskip-v4\n", "\n", "Also, **if you want to learn to implement Deep Q-Learning by yourself**, you definitely should look at CleanRL implementation: https://github.com/vwxyzjn/cleanrl/blob/master/cleanrl/dqn_atari.py\n", "\n", "\"Environments\"/" ] }, { "cell_type": "markdown", "metadata": { "id": "paS-XKo4-kmu" }, "source": [ "________________________________________________________________________\n", "Congrats on finishing this chapter!\n", "\n", "If youโ€™re still feel confused with all these elements...it's totally normal! **This was the same for me and for all people who studied RL.**\n", "\n", "Take time to really **grasp the material before continuing and try the additional challenges**. Itโ€™s important to master these elements and having a solid foundations.\n", "\n", "In the next unit, **weโ€™re going to learn about [Optuna](https://optuna.org/)**. One of the most critical task in Deep Reinforcement Learning is to find a good set of training hyperparameters. And Optuna is a library that helps you to automate the search.\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "5WRx7tO7-mvC" }, "source": [ "\n", "\n", "### This is a course built with you ๐Ÿ‘ท๐Ÿฟโ€โ™€๏ธ\n", "\n", "Finally, we want to improve and update the course iteratively with your feedback. If you have some, please fill this form ๐Ÿ‘‰ https://forms.gle/3HgA7bEHwAmmLfwh9\n", "\n", "We're constantly trying to improve our tutorials, so **if you find some issues in this notebook**, please [open an issue on the Github Repo](https://github.com/huggingface/deep-rl-class/issues)." ] }, { "cell_type": "markdown", "source": [ "See you on [Bonus unit 2](https://github.com/huggingface/deep-rl-class/tree/main/unit2#unit-2-introduction-to-q-learning)! ๐Ÿ”ฅ TODO CHANGE LINK" ], "metadata": { "id": "Kc3udPT-RcXc" } }, { "cell_type": "markdown", "metadata": { "id": "fS3Xerx0fIMV" }, "source": [ "### Keep Learning, Stay Awesome ๐Ÿค—" ] } ], "metadata": { "colab": { "private_outputs": true, "provenance": [] }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "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.10.6" }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false }, "accelerator": "GPU", "gpuClass": "standard" }, "nbformat": 4, "nbformat_minor": 0 }