From b88c22e93a13105d614864bf8b28c646c0048fea Mon Sep 17 00:00:00 2001 From: Jossua Seksik <jossua.seksik@ecl20.ec-lyon.fr> Date: Tue, 5 Mar 2024 19:46:29 +0100 Subject: [PATCH] 2 scripts & Readme --- README.md | 195 ++---------------------------------------- a2c_sb3_cartpole.py | 28 ++++++ image.png | Bin 0 -> 36284 bytes reinforce_cartpole.py | 96 +++++++++++++++++++++ 4 files changed, 132 insertions(+), 187 deletions(-) create mode 100644 a2c_sb3_cartpole.py create mode 100644 image.png create mode 100644 reinforce_cartpole.py diff --git a/README.md b/README.md index 009ba30..1b112f4 100644 --- a/README.md +++ b/README.md @@ -2,209 +2,30 @@ MSO 3.4 Apprentissage Automatique -# - -In this hands-on project, we will first implement a simple RL algorithm and apply it to solve the CartPole-v1 environment. Once we become familiar with the basic workflow, we will learn to use various tools for machine learning model training, monitoring, and sharing, by applying these tools to train a robotic arm. - -## To be handed in - -This work must be done individually. The expected output is a repository named `hands-on-rl` on https://gitlab.ec-lyon.fr. - -We assume that `git` is installed, and that you are familiar with the basic `git` commands. (Optionnaly, you can use GitHub Desktop.) -We also assume that you have access to the [ECL GitLab](https://gitlab.ec-lyon.fr/). If necessary, please consult [this tutorial](https://gitlab.ec-lyon.fr/edelland/inf_tc2/-/blob/main/Tutoriel_gitlab/tutoriel_gitlab.md). - -Your repository must contain a `README.md` file that explains **briefly** the successive steps of the project. It must be private, so you need to add your teacher as "developer" member. - -Throughout the subject, you will find a 🛠 symbol indicating that a specific production is expected. - -The last commit is due before 11:59 pm on March 5, 2024. Subsequent commits will not be considered. - -> ⚠️ **Warning** -> Ensure that you only commit the files that are requested. For example, your directory should not contain the generated `.zip` files, nor the `runs` folder... At the end, your repository must contain one `README.md`, three python scripts, and optionally image files for the plots. - -## Before you start - -Make sure you know the basics of Reinforcement Learning. In case of need, you can refer to the [introduction of the Hugging Face RL course](https://huggingface.co/blog/deep-rl-intro). - -## Introduction to Gym - -[Gym](https://gymnasium.farama.org/) is a framework for developing and evaluating reinforcement learning environments. It offers various environments, including classic control and toy text scenarios, to test RL algorithms. ### Installation -We recommend to use Python virtual environnements to install the required modules : https://docs.python.org/3/library/venv.html - -First, install Pytorch : https://pytorch.org/get-started/locally. - -Then install the following modules : - +Modules to be installed in order to start the project : ```sh pip install gym==0.26.2 -``` - -Install also pyglet for the rendering. - -```sh pip install pyglet==2.0.10 -``` - -If needed - -```sh pip install pygame==2.5.2 -``` - -```sh pip install PyQt5 -``` - - -### Usage - -Here is an example of how to use Gym to solve the `CartPole-v1` environment [Documentation](https://gymnasium.farama.org/environments/classic_control/cart_pole/): - -```python -import gym - -# Create the environment -env = gym.make("CartPole-v1", render_mode="human") - -# Reset the environment and get the initial observation -observation = env.reset() - -for _ in range(100): - # Select a random action from the action space - action = env.action_space.sample() - # Apply the action to the environment - # Returns next observation, reward, done signal (indicating - # if the episode has ended), and an additional info dictionary - observation, reward, terminated, truncated, info = env.step(action) - # Render the environment to visualize the agent's behavior - env.render() - if terminated: - # Terminated before max step - break - -env.close() -``` - -## REINFORCE - -The REINFORCE algorithm (also known as Vanilla Policy Gradient) is a policy gradient method that optimizes the policy directly using gradient descent. The following is the pseudocode of the REINFORCE algorithm: - -```txt -Setup the CartPole environment -Setup the agent as a simple neural network with: - - One fully connected layer with 128 units and ReLU activation followed by a dropout layer - - One fully connected layer followed by softmax activation -Repeat 500 times: - Reset the environment - Reset the buffer - Repeat until the end of the episode: - Compute action probabilities - Sample the action based on the probabilities and store its probability in the buffer - Step the environment with the action - Compute and store in the buffer the return using gamma=0.99 - Normalize the return - Compute the policy loss as -sum(log(prob) * return) - Update the policy using an Adam optimizer and a learning rate of 5e-3 -``` -To learn more about REINFORCE, you can refer to [this unit](https://huggingface.co/learn/deep-rl-course/unit4/introduction). - -> 🛠 **To be handed in** -> Use PyTorch to implement REINFORCE and solve the CartPole environement. Share the code in `reinforce_cartpole.py`, and share a plot showing the total reward accross episodes in the `README.md`. - -## Familiarization with a complete RL pipeline: Application to training a robotic arm - -In this section, you will use the Stable-Baselines3 package to train a robotic arm using RL. You'll get familiar with several widely-used tools for training, monitoring and sharing machine learning models. - -### Get familiar with Stable-Baselines3 - -Stable-Baselines3 (SB3) is a high-level RL library that provides various algorithms and integrated tools to easily train and test reinforcement learning models. - -#### Installation - -```sh pip install stable-baselines3 pip install moviepy ``` -#### Usage - -Use the [Stable-Baselines3 documentation](https://stable-baselines3.readthedocs.io/en/master/) to implement the code to solve the CartPole environment with the Advantage Actor-Critic (A2C) algorithm. - - -> 🛠 **To be handed in** -> Store the code in `a2c_sb3_cartpole.py`. Unless otherwise stated, you'll work upon this file for the next sections. - -### Get familiar with Hugging Face Hub - -Hugging Face Hub is a platform for easy sharing and versioning of trained machine learning models. With Hugging Face Hub, you can quickly and easily share your models with others and make them usable through the API. For example, see the trained A2C agent for CartPole: https://huggingface.co/sb3/a2c-CartPole-v1. Hugging Face Hub provides an API to download and upload SB3 models. - -#### Installation of `huggingface_sb3` - -```sh -pip install huggingface-sb3==2.3.1 -``` - -#### Upload the model on the Hub - -Follow the [Hugging Face Hub documentation](https://huggingface.co/docs/hub/stable-baselines3) to upload the previously learned model to the Hub. - -> 🛠 **To be handed in** -> Link the trained model in the `README.md` file. - -> 📝 **Note** -> [RL-Zoo3](https://stable-baselines3.readthedocs.io/en/master/guide/rl_zoo.html) provides more advanced features to save hyperparameters, generate renderings and metrics. Feel free to try them. - -### Get familiar with Weights & Biases - -Weights & Biases (W&B) is a tool for machine learning experiment management. With W&B, you can track and compare your experiments, visualize your model training and performance. - -#### Installation - -You'll need to install both `wand` and `tensorboar`. - -```shell -pip install wandb tensorboard -``` - -Use the documentation of [Stable-Baselines3](https://stable-baselines3.readthedocs.io/en/master/) and [Weights & Biases](https://docs.wandb.ai/guides/integrations/stable-baselines-3) to track the CartPole training. Make the run public. - -🛠 Share the link of the wandb run in the `README.md` file. - -> ⚠️ **Warning** -> Make sure to make the run public! - -### Full workflow with panda-gym - -[Panda-gym](https://github.com/qgallouedec/panda-gym) is a collection of environments for robotic simulation and control. It provides a range of challenges for training robotic agents in a simulated environment. In this section, you will get familiar with one of the environments provided by panda-gym, the `PandaReachJointsDense-v3`. The objective is to learn how to reach any point in 3D space by directly controlling the robot's articulations. - -#### Installation - -```shell -pip install panda-gym==3.0.7 -``` - -#### Train, track, and share - -Use the Stable-Baselines3 package to train A2C model on the `PandaReachJointsDense-v2` environment. 500k timesteps should be enough. Track the environment with Weights & Biases. Once the training is over, upload the trained model on the Hub. - -> 🛠 **To be handed in** -> Share all the code in `a2c_sb3_panda_reach.py`. Share the link of the wandb run and the trained model in the `README.md` file. - -## Contribute - -This tutorial may contain errors, inaccuracies, typos or areas for improvement. Feel free to contribute to its improvement by opening an issue. +## REINFORCE -## Author +You will find the reinforcement algorithm on the .py file : 'reinforce_cartpole.py'. -Quentin Gallouédec +Here is the final plot obtained after running it, showing the total reward after the 200 episodes. -Updates by Léo Schneider, Emmanuel Dellandréa + -## License +## Stable-Baselines3 and HuggingFace -MIT +We are now solving the CartPole with the A2C algorithm, from the Stable-Baselines3 package. +We saved the model through Hugging Face, which is available via the following link : https://huggingface.co/jossuaseksik/a2c-sb3_cartpole/tree/main diff --git a/a2c_sb3_cartpole.py b/a2c_sb3_cartpole.py new file mode 100644 index 0000000..32bc0f3 --- /dev/null +++ b/a2c_sb3_cartpole.py @@ -0,0 +1,28 @@ +import gym +from stable_baselines3 import A2C +from gymnasium.envs.registration import register +from huggingface_sb3 import push_to_hub + + +config = { + "policy_type": "MlpPolicy", + "total_timesteps": 5000, + "env_name": "CartPole-v1", + } + + +register(id="CartPole-v1", entry_point='gym.envs.classic_control:CartPoleEnv', max_episode_steps=200) + +env = gym.make("CartPole-v1", render_mode="rgb_array") + +model = A2C("MlpPolicy", env, verbose=1) +model.learn(total_timesteps=config["total_timesteps"]) + +model.save("CartPole-v1.zip") + +push_to_hub( + repo_id="jossuaseksik/a2c-sb3_cartpole", + filename="CartPole-v1.zip", + commit_message="Adding CartPole model trained with A2C on HuggingFace", + token="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" +) diff --git a/image.png b/image.png new file mode 100644 index 0000000000000000000000000000000000000000..59fdf54caa6ef3a676612dbad4245f41682f57af GIT binary patch literal 36284 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 literal 0 HcmV?d00001 diff --git a/reinforce_cartpole.py b/reinforce_cartpole.py new file mode 100644 index 0000000..0eec71b --- /dev/null +++ b/reinforce_cartpole.py @@ -0,0 +1,96 @@ +import matplotlib.pyplot as plt + +# PyTorch +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim +from torch.distributions import Categorical + +# Gym +import gym +import pygame + + +env_id = "CartPole-v1" +# Create the env +env = gym.make(env_id, render_mode="human") + +# Get the state space and action space +s_size = env.observation_space.shape[0] +a_size = env.action_space.n + +# 4 entrées : la position du cart, sa vitesse, l'angle de la barre, sa vitesse angulaire +# 2 sorties : aller à droite et aller a gauche +agent = nn.Sequential(nn.Linear(s_size, 128), + nn.ReLU(), + nn.Dropout(), + nn.Linear(128,a_size), + nn.Softmax()) + +print(agent) + +optimizer = optim.Adam(agent.parameters(), lr=5e-3) + +episode_rewards = [] +gamma=0.99 + +for _ in range (200): + observation = env.reset() + + rewards = [] + log_probs = [] + terminated = False + total_reward = 0 + + while not(terminated): + # Convert observation to tensor + observation_array = observation[0] if isinstance(observation, tuple) else observation + observation_tensor = torch.FloatTensor(observation_array).unsqueeze(0) + # observation_tensor = torch.FloatTensor(observation).unsqueeze(0) + # Compute action probabilities + probs = agent(observation_tensor) + m = Categorical(probs) + # Sample action + action = m.sample() + log_prob = m.log_prob(action) + observation, reward, terminated, truncated, info = env.step(action.item()) + env.render() + + log_probs.append(log_prob) + rewards.append(reward) + total_reward += reward + + + episode_rewards.append(total_reward) + + # Compute returns + R = 0 + returns = [] + for r in rewards[::-1]: + R = r + gamma * R + returns.insert(0, R) + returns = torch.tensor(returns) + returns = (returns - returns.mean()) / (returns.std() + 1e-5) + + # Compute policy loss + policy_loss = [] + for log_prob, R in zip(log_probs, returns): + policy_loss.append(log_prob * R) + policy_loss = - torch.cat(policy_loss).sum() + + # Update policy + optimizer.zero_grad() + policy_loss.backward() + optimizer.step() + + print(f'Episode {_} finished') + +env.close() + + +plt.plot(episode_rewards) +plt.title('Total Reward per Episode') +plt.xlabel('Episode') +plt.ylabel('Total Reward') +plt.show() \ No newline at end of file -- GitLab