From 4d9aef4022acb4bf6e849abaf9c2659a054eef78 Mon Sep 17 00:00:00 2001
From: cgerest <148561679+corentingst@users.noreply.github.com>
Date: Tue, 5 Mar 2024 19:34:32 +0100
Subject: [PATCH] Add work to git repo

---
 README.md              | 230 +++++++----------------------------------
 a2c_sb3_cartpole.py    |  52 ++++++++++
 a2c_sb3_panda_reach.py |  59 +++++++++++
 push_model_HF.py       |  10 ++
 reinforce_cartpole.py  | 101 ++++++++++++++++++
 rewards_cartpole.png   | Bin 0 -> 30905 bytes
 train_wb.py            |  42 ++++++++
 7 files changed, 303 insertions(+), 191 deletions(-)
 create mode 100644 a2c_sb3_cartpole.py
 create mode 100644 a2c_sb3_panda_reach.py
 create mode 100644 push_model_HF.py
 create mode 100644 reinforce_cartpole.py
 create mode 100644 rewards_cartpole.png
 create mode 100644 train_wb.py

diff --git a/README.md b/README.md
index 009ba30..f0139ad 100644
--- a/README.md
+++ b/README.md
@@ -1,210 +1,58 @@
-# TD 1 : Hands-On Reinforcement Learning
+# Rendu TD 1 : Hands-On Reinforcement Learning
 
 MSO 3.4 Apprentissage Automatique
 
-# 
+Corentin GEREST
 
-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.
+## Installation
+Nécéssite Python version 3.9 ou ultérieure.
 
-## 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 :
-
-
-```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/):
+Afin de faire fonctionner les fichiers python suivants, vous devrez au préalable installer les bibliothèques suivantes à l'aide de pip:
 
 ```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()
+    pip install torch torchvision torchaudio
+    pip install gym==0.26.2
+    pip install pyglet==2.0.10
+    pip install pygame==2.5.2
+    pip install PyQt5
+    pip install stable-baselines3
+    pip install moviepy
+    pip install huggingface-sb3==2.3.1
+    pip install wandb tensorboard
+    pip install panda-gym==3.0.7
 ```
+## Liste des fichiers
+Ce repo contient les fichiers suivants:
+- ``reinforce_cartpole.py``
+- ``a2c_sb3_cartpole.py``
+- ``push_model_HF.py``
+- ``train_wb.py``
+- ``a2c_sb3_panda_reach.py``
+- ``rewards_cartpole.png``
 
-## 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
+## Utilisation
+Pour exécuter chaque fichier, vous pouver utiliser un terminal. avec la commande
+```terminal
+    python 'nom du fichier'
 ```
 
-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.
+Dans le 1er fichier: reinforce_cartpole.py, on implémente la méthode REINFORCE sur l'environnement CartPole-v1 et on visualise l'évolution du reward au cours des itérations (cf rewards_cartpole.png).
 
-> 🛠 **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.
+![Image](Reinforce_cartpole_rewards2.png)
 
-## Contribute
+Dans le 2ème fichier: a2c_sb3_cartpole.py, on se familiarise avec le package Stable-Baselines3 qui fournit des outils intégrés, et on l'utilise pour résoudre l'environnement CartPole avec l'algo A2C (Advantage Actor-Critic). 
+En plus d'avoir accès à l'évolution du reward au cours des itérations, ce script sauvegarde un modèle sous le nom [insérer nom final].
+Afin d'upload ce modèle sur Hugging Face, j'ai utilisé le court script 'push_model_HF.py'.
+Le modèle entrainé est retrouvable ici: https://huggingface.co/CorentinGst/Cartpolev1/tree/main/a2c_cartpole_model.
 
-This tutorial may contain errors, inaccuracies, typos or areas for improvement. Feel free to contribute to its improvement by opening an issue.
+Dans le 3ème fichier 'train_wb.py', je track l'entraînement sur l'environnement CartPole via Weights and Biases (W&B). Le résultat est visible ici: https://wandb.ai/corentin-ge/wandb_test_cartpole/runs/ybbl1bih?workspace=user-corentin-ge
 
-## Author
+Finalement, en mettant bout à bout ces différentes étapes, on peut constituer un flux de travail complet sur un nouvel environnement: PandaReachJointsDense.
 
-Quentin Gallouédec
+HF: 
 
-Updates by Léo Schneider, Emmanuel Dellandréa
+W&B: https://wandb.ai/corentin-ge/a2c_sb3_panda_reach/runs/pqlrv40v?workspace=user-corentin-ge
 
-## License
 
-MIT
+## Crédits/Citation
+## License
\ No newline at end of file
diff --git a/a2c_sb3_cartpole.py b/a2c_sb3_cartpole.py
new file mode 100644
index 0000000..2e817e9
--- /dev/null
+++ b/a2c_sb3_cartpole.py
@@ -0,0 +1,52 @@
+import gym
+from stable_baselines3 import A2C
+from stable_baselines3.common.env_util import make_vec_env
+from stable_baselines3.common.evaluation import evaluate_policy
+import matplotlib.pyplot as plt
+import numpy as np
+from tqdm import tqdm
+
+if __name__ == "__main__":
+    episodes = 500
+
+    # Create and wrap the CartPole environment
+    env = make_vec_env("CartPole-v1", n_envs=4)
+    
+    # Define the A2C model
+    model = A2C('MlpPolicy', env, verbose=1)
+
+    # Training loop
+    episode_rewards = []
+    for episode in tqdm(range(episodes)):
+        # Reinitialize environment and rewards for each episode
+        obs = env.reset()
+        episode_reward = 0
+
+        while True:
+            # Compute action probabilities
+            action, _states = model.predict(obs)
+            obs, reward, done, _ = env.step(action)
+            episode_reward += np.sum(reward)
+
+            # Break if any environment is done
+            if np.any(done):
+                break
+        
+        episode_rewards.append(episode_reward)
+
+        # Log progress
+        # print(f"Episode: {episode + 1}, Reward: {episode_reward_sum}")
+
+    # Save model
+    model.save("a2c_cartpole_model")
+
+    # Close environments
+    env.close()
+    
+    # Plot result
+    plt.plot(episode_rewards)
+    plt.xlabel('Episode')
+    plt.ylabel('Total reward')
+    plt.title('Evolution of reward')
+    plt.show()
+
diff --git a/a2c_sb3_panda_reach.py b/a2c_sb3_panda_reach.py
new file mode 100644
index 0000000..ea9d1d3
--- /dev/null
+++ b/a2c_sb3_panda_reach.py
@@ -0,0 +1,59 @@
+import gym
+from stable_baselines3 import A2C
+from stable_baselines3.common.monitor import Monitor
+from stable_baselines3.common.vec_env import DummyVecEnv
+import wandb
+import panda_gym
+from wandb.integration.sb3 import WandbCallback
+from huggingface_hub import login
+from huggingface_sb3 import push_to_hub
+
+
+if __name__ == "__main__":
+    # Log in HF
+    login()
+
+    # Initialize a new wandb run
+    # Configs
+    config = {
+        "policy_type": "MultiInputPolicy",
+        "total_timesteps": 500_000,
+        "env_name": "PandaReachJointsDense-v3",
+    }
+
+    # WB initialization
+    run = wandb.init(
+        project="a2c_sb3_panda_reach",
+        sync_tensorboard=True,
+        monitor_gym=True,
+    )
+
+    # WB callback
+    wandb_callback = WandbCallback(
+        gradient_save_freq=100,
+        model_save_path=f"models/{run.id}",
+        verbose=2,
+    )
+
+    env = gym.make("PandaReachJointsDense-v3")
+
+    model = A2C("MultiInputPolicy",
+        env,
+        verbose=1,
+        tensorboard_log=f"runs/{run.id}"
+    )
+    
+    model.learn(
+        total_timesteps=500_000,
+        callback=wandb_callback
+    )
+    model.save("PandaReachJointsDense_1.zip")
+
+    run.finish()
+
+    # Upload on HF
+    push_to_hub(
+        repo_id="CorentinGst/PandaReachJointsDense_1",
+        filename="PandaReachJointsDense_1.zip",
+        commit_message="Add my 1st model trained on PandaReachJointsDense-v3 env",
+    )
\ No newline at end of file
diff --git a/push_model_HF.py b/push_model_HF.py
new file mode 100644
index 0000000..e0705f1
--- /dev/null
+++ b/push_model_HF.py
@@ -0,0 +1,10 @@
+from huggingface_hub import login
+from huggingface_sb3 import push_to_hub
+
+login()
+
+push_to_hub(
+    repo_id="CorentinGst/CartPolev2",
+    filename="a2c_cartpole_model.zip",
+    commit_message="Test HF push API ",
+)
\ No newline at end of file
diff --git a/reinforce_cartpole.py b/reinforce_cartpole.py
new file mode 100644
index 0000000..3fee45c
--- /dev/null
+++ b/reinforce_cartpole.py
@@ -0,0 +1,101 @@
+import numpy as np
+from tqdm import tqdm
+import matplotlib.pyplot as plt
+
+import gym
+import torch
+import torch.nn as nn
+import torch.optim as optim
+
+
+# Define the neural network for the policy
+class PolicyNetwork(nn.Module):
+    def __init__(self, input_dim, output_dim):
+        super(PolicyNetwork, self).__init__()
+        self.fc1 = nn.Linear(input_dim, 128)
+        self.relu = nn.ReLU()
+        self.dropout = nn.Dropout(p=0.6)
+        self.fc2 = nn.Linear(128, output_dim)
+        self.softmax = nn.Softmax(dim=1)
+
+    def forward(self, x):
+        x = self.fc1(x)
+        x = self.relu(x)
+        x = self.dropout(x)
+        x = self.fc2(x)
+        return self.softmax(x)
+
+# Normalize function
+def normalize_rewards(rewards):
+    rewards = np.array(rewards)
+    rewards = (rewards - np.mean(rewards)) / (np.std(rewards) + 1e-9)
+    return rewards
+
+
+if __name__ == "__main__":
+    
+    # Hyperparameters
+    learning_rate = 5e-3
+    gamma = 0.99
+    episodes = 450
+
+    # Environment setup
+    env = gym.make("CartPole-v1")  # , render_mode="human")
+
+    input_dim = env.observation_space.shape[0]
+    output_dim = env.action_space.n
+
+    # Policy network
+    policy = PolicyNetwork(input_dim, output_dim)
+    optimizer = optim.Adam(policy.parameters(), lr=learning_rate)
+
+    # Training loop
+    episode_rewards = []
+    for episode in tqdm(range(episodes)):
+
+        state = env.reset()[0]
+        # --> here with my python environment I need to specify index [0]
+        # but if I use another python environment for example with Google collab
+        # I have to use the following script:
+            # "state = env.reset()"
+
+        saved_log_probs = []
+        rewards = []
+
+        while True:
+            state_tensor = torch.from_numpy(state).float().unsqueeze(0)
+            action_probs = policy(state_tensor)
+            m = torch.distributions.Categorical(action_probs)
+            action = m.sample()
+            saved_log_probs.append(m.log_prob(action))
+            state, reward, done, _, _ = env.step(action.item())
+            rewards.append(reward)
+            if done:
+                break
+
+        # Compute returns
+        returns = torch.tensor([sum(rewards[i:] * (0.99 ** np.arange(len(rewards) - i)))
+                                 for i in range(len(rewards))])
+        returns = (returns - returns.mean()) / (returns.std() + 1e-9)
+
+        # Compute policy loss and entropy loss
+        policy_loss = -torch.stack(saved_log_probs).mul(returns).sum()
+        entropy_loss = -0.01 * (action_probs * torch.log(action_probs)).sum(dim=1).mean()
+
+        total_loss = policy_loss + entropy_loss
+
+        optimizer.zero_grad()
+        total_loss.backward()
+        optimizer.step()
+
+        episode_reward = sum(rewards)
+        episode_rewards.append(episode_reward)
+        
+
+    # Plotting
+    plt.plot(episode_rewards)
+    plt.xlabel('Episode')
+    plt.ylabel('Total reward')
+    plt.title('REINFORCE on CartPole')
+    plt.savefig('rewards_cartpole.png')
+    plt.show()
\ No newline at end of file
diff --git a/rewards_cartpole.png b/rewards_cartpole.png
new file mode 100644
index 0000000000000000000000000000000000000000..fd2e3b609d42a37c2be425b4173c53e3473d307e
GIT binary patch
literal 30905
zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A#=yW}dhyN^1_lPp64!{5;QX|b^2DN4
z2H(Vzf}H%4oXjMJvecsD%=|oKJqtZ!9fgdNl7eC@ef?ax0=@jAbp7McB7zwh7&r?&
zB8wRq_!B{xafSWzOa_JuHBT4Ekcv5P@0Qnyl>W2-aD7_JW$l-od&31;76&a+UZfEo
zVzcqjmoFO_s<h^Hy$ElfbNBOx=6On8>i2Fwa8T^Hq<D$BMa)A{;L_&Vx}Se18&95j
zbJE={cT?ieA6MqTG4tll^Eops&;Pz`(xkwlproX<sA1vPQpS#sj*b<%h72l7N=jS?
zJPe&39UV+O%nl$042KyebaZrR955IO(krgcwW$=6>Sa4UUH^M&U<U^eL+77spPrsx
zcrjy%{oc6#En7_P)ct;IQT=Vr;cv;u`$BW{|G&Pyef{CO@^^PMb*rDvOkZ#@W5Sdv
zEwg4xwbz!vy(M}*u6k|K%+=Su{QSx){^{@k(<Gg@gVEE|(?Ejf#jUN{|NcC;fBfa;
zWxm^8se=ETnwl<b%?`Ku@t|2lTf6vI+}gOkQo+mpT$lUJ6_AnXxpF1s&qMzD1OE1Z
zRdP2MK6aa)dM(2wVrS9P%eB9|)Q?{g;*+!KNS{~9rtUwlBx3nLzoSQwKHPL#?{K?(
z9mnjm*A_ihShQ{F_fp1=6MNI=*NWZURoZ+p<H)tO(Hm=i7UkUABl-LLdv_0yj-=aP
zzLcb-rdqyHwz9gl__|g3JDF*Ev0d%*bvG8jRrj0IaXW9f??xRHlaP-;&YIsp;>>T`
z^6u{L$BpcA4qjede6m(8-|yGU&#(Vyx$pnK>X^c#qI|#Oc9m!<DJccS#`enB{}IgJ
z_fxIx{k`6^v(3G4b2K$rzuzN#db<Ac3k#hM>;KiLsH-pDut8vT`1)f%K0f|<T7SRB
zxBm~C`5$dMtyf&J_skie{=S`CO`pz~_4vWT=7=pBg2(z~yVu3;wpug2ez}*I*N2bC
z<sYxx{qE32W%msgA0LTnG7J7}aB!*1ytyfri6QZLpKRCDe%o&|7#x25`FvjV^zj}^
zWgZEG1)jfScN8pSaM<x=l6T9JB`OP-Epz)gM=y34$K_?d!8*(eXJ#57f190qZ%^cf
ztgVMu1TJoQ^(yP=uH@r=oSvSZPF`MJ0Z~z}0;WxxBy{v!{h!D3tPF>?<=$SBTL1s|
zeO87;cXk%D&OZC>!!P;zKO49FZR3?@VK}rZboHHSH?QxpT=s0m+O?u<!d7p{x~j$4
zup#j<TYK)D+U2WOuWtSFr9{!jCT7Lz)t`TS^_yd%$RIFHH~QL{Ny35N38Dsp*2Y;^
zG#DJ>;^MmB|9-iAzFT3T;WWM2TS~vH-|c+9;9|yyi|+D@IyycZ*SYu0MQlpp<l^T3
zc+UF0$u9k`h1aiLQ_|MvuKoS(sJH%JmR`5VALiKqed#Y@nB>AO(|LDQ=xT$U8wM?H
zZHt1J`|bF8En0Tf<NW=9%UoPs9=y4^d4^#!o05{!gb5QG+~q1+!d72>`){x9vP+kO
zY(AY(mN3Z>P*PG75EX4*8NB?__WO0gHtuWw#qBIoomcb8bIH=BiaI(x`FlRH)&2i{
zpP6CZzF%1@SCv0L)~k0~LQJgfwEljXt5>gTXlgPt$k^A(?EnAwy`Z?b`r7~RcE6XZ
zwP$?r;o;#Qci-2w@7Q6{($bRf<HN%r@9Y1+zF6G3;-v(G&{pH5=(RU)M6{QNtrmTL
zet!9n)$7)M%ecSTt@qH5!p9p@P6}PQcFk<p-isL}6}pp8vM{Vzx$<DY{lAXD#cm6u
zx99oI|9{;6pCDT^<Ndndxr^5?wR?AVw)x^MTST_sDdH}%n(Ka?onh+KsebpB9R=>#
z<^TNj^v7ZOe++Z|+Sjbnxl{Z7?vGci*B4w34Y%ClyCrJv44X=$M~@$WyyUH)cxHxS
z#m}eHKfc@jepfATe*eoKA0Pkt^?H5b+pX6hO%0Db82|rQ_?z3?`IC?JI668u9{zUT
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

literal 0
HcmV?d00001

diff --git a/train_wb.py b/train_wb.py
new file mode 100644
index 0000000..b44d27e
--- /dev/null
+++ b/train_wb.py
@@ -0,0 +1,42 @@
+import gym
+import numpy as np
+
+from stable_baselines3 import A2C
+from stable_baselines3.common.env_util import make_vec_env
+
+from stable_baselines3.common.callbacks import EvalCallback
+import wandb
+from wandb.integration.sb3 import WandbCallback
+
+
+if __name__ == "__main__":
+    # Configuration for W&B
+    wandb.init(project="wandb_test_cartpole", name="cartpole_v1")
+
+    # Create environnement
+    env = make_vec_env("CartPole-v1", n_envs=4)
+
+    # Model initialization
+    model = A2C("MlpPolicy", env, verbose=1, tensorboard_log="./wandb_test_cartpole_tensorboard/")
+
+    # Evaluation callback
+    eval_callback = EvalCallback(
+        env,
+        best_model_save_path='./logs/',
+        log_path='./logs/',
+        eval_freq=500,
+        deterministic=True,
+        render=False
+    )
+
+    # Weights & Biases callback
+    wb_callback = WandbCallback(
+        gradient_save_freq=1000,
+        model_save_path=f"models/{wandb.run.id}",
+        verbose=2,
+    )
+
+    # Actual training
+    model.learn(total_timesteps=25000, callback=[eval_callback, wb_callback])
+    model.save("test_wb_cartpole")
+    wandb.finish()
\ No newline at end of file
-- 
GitLab