diff --git a/projects/README.md b/projects/README.md index 276c7e5..bb6196a 100644 --- a/projects/README.md +++ b/projects/README.md @@ -22,16 +22,19 @@ 注:点击对应的名称会跳到[codes](./codes/)下对应的算法中,其他版本还请读者自行翻阅 -| 算法名称 | 参考文献 | 备注 | -| :-------------------------------------: | :----------------------------------------------------------: | :--: | -| [Policy Gradient](codes/PolicyGradient) | [Policy Gradient paper](https://proceedings.neurips.cc/paper/1999/file/464d828b85b0bed98e80ade0a5c43b0f-Paper.pdf) | | -| DQN-CNN | | 待更 | -| [DoubleDQN](codes/DoubleDQN) | [Double DQN Paper](https://arxiv.org/abs/1509.06461) | | -| [SoftQ](codes/SoftQ) | [Soft Q-learning paper](https://arxiv.org/abs/1702.08165) | | -| [SAC](codes/SAC) | [SAC paper](https://arxiv.org/pdf/1812.05905.pdf) | | -| [SAC-Discrete](codes/SAC) | [SAC-Discrete paper](https://arxiv.org/pdf/1910.07207.pdf) | | -| SAC-S | [SAC-S paper](https://arxiv.org/abs/1801.01290) | | -| DSAC | [DSAC paper](https://paperswithcode.com/paper/addressing-value-estimation-errors-in) | 待更 | +| 算法名称 | 参考文献 | 作者 | 备注 | +| :-------------------------------------: | :----------------------------------------------------------: | :--------------------------------------------------: | :--: | +| [Policy Gradient](codes/PolicyGradient) | [Policy Gradient paper](https://proceedings.neurips.cc/paper/1999/file/464d828b85b0bed98e80ade0a5c43b0f-Paper.pdf) | [johnjim0816](https://github.com/johnjim0816) | | +| [Monte Carlo](codes/MonteCarlo) | | [johnjim0816](https://github.com/johnjim0816) | | +| [DQN](codes/DQN) | | [johnjim0816](https://github.com/johnjim0816) | | +| DQN-CNN | | | 待更 | +| [PER_DQN](codes/PER_DQN) | [PER DQN Paper](https://arxiv.org/abs/1511.05952) | [wangzhongren](https://github.com/wangzhongren-code) | | +| [DoubleDQN](codes/DoubleDQN) | [Double DQN Paper](https://arxiv.org/abs/1509.06461) | [johnjim0816](https://github.com/johnjim0816) | | +| [SoftQ](codes/SoftQ) | [Soft Q-learning paper](https://arxiv.org/abs/1702.08165) | [johnjim0816](https://github.com/johnjim0816) | | +| [SAC](codes/SAC) | [SAC paper](https://arxiv.org/pdf/1812.05905.pdf) | | | +| [SAC-Discrete](codes/SAC) | [SAC-Discrete paper](https://arxiv.org/pdf/1910.07207.pdf) | | | +| SAC-S | [SAC-S paper](https://arxiv.org/abs/1801.01290) | | | +| DSAC | [DSAC paper](https://paperswithcode.com/paper/addressing-value-estimation-errors-in) | | 待更 | ## 3. 算法环境 diff --git a/projects/assets/pseudocodes/pseudocodes.pdf b/projects/assets/pseudocodes/pseudocodes.pdf index cfe734a..5232181 100644 Binary files a/projects/assets/pseudocodes/pseudocodes.pdf and b/projects/assets/pseudocodes/pseudocodes.pdf differ diff --git a/projects/assets/pseudocodes/pseudocodes.tex b/projects/assets/pseudocodes/pseudocodes.tex index 7af7feb..0033ae8 100644 --- a/projects/assets/pseudocodes/pseudocodes.tex +++ b/projects/assets/pseudocodes/pseudocodes.tex @@ -126,6 +126,46 @@ \footnotetext[3]{$\theta_i \leftarrow \theta_i - \lambda \nabla_{\theta_{i}} L_{i}\left(\theta_{i}\right)$} \footnotetext[4]{此处也可像原论文中放到小循环中改成每$C$步,但没有每$C$个回合稳定} \clearpage + + +\section{PER\_DQN算法} +\begin{algorithm}[H] % [H]固定位置 + \floatname{algorithm}{{PER\_DQN算法}\footnotemark[1]} + \renewcommand{\thealgorithm}{} % 去掉算法标号 + \caption{} + \renewcommand{\algorithmicrequire}{\textbf{输入:}} + \renewcommand{\algorithmicensure}{\textbf{输出:}} + \begin{algorithmic}[1] + % \REQUIRE $n \geq 0 \vee x \neq 0$ % 输入 + % \ENSURE $y = x^n$ % 输出 + \STATE 初始化策略网络参数$\theta$ % 初始化 + \STATE 复制参数到目标网络$\hat{Q} \leftarrow Q$ + \STATE 初始化经验回放$D$ + \FOR {回合数 = $1,M$} + \STATE 重置环境,获得初始状态$s_t$ + \FOR {时步 = $1,t$} + \STATE 根据$\varepsilon-greedy$策略采样动作$a_t$ + \STATE 环境根据$a_t$反馈奖励$r_t$和下一个状态$s_{t+1}$ + \STATE 存储transition即$(s_t,a_t,r_t,s_{t+1})$到经验回放$D$,并根据TD-error损失确定其优先级$p_t$ + \STATE 更新环境状态$s_{t+1} \leftarrow s_t$ + \STATE {\bfseries 更新策略:} + \STATE 按照经验回放中的优先级别,每个样本采样概率为$P(j)=p_j^\alpha / \sum_i p_i^\alpha$,从$D$中采样一个大小为batch的transition + \STATE 计算各个样本重要性采样权重 $w_j=(N \cdot P(j))^{-\beta} / \max _i w_i$ + \STATE 计算TD-error $\delta_j$ ; 并根据TD-error更新优先级$p_j$ + \STATE 计算实际的$Q$值,即$y_{j}$\footnotemark[2] + \STATE 根据重要性采样权重调整损失 $L(\theta)=\left(y_{j}-Q\left(s_{j}, a_{j} ; \theta\right)\cdot w_j \right)^{2}$,并将其关于参数$\theta$做随机梯度下降\footnotemark[3] + \ENDFOR + \STATE 每$C$个回合复制参数$\hat{Q}\leftarrow Q$\footnotemark[4]] + \ENDFOR + \end{algorithmic} +\end{algorithm} +\footnotetext[1]{Playing Atari with Deep Reinforcement Learning} +\footnotetext[2]{$y_{i}= \begin{cases}r_{i} & \text {对于终止状态} s_{i+1} \\ r_{i}+\gamma \max _{a^{\prime}} Q\left(s_{i+1}, a^{\prime} ; \theta\right) & \text {对于非终止状态} s_{i+1}\end{cases}$} +\footnotetext[3]{$\theta_i \leftarrow \theta_i - \lambda \nabla_{\theta_{i}} L_{i}\left(\theta_{i}\right)$} +\footnotetext[4]{此处也可像原论文中放到小循环中改成每$C$步,但没有每$C$个回合稳定} +\clearpage + + \section{Policy Gradient算法} \begin{algorithm}[H] % [H]固定位置 \floatname{algorithm}{{REINFORCE算法:Monte-Carlo Policy Gradient}\footnotemark[1]} diff --git a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/models/Q_table b/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/models/Q_table deleted file mode 100644 index e21a117..0000000 Binary files a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/models/Q_table and /dev/null differ diff --git a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/params.json b/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/params.json deleted file mode 100644 index 6f75e32..0000000 --- a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/params.json +++ /dev/null @@ -1 +0,0 @@ -{"algo_name": "First-Visit MC", "env_name": "Racetrack", "train_eps": 200, "test_eps": 20, "gamma": 0.9, "epsilon": 0.15, "device": "cpu", "result_path": "/Users/jj/Desktop/rl-tutorials/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/", "model_path": "/Users/jj/Desktop/rl-tutorials/codes/MonteCarlo/outputs/Racetrack/20220815-180742/models/", "save_fig": true} \ No newline at end of file diff --git a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/test_rewards.npy b/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/test_rewards.npy deleted file mode 100644 index c0de5ac..0000000 Binary files a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/test_rewards.npy and /dev/null differ diff --git a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/testing_curve.png b/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/testing_curve.png deleted file mode 100644 index 3c9cda1..0000000 Binary files a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/testing_curve.png and /dev/null differ diff --git a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/train_rewards.npy b/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/train_rewards.npy deleted file mode 100644 index 026a78d..0000000 Binary files a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/train_rewards.npy and /dev/null differ diff --git a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/training_curve.png b/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/training_curve.png deleted file mode 100644 index 9e8c483..0000000 Binary files a/projects/codes/MonteCarlo/outputs/Racetrack/20220815-180742/results/training_curve.png and /dev/null differ diff --git a/projects/codes/MonteCarlo/task0.py b/projects/codes/MonteCarlo/task0.py index 4570967..75e52e1 100644 --- a/projects/codes/MonteCarlo/task0.py +++ b/projects/codes/MonteCarlo/task0.py @@ -5,7 +5,7 @@ Author: John Email: johnjim0816@gmail.com Date: 2021-03-11 14:26:44 LastEditor: John -LastEditTime: 2022-11-06 00:44:56 +LastEditTime: 2022-11-08 23:35:18 Discription: Environment: ''' @@ -24,9 +24,6 @@ from common.launcher import Launcher from MonteCarlo.agent import FisrtVisitMC from MonteCarlo.config.config import GeneralConfigMC,AlgoConfigMC - -curr_time = datetime.datetime.now().strftime( - "%Y%m%d-%H%M%S") # obtain current time class Main(Launcher): def __init__(self) -> None: super().__init__() diff --git a/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/config.yaml b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/config.yaml new file mode 100644 index 0000000..39f8743 --- /dev/null +++ b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/config.yaml @@ -0,0 +1,25 @@ +general_cfg: + algo_name: PER_DQN + device: cpu + env_name: CartPole-v1 + eval_eps: 10 + eval_per_episode: 5 + load_checkpoint: true + load_path: Train_CartPole-v1_PER_DQN_20221113-162804 + max_steps: 200 + mode: test + save_fig: true + seed: 0 + show_fig: false + test_eps: 10 + train_eps: 200 +algo_cfg: + batch_size: 64 + buffer_size: 100000 + epsilon_decay: 500 + epsilon_end: 0.01 + epsilon_start: 0.95 + gamma: 0.95 + hidden_dim: 256 + lr: 0.0001 + target_update: 4 diff --git a/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/logs/log.txt b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/logs/log.txt new file mode 100644 index 0000000..9fe5454 --- /dev/null +++ b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/logs/log.txt @@ -0,0 +1,14 @@ +2022-11-14 10:46:49 - r - INFO: - n_states: 4, n_actions: 2 +2022-11-14 10:46:49 - r - INFO: - Start testing! +2022-11-14 10:46:49 - r - INFO: - Env: CartPole-v1, Algorithm: PER_DQN, Device: cpu +2022-11-14 10:46:49 - r - INFO: - Episode: 1/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 2/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 3/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 4/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 5/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 6/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 7/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 8/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 9/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Episode: 10/10, Reward: 200.000, Step: 200 +2022-11-14 10:46:49 - r - INFO: - Finish testing! diff --git a/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/models/checkpoint.pt b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/models/checkpoint.pt new file mode 100644 index 0000000..06d607b Binary files /dev/null and b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/models/checkpoint.pt differ diff --git a/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/results/learning_curve.png b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/results/learning_curve.png new file mode 100644 index 0000000..f1e8056 Binary files /dev/null and b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/results/learning_curve.png differ diff --git a/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/results/res.csv b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/results/res.csv new file mode 100644 index 0000000..cbbcf2e --- /dev/null +++ b/projects/codes/PER_DQN/Test_CartPole-v1_PER_DQN_20221114-104649/results/res.csv @@ -0,0 +1,11 @@ +episodes,rewards,steps +0,200.0,200 +1,200.0,200 +2,200.0,200 +3,200.0,200 +4,200.0,200 +5,200.0,200 +6,200.0,200 +7,200.0,200 +8,200.0,200 +9,200.0,200 diff --git a/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/config.yaml b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/config.yaml new file mode 100644 index 0000000..bd4f2bd --- /dev/null +++ b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/config.yaml @@ -0,0 +1,25 @@ +general_cfg: + algo_name: PER_DQN + device: cuda + env_name: CartPole-v1 + eval_eps: 10 + eval_per_episode: 5 + load_checkpoint: false + load_path: tasks + max_steps: 200 + mode: train + save_fig: true + seed: 1 + show_fig: false + test_eps: 10 + train_eps: 200 +algo_cfg: + batch_size: 64 + buffer_size: 100000 + epsilon_decay: 500 + epsilon_end: 0.01 + epsilon_start: 0.95 + gamma: 0.95 + hidden_dim: 256 + lr: 0.0001 + target_update: 4 diff --git a/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/logs/log.txt b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/logs/log.txt new file mode 100644 index 0000000..1cea48c --- /dev/null +++ b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/logs/log.txt @@ -0,0 +1,224 @@ +2022-11-13 16:28:04 - r - INFO: - n_states: 4, n_actions: 2 +2022-11-13 16:28:19 - r - INFO: - Start training! +2022-11-13 16:28:19 - r - INFO: - Env: CartPole-v1, Algorithm: PER_DQN, Device: cuda +2022-11-13 16:28:23 - r - INFO: - Episode: 1/200, Reward: 18.000, Step: 18 +2022-11-13 16:28:24 - r - INFO: - Episode: 2/200, Reward: 35.000, Step: 35 +2022-11-13 16:28:24 - r - INFO: - Episode: 3/200, Reward: 13.000, Step: 13 +2022-11-13 16:28:24 - r - INFO: - Episode: 4/200, Reward: 20.000, Step: 20 +2022-11-13 16:28:24 - r - INFO: - Episode: 5/200, Reward: 24.000, Step: 24 +2022-11-13 16:28:24 - r - INFO: - Current episode 5 has the best eval reward: 9.100 +2022-11-13 16:28:24 - r - INFO: - Episode: 6/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:24 - r - INFO: - Episode: 7/200, Reward: 20.000, Step: 20 +2022-11-13 16:28:24 - r - INFO: - Episode: 8/200, Reward: 19.000, Step: 19 +2022-11-13 16:28:25 - r - INFO: - Episode: 9/200, Reward: 30.000, Step: 30 +2022-11-13 16:28:25 - r - INFO: - Episode: 10/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:25 - r - INFO: - Current episode 10 has the best eval reward: 9.200 +2022-11-13 16:28:25 - r - INFO: - Episode: 11/200, Reward: 16.000, Step: 16 +2022-11-13 16:28:25 - r - INFO: - Episode: 12/200, Reward: 16.000, Step: 16 +2022-11-13 16:28:25 - r - INFO: - Episode: 13/200, Reward: 12.000, Step: 12 +2022-11-13 16:28:25 - r - INFO: - Episode: 14/200, Reward: 28.000, Step: 28 +2022-11-13 16:28:25 - r - INFO: - Episode: 15/200, Reward: 22.000, Step: 22 +2022-11-13 16:28:25 - r - INFO: - Current episode 15 has the best eval reward: 9.300 +2022-11-13 16:28:25 - r - INFO: - Episode: 16/200, Reward: 14.000, Step: 14 +2022-11-13 16:28:25 - r - INFO: - Episode: 17/200, Reward: 9.000, Step: 9 +2022-11-13 16:28:26 - r - INFO: - Episode: 18/200, Reward: 13.000, Step: 13 +2022-11-13 16:28:26 - r - INFO: - Episode: 19/200, Reward: 19.000, Step: 19 +2022-11-13 16:28:26 - r - INFO: - Episode: 20/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:26 - r - INFO: - Episode: 21/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:26 - r - INFO: - Episode: 22/200, Reward: 12.000, Step: 12 +2022-11-13 16:28:26 - r - INFO: - Episode: 23/200, Reward: 9.000, Step: 9 +2022-11-13 16:28:26 - r - INFO: - Episode: 24/200, Reward: 12.000, Step: 12 +2022-11-13 16:28:26 - r - INFO: - Episode: 25/200, Reward: 11.000, Step: 11 +2022-11-13 16:28:26 - r - INFO: - Current episode 25 has the best eval reward: 9.800 +2022-11-13 16:28:26 - r - INFO: - Episode: 26/200, Reward: 11.000, Step: 11 +2022-11-13 16:28:26 - r - INFO: - Episode: 27/200, Reward: 13.000, Step: 13 +2022-11-13 16:28:26 - r - INFO: - Episode: 28/200, Reward: 11.000, Step: 11 +2022-11-13 16:28:27 - r - INFO: - Episode: 29/200, Reward: 13.000, Step: 13 +2022-11-13 16:28:27 - r - INFO: - Episode: 30/200, Reward: 20.000, Step: 20 +2022-11-13 16:28:27 - r - INFO: - Current episode 30 has the best eval reward: 12.200 +2022-11-13 16:28:27 - r - INFO: - Episode: 31/200, Reward: 16.000, Step: 16 +2022-11-13 16:28:27 - r - INFO: - Episode: 32/200, Reward: 9.000, Step: 9 +2022-11-13 16:28:27 - r - INFO: - Episode: 33/200, Reward: 16.000, Step: 16 +2022-11-13 16:28:27 - r - INFO: - Episode: 34/200, Reward: 15.000, Step: 15 +2022-11-13 16:28:27 - r - INFO: - Episode: 35/200, Reward: 12.000, Step: 12 +2022-11-13 16:28:27 - r - INFO: - Current episode 35 has the best eval reward: 12.500 +2022-11-13 16:28:27 - r - INFO: - Episode: 36/200, Reward: 12.000, Step: 12 +2022-11-13 16:28:27 - r - INFO: - Episode: 37/200, Reward: 16.000, Step: 16 +2022-11-13 16:28:28 - r - INFO: - Episode: 38/200, Reward: 13.000, Step: 13 +2022-11-13 16:28:28 - r - INFO: - Episode: 39/200, Reward: 18.000, Step: 18 +2022-11-13 16:28:28 - r - INFO: - Episode: 40/200, Reward: 18.000, Step: 18 +2022-11-13 16:28:28 - r - INFO: - Current episode 40 has the best eval reward: 20.400 +2022-11-13 16:28:28 - r - INFO: - Episode: 41/200, Reward: 48.000, Step: 48 +2022-11-13 16:28:29 - r - INFO: - Episode: 42/200, Reward: 52.000, Step: 52 +2022-11-13 16:28:29 - r - INFO: - Episode: 43/200, Reward: 33.000, Step: 33 +2022-11-13 16:28:29 - r - INFO: - Episode: 44/200, Reward: 15.000, Step: 15 +2022-11-13 16:28:29 - r - INFO: - Episode: 45/200, Reward: 18.000, Step: 18 +2022-11-13 16:28:29 - r - INFO: - Episode: 46/200, Reward: 22.000, Step: 22 +2022-11-13 16:28:29 - r - INFO: - Episode: 47/200, Reward: 19.000, Step: 19 +2022-11-13 16:28:30 - r - INFO: - Episode: 48/200, Reward: 19.000, Step: 19 +2022-11-13 16:28:30 - r - INFO: - Episode: 49/200, Reward: 11.000, Step: 11 +2022-11-13 16:28:30 - r - INFO: - Episode: 50/200, Reward: 9.000, Step: 9 +2022-11-13 16:28:30 - r - INFO: - Episode: 51/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:30 - r - INFO: - Episode: 52/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:30 - r - INFO: - Episode: 53/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:30 - r - INFO: - Episode: 54/200, Reward: 10.000, Step: 10 +2022-11-13 16:28:30 - r - INFO: - Episode: 55/200, Reward: 9.000, Step: 9 +2022-11-13 16:28:30 - r - INFO: - Episode: 56/200, Reward: 17.000, Step: 17 +2022-11-13 16:28:31 - r - INFO: - Episode: 57/200, Reward: 75.000, Step: 75 +2022-11-13 16:28:31 - r - INFO: - Episode: 58/200, Reward: 28.000, Step: 28 +2022-11-13 16:28:31 - r - INFO: - Episode: 59/200, Reward: 30.000, Step: 30 +2022-11-13 16:28:32 - r - INFO: - Episode: 60/200, Reward: 54.000, Step: 54 +2022-11-13 16:28:32 - r - INFO: - Current episode 60 has the best eval reward: 34.600 +2022-11-13 16:28:32 - r - INFO: - Episode: 61/200, Reward: 22.000, Step: 22 +2022-11-13 16:28:32 - r - INFO: - Episode: 62/200, Reward: 28.000, Step: 28 +2022-11-13 16:28:32 - r - INFO: - Episode: 63/200, Reward: 26.000, Step: 26 +2022-11-13 16:28:33 - r - INFO: - Episode: 64/200, Reward: 32.000, Step: 32 +2022-11-13 16:28:33 - r - INFO: - Episode: 65/200, Reward: 30.000, Step: 30 +2022-11-13 16:28:33 - r - INFO: - Episode: 66/200, Reward: 29.000, Step: 29 +2022-11-13 16:28:34 - r - INFO: - Episode: 67/200, Reward: 28.000, Step: 28 +2022-11-13 16:28:34 - r - INFO: - Episode: 68/200, Reward: 38.000, Step: 38 +2022-11-13 16:28:34 - r - INFO: - Episode: 69/200, Reward: 28.000, Step: 28 +2022-11-13 16:28:34 - r - INFO: - Episode: 70/200, Reward: 22.000, Step: 22 +2022-11-13 16:28:34 - r - INFO: - Current episode 70 has the best eval reward: 36.700 +2022-11-13 16:28:35 - r - INFO: - Episode: 71/200, Reward: 40.000, Step: 40 +2022-11-13 16:28:35 - r - INFO: - Episode: 72/200, Reward: 27.000, Step: 27 +2022-11-13 16:28:35 - r - INFO: - Episode: 73/200, Reward: 24.000, Step: 24 +2022-11-13 16:28:35 - r - INFO: - Episode: 74/200, Reward: 47.000, Step: 47 +2022-11-13 16:28:36 - r - INFO: - Episode: 75/200, Reward: 127.000, Step: 127 +2022-11-13 16:28:37 - r - INFO: - Episode: 76/200, Reward: 48.000, Step: 48 +2022-11-13 16:28:37 - r - INFO: - Episode: 77/200, Reward: 27.000, Step: 27 +2022-11-13 16:28:37 - r - INFO: - Episode: 78/200, Reward: 65.000, Step: 65 +2022-11-13 16:28:38 - r - INFO: - Episode: 79/200, Reward: 75.000, Step: 75 +2022-11-13 16:28:38 - r - INFO: - Episode: 80/200, Reward: 47.000, Step: 47 +2022-11-13 16:28:38 - r - INFO: - Current episode 80 has the best eval reward: 37.200 +2022-11-13 16:28:39 - r - INFO: - Episode: 81/200, Reward: 34.000, Step: 34 +2022-11-13 16:28:39 - r - INFO: - Episode: 82/200, Reward: 38.000, Step: 38 +2022-11-13 16:28:39 - r - INFO: - Episode: 83/200, Reward: 24.000, Step: 24 +2022-11-13 16:28:39 - r - INFO: - Episode: 84/200, Reward: 47.000, Step: 47 +2022-11-13 16:28:40 - r - INFO: - Episode: 85/200, Reward: 35.000, Step: 35 +2022-11-13 16:28:40 - r - INFO: - Current episode 85 has the best eval reward: 66.900 +2022-11-13 16:28:41 - r - INFO: - Episode: 86/200, Reward: 103.000, Step: 103 +2022-11-13 16:28:41 - r - INFO: - Episode: 87/200, Reward: 64.000, Step: 64 +2022-11-13 16:28:42 - r - INFO: - Episode: 88/200, Reward: 59.000, Step: 59 +2022-11-13 16:28:43 - r - INFO: - Episode: 89/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:44 - r - INFO: - Episode: 90/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:46 - r - INFO: - Current episode 90 has the best eval reward: 200.000 +2022-11-13 16:28:47 - r - INFO: - Episode: 91/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:48 - r - INFO: - Episode: 92/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:50 - r - INFO: - Episode: 93/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:51 - r - INFO: - Episode: 94/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:52 - r - INFO: - Episode: 95/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:54 - r - INFO: - Current episode 95 has the best eval reward: 200.000 +2022-11-13 16:28:55 - r - INFO: - Episode: 96/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:56 - r - INFO: - Episode: 97/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:58 - r - INFO: - Episode: 98/200, Reward: 200.000, Step: 200 +2022-11-13 16:28:59 - r - INFO: - Episode: 99/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:00 - r - INFO: - Episode: 100/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:02 - r - INFO: - Current episode 100 has the best eval reward: 200.000 +2022-11-13 16:29:04 - r - INFO: - Episode: 101/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:05 - r - INFO: - Episode: 102/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:06 - r - INFO: - Episode: 103/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:07 - r - INFO: - Episode: 104/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:09 - r - INFO: - Episode: 105/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:10 - r - INFO: - Current episode 105 has the best eval reward: 200.000 +2022-11-13 16:29:11 - r - INFO: - Episode: 106/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:13 - r - INFO: - Episode: 107/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:14 - r - INFO: - Episode: 108/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:16 - r - INFO: - Episode: 109/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:17 - r - INFO: - Episode: 110/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:20 - r - INFO: - Episode: 111/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:21 - r - INFO: - Episode: 112/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:22 - r - INFO: - Episode: 113/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:23 - r - INFO: - Episode: 114/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:25 - r - INFO: - Episode: 115/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:26 - r - INFO: - Current episode 115 has the best eval reward: 200.000 +2022-11-13 16:29:27 - r - INFO: - Episode: 116/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:29 - r - INFO: - Episode: 117/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:30 - r - INFO: - Episode: 118/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:31 - r - INFO: - Episode: 119/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:33 - r - INFO: - Episode: 120/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:34 - r - INFO: - Current episode 120 has the best eval reward: 200.000 +2022-11-13 16:29:35 - r - INFO: - Episode: 121/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:37 - r - INFO: - Episode: 122/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:38 - r - INFO: - Episode: 123/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:39 - r - INFO: - Episode: 124/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:41 - r - INFO: - Episode: 125/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:43 - r - INFO: - Episode: 126/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:45 - r - INFO: - Episode: 127/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:46 - r - INFO: - Episode: 128/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:47 - r - INFO: - Episode: 129/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:49 - r - INFO: - Episode: 130/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:51 - r - INFO: - Episode: 131/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:53 - r - INFO: - Episode: 132/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:54 - r - INFO: - Episode: 133/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:55 - r - INFO: - Episode: 134/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:57 - r - INFO: - Episode: 135/200, Reward: 200.000, Step: 200 +2022-11-13 16:29:59 - r - INFO: - Episode: 136/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:01 - r - INFO: - Episode: 137/200, Reward: 185.000, Step: 185 +2022-11-13 16:30:02 - r - INFO: - Episode: 138/200, Reward: 193.000, Step: 193 +2022-11-13 16:30:03 - r - INFO: - Episode: 139/200, Reward: 192.000, Step: 192 +2022-11-13 16:30:04 - r - INFO: - Episode: 140/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:07 - r - INFO: - Episode: 141/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:08 - r - INFO: - Episode: 142/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:10 - r - INFO: - Episode: 143/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:11 - r - INFO: - Episode: 144/200, Reward: 191.000, Step: 191 +2022-11-13 16:30:12 - r - INFO: - Episode: 145/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:15 - r - INFO: - Episode: 146/200, Reward: 184.000, Step: 184 +2022-11-13 16:30:17 - r - INFO: - Episode: 147/200, Reward: 198.000, Step: 198 +2022-11-13 16:30:18 - r - INFO: - Episode: 148/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:19 - r - INFO: - Episode: 149/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:21 - r - INFO: - Episode: 150/200, Reward: 192.000, Step: 192 +2022-11-13 16:30:23 - r - INFO: - Episode: 151/200, Reward: 186.000, Step: 186 +2022-11-13 16:30:25 - r - INFO: - Episode: 152/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:26 - r - INFO: - Episode: 153/200, Reward: 194.000, Step: 194 +2022-11-13 16:30:27 - r - INFO: - Episode: 154/200, Reward: 199.000, Step: 199 +2022-11-13 16:30:29 - r - INFO: - Episode: 155/200, Reward: 183.000, Step: 183 +2022-11-13 16:30:32 - r - INFO: - Episode: 156/200, Reward: 173.000, Step: 173 +2022-11-13 16:30:33 - r - INFO: - Episode: 157/200, Reward: 197.000, Step: 197 +2022-11-13 16:30:34 - r - INFO: - Episode: 158/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:36 - r - INFO: - Episode: 159/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:37 - r - INFO: - Episode: 160/200, Reward: 196.000, Step: 196 +2022-11-13 16:30:40 - r - INFO: - Episode: 161/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:42 - r - INFO: - Episode: 162/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:43 - r - INFO: - Episode: 163/200, Reward: 194.000, Step: 194 +2022-11-13 16:30:44 - r - INFO: - Episode: 164/200, Reward: 185.000, Step: 185 +2022-11-13 16:30:45 - r - INFO: - Episode: 165/200, Reward: 173.000, Step: 173 +2022-11-13 16:30:48 - r - INFO: - Episode: 166/200, Reward: 192.000, Step: 192 +2022-11-13 16:30:49 - r - INFO: - Episode: 167/200, Reward: 164.000, Step: 164 +2022-11-13 16:30:50 - r - INFO: - Episode: 168/200, Reward: 188.000, Step: 188 +2022-11-13 16:30:52 - r - INFO: - Episode: 169/200, Reward: 189.000, Step: 189 +2022-11-13 16:30:53 - r - INFO: - Episode: 170/200, Reward: 197.000, Step: 197 +2022-11-13 16:30:55 - r - INFO: - Episode: 171/200, Reward: 187.000, Step: 187 +2022-11-13 16:30:57 - r - INFO: - Episode: 172/200, Reward: 200.000, Step: 200 +2022-11-13 16:30:58 - r - INFO: - Episode: 173/200, Reward: 195.000, Step: 195 +2022-11-13 16:30:59 - r - INFO: - Episode: 174/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:01 - r - INFO: - Episode: 175/200, Reward: 195.000, Step: 195 +2022-11-13 16:31:03 - r - INFO: - Episode: 176/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:05 - r - INFO: - Episode: 177/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:06 - r - INFO: - Episode: 178/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:07 - r - INFO: - Episode: 179/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:09 - r - INFO: - Episode: 180/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:11 - r - INFO: - Episode: 181/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:13 - r - INFO: - Episode: 182/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:14 - r - INFO: - Episode: 183/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:15 - r - INFO: - Episode: 184/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:17 - r - INFO: - Episode: 185/200, Reward: 173.000, Step: 173 +2022-11-13 16:31:19 - r - INFO: - Episode: 186/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:21 - r - INFO: - Episode: 187/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:22 - r - INFO: - Episode: 188/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:23 - r - INFO: - Episode: 189/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:24 - r - INFO: - Episode: 190/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:26 - r - INFO: - Current episode 190 has the best eval reward: 200.000 +2022-11-13 16:31:27 - r - INFO: - Episode: 191/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:29 - r - INFO: - Episode: 192/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:30 - r - INFO: - Episode: 193/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:31 - r - INFO: - Episode: 194/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:33 - r - INFO: - Episode: 195/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:34 - r - INFO: - Current episode 195 has the best eval reward: 200.000 +2022-11-13 16:31:35 - r - INFO: - Episode: 196/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:37 - r - INFO: - Episode: 197/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:38 - r - INFO: - Episode: 198/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:39 - r - INFO: - Episode: 199/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:40 - r - INFO: - Episode: 200/200, Reward: 200.000, Step: 200 +2022-11-13 16:31:42 - r - INFO: - Current episode 200 has the best eval reward: 200.000 +2022-11-13 16:31:42 - r - INFO: - Finish training! diff --git a/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/models/checkpoint.pt b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/models/checkpoint.pt new file mode 100644 index 0000000..acaef5b Binary files /dev/null and b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/models/checkpoint.pt differ diff --git a/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/results/learning_curve.png b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/results/learning_curve.png new file mode 100644 index 0000000..6f666e3 Binary files /dev/null and b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/results/learning_curve.png differ diff --git a/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/results/res.csv b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/results/res.csv new file mode 100644 index 0000000..1c3339f --- /dev/null +++ b/projects/codes/PER_DQN/Train_CartPole-v1_PER_DQN_20221113-162804/results/res.csv @@ -0,0 +1,201 @@ +episodes,rewards,steps +0,18.0,18 +1,35.0,35 +2,13.0,13 +3,20.0,20 +4,24.0,24 +5,10.0,10 +6,20.0,20 +7,19.0,19 +8,30.0,30 +9,10.0,10 +10,16.0,16 +11,16.0,16 +12,12.0,12 +13,28.0,28 +14,22.0,22 +15,14.0,14 +16,9.0,9 +17,13.0,13 +18,19.0,19 +19,10.0,10 +20,10.0,10 +21,12.0,12 +22,9.0,9 +23,12.0,12 +24,11.0,11 +25,11.0,11 +26,13.0,13 +27,11.0,11 +28,13.0,13 +29,20.0,20 +30,16.0,16 +31,9.0,9 +32,16.0,16 +33,15.0,15 +34,12.0,12 +35,12.0,12 +36,16.0,16 +37,13.0,13 +38,18.0,18 +39,18.0,18 +40,48.0,48 +41,52.0,52 +42,33.0,33 +43,15.0,15 +44,18.0,18 +45,22.0,22 +46,19.0,19 +47,19.0,19 +48,11.0,11 +49,9.0,9 +50,10.0,10 +51,10.0,10 +52,10.0,10 +53,10.0,10 +54,9.0,9 +55,17.0,17 +56,75.0,75 +57,28.0,28 +58,30.0,30 +59,54.0,54 +60,22.0,22 +61,28.0,28 +62,26.0,26 +63,32.0,32 +64,30.0,30 +65,29.0,29 +66,28.0,28 +67,38.0,38 +68,28.0,28 +69,22.0,22 +70,40.0,40 +71,27.0,27 +72,24.0,24 +73,47.0,47 +74,127.0,127 +75,48.0,48 +76,27.0,27 +77,65.0,65 +78,75.0,75 +79,47.0,47 +80,34.0,34 +81,38.0,38 +82,24.0,24 +83,47.0,47 +84,35.0,35 +85,103.0,103 +86,64.0,64 +87,59.0,59 +88,200.0,200 +89,200.0,200 +90,200.0,200 +91,200.0,200 +92,200.0,200 +93,200.0,200 +94,200.0,200 +95,200.0,200 +96,200.0,200 +97,200.0,200 +98,200.0,200 +99,200.0,200 +100,200.0,200 +101,200.0,200 +102,200.0,200 +103,200.0,200 +104,200.0,200 +105,200.0,200 +106,200.0,200 +107,200.0,200 +108,200.0,200 +109,200.0,200 +110,200.0,200 +111,200.0,200 +112,200.0,200 +113,200.0,200 +114,200.0,200 +115,200.0,200 +116,200.0,200 +117,200.0,200 +118,200.0,200 +119,200.0,200 +120,200.0,200 +121,200.0,200 +122,200.0,200 +123,200.0,200 +124,200.0,200 +125,200.0,200 +126,200.0,200 +127,200.0,200 +128,200.0,200 +129,200.0,200 +130,200.0,200 +131,200.0,200 +132,200.0,200 +133,200.0,200 +134,200.0,200 +135,200.0,200 +136,185.0,185 +137,193.0,193 +138,192.0,192 +139,200.0,200 +140,200.0,200 +141,200.0,200 +142,200.0,200 +143,191.0,191 +144,200.0,200 +145,184.0,184 +146,198.0,198 +147,200.0,200 +148,200.0,200 +149,192.0,192 +150,186.0,186 +151,200.0,200 +152,194.0,194 +153,199.0,199 +154,183.0,183 +155,173.0,173 +156,197.0,197 +157,200.0,200 +158,200.0,200 +159,196.0,196 +160,200.0,200 +161,200.0,200 +162,194.0,194 +163,185.0,185 +164,173.0,173 +165,192.0,192 +166,164.0,164 +167,188.0,188 +168,189.0,189 +169,197.0,197 +170,187.0,187 +171,200.0,200 +172,195.0,195 +173,200.0,200 +174,195.0,195 +175,200.0,200 +176,200.0,200 +177,200.0,200 +178,200.0,200 +179,200.0,200 +180,200.0,200 +181,200.0,200 +182,200.0,200 +183,200.0,200 +184,173.0,173 +185,200.0,200 +186,200.0,200 +187,200.0,200 +188,200.0,200 +189,200.0,200 +190,200.0,200 +191,200.0,200 +192,200.0,200 +193,200.0,200 +194,200.0,200 +195,200.0,200 +196,200.0,200 +197,200.0,200 +198,200.0,200 +199,200.0,200 diff --git a/projects/codes/PER_DQN/config/CartPole-v1_PER_DQN_Test.yaml b/projects/codes/PER_DQN/config/CartPole-v1_PER_DQN_Test.yaml new file mode 100644 index 0000000..a1db2ab --- /dev/null +++ b/projects/codes/PER_DQN/config/CartPole-v1_PER_DQN_Test.yaml @@ -0,0 +1,22 @@ +general_cfg: + algo_name: PER_DQN + device: cpu + env_name: CartPole-v1 + mode: test + load_checkpoint: true + load_path: Train_CartPole-v1_PER_DQN_20221113-162804 + max_steps: 200 + save_fig: true + seed: 0 + show_fig: false + test_eps: 10 + train_eps: 200 +algo_cfg: + batch_size: 64 + buffer_size: 100000 + epsilon_decay: 500 + epsilon_end: 0.01 + epsilon_start: 0.95 + gamma: 0.95 + lr: 0.0001 + target_update: 4 diff --git a/projects/codes/PER_DQN/config/CartPole-v1_PER_DQN_Train.yaml b/projects/codes/PER_DQN/config/CartPole-v1_PER_DQN_Train.yaml new file mode 100644 index 0000000..553622f --- /dev/null +++ b/projects/codes/PER_DQN/config/CartPole-v1_PER_DQN_Train.yaml @@ -0,0 +1,22 @@ +general_cfg: + algo_name: PER_DQN + device: cuda + env_name: CartPole-v1 + mode: train + load_checkpoint: false + load_path: Train_CartPole-v1_PER_DQN_20221026-054757 + max_steps: 200 + save_fig: true + seed: 0 + show_fig: false + test_eps: 10 + train_eps: 200 +algo_cfg: + batch_size: 64 + buffer_size: 100000 + epsilon_decay: 500 + epsilon_end: 0.01 + epsilon_start: 0.95 + gamma: 0.95 + lr: 0.0001 + target_update: 4 diff --git a/projects/codes/PER_DQN/config/config.py b/projects/codes/PER_DQN/config/config.py new file mode 100644 index 0000000..a92c7e0 --- /dev/null +++ b/projects/codes/PER_DQN/config/config.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +Author: JiangJi +Email: johnjim0816@gmail.com +Date: 2022-10-30 00:37:33 +LastEditor: JiangJi +LastEditTime: 2022-10-30 01:19:08 +Discription: default parameters of DQN +''' +from common.config import GeneralConfig,AlgoConfig +class GeneralConfigDQN(GeneralConfig): + def __init__(self) -> None: + self.env_name = "CartPole-v1" # name of environment + self.algo_name = "PER_DQN" # name of algorithm + self.mode = "train" # train or test + self.seed = 1 # random seed + self.device = "cuda" # device to use + self.train_eps = 200 # number of episodes for training + self.test_eps = 10 # number of episodes for testing + self.max_steps = 200 # max steps for each episode + self.load_checkpoint = False + self.load_path = "tasks" # path to load model + self.show_fig = False # show figure or not + self.save_fig = True # save figure or not + +class AlgoConfigDQN(AlgoConfig): + def __init__(self) -> None: + # set epsilon_start=epsilon_end can obtain fixed epsilon=epsilon_end + self.epsilon_start = 0.95 # epsilon start value + self.epsilon_end = 0.01 # epsilon end value + self.epsilon_decay = 500 # epsilon decay rate + self.hidden_dim = 256 # hidden_dim for MLP + self.gamma = 0.95 # discount factor + self.lr = 0.0001 # learning rate + self.buffer_size = 100000 # size of replay buffer + self.batch_size = 64 # batch size + self.target_update = 4 # target network update frequency diff --git a/projects/codes/PER_DQN/per_dqn.py b/projects/codes/PER_DQN/per_dqn.py new file mode 100644 index 0000000..6fbf651 --- /dev/null +++ b/projects/codes/PER_DQN/per_dqn.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +Author: DingLi +Email: wangzhongren@sjtu.edu.cn +Date: 2022-10-31 22:54:00 +LastEditor: DingLi +LastEditTime: 2022-11-14 10:43:18 +Discription: CartPole-v1 +''' + +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-12 00:50:49 +@LastEditor: John +LastEditTime: 2022-10-26 07:50:24 +@Discription: +@Environment: python 3.7.7 +''' +'''off-policy +''' + +import torch +import torch.nn as nn +import torch.optim as optim +import random +import math +import numpy as np + +class PER_DQN: + def __init__(self,model,memory,cfg): + + self.n_actions = cfg.n_actions + self.device = torch.device(cfg.device) + self.gamma = cfg.gamma + ## e-greedy parameters + self.sample_count = 0 # sample count for epsilon decay + self.epsilon = cfg.epsilon_start + self.sample_count = 0 + self.epsilon_start = cfg.epsilon_start + self.epsilon_end = cfg.epsilon_end + self.epsilon_decay = cfg.epsilon_decay + self.batch_size = cfg.batch_size + self.policy_net = model.to(self.device) + self.target_net = model.to(self.device) + ## copy parameters from policy net to target net + for target_param, param in zip(self.target_net.parameters(),self.policy_net.parameters()): + target_param.data.copy_(param.data) + # self.target_net.load_state_dict(self.policy_net.state_dict()) # or use this to copy parameters + self.optimizer = optim.Adam(self.policy_net.parameters(), lr=cfg.lr) + self.memory = memory + self.update_flag = False + + def sample_action(self, state): + ''' sample action with e-greedy policy + ''' + self.sample_count += 1 + # epsilon must decay(linear,exponential and etc.) for balancing exploration and exploitation + self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \ + math.exp(-1. * self.sample_count / self.epsilon_decay) + if random.random() > self.epsilon: + with torch.no_grad(): + state = torch.tensor(state, device=self.device, dtype=torch.float32).unsqueeze(dim=0) + q_values = self.policy_net(state) + action = q_values.max(1)[1].item() # choose action corresponding to the maximum q value + else: + action = random.randrange(self.n_actions) + return action + # @torch.no_grad() + # def sample_action(self, state): + # ''' sample action with e-greedy policy + # ''' + # self.sample_count += 1 + # # epsilon must decay(linear,exponential and etc.) for balancing exploration and exploitation + # self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \ + # math.exp(-1. * self.sample_count / self.epsilon_decay) + # if random.random() > self.epsilon: + # state = torch.tensor(state, device=self.device, dtype=torch.float32).unsqueeze(dim=0) + # q_values = self.policy_net(state) + # action = q_values.max(1)[1].item() # choose action corresponding to the maximum q value + # else: + # action = random.randrange(self.n_actions) + # return action + def predict_action(self,state): + ''' predict action + ''' + with torch.no_grad(): + state = torch.tensor(state, device=self.device, dtype=torch.float32).unsqueeze(dim=0) + q_values = self.policy_net(state) + action = q_values.max(1)[1].item() # choose action corresponding to the maximum q value + return action + def update(self): + if len(self.memory) < self.batch_size: # when transitions in memory donot meet a batch, not update + # print ("self.batch_size = ", self.batch_size) + return + else: + if not self.update_flag: + print("Begin to update!") + self.update_flag = True + # sample a batch of transitions from replay buffer + (state_batch, action_batch, reward_batch, next_state_batch, done_batch), idxs_batch, is_weights_batch = self.memory.sample( + self.batch_size) + state_batch = torch.tensor(np.array(state_batch), device=self.device, dtype=torch.float) # shape(batchsize,n_states) + action_batch = torch.tensor(action_batch, device=self.device).unsqueeze(1) # shape(batchsize,1) + reward_batch = torch.tensor(reward_batch, device=self.device, dtype=torch.float).unsqueeze(1) # shape(batchsize,1) + next_state_batch = torch.tensor(np.array(next_state_batch), device=self.device, dtype=torch.float) # shape(batchsize,n_states) + done_batch = torch.tensor(np.float32(done_batch), device=self.device).unsqueeze(1) # shape(batchsize,1) + q_value_batch = self.policy_net(state_batch).gather(dim=1, index=action_batch) # shape(batchsize,1),requires_grad=True + next_max_q_value_batch = self.target_net(next_state_batch).max(1)[0].detach().unsqueeze(1) + expected_q_value_batch = reward_batch + self.gamma * next_max_q_value_batch* (1-done_batch) + + loss = torch.mean(torch.pow((q_value_batch - expected_q_value_batch) * torch.from_numpy(is_weights_batch).cuda(), 2)) + # loss = nn.MSELoss()(q_value_batch, expected_q_value_batch) # shape same to + + abs_errors = np.sum(np.abs(q_value_batch.cpu().detach().numpy() - expected_q_value_batch.cpu().detach().numpy()), axis=1) + self.memory.batch_update(idxs_batch, abs_errors) + + # backpropagation + self.optimizer.zero_grad() + loss.backward() + # clip to avoid gradient explosion + for param in self.policy_net.parameters(): + param.grad.data.clamp_(-1, 1) + self.optimizer.step() + if self.sample_count % self.target_update == 0: # target net update, target_update means "C" in pseucodes + self.target_net.load_state_dict(self.policy_net.state_dict()) + + def save_model(self, fpath): + from pathlib import Path + # create path + Path(fpath).mkdir(parents=True, exist_ok=True) + torch.save(self.target_net.state_dict(), f"{fpath}/checkpoint.pt") + + def load_model(self, fpath): + checkpoint = torch.load(f"{fpath}/checkpoint.pt",map_location=self.device) + self.target_net.load_state_dict(checkpoint) + for target_param, param in zip(self.target_net.parameters(), self.policy_net.parameters()): + param.data.copy_(target_param.data) diff --git a/projects/codes/PER_DQN/task0.py b/projects/codes/PER_DQN/task0.py new file mode 100644 index 0000000..8b6247b --- /dev/null +++ b/projects/codes/PER_DQN/task0.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +Author: DingLi +Email: wangzhongren@sjtu.edu.cn +Date: 2022-10-31 22:54:00 +LastEditor: DingLi +LastEditTime: 2022-11-14 10:45:11 +Discription: CartPole-v1 +''' + +''' +Author: JiangJi +Email: johnjim0816@gmail.com +Date: 2022-10-12 11:09:54 +LastEditor: JiangJi +LastEditTime: 2022-10-30 01:29:25 +Discription: CartPole-v1,Acrobot-v1 +''' +import sys,os +curr_path = os.path.dirname(os.path.abspath(__file__)) # current path +parent_path = os.path.dirname(curr_path) # parent path +sys.path.append(parent_path) # add to system path +import gym +import torch + +from common.utils import all_seed,merge_class_attrs +from common.models import MLP +from common.memories import ReplayBuffer, ReplayTree +from common.launcher import Launcher +from envs.register import register_env +from per_dqn import PER_DQN +from config.config import GeneralConfigDQN,AlgoConfigDQN +class Main(Launcher): + def __init__(self) -> None: + super().__init__() + self.cfgs['general_cfg'] = merge_class_attrs(self.cfgs['general_cfg'],GeneralConfigDQN()) + self.cfgs['algo_cfg'] = merge_class_attrs(self.cfgs['algo_cfg'],AlgoConfigDQN()) + def env_agent_config(self,cfg,logger): + ''' create env and agent + ''' + register_env(cfg.env_name) + env = gym.make(cfg.env_name,new_step_api=True) # create env + all_seed(env,seed=cfg.seed) # set random seed + try: # state dimension + n_states = env.observation_space.n # print(hasattr(env.observation_space, 'n')) + except AttributeError: + n_states = env.observation_space.shape[0] # print(hasattr(env.observation_space, 'shape')) + n_actions = env.action_space.n # action dimension + logger.info(f"n_states: {n_states}, n_actions: {n_actions}") # print info + # update to cfg paramters + setattr(cfg, 'n_states', n_states) + setattr(cfg, 'n_actions', n_actions) + # cfg.update({"n_states":n_states,"n_actions":n_actions}) # update to cfg paramters + model = MLP(n_states,n_actions,hidden_dim=cfg.hidden_dim) + memory = ReplayTree(cfg.buffer_size) # replay SumTree + agent = PER_DQN(model,memory,cfg) # create agent + return env, agent + + def train_one_episode(self,env, agent, cfg): + ''' train one episode + ''' + ep_step = 0 + state = env.reset() # reset and obtain initial state + for _ in range(cfg.max_steps): + ep_step += 1 + action = agent.sample_action(state) # sample action + next_state, reward, terminated, truncated , info = env.step(action) # update env and return transitions under new_step_api of OpenAI Gym + + policy_val = agent.policy_net(torch.tensor(state, device = cfg.device))[action] + target_val = agent.target_net(torch.tensor(next_state, device = cfg.device)) + + if terminated: + error = abs(policy_val - reward) + else: + error = abs(policy_val - reward - cfg.gamma * torch.max(target_val)) + agent.memory.push(error.cpu().detach().numpy(), (state, action, reward, + next_state, terminated)) # save transitions + state = next_state # update next state for env + agent.update() # update agent + ep_reward += reward # + if terminated: + break + return agent, ep_reward, ep_step + + def test_one_episode(self, env, agent, cfg): + ep_reward = 0 # reward per episode + ep_step = 0 + state = env.reset() # reset and obtain initial state + for _ in range(cfg.max_steps): + ep_step+=1 + action = agent.predict_action(state) # predict action + next_state, reward, terminated, _, _ = env.step(action) + state = next_state + ep_reward += reward + if terminated: + break + return agent, ep_reward, ep_step + + +if __name__ == "__main__": + main = Main() + main.run() + diff --git a/projects/codes/common/launcher.py b/projects/codes/common/launcher.py index 148d200..2c0793c 100644 --- a/projects/codes/common/launcher.py +++ b/projects/codes/common/launcher.py @@ -36,11 +36,11 @@ class Launcher: ep_reward = 0 ep_step = 0 return agent,ep_reward,ep_step - def test_one_episode(self,env, agent, cfg): + def test_one_episode(self, env, agent, cfg): ep_reward = 0 ep_step = 0 return agent,ep_reward,ep_step - def evaluate(self,env, agent, cfg): + def evaluate(self, env, agent, cfg): sum_eval_reward = 0 for _ in range(cfg.eval_eps): _,eval_ep_reward,_ = self.test_one_episode(env, agent, cfg) diff --git a/projects/codes/common/memories.py b/projects/codes/common/memories.py index 1317dd1..fd50ab9 100644 --- a/projects/codes/common/memories.py +++ b/projects/codes/common/memories.py @@ -10,6 +10,7 @@ LastEditTime: 2022-08-28 23:44:06 @Environment: python 3.7.7 ''' import random +import numpy as np from collections import deque class ReplayBuffer: def __init__(self, capacity): @@ -71,4 +72,136 @@ class PGReplay(ReplayBufferQue): ''' sample all the transitions ''' batch = list(self.buffer) - return zip(*batch) \ No newline at end of file + return zip(*batch) + +class SumTree: + '''SumTree for the per(Prioritized Experience Replay) DQN. + This SumTree code is a modified version and the original code is from: + https://github.com/MorvanZhou/Reinforcement-learning-with-tensorflow/blob/master/contents/5.2_Prioritized_Replay_DQN/RL_brain.py + ''' + def __init__(self, capacity: int): + self.capacity = capacity + self.data_pointer = 0 + self.n_entries = 0 + self.tree = np.zeros(2 * capacity - 1) + self.data = np.zeros(capacity, dtype = object) + + def update(self, tree_idx, p): + '''Update the sampling weight + ''' + change = p - self.tree[tree_idx] + self.tree[tree_idx] = p + + while tree_idx != 0: + tree_idx = (tree_idx - 1) // 2 + self.tree[tree_idx] += change + + def add(self, p, data): + '''Adding new data to the sumTree + ''' + tree_idx = self.data_pointer + self.capacity - 1 + self.data[self.data_pointer] = data + # print ("tree_idx=", tree_idx) + # print ("nonzero = ", np.count_nonzero(self.tree)) + self.update(tree_idx, p) + + self.data_pointer += 1 + if self.data_pointer >= self.capacity: + self.data_pointer = 0 + + if self.n_entries < self.capacity: + self.n_entries += 1 + + def get_leaf(self, v): + '''Sampling the data + ''' + parent_idx = 0 + while True: + cl_idx = 2 * parent_idx + 1 + cr_idx = cl_idx + 1 + if cl_idx >= len(self.tree): + leaf_idx = parent_idx + break + else: + if v <= self.tree[cl_idx] : + parent_idx = cl_idx + else: + v -= self.tree[cl_idx] + parent_idx = cr_idx + + data_idx = leaf_idx - self.capacity + 1 + return leaf_idx, self.tree[leaf_idx], self.data[data_idx] + + def total(self): + return int(self.tree[0]) + +class ReplayTree: + '''ReplayTree for the per(Prioritized Experience Replay) DQN. + ''' + def __init__(self, capacity): + self.capacity = capacity # the capacity for memory replay + self.tree = SumTree(capacity) + self.abs_err_upper = 1. + + ## hyper parameter for calculating the importance sampling weight + self.beta_increment_per_sampling = 0.001 + self.alpha = 0.6 + self.beta = 0.4 + self.epsilon = 0.01 + self.abs_err_upper = 1. + + def __len__(self): + ''' return the num of storage + ''' + return self.tree.total() + + def push(self, error, sample): + '''Push the sample into the replay according to the importance sampling weight + ''' + p = (np.abs(error) + self.epsilon) ** self.alpha + self.tree.add(p, sample) + + + def sample(self, batch_size): + '''This is for sampling a batch data and the original code is from: + https://github.com/rlcode/per/blob/master/prioritized_memory.py + ''' + pri_segment = self.tree.total() / batch_size + + priorities = [] + batch = [] + idxs = [] + + is_weights = [] + + self.beta = np.min([1., self.beta + self.beta_increment_per_sampling]) + min_prob = np.min(self.tree.tree[-self.tree.capacity:]) / self.tree.total() + + for i in range(batch_size): + a = pri_segment * i + b = pri_segment * (i+1) + + s = random.uniform(a, b) + idx, p, data = self.tree.get_leaf(s) + + priorities.append(p) + batch.append(data) + idxs.append(idx) + prob = p / self.tree.total() + + sampling_probabilities = np.array(priorities) / self.tree.total() + is_weights = np.power(self.tree.n_entries * sampling_probabilities, -self.beta) + is_weights /= is_weights.max() + + return zip(*batch), idxs, is_weights + + def batch_update(self, tree_idx, abs_errors): + '''Update the importance sampling weight + ''' + abs_errors += self.epsilon + + clipped_errors = np.minimum(abs_errors, self.abs_err_upper) + ps = np.power(clipped_errors, self.alpha) + + for ti, p in zip(tree_idx, ps): + self.tree.update(ti, p) diff --git a/projects/codes/common/utils.py b/projects/codes/common/utils.py index 62c343d..212ec5f 100644 --- a/projects/codes/common/utils.py +++ b/projects/codes/common/utils.py @@ -5,7 +5,7 @@ Author: John Email: johnjim0816@gmail.com Date: 2021-03-12 16:02:24 LastEditor: John -LastEditTime: 2022-10-26 07:38:17 +LastEditTime: 2022-11-14 10:27:43 Discription: Environment: ''' @@ -179,6 +179,8 @@ def all_seed(env,seed = 1): import torch import numpy as np import random + if seed == 0: + return # print(f"seed = {seed}") env.seed(seed) # env config np.random.seed(seed) diff --git a/projects/notebooks/1.QLearning.ipynb b/projects/notebooks/1.QLearning.ipynb deleted file mode 100644 index 4116815..0000000 --- a/projects/notebooks/1.QLearning.ipynb +++ /dev/null @@ -1,454 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1、定义算法\n", - "强化学习算法的模式都比较固定,一般包括sample(即训练时采样动作),predict(测试时预测动作),update(算法更新)以及保存模型和加载模型等几个方法,其中对于每种算法samle和update的方式是不相同,而其他方法就大同小异。" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import math\n", - "import torch\n", - "from collections import defaultdict\n", - "\n", - "class QLearning(object):\n", - " def __init__(self,n_states,\n", - " n_actions,cfg):\n", - " self.n_actions = n_actions \n", - " self.lr = cfg.lr # 学习率\n", - " self.gamma = cfg.gamma \n", - " self.epsilon = cfg.epsilon_start\n", - " self.sample_count = 0 \n", - " self.epsilon_start = cfg.epsilon_start\n", - " self.epsilon_end = cfg.epsilon_end\n", - " self.epsilon_decay = cfg.epsilon_decay\n", - " self.Q_table = defaultdict(lambda: np.zeros(n_actions)) # 用嵌套字典存放状态->动作->状态-动作值(Q值)的映射,即Q表\n", - " def sample_action(self, state):\n", - " ''' 采样动作,训练时用\n", - " '''\n", - " self.sample_count += 1\n", - " self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \\\n", - " math.exp(-1. * self.sample_count / self.epsilon_decay) # epsilon是会递减的,这里选择指数递减\n", - " # e-greedy 策略\n", - " if np.random.uniform(0, 1) > self.epsilon:\n", - " action = np.argmax(self.Q_table[str(state)]) # 选择Q(s,a)最大对应的动作\n", - " else:\n", - " action = np.random.choice(self.n_actions) # 随机选择动作\n", - " return action\n", - " def predict_action(self,state):\n", - " ''' 预测或选择动作,测试时用\n", - " '''\n", - " action = np.argmax(self.Q_table[str(state)])\n", - " return action\n", - " def update(self, state, action, reward, next_state, done):\n", - " Q_predict = self.Q_table[str(state)][action] \n", - " if done: # 终止状态\n", - " Q_target = reward \n", - " else:\n", - " Q_target = reward + self.gamma * np.max(self.Q_table[str(next_state)]) \n", - " self.Q_table[str(state)][action] += self.lr * (Q_target - Q_predict)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2、定义训练\n", - "强化学习算法的训练方式也比较固定,如下:\n", - "```python\n", - "for i_ep in range(train_eps): # 遍历每个回合\n", - " state = env.reset() # 重置环境,即开始新的回合\n", - " while True: # 对于一些比较复杂的游戏可以设置每回合最大的步长,例如while ep_step<100,就是每回合最大步长为100。\n", - " action = agent.sample(state) # 根据算法采样一个动作\n", - " next_state, reward, done, _ = env.step(action) # 与环境进行一次动作交互\n", - " agent.memory.push(state, action, reward, next_state, done) # 记录memory\n", - " agent.update(state, action, reward, next_state, done) # 算法更新\n", - " state = next_state # 更新状态\n", - " if done:\n", - " break\n", - "```\n", - "首先对于每个回合,回合开始时环境需要重置,好比我们每次开一把游戏需要从头再来一样。我们可以设置智能体在每回合数的最大步长,尤其是对于比较复杂的游戏,这样做的好处之一就是帮助智能体在训练中快速收敛,比如我们先验地知道最优解的大概步数,那么理论上智能体收敛时也应该是这个步数附近,设置最大步数可以方便智能体接近这个最优解。在每个回合中,智能体首先需要采样(sample),或者说采用探索策略例如常见的$\\varepsilon$-greedy策略或者UCB探索策略等等。采样的过程是将当前的状态state作为输入,智能体采样输出动作action。然后环境根据采样出来的动作反馈出下一个状态以及相应的reward等信息。接下来对于具有memory的智能体例如包含replay memory的DQN来说,需要将相应的transition(记住这个词,中文不好翻译,通常是状态、动作、奖励等信息)。紧接着就是智能体更新,对于深度强化学习此时一般从memory中随机采样一些transition进行更新,对于Q learning一般是采样上一次的transition。更新公式是比较关键的部分,但是也很通用,一般基于值的算法更新公式都是一个套路如下:\n", - "$$\n", - "y_{j}= \\begin{cases}r_{j} & \\text { for terminal } s_{t+1} \\\\ r_{j}+\\gamma \\max _{a^{\\prime}} Q\\left(s_{t+1}, a^{\\prime} ; \\theta\\right) & \\text { for non-terminal } s_{t+1}\\end{cases}\n", - "$$\n", - "智能体更新完之后,通常需要更新状态,即```state = next_state```,然后会检查是否完成了这一回合的游戏,即```done==True```,注意完成并不代表这回合成功,也有可能是失败的太离谱,等同学们有了自定义强化学习环境的经验就知道了(等你长大就知道了XD)。\n", - "如果需要记录奖励、损失等等的话可以再加上,如下方代码,实际项目中更多地使用tensorboard来记录相应的数据,甚至于笔者就在这些教学代码中使用过,但是看起来有些繁琐,容易给大家增加不必要的学习难度,因此学有余力以及需要在项目研究中做强化学习的可以去看看,也很简单。\n", - "此外稍微复杂一些的强化学习不是一次性写完代码就能收敛的,这时需要我们做一个调参侠。为了检查我们参数调得好不好,可以在终端print出奖励、损失以及epsilon等随着回合数的变化,这点说明一下强化学习的训练过程一般都是先探索然后收敛的,官方的话就是权衡exploration and exploitation。e-greedy策略的做法就是前期探索,然后逐渐减小探索率至慢慢收敛,也就是这个epsilon。这个值越大比如0.9就说明智能体90%的概率在随机探索,通常情况下会设置三个值,epsilon_start、epsilon_end以及epsilon_decay,即初始值、终止值和衰减率,其中初始值一般是0.95不变,终止值是0.01,也就是说即使在收敛阶段也让智能体保持很小概率的探索,这样做的原因就是智能体已经学出了一个不错的策略,但是保不齐还有更好的策略,好比我们知道要出人头地学历高比较重要,但是“人还是要有梦想的,万一实现了呢”,总是存在意外的可能,对吧。回归正题,比较关键的是epsilon_decay这个衰减率,这个epsilon衰减太快了学来的策略往往过拟合,好比一条只能选择一朵花的花道上,你早早选择了一朵看起来还可以的花,却错过了后面更多的好花。但是衰减的太慢会影响收敛的速度,好比你走过了花道的尽头也还没选出一朵花来,相比前者不如更甚。当然强化学习的调参相比于深度学习只能说是有过之无不及,比较复杂,不止epsilon这一个,这就需要同学们的耐心学习了。\n", - "强化学习测试的代码跟训练基本上是一样的,因此我放到同一个代码段里。相比于训练代码,测试代码主要有以下几点不同:1、测试模型的过程是不需要更新的,这个是不言而喻的;2、测试代码不需要采样(sample)动作,相比之代替的是预测(sample)动作,其区别就是采样动作时可能会使用各种策略例如$\\varepsilon$-greedy策略,而预测动作不需要,只需要根据训练时学习好的Q表或者网络模型代入状态得到动作即可;3、测试过程终端一般只需要看奖励,不需要看epislon等,反正它在测试中也是无意义的。" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "def train(cfg,env,agent):\n", - " print('开始训练!')\n", - " print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')\n", - " rewards = [] # 记录奖励\n", - " for i_ep in range(cfg.train_eps):\n", - " ep_reward = 0 # 记录每个回合的奖励\n", - " state = env.reset() # 重置环境,即开始新的回合\n", - " while True:\n", - " action = agent.sample_action(state) # 根据算法采样一个动作\n", - " next_state, reward, done, _ = env.step(action) # 与环境进行一次动作交互\n", - " agent.update(state, action, reward, next_state, done) # Q学习算法更新\n", - " state = next_state # 更新状态\n", - " ep_reward += reward\n", - " if done:\n", - " break\n", - " rewards.append(ep_reward)\n", - " if (i_ep+1)%20==0:\n", - " print(f\"回合:{i_ep+1}/{cfg.train_eps},奖励:{ep_reward:.1f},Epsilon:{agent.epsilon:.3f}\")\n", - " print('完成训练!')\n", - " return {\"rewards\":rewards}\n", - "def test(cfg,env,agent):\n", - " print('开始测试!')\n", - " print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')\n", - " rewards = [] # 记录所有回合的奖励\n", - " for i_ep in range(cfg.test_eps):\n", - " ep_reward = 0 # 记录每个episode的reward\n", - " state = env.reset() # 重置环境, 重新开一局(即开始新的一个回合)\n", - " while True:\n", - " action = agent.predict_action(state) # 根据算法选择一个动作\n", - " next_state, reward, done, _ = env.step(action) # 与环境进行一个交互\n", - " state = next_state # 更新状态\n", - " ep_reward += reward\n", - " if done:\n", - " break\n", - " rewards.append(ep_reward)\n", - " print(f\"回合数:{i_ep+1}/{cfg.test_eps}, 奖励:{ep_reward:.1f}\")\n", - " print('完成测试!')\n", - " return {\"rewards\":rewards}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3、定义环境\n", - "\n", - "OpenAI Gym中其实集成了很多强化学习环境,足够大家学习了,但是在做强化学习的应用中免不了要自己创建环境,比如在本项目中其实不太好找到Qlearning能学出来的环境,Qlearning实在是太弱了,需要足够简单的环境才行,因此本项目写了一个环境,大家感兴趣的话可以看一下,一般环境接口最关键的部分即使reset和step。" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "import turtle\n", - "import numpy as np\n", - "\n", - "# turtle tutorial : https://docs.python.org/3.3/library/turtle.html\n", - "\n", - "class CliffWalkingWapper(gym.Wrapper):\n", - " def __init__(self, env):\n", - " gym.Wrapper.__init__(self, env)\n", - " self.t = None\n", - " self.unit = 50\n", - " self.max_x = 12\n", - " self.max_y = 4\n", - "\n", - " def draw_x_line(self, y, x0, x1, color='gray'):\n", - " assert x1 > x0\n", - " self.t.color(color)\n", - " self.t.setheading(0)\n", - " self.t.up()\n", - " self.t.goto(x0, y)\n", - " self.t.down()\n", - " self.t.forward(x1 - x0)\n", - "\n", - " def draw_y_line(self, x, y0, y1, color='gray'):\n", - " assert y1 > y0\n", - " self.t.color(color)\n", - " self.t.setheading(90)\n", - " self.t.up()\n", - " self.t.goto(x, y0)\n", - " self.t.down()\n", - " self.t.forward(y1 - y0)\n", - "\n", - " def draw_box(self, x, y, fillcolor='', line_color='gray'):\n", - " self.t.up()\n", - " self.t.goto(x * self.unit, y * self.unit)\n", - " self.t.color(line_color)\n", - " self.t.fillcolor(fillcolor)\n", - " self.t.setheading(90)\n", - " self.t.down()\n", - " self.t.begin_fill()\n", - " for i in range(4):\n", - " self.t.forward(self.unit)\n", - " self.t.right(90)\n", - " self.t.end_fill()\n", - "\n", - " def move_player(self, x, y):\n", - " self.t.up()\n", - " self.t.setheading(90)\n", - " self.t.fillcolor('red')\n", - " self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit)\n", - "\n", - " def render(self):\n", - " if self.t == None:\n", - " self.t = turtle.Turtle()\n", - " self.wn = turtle.Screen()\n", - " self.wn.setup(self.unit * self.max_x + 100,\n", - " self.unit * self.max_y + 100)\n", - " self.wn.setworldcoordinates(0, 0, self.unit * self.max_x,\n", - " self.unit * self.max_y)\n", - " self.t.shape('circle')\n", - " self.t.width(2)\n", - " self.t.speed(0)\n", - " self.t.color('gray')\n", - " for _ in range(2):\n", - " self.t.forward(self.max_x * self.unit)\n", - " self.t.left(90)\n", - " self.t.forward(self.max_y * self.unit)\n", - " self.t.left(90)\n", - " for i in range(1, self.max_y):\n", - " self.draw_x_line(\n", - " y=i * self.unit, x0=0, x1=self.max_x * self.unit)\n", - " for i in range(1, self.max_x):\n", - " self.draw_y_line(\n", - " x=i * self.unit, y0=0, y1=self.max_y * self.unit)\n", - "\n", - " for i in range(1, self.max_x - 1):\n", - " self.draw_box(i, 0, 'black')\n", - " self.draw_box(self.max_x - 1, 0, 'yellow')\n", - " self.t.shape('turtle')\n", - "\n", - " x_pos = self.s % self.max_x\n", - " y_pos = self.max_y - 1 - int(self.s / self.max_x)\n", - " self.move_player(x_pos, y_pos)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "import gym\n", - "def env_agent_config(cfg,seed=1):\n", - " '''创建环境和智能体\n", - " Args:\n", - " cfg ([type]): [description]\n", - " seed (int, optional): 随机种子. Defaults to 1.\n", - " Returns:\n", - " env [type]: 环境\n", - " agent : 智能体\n", - " ''' \n", - " env = gym.make(cfg.env_name) \n", - " env = CliffWalkingWapper(env)\n", - " env.seed(seed) # 设置随机种子\n", - " n_states = env.observation_space.n # 状态维度\n", - " n_actions = env.action_space.n # 动作维度\n", - " agent = QLearning(n_states,n_actions,cfg)\n", - " return env,agent" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4、设置参数\n", - "\n", - "到这里所有qlearning模块就算完成了,下面需要设置一些参数,方便大家“炼丹”,其中默认的是笔者已经调好的~。另外为了定义了一个画图函数,用来描述奖励的变化。" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "import datetime\n", - "import argparse\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "def get_args():\n", - " \"\"\" \n", - " \"\"\"\n", - " curr_time = datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\") # 获取当前时间\n", - " parser = argparse.ArgumentParser(description=\"hyperparameters\") \n", - " parser.add_argument('--algo_name',default='Q-learning',type=str,help=\"name of algorithm\")\n", - " parser.add_argument('--env_name',default='CliffWalking-v0',type=str,help=\"name of environment\")\n", - " parser.add_argument('--train_eps',default=400,type=int,help=\"episodes of training\") # 训练的回合数\n", - " parser.add_argument('--test_eps',default=20,type=int,help=\"episodes of testing\") # 测试的回合数\n", - " parser.add_argument('--gamma',default=0.90,type=float,help=\"discounted factor\") # 折扣因子\n", - " parser.add_argument('--epsilon_start',default=0.95,type=float,help=\"initial value of epsilon\") # e-greedy策略中初始epsilon\n", - " parser.add_argument('--epsilon_end',default=0.01,type=float,help=\"final value of epsilon\") # e-greedy策略中的终止epsilon\n", - " parser.add_argument('--epsilon_decay',default=300,type=int,help=\"decay rate of epsilon\") # e-greedy策略中epsilon的衰减率\n", - " parser.add_argument('--lr',default=0.1,type=float,help=\"learning rate\")\n", - " parser.add_argument('--device',default='cpu',type=str,help=\"cpu or cuda\") \n", - " args = parser.parse_args([]) \n", - " return args\n", - "curr_time = datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\") # 获取当前时间\n", - "\n", - "def smooth(data, weight=0.9): \n", - " '''用于平滑曲线,类似于Tensorboard中的smooth\n", - "\n", - " Args:\n", - " data (List):输入数据\n", - " weight (Float): 平滑权重,处于0-1之间,数值越高说明越平滑,一般取0.9\n", - "\n", - " Returns:\n", - " smoothed (List): 平滑后的数据\n", - " '''\n", - " last = data[0] # First value in the plot (first timestep)\n", - " smoothed = list()\n", - " for point in data:\n", - " smoothed_val = last * weight + (1 - weight) * point # 计算平滑值\n", - " smoothed.append(smoothed_val) \n", - " last = smoothed_val \n", - " return smoothed\n", - "\n", - "def plot_rewards(rewards,cfg, tag='train'):\n", - " sns.set()\n", - " plt.figure() # 创建一个图形实例,方便同时多画几个图\n", - " plt.title(\"learning curve on {} of {} for {}\".format(\n", - " cfg.device, cfg.algo_name, cfg.env_name))\n", - " plt.xlabel('epsiodes')\n", - " plt.plot(rewards, label='rewards')\n", - " plt.plot(smooth(rewards), label='smoothed')\n", - " plt.legend()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5、我准备好了!\n", - "\n", - "到现在我们真的可以像海绵宝宝那样大声说出来“我准备好了!“,跟着注释来看下效果吧~。" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "开始训练!\n", - "环境:CliffWalking-v0, 算法:Q-learning, 设备:cpu\n", - "回合:20/400,奖励:-45.0,Epsilon:0.010\n", - "回合:40/400,奖励:-34.0,Epsilon:0.010\n", - "回合:60/400,奖励:-47.0,Epsilon:0.010\n", - "回合:80/400,奖励:-88.0,Epsilon:0.010\n", - "回合:100/400,奖励:-53.0,Epsilon:0.010\n", - "回合:120/400,奖励:-23.0,Epsilon:0.010\n", - "回合:140/400,奖励:-20.0,Epsilon:0.010\n", - "回合:160/400,奖励:-29.0,Epsilon:0.010\n", - "回合:180/400,奖励:-42.0,Epsilon:0.010\n", - "回合:200/400,奖励:-28.0,Epsilon:0.010\n", - "回合:220/400,奖励:-20.0,Epsilon:0.010\n", - "回合:240/400,奖励:-20.0,Epsilon:0.010\n", - "回合:260/400,奖励:-17.0,Epsilon:0.010\n", - "回合:280/400,奖励:-13.0,Epsilon:0.010\n", - "回合:300/400,奖励:-13.0,Epsilon:0.010\n", - "回合:320/400,奖励:-13.0,Epsilon:0.010\n", - "回合:340/400,奖励:-13.0,Epsilon:0.010\n", - "回合:360/400,奖励:-13.0,Epsilon:0.010\n", - "回合:380/400,奖励:-13.0,Epsilon:0.010\n", - "回合:400/400,奖励:-14.0,Epsilon:0.010\n", - "完成训练!\n", - "开始测试!\n", - "环境:CliffWalking-v0, 算法:Q-learning, 设备:cpu\n", - "回合数:1/20, 奖励:-13.0\n", - "回合数:2/20, 奖励:-13.0\n", - "回合数:3/20, 奖励:-13.0\n", - "回合数:4/20, 奖励:-13.0\n", - "回合数:5/20, 奖励:-13.0\n", - "回合数:6/20, 奖励:-13.0\n", - "回合数:7/20, 奖励:-13.0\n", - "回合数:8/20, 奖励:-13.0\n", - "回合数:9/20, 奖励:-13.0\n", - "回合数:10/20, 奖励:-13.0\n", - "回合数:11/20, 奖励:-13.0\n", - "回合数:12/20, 奖励:-13.0\n", - "回合数:13/20, 奖励:-13.0\n", - "回合数:14/20, 奖励:-13.0\n", - "回合数:15/20, 奖励:-13.0\n", - "回合数:16/20, 奖励:-13.0\n", - "回合数:17/20, 奖励:-13.0\n", - "回合数:18/20, 奖励:-13.0\n", - "回合数:19/20, 奖励:-13.0\n", - "回合数:20/20, 奖励:-13.0\n", - "完成测试!\n" - ] - }, - { - "data": { - "image/png": "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PVmOHDmyxHG6XC7mzJlDs2bNALx/kxMnTnDzzTdz00030blzZ+Li4vjuu++876vMZ8hgMHg/H8XLUK/Xl1i/PCeg85VXafF5NG/eHIfDwcGDB2nUqJF3eVFREQ899BDPP//8Bfd9tvDwcBo0aMBXX32FTqfzJqo+ffqwbds2fvrpJ5544okLfi+L69KlC506dWLSpEksXry41M9ARb6PJ0+eZNy4cd7lb731FnFxcUyfPp3k5GS2bNniba6LiooiNTXV20ybkpJC69atK1wuVUmaj8qpZ8+efPDBB9hsNlwuF1OmTOHll1/m4MGD5Obm8uijj9KvXz9++ukn7zpVLTY2ls8++wybzYbD4SizltG9e3e+/vprb/X+tddeY8GCBYSHh7N3716KiopwOBwlTjylGTFiBNOmTaNVq1bek3FZ5XC2Xr16sWjRIux2Oy6Xiw8++IAePXqU+1gtFgvt2rXzjgA5fvw4t9xyCzk5OQDe5ceOHWPDhg307t2b8PBwjh07Rnp6OpqmlTmSo2vXrmzYsMFb3ff0bfzjH/84b0yPP/4477zzDuvWrQPcV5jXX389EyZM4NFHH8VkMpGUlORtMrvllltKvL9nz54sWLAATdOw2Wzcf//9vP/+++zatYvw8HAeeOABevXq5f27XKjmURmxsbF88sknuFwuCgoKWLFixQVrR5UtL6PRyNixY5k8eTJpaWmAuynmhRdeoKCggDp16lTqGHr37s0bb7xBnz59vMv69OnD8uXLiYiIIDw8vELfy/bt23P77bcTHBxcanNuWcr6PtapU8f7GVi+fDl16tTBZDKRkJBAYmIiAwYMwGw2A+4ayOLFiwE4ceIE33//PX379q1UuVQVqSmU0wMPPMCMGTO47rrrcDqdtGnThsTERAIDA+nTpw/x8fHUqlWLhg0b0rx5cw4ePFhmVbSyrr/+evbv38/w4cMJDAykfv363g9XcbGxsezbt897UmrevDnTpk0jICCALl26EB8fj9Vq5eqrrz5v08Hw4cN5+eWXS5z0yyqHs91///3MmDGD4cOH43A46NixI1OmTKnQ8b700ks899xzLFy4EEVRSEpK8l5RHTlyhOuvv57CwkKeeuopmjZtCrivzm+44QasVmuJk0ZxzZs355lnnuGhhx7C6XQSEBDA/PnzCQ4OPm88bdq04d///jdz5szhhRde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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# 获取参数\n", - "cfg = get_args() \n", - "# 训练\n", - "env, agent = env_agent_config(cfg)\n", - "res_dic = train(cfg, env, agent)\n", - " \n", - "plot_rewards(res_dic['rewards'], cfg, tag=\"train\") \n", - "# 测试\n", - "res_dic = test(cfg, env, agent)\n", - "plot_rewards(res_dic['rewards'], cfg, tag=\"test\") # 画出结果" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.7.13 ('easyrl')", - "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.7.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "8994a120d39b6e6a2ecc94b4007f5314b68aa69fc88a7f00edf21be39b41f49c" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/projects/notebooks/MonteCarlo.ipynb b/projects/notebooks/MonteCarlo.ipynb new file mode 100644 index 0000000..c0613ce --- /dev/null +++ b/projects/notebooks/MonteCarlo.ipynb @@ -0,0 +1,480 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1、定义算法" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "import numpy as np\n", + "class FisrtVisitMC:\n", + " ''' On-Policy First-Visit MC Control\n", + " '''\n", + " def __init__(self,cfg):\n", + " self.n_actions = cfg.n_actions\n", + " self.epsilon = cfg.epsilon\n", + " self.gamma = cfg.gamma \n", + " self.Q_table = defaultdict(lambda: np.zeros(cfg.n_actions))\n", + " self.returns_sum = defaultdict(float) # 保存return之和\n", + " self.returns_count = defaultdict(float)\n", + " \n", + " def sample_action(self,state):\n", + " state = str(state)\n", + " if np.random.uniform(0, 1) > self.epsilon:\n", + " action = np.argmax(self.Q_table[str(state)]) # 选择Q(s,a)最大对应的动作\n", + " else:\n", + " action = np.random.choice(self.n_actions) # 随机选择动作\n", + " return action\n", + " # if state in self.Q_table.keys():\n", + " # best_action = np.argmax(self.Q_table[state])\n", + " # action_probs = np.ones(self.n_actions, dtype=float) * self.epsilon / self.n_actions\n", + " # action_probs[best_action] += (1.0 - self.epsilon)\n", + " # action = np.random.choice(np.arange(len(action_probs)), p=action_probs)\n", + " # else:\n", + " # action = np.random.randint(0,self.n_actions)\n", + " # return action\n", + " def predict_action(self,state):\n", + " state = str(state)\n", + " state = str(state)\n", + " if np.random.uniform(0, 1) > self.epsilon:\n", + " action = np.argmax(self.Q_table[str(state)]) # 选择Q(s,a)最大对应的动作\n", + " else:\n", + " action = np.random.choice(self.n_actions) # 随机选择动作\n", + " return action\n", + " # if state in self.Q_table.keys():\n", + " # best_action = np.argmax(self.Q_table[state])\n", + " # action_probs = np.ones(self.n_actions, dtype=float) * self.epsilon / self.n_actions\n", + " # action_probs[best_action] += (1.0 - self.epsilon)\n", + " # action = np.argmax(self.Q_table[state])\n", + " # else:\n", + " # action = np.random.randint(0,self.n_actions)\n", + " # return action\n", + " def update(self,one_ep_transition):\n", + " # Find all (state, action) pairs we've visited in this one_ep_transition\n", + " # We convert each state to a tuple so that we can use it as a dict key\n", + " sa_in_episode = set([(str(x[0]), x[1]) for x in one_ep_transition])\n", + " for state, action in sa_in_episode:\n", + " sa_pair = (state, action)\n", + " # Find the first occurence of the (state, action) pair in the one_ep_transition\n", + "\n", + " first_occurence_idx = next(i for i,x in enumerate(one_ep_transition)\n", + " if str(x[0]) == state and x[1] == action)\n", + " # Sum up all rewards since the first occurance\n", + " G = sum([x[2]*(self.gamma**i) for i,x in enumerate(one_ep_transition[first_occurence_idx:])])\n", + " # Calculate average return for this state over all sampled episodes\n", + " self.returns_sum[sa_pair] += G\n", + " self.returns_count[sa_pair] += 1.0\n", + " self.Q_table[state][action] = self.returns_sum[sa_pair] / self.returns_count[sa_pair]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2、定义训练" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "def train(cfg,env,agent):\n", + " print('开始训练!')\n", + " print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')\n", + " rewards = [] # 记录奖励\n", + " for i_ep in range(cfg.train_eps):\n", + " ep_reward = 0 # 记录每个回合的奖励\n", + " one_ep_transition = []\n", + " state = env.reset(seed=cfg.seed) # 重置环境,即开始新的回合\n", + " for _ in range(cfg.max_steps):\n", + " action = agent.sample_action(state) # 根据算法采样一个动作\n", + " next_state, reward, terminated, info = env.step(action) # 与环境进行一次动作交互\n", + " one_ep_transition.append((state, action, reward)) # 保存transitions\n", + " agent.update(one_ep_transition) # 更新智能体\n", + " state = next_state # 更新状态\n", + " ep_reward += reward \n", + " if terminated:\n", + " break\n", + " rewards.append(ep_reward)\n", + " if (i_ep+1)%10==0:\n", + " print(f\"回合:{i_ep+1}/{cfg.train_eps},奖励:{ep_reward:.1f}\")\n", + " print('完成训练!')\n", + " return {\"rewards\":rewards}\n", + "def test(cfg,env,agent):\n", + " print('开始测试!')\n", + " print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')\n", + " rewards = [] # 记录所有回合的奖励\n", + " for i_ep in range(cfg.test_eps):\n", + " ep_reward = 0 # 记录每个episode的reward\n", + " state = env.reset(seed=cfg.seed) # 重置环境, 重新开一局(即开始新的一个回合)\n", + " for _ in range(cfg.max_steps):\n", + " action = agent.predict_action(state) # 根据算法选择一个动作\n", + " next_state, reward, terminated, info = env.step(action) # 与环境进行一个交互\n", + " state = next_state # 更新状态\n", + " ep_reward += reward\n", + " if terminated:\n", + " break\n", + " rewards.append(ep_reward)\n", + " print(f\"回合数:{i_ep+1}/{cfg.test_eps}, 奖励:{ep_reward:.1f}\")\n", + " print('完成测试!')\n", + " return {\"rewards\":rewards}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3、定义环境" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "import gym\n", + "import turtle\n", + "import numpy as np\n", + "\n", + "# turtle tutorial : https://docs.python.org/3.3/library/turtle.html\n", + "\n", + "class CliffWalkingWapper(gym.Wrapper):\n", + " def __init__(self, env):\n", + " gym.Wrapper.__init__(self, env)\n", + " self.t = None\n", + " self.unit = 50\n", + " self.max_x = 12\n", + " self.max_y = 4\n", + "\n", + " def draw_x_line(self, y, x0, x1, color='gray'):\n", + " assert x1 > x0\n", + " self.t.color(color)\n", + " self.t.setheading(0)\n", + " self.t.up()\n", + " self.t.goto(x0, y)\n", + " self.t.down()\n", + " self.t.forward(x1 - x0)\n", + "\n", + " def draw_y_line(self, x, y0, y1, color='gray'):\n", + " assert y1 > y0\n", + " self.t.color(color)\n", + " self.t.setheading(90)\n", + " self.t.up()\n", + " self.t.goto(x, y0)\n", + " self.t.down()\n", + " self.t.forward(y1 - y0)\n", + "\n", + " def draw_box(self, x, y, fillcolor='', line_color='gray'):\n", + " self.t.up()\n", + " self.t.goto(x * self.unit, y * self.unit)\n", + " self.t.color(line_color)\n", + " self.t.fillcolor(fillcolor)\n", + " self.t.setheading(90)\n", + " self.t.down()\n", + " self.t.begin_fill()\n", + " for i in range(4):\n", + " self.t.forward(self.unit)\n", + " self.t.right(90)\n", + " self.t.end_fill()\n", + "\n", + " def move_player(self, x, y):\n", + " self.t.up()\n", + " self.t.setheading(90)\n", + " self.t.fillcolor('red')\n", + " self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit)\n", + "\n", + " def render(self):\n", + " if self.t == None:\n", + " self.t = turtle.Turtle()\n", + " self.wn = turtle.Screen()\n", + " self.wn.setup(self.unit * self.max_x + 100,\n", + " self.unit * self.max_y + 100)\n", + " self.wn.setworldcoordinates(0, 0, self.unit * self.max_x,\n", + " self.unit * self.max_y)\n", + " self.t.shape('circle')\n", + " self.t.width(2)\n", + " self.t.speed(0)\n", + " self.t.color('gray')\n", + " for _ in range(2):\n", + " self.t.forward(self.max_x * self.unit)\n", + " self.t.left(90)\n", + " self.t.forward(self.max_y * self.unit)\n", + " self.t.left(90)\n", + " for i in range(1, self.max_y):\n", + " self.draw_x_line(\n", + " y=i * self.unit, x0=0, x1=self.max_x * self.unit)\n", + " for i in range(1, self.max_x):\n", + " self.draw_y_line(\n", + " x=i * self.unit, y0=0, y1=self.max_y * self.unit)\n", + "\n", + " for i in range(1, self.max_x - 1):\n", + " self.draw_box(i, 0, 'black')\n", + " self.draw_box(self.max_x - 1, 0, 'yellow')\n", + " self.t.shape('turtle')\n", + "\n", + " x_pos = self.s % self.max_x\n", + " y_pos = self.max_y - 1 - int(self.s / self.max_x)\n", + " self.move_player(x_pos, y_pos)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "import gym\n", + "import os\n", + "def all_seed(env,seed = 1):\n", + " ''' omnipotent seed for RL, attention the position of seed function, you'd better put it just following the env create function\n", + " Args:\n", + " env (_type_): \n", + " seed (int, optional): _description_. Defaults to 1.\n", + " '''\n", + " import torch\n", + " import numpy as np\n", + " import random\n", + " # print(f\"seed = {seed}\")\n", + " env.seed(seed) # env config\n", + " np.random.seed(seed)\n", + " random.seed(seed)\n", + " torch.manual_seed(seed) # config for CPU\n", + " torch.cuda.manual_seed(seed) # config for GPU\n", + " os.environ['PYTHONHASHSEED'] = str(seed) # config for python scripts\n", + " # config for cudnn\n", + " torch.backends.cudnn.deterministic = True\n", + " torch.backends.cudnn.benchmark = False\n", + " torch.backends.cudnn.enabled = False\n", + " \n", + "def env_agent_config(cfg):\n", + " '''创建环境和智能体\n", + " ''' \n", + " env = gym.make(cfg.env_name,new_step_api=True) # 创建环境\n", + " env = CliffWalkingWapper(env)\n", + " if cfg.seed !=0: # set random seed\n", + " all_seed(env,seed=cfg.seed) \n", + " try: # 状态维度\n", + " n_states = env.observation_space.n # print(hasattr(env.observation_space, 'n'))\n", + " except AttributeError:\n", + " n_states = env.observation_space.shape[0]\n", + " n_actions = env.action_space.n # 动作维度\n", + " setattr(cfg, 'n_states', n_states) # 将状态维度添加到配置参数中\n", + " setattr(cfg, 'n_actions', n_actions) # 将动作维度添加到配置参数中\n", + " agent = FisrtVisitMC(cfg)\n", + " return env,agent" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4、设置参数" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "class Config:\n", + " '''配置参数\n", + " '''\n", + " def __init__(self):\n", + " self.env_name = 'CliffWalking-v0' # 环境名称\n", + " self.algo_name = \"FirstVisitMC\" # 算法名称\n", + " self.train_eps = 400 # 训练回合数\n", + " self.test_eps = 20 # 测试回合数\n", + " self.max_steps = 200 # 每个回合最大步数\n", + " self.epsilon = 0.1 # 贪婪度\n", + " self.gamma = 0.9 # 折扣因子\n", + " self.lr = 0.5 # 学习率\n", + " self.seed = 1 # 随机种子\n", + " # if torch.cuda.is_available(): # 是否使用GPUs\n", + " # self.device = torch.device('cuda')\n", + " # else:\n", + " # self.device = torch.device('cpu')\n", + " self.device = torch.device('cpu')\n", + "def smooth(data, weight=0.9): \n", + " '''用于平滑曲线\n", + " '''\n", + " last = data[0] # First value in the plot (first timestep)\n", + " smoothed = list()\n", + " for point in data:\n", + " smoothed_val = last * weight + (1 - weight) * point # 计算平滑值\n", + " smoothed.append(smoothed_val) \n", + " last = smoothed_val \n", + " return smoothed\n", + "\n", + "def plot_rewards(rewards,title=\"learning curve\"):\n", + " sns.set()\n", + " plt.figure() # 创建一个图形实例,方便同时多画几个图\n", + " plt.title(f\"{title}\")\n", + " plt.xlim(0, len(rewards), 10) # 设置x轴的范围\n", + " plt.xlabel('epsiodes')\n", + " plt.plot(rewards, label='rewards')\n", + " plt.plot(smooth(rewards), label='smoothed')\n", + " plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5、我准备好了!" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "开始训练!\n", + "环境:CliffWalking-v0, 算法:FirstVisitMC, 设备:cpu\n", + "回合:10/400,奖励:-200.0\n", + "回合:20/400,奖励:-200.0\n", + "回合:30/400,奖励:-200.0\n", + "回合:40/400,奖励:-200.0\n", + "回合:50/400,奖励:-200.0\n", + "回合:60/400,奖励:-200.0\n", + "回合:70/400,奖励:-200.0\n", + "回合:80/400,奖励:-200.0\n", + "回合:90/400,奖励:-200.0\n", + "回合:100/400,奖励:-200.0\n", + "回合:110/400,奖励:-200.0\n", + "回合:120/400,奖励:-200.0\n", + "回合:130/400,奖励:-200.0\n", + "回合:140/400,奖励:-200.0\n", + "回合:150/400,奖励:-200.0\n", + "回合:160/400,奖励:-200.0\n", + "回合:170/400,奖励:-200.0\n", + "回合:180/400,奖励:-200.0\n", + "回合:190/400,奖励:-200.0\n", + "回合:200/400,奖励:-200.0\n", + "回合:210/400,奖励:-200.0\n", + "回合:220/400,奖励:-200.0\n", + "回合:230/400,奖励:-200.0\n", + "回合:240/400,奖励:-200.0\n", + "回合:250/400,奖励:-200.0\n", + "回合:260/400,奖励:-200.0\n", + "回合:270/400,奖励:-299.0\n", + "回合:280/400,奖励:-200.0\n", + "回合:290/400,奖励:-200.0\n", + "回合:300/400,奖励:-200.0\n", + "回合:310/400,奖励:-200.0\n", + "回合:320/400,奖励:-200.0\n", + "回合:330/400,奖励:-200.0\n", + "回合:340/400,奖励:-200.0\n", + "回合:350/400,奖励:-200.0\n", + "回合:360/400,奖励:-200.0\n", + "回合:370/400,奖励:-200.0\n", + "回合:380/400,奖励:-200.0\n", + "回合:390/400,奖励:-200.0\n", + "回合:400/400,奖励:-200.0\n", + "完成训练!\n", + "开始测试!\n", + "环境:CliffWalking-v0, 算法:FirstVisitMC, 设备:cpu\n", + "回合数:1/20, 奖励:-200.0\n", + "回合数:2/20, 奖励:-200.0\n", + "回合数:3/20, 奖励:-200.0\n", + "回合数:4/20, 奖励:-200.0\n", + "回合数:5/20, 奖励:-200.0\n", + "回合数:6/20, 奖励:-200.0\n", + "回合数:7/20, 奖励:-200.0\n", + "回合数:8/20, 奖励:-200.0\n", + "回合数:9/20, 奖励:-200.0\n", + "回合数:10/20, 奖励:-299.0\n", + "回合数:11/20, 奖励:-200.0\n", + "回合数:12/20, 奖励:-200.0\n", + "回合数:13/20, 奖励:-200.0\n", + "回合数:14/20, 奖励:-200.0\n", + "回合数:15/20, 奖励:-200.0\n", + "回合数:16/20, 奖励:-200.0\n", + "回合数:17/20, 奖励:-200.0\n", + "回合数:18/20, 奖励:-200.0\n", + "回合数:19/20, 奖励:-200.0\n", + "回合数:20/20, 奖励:-200.0\n", + "完成测试!\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAHJCAYAAABtzYa7AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAACPp0lEQVR4nO3dd3wU1drA8d+29EogCVV6kBISSIDQREBFQEXQq1dBUbGgiAIKqFwBAb0KghQREVAQuaKCXBUs14r6UiOC9I4ESAIkIUDKZnfn/WPZYTfZNNI2mef7+aDZqedMfeacM2d0iqIoCCGEEEJoiL6qEyCEEEIIUdkkABJCCCGE5kgAJIQQQgjNkQBICCGEEJojAZAQQgghNEcCICGEEEJojgRAQgghhNAcCYCEEEIIoTkSAFUD0lelEKVXleeNnLNCeD4JgDzcDz/8wIQJE8plWWvXriUqKoqkpKQKnUdoywcffEC3bt2Ijo5m4cKFbqfp3bs3UVFRhf5LS0sDICoqivnz55cpPZmZmYwfP57t27cDMGnSJFq3bs3Zs2cLneeJJ56gd+/e2Gw2evfuzcSJE0u8vvzTL1y4kKVLl6q/HedQVFQUx44dc7uMjRs3qtPkl5KSwhtvvEG/fv1o37493bt354knnlDzV5QDBw4waNAg2rZtS//+/Uucp9L666+/eP755+nVqxfR0dH07duXf/3rX5w8edJlOuf9u2XLFqKiotiyZYs6fubMmXTq1ImYmBjWrVvH5s2bueWWW2jbtq26fX788ccC6x84cCBRUVFs2LChwLjbbruNBx98sET5yJ+m+fPnu90nDklJSURFRbF27doSLb+yfPXVVwwYMIDo6GhuvfVWPv/886pOkkcyVnUCRNE++OCDcltWr169WL16NeHh4RU6j9COS5cu8frrr9OrVy8efvhhGjRoUOi0N9xwA08++aTbcUFBQQCsXr2ayMjIMqVp3759/Pe//2XIkCEADBkyhE8//ZT169czfPjwAtOfP3+eX3/9lZEjR6LX61mwYAEBAQElXl/+6efOncuoUaMKTKfX6/nmm28YOXJkgXHubtwAiYmJPPXUU4SGhvLAAw/QpEkTMjIyWL16NcOGDeO1115j0KBBhabt7bff5vTp07z99tvUqlWrxHkqjY8++ohXX32Vzp07M27cOMLDwzlx4gRLly7lu+++Y/ny5bRq1arAfG3atGH16tU0b94cgIMHD7JkyRL+8Y9/cMcdd9C0aVNGjBiBzWZj8eLFhIWFMWTIEHbs2EHv3r3V5SQnJ3Po0CFCQkL49ddfXQK9jIwMDh06xNixYysk7+Hh4axevZpGjRpVyPKvxbfffstzzz3HAw88QI8ePfj++++ZOHEiXl5eDBgwoKqT51EkANKQWrVqlfoieC3zCO24cOECNpuNvn37Eh8fX+S0tWrVIiYmpshpiht/LWJjY2nWrBlffvml2wDoyy+/xGazMXjwYABat25dquWXdPoOHTrw9ddfFwiAzGYz33//Pddffz379u1Th2dkZPDss8/SuHFj3n//fXx9fdVxt9xyC4899hgvv/wy3bt3p3bt2m7XmZ6eTsuWLbnhhhtKlaeSSkxMZMaMGdx///289NJL6vDOnTvTt29fBg0axIsvvui2hCQgIMBlf2dkZAAwYMAA4uLi1GHx8fF07doVgHbt2vHHH3+4LOfXX3/Fz8+Pe++9lzVr1riM2759O4qi0K1bt/LIbgFeXl4VcsyWxezZs+nXrx8vvvgiAD169ODChQvMnTtXAqB8pArMgw0bNoytW7eydetWtVjWUUT78ccfc+ONN9KhQwd+//13AD799FMGDx5MTEwM0dHR3HHHHXz99dfq8vJXZ02cOJHhw4ezZs0atZj5jjvuYOPGjWWaB2DHjh3cf//9xMTE0KtXL5YvX87w4cOLrVr4888/efjhh+nQoQNdunRh7NixpKSkuE2LQ/4qiKioKBYsWMDgwYOJjo5mwYIFXH/99axcudJlvrS0NNq0aaOWsjmeNG+66Sbatm3LLbfcwocffljsfrp48SKvvfYaffv2pV27dgwcOJDPPvusQBrnzZvH66+/TteuXYmOjuaRRx7h+PHjRS7bbDbz1ltv0adPH6Kjoxk4cKBLcfawYcOYOHEiixYtomvXrnTs2JEnn3ySU6dOqdNMnDjR5YkZSl50//vvv3PffffRsWNH9Qn/zJkzgH1/OJb74osvFllVUFLuqkjyH+tpaWmMGzeObt260a5dO+644w7WrVunzvPAAw8A8MADDzBs2DDAXgq0e/dut1VQn3/+OV27dqVevXpAwePpq6++4vbbbyc6OpouXbrw3HPPqcdk/ukd22DBggUFtkf//v05cOBAgTRs3LgRnU5Hz549XYavW7eO1NRUXnzxRZfgB+ylSc899xz3338/ly5dKnRbbt26lW3btrns6+PHjzN69Gi6detGTEwMw4YNIzExUZ3PcWy8//77arVb/sDCYenSpQQGBrotYalVqxYTJ06kT58+ZGVlFRjvXN00f/58dV89+OCDapXpqVOnWLdunTpd165d+euvvzCbzepyfv31Vzp37kyPHj04e/Ys+/fvV8clJiYSGhqqBqnbtm3jkUceIT4+nrZt29K7d2/mz5+PzWZzm7/8Tp8+Ta9evRg8eDCZmZkFzqO1a9fSunVrdu7cyT333EO7du248cYbXapEAVJTUxkzZgydOnUiPj6el19+mTlz5hQ4T50lJycXex1LSkri+PHj3HTTTS7T3HLLLZw4caLY643WSADkwSZPnkzr1q1p3bo1q1evpk2bNuq4BQsWMGHCBF5++WViY2P56KOPePnll+nbty/vvvsus2bNwsvLi+eee47k5ORC17F7926WLl3K6NGjefvttzEYDDz99NNcuHDhmuc5cuSI+qQ9e/Zsnn76aRYvXuxykXVn7969DB06lNzcXN544w2mTp3K7t27eeSRR7BYLKXYcrBo0SJuu+025s2bxy233EKnTp1Yv369yzTffPMNiqKoT0VTpkxh3rx53H777SxatIh+/frx6quv8vbbbxe6npycHO677z6+/PJLRowYwcKFC+nYsSMvvfQSixYtcpl2xYoVHD16lNdee43p06eze/fuYtt3Pffcc7z//vvcfffdvPvuu3Tv3p2JEyfy1VdfqdP88MMPrF27lkmTJjF16lT27dvHsGHDyM7OLtU2y2/dunU8/PDD1K1bl9mzZ/PCCy+wY8cO7rnnHs6fP0+vXr1YsGABACNHjmT16tVFLk9RFCwWS4F/xcl/rD///PMcOXKEqVOn8t5779G6dWsmTJjA5s2badOmDS+//DIAL7/8MpMnTwbgjjvuwGg08uWXX7ose//+/ezfv5+7777b7boTExMZP348N998M++99x4vvPACmzdvZty4cW6nd2yDu+66q8D26NatG8HBwXzzzTcuwzds2MBNN92EyWRyGf7rr79Su3ZtoqOj3a6rVatWTJgwgcaNGxeaFufrR69evTh8+DCDBw8mKSmJSZMmMWvWLHQ6HQ8++CBbt251mX/+/Pk8+uijvPHGG25LUBRF4bfffiMhIaFAgObQv39/nnrqKfz8/NyOd7j77rtd9tucOXNYvXo1derU4YYbblCvfwkJCeTm5rJ3714ArFYrmzZtonv37sTExBAQEMCvv/6qLnfbtm107doVnU7H/v37GT58OCEhIcyZM4d33nmHuLg4FixY4PKgWJizZ8+q87///vtqtW1+NpuNZ599lv79+7N48WI6dOjAG2+8oabLbDbz4IMP8scff/Diiy/y2muvsX//fpYtW1bk+iMjI4u9jh05cgSgwDFx3XXXARTaBk2rpArMgzVv3lxtW5C/mPW+++6jX79+6u+TJ0/yyCOPuLSxqF+/PoMHDyYxMbHQos+LFy+ydu1atQ7bz8+PoUOHqo0Pr2Wed999l8DAQJYsWaJeGJs2bcq9995bZH4XLVpESEgIy5Ytw9vbG7DXsY8bN45Dhw4VOW9+cXFxPPTQQ+rvO+64gxdffJHTp0+rT/rr16+na9eu1KlTh2PHjvHJJ58wduxYHnvsMQC6d++OTqfj3Xff5b777iM0NLTAetauXcvBgwf5+OOPiY2NBexFzhaLhYULF3LvvfcSEhIC2Nu5LFy4EIPBAMDff//N/PnzSU9Pd7vsgwcP8u233/Liiy+qjTgTEhI4deoUW7ZsYeDAgQBkZ2ezdu1aGjZsCNi39Z133sm6dev45z//Wart5mCz2Zg1axbdu3fnzTffVId36NCB/v37s3TpUsaPH8/1118PQKNGjYqtCli3bp1aUuNs9erVRc6b/1jfunUrTz31FH379gWgU6dOhISE4OXlRUBAgNqmpHnz5urftWvXplevXnz11VeMHj3aJU2hoaGFPnknJibi4+PDY489hpeXFwAhISH89ddfKIqCTqdzmd6Rj8jIyAJ5MhqN9O3b16UaLDs7m59++om33367wANCcnIy9evXL3S7FMcREDin65VXXsHLy4sVK1ao43r16sXAgQN54403XEoub731VrUdlTvp6enk5uYW2e6rpCIjI132W/v27QF7FZNz1Wn79u3x8/Pjjz/+ICYmhp07d5KZmUn37t0xGo107tyZX3/9lUcffZTLly+zb98+9bqzf/9+unbtysyZM9Hr7c/+3bp148cff2TLli1FVg+lp6fz0EMP4ePjw/vvv09wcHCh0yqKwpNPPqkG1R07duR///sfP//8Mz169OCLL77g6NGjrFmzhrZt2wLQpUsX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0Ov1dOnSxWV8t27d2L17N3/99Zf6+jzYj3nH6/mO0q3du3eTlpZW7DWyTp069OzZk1tvvZW5c+eWqWPYTp06kZSU5NLlQU5Ojkvj7YiIiAIlpQ5FXcccAeC3337rss7vvvuOxo0bl0t7rZpEGkF7uKCgIHbs2MGmTZsK7W8kLCyM+vXr89FHHxEZGUlQUBC//vqr+qRS1reBSuuJJ55gw4YNjBgxgocffpjMzEzmzp2LXq8vst3Ek08+yT333MPjjz/OAw88QE5ODm+99RbR0dF069aNnJwcfHx8+Pe//80zzzzD5cuXmTdvnlpaURyDwcCAAQNYuXIlERERLu0uoqKiuP322/nXv/7FqVOnaNu2LceOHWPOnDkubQzyGzx4MKtWreKpp55i9OjRNGjQgB9//JE1a9YwatSoQt8UKYlWrVrRr18/Zs6cSU5ODtdffz0bN27kp59+Ut++Avv+HTFiBCNHjuTy5cvMmTOHli1bqu13brzxRj788ENeeukl7rrrLg4ePMj7779fZKCg1+sZO3YsL7zwAuPGjeP2228nPT2dBQsWEBwc7NLAvDLVr1+fyMhIpk+fzqVLl2jUqBG7d+/ml19+4fHHHweuVgP8/PPPBAcHu3TC16RJEzp06MCrr74KUGzvyF26dOH9999n4sSJ3H777eTl5bFkyRJCQkIK3HgdgoKC+OOPP9i2bZsaWDvr1KkTderU4d1332X48OGFnhOBgYH8+9//ZtSoUdx9990MHTqUxo0bk5yczEcffcSuXbt488033VaBFmbUqFFs3LiRBx54gMceewyTycTKlSs5efIkS5YsKfFyHGJiYnjmmWd46623OHLkCIMGDSI0NJRDhw6xdOlScnNz3QZHZaHT6ejSpQvr1693aejt0L17d/W1fOdzPDo6mq+//pr//Oc/NGvWjP379/POO++g0+lKfI188cUX+fXXX5k8eXKBV9tLauDAgSxevJinnnqKZ555hqCgIN5//33Onz+vNmwuSlHXMYCnnnqKF154gZCQEHr37s0PP/zA119/zZw5c64pvTWZBEAe7v7772f37t08+uijvPbaa4X2yLxw4UJmzJih9vjZvHlz3nnnHV599VW2b9+u9rFRGa677jqWLl3KG2+8wejRowkLC+Pxxx/nnXfeUd9GcKd169Z8+OGHvPnmmzz77LMEBARwww03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fHx8FaasfB06dIgOHTq45BNg9+7dNG/enPj4eBITE7Fareq4zZs306RJE8LCwio7uRWmuHzW1ONh/PjxDB8+3GXYX3/9BdifKKtrvletWsW0adO4//77mT17tktxd1xcHFu3bnWZfvPmzXTo0AG9Xk/Hjh2x2Wxqo2Cw9zWSkpLi0XmGovM9bNgwXnjhBZfp//rrL0wmE40bN67W+T537hxjx45l06ZN6rC8vDz27t1Ls2bNauz5XVy+a+L5PWvWLDZs2MC6devUfwCjR49mxowZlbuvy/4im+eaPXu20qlTJ+X777936SvAbDZXddLKjdVqVYYMGaL0799f2bZtm3L48GHl1VdfVdq2bascOHBAOXfunBIfH69MmDBBOXTokLJmzRqlXbt2ytq1a6s66WUyYcIEl9fBS5LPmnA85M/3999/r7Rs2VKZP3++cuLECeXnn39WevfurYwdO1adprrl++jRo0qbNm2Up556yqXvk9TUVCUzM1M5ePCg0qZNG2XmzJnK4cOHlaVLlxboB2js2LFK7969lc2bN6v94eTvP8nTFJfvDz/8ULn++uuVVatWKX///beyfv16pXPnzsrs2bPVZVTHfDuMGDFCufnmm5WtW7cqBw4cUMaOHavEx8crp06dqtHnd1H5ronntzvOr8FX5r6u0QGQxWJR3njjDaVLly5KTEyM8uijjyonT56s6mSVu7NnzyoTJ05UunXrprRr10655557lG3btqnjd+7cqfzjH/9Q2rZtq9x4443Khx9+WIWpLR/5AwFFKT6fNeF4cJfvDRs2KIMGDVKio6OVbt26Kf/+97+VnJwcdXx1y/c777yjtGzZ0u2/CRMmKIqiKL/88osycOBApW3btkq/fv2U9evXuyzj8uXLyksvvaTExcUpcXFxytixY5W0tLSqyE6JlSTfK1euVG699Vb1GH/nnXcUq9WqLqM65tshMzNTmTx5stKtWzclOjpaefjhh5WDBw+q42vq+V1cvmva+e2OcwCkKJW3r3WKoijlUawlhBBCCFFd1Ng2QEIIIYQQhZEASAghhBCaIwGQEEIIITRHAiAhhBBCaI4EQEIIIYTQHAmAhBBCCKE5EgAJIYQQQnMkABJCCCGE5kgAJISoFpKSkoiKimLt2rVlXtbEiRPp3bt3OaRKCFFdGas6AUIIURLh4eGsXr2aRo0aVXVShBA1gARAQohqwcvLi5iYmKpOhhCihpAqMCFEufj0008ZMGAAbdu2pVevXsyfPx+r1QrYq5yGDRvGZ599xo033khsbCwPPvgg+/fvV+e32WzMmTOH3r1707ZtW3r37s2bb75JXl4e4L4K7Pjx44wePZpu3boRExPDsGHDSExMdEnXhQsXeOGFF+jUqRPx8fHMnDkTm81WIP3ff/89gwcPpl27dnTr1o3p06eTlZWljs/JyWHKlCn07NmTtm3b0q9fP5YuXVqu21AIUXmkBEgIUWbvvvsuc+bMYejQobzwwgvs27eP+fPnc+bMGV599VUA9u3bx9GjRxk7dizBwcHMmzePoUOHsmHDBsLDw3nvvff4z3/+w4QJE2jYsCE7d+5kzpw5mEwmRo8eXWCdhw8f5h//+AeNGzdm0qRJmEwmVqxYwYMPPsiyZcvo1KkTNpuNESNGcOrUKSZMmEBISAhLlizhr7/+Ijw8XF3Wl19+yXPPPcdtt93Gs88+y6lTp5gzZw6HDx/m/fffR6fT8eqrr/Lbb78xYcIEateuzcaNG3njjTcICQlhyJAhlbathRDlQwIgIUSZXLx4kYULF3LPPfcwadIkALp3705ISAiTJk3ioYceUqdbtGgRcXFxAERHR9O3b19WrFjBc889x9atW2nbtq0aTHTq1AlfX18CAwPdrnfBggV4eXmxYsUKAgICAOjVqxcDBw7kjTfe4LPPPmPjxo3s2rWL9957j549ewKQkJDg0gBaURRmzZpFjx49mDVrljq8cePGDB8+nF9++YVevXqxdetWunXrxoABAwDo3Lkzfn5+hIWFlefmFEJUEqkCE0KUyY4dO8jJyaF3795YLBb1nyPI+P333wFo0KCBGvyAvVFzbGws27ZtA+wBxe+//859993HkiVLOHz4MEOHDuWOO+5wu96tW7dy4403qsEPgNFoZMCAAezevZvLly+zfft2TCYTPXr0UKfx8/PjhhtuUH8fPXqU5OTkAumPj48nICBATX/nzp355JNPePTRR1m5ciUnT57kqaeeolevXuWzIYUQlUpKgIQQZZKRkQHAY4895nZ8amoqABEREQXGhYWFsWfPHgBGjBiBv78/a9asYdasWcycOZMWLVowadIkunTpUmDeCxcuULt27QLDa9eujaIoXLp0iQsXLhASEoJOp3OZpk6dOgXSP3XqVKZOnVpo+l966SUiIyP54osvmDZtGtOmTSM2NpYpU6bQqlUrt3kXQnguCYCEEGUSFBQEwKxZs2jcuHGB8bVr12bu3Lmkp6cXGHfu3Dm1Ckmv13P//fdz//33c/78eX755RcWLVrE008/rZbCOAsODubcuXMFhp89exaA0NBQQkNDSU9Px2q1YjAY1GkcQY9z+sePH0+nTp3crgfsb6GNHDmSkSNHcvr0aX766ScWLlzIuHHjWL9+fWGbRwjhoaQKTAhRJu3bt8dkMpGSkkK7du3Uf0ajkdmzZ5OUlATY39g6cuSIOl9KSgo7duwgISEBgHvvvZfp06cD9pKhwYMHc//995OZmcmlS5cKrDc+Pp6ffvrJZZzVamX9+vW0a9cOLy8vEhISsFgsfP/99+o0ZrPZJaBq2rQpYWFhJCUluaQ/IiKCN998k71795KTk8Mtt9zCsmXLAKhXrx73338/AwYM4PTp0+W4NYUQlUVKgIQQZRIaGsqIESOYO3culy5donPnzqSkpDB37lx0Op1aPaQoCk888QRjxozBYDCwYMECgoODGTZsGGAPaJYtW0bt2rWJjY0lJSWF999/n06dOlGrVi2XV9IBRo0axcaNG3nggQd47LHHMJlMatucJUuWAPYGz927d2fSpEmcP3+e+vXrs2LFCtLS0tSSJ4PBwJgxY3j55ZcxGAzceOONZGZmsnDhQlJSUmjTpg0+Pj60adOGBQsWYDKZiIqK4tixY3z++efccsstlbi1hRDlRacoilLViRBCVH8fffQRq1at4sSJEwQHB5OQkMDYsWOpV68eEydOZOvWrTz66KO8/fbbZGdn07VrVyZMmECDBg0AsFgsvPPOO3zxxRckJycTGBhI7969GTduHKGhoSQlJdGnTx9ee+01Bg8eDNhfrZ89ezbbt29Hp9MRHR3NqFGjXBpbZ2dnM2vWLNavX09ubi79+/fHz8+PH374gR9//FGdbsOGDSxZsoRDhw7h5+dHhw4dePbZZ4mKigLg0qVLvPXWW/zwww+cPXuWsLAw+vfvzzPPPIOPj08lbmkhRHmQAEgIUeEcAZBzwCGEEFVJ2gAJIYQQQnMkABJCCCGE5kgVmBBCCCE0R0qAhBBCCKE5EgAJIYQQQnMkABJCCCGE5kgAJIQQQgjNkQBICCGEEJojAZAQQgghNEcCICGEEEJojgRAQgghhNCc/wfvtSb4uTBH9gAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkIAAAHJCAYAAABpOFaGAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB5j0lEQVR4nO3deXzL9+MH8FeSJk3vS7XOGasabVFaurptmGuGbb6oumaYY9iUzVwdcxRzX3XMOZthB7PZZmx+rpYxw9ymQ5W2qmea5PP7I/LRSHonbSqv5+Phof3kk0/e73ya5JX39ZEIgiCAiIiIyAZJy7sAREREROWFQYiIiIhsFoMQERER2SwGISIiIrJZDEJERERksxiEiIiIyGYxCBEREZHNYhAiIiIim8UgVIFYau1LrqlJz4Ly/Dvma4io4mIQqiB++eUXREVFmf248fHxGDZsmPh7QkIC/P39sWvXLrM/Fj0bjh07ho4dOyIgIABDhw41uc+kSZPg7++f77/9+/cDACIiIhAREVHqMq1YsQLr1q0DAHz77bfw9/fHDz/8kO/+69evR7169fDvv/9i0qRJaNeuXZEf6+n9n35t6l9D/v7+2LFjh8ljPHr0CIGBgfD398fx48cNbsvJycHGjRvRq1cvNGnSBKGhoejTpw/27NlTaOBKT0/H8OHD0bBhQ4SEhODGjRtFrldxJCYmYt68eejUqRMaNmyIFi1aYPjw4YiLizPY7+nz6+/vj6VLl4q/7927F23btkVAQACmTp2Ku3fvol+/fggMDERoaCjq1auHOXPmGD3+zJkz4e/vj2nTphndFh0djUaNGkGlUhWpLnnLdPz4cZPnJK927dph0qRJRTp2Wfnrr78QERGBxo0bo0WLFli4cGGR60+AXXkXgIpm48aNFjnuV199hatXr4q/V65cGTt27EDNmjUt8nhU8c2bNw9arRZr1qyBl5dXvvt5e3tj2bJlJm+rVasWAJj8ICuJxYsXY9SoUQCADh06YObMmfjuu+/w6quvmtx/9+7dCA0NRc2aNTFy5EgMGDCgyI/19P75vTalUin279+Pt956y+i2AwcOmPygun//PoYOHYo7d+4gIiICQUFB0Gq1OHjwICZNmoS4uDhER0dDIpGYfMw9e/bg4MGDmDp1Kvz8/FC9evUi16uo4uPj8e6778LDwwMDBgzA888/j9TUVOzYsQMRERH49NNP0aNHD5P33bFjB3x9fcXfZ86ciVq1amHOnDnw8fHB559/jj///BPz58+Hj48P5s2bh9OnTxsd5/fff4e7uzv++OMPo9tOnjyJpk2bQqFQmK3OeS1btgzOzs4WOXZJ3Lp1C4MGDUKjRo3w2Wef4erVq1i0aBFSU1Mxc+bM8i5ehcAgRAYUCgUaNWpU3sUgK5aamoqQkBC89NJLBe5XlL+lF154wYwl01EqlejatSt27tyJhw8fws3NzeD28+fP49KlS5g/fz4AFDv0F3X/4OBgHD9+HMnJyfD09DS4be/evXjxxRdx4cIFg+1RUVG4e/cuduzYIYZFAGjTpg2qVq2KhQsXom3btmjfvr3Jx0xNTQUA9O3bN9+wVBqpqal47733UKtWLWzYsAEODg7ibR07dsSwYcMwdepUtGjRApUqVTK6/9N/D6mpqQgPD0ezZs3E3ytXrozOnTsDAJo3b45169YhJycH9vb2AIB///0X//77LyZMmIAFCxbg2rVrqF27NgAgLS0Nly9fxuuvv272uuvVr1/fYscuibVr18LJyQkrVqyAQqFA69atoVQqER0djeHDh6Nq1arlXUSrx66xCiAiIgInTpzAiRMnDJptU1NTMXXqVLz00ksIDAzEm2++iaNHjxrc98iRI3jzzTfRuHFjhISEYMSIEWIL0KRJk7B79278999/YnfY011ju3btQv369XHmzBm89dZbCAwMRNu2bcVuCL179+5h3LhxCA0NRUhICKZOnYpFixYV2uVw7949REVFISwsDI0bN0b//v3Fb4D5ddM93TURERGB999/H2PGjEGjRo0waNAgdOzYEWPGjDF6vNdeew0jRowQf//555/Rs2dPBAYGIjw8HJ988gkyMzMLLLNGo8HWrVvRrVs3BAUFoU2bNoiJiUFOTo5BGQcOHIivv/5a7EZ67bXXcPjw4QKPDei+1b/++uto2LAh2rRpgwULFoitB0uXLkW7du1w8OBBsVvizTffNGjK37VrF/z9/ZGQkGBw3KI06d+4cQNjxoxBeHg4GjVqhIiICMTHxwN4cj7+++8/7Nmzp9AuhKIw1XWybNky9OzZE0FBQVi2bBm0Wq34txQQEIB27dphwYIFyM3NFe8D6L6p63/u1asXcnNzxS64vHbv3g1XV1d07NgRgPHf07lz5xAZGYkmTZqg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vn07bt26hX379mHevHkYMmQInJ2dy6rYBSrscysiIgJnz55FTEwMrl69ivXr12P//v0YOnSoeIy8f+eAbkblhg0bsHv3bly5cgUffvghsrOzi9/9W6zJ9lZKrVYL8+bNE5o3by40atRIePvtt4Vbt24JgiAIt27dEurWrSt8/fXX4v73798XRo8eLTRq1Eho1qyZMG3aNCE7O7u8il9sK1euFOrWrWvyX1RUlHDs2DGhbt26wrFjx8T7/N///Z/w1ltvCY0aNRJCQ0OFyZMnC6mpqeVYi5JLSkoSJk2aJISHhwuBgYHCW2+9JZw8eVIQhGfzfOc1dOhQ4b333jN5W926dYUlS5aIv9+8eVMYPXq0EBoaKjRs2FAYPHiw8M8//5RVUUstKirKaH2VM2fOCG+++aYQEBAgtG3bVti8ebPRfdq2bWuwbffu3cIrr7wiBAYGCq+//nqBC7RZg7z1VqvVQmBgYL6vd/37XP/+/Q2eq0ePHgmzZ88WWrduLQQEBAivvfaacODAgXKpT1GZOt/79u0TevToIQQFBQnh4eHCnDlzDF67z9r51jtz5ozR+md5LVmyRKhbt67Bti1btgivvvqq+NpYuXKloNFoLFbu4irsc0sQBOHQoUNC165dhYCAAKFTp07C3r17DY7x9N+5IAhCbGys0KpVKyEoKEjo27evcP78+WKXTSIIJiboExEREdmACt81RkRERFRSDEJERERksxiEiIiIyGYxCBEREZHNYhAiIiIim8UgRERERDaLQYiIiIhsFoMQERER2SwGISKqEBISEuDv7290Da2SmDRpEtq1a2eGUhFRRWdX3gUgIiqKypUrY8eOHahZs2Z5F4WIniEMQkRUISgUCjRq1Ki8i0FEzxh2jRGRWXz11Vfo0qULAgIC0KZNGyxdulS8OvqkSZMQERGBnTt3om3btmjcuDEiIyNx8eJF8f5arRaLFi1Cu3btEBAQgHbt2mHBggXIzc0FYLpr7MaNGxgzZgzCw8PRqFEjREREID4+3qBcDx8+xOTJkxEaGoqQkBDMnz8fWq3WqPw///wzevbsicDAQISHh+OTTz5BZmameHt2djamT5+OVq1aISAgAJ06dcK6devM+hwSUdljixARldrq1auxaNEi9O/fH5MnT8aFCxewdOlS3LlzB7NnzwYAXLhwAdeuXcP48ePh5uaGJUuW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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# 获取参数\n", + "cfg = Config() \n", + "# 训练\n", + "env, agent = env_agent_config(cfg)\n", + "res_dic = train(cfg, env, agent)\n", + " \n", + "plot_rewards(res_dic['rewards'], title=f\"training curve on {cfg.device} of {cfg.algo_name} for {cfg.env_name}\") \n", + "# 测试\n", + "res_dic = test(cfg, env, agent)\n", + "plot_rewards(res_dic['rewards'], title=f\"testing curve on {cfg.device} of {cfg.algo_name} for {cfg.env_name}\") # 画出结果" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.12 ('easyrl')", + "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.7.12" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "f5a9629e9f3b9957bf68a43815f911e93447d47b3d065b6a8a04975e44c504d9" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/projects/notebooks/Q-learning/Q-learning探索策略研究.ipynb b/projects/notebooks/Q-learning/Q-learning探索策略研究.ipynb new file mode 100644 index 0000000..40583fd --- /dev/null +++ b/projects/notebooks/Q-learning/Q-learning探索策略研究.ipynb @@ -0,0 +1,32 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Q learning with different exploration strategies\n", + "\n", + "Authors: [johnjim0816](https://github.com/johnjim0816)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.13 ('easyrl')", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.7.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "8994a120d39b6e6a2ecc94b4007f5314b68aa69fc88a7f00edf21be39b41f49c" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/projects/notebooks/Q-learning/QLearning.ipynb b/projects/notebooks/Q-learning/QLearning.ipynb new file mode 100644 index 0000000..debb47e --- /dev/null +++ b/projects/notebooks/Q-learning/QLearning.ipynb @@ -0,0 +1,459 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1、定义算法\n", + "强化学习算法的模式都比较固定,一般包括sample(即训练时采样动作),predict(测试时预测动作),update(算法更新)以及保存模型和加载模型等几个方法,其中对于每种算法samle和update的方式是不相同,而其他方法就大同小异。" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import math\n", + "import torch\n", + "from collections import defaultdict\n", + "\n", + "class QLearning(object):\n", + " def __init__(self,n_states,\n", + " n_actions,cfg):\n", + " self.n_actions = n_actions \n", + " self.lr = cfg.lr # 学习率\n", + " self.gamma = cfg.gamma \n", + " self.epsilon = cfg.epsilon_start\n", + " self.sample_count = 0 \n", + " self.epsilon_start = cfg.epsilon_start\n", + " self.epsilon_end = cfg.epsilon_end\n", + " self.epsilon_decay = cfg.epsilon_decay\n", + " self.Q_table = defaultdict(lambda: np.zeros(n_actions)) # 用嵌套字典存放状态->动作->状态-动作值(Q值)的映射,即Q表\n", + " def sample_action(self, state):\n", + " ''' 采样动作,训练时用\n", + " '''\n", + " self.sample_count += 1\n", + " self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \\\n", + " math.exp(-1. * self.sample_count / self.epsilon_decay) # epsilon是会递减的,这里选择指数递减\n", + " # e-greedy 策略\n", + " if np.random.uniform(0, 1) > self.epsilon:\n", + " action = np.argmax(self.Q_table[str(state)]) # 选择Q(s,a)最大对应的动作\n", + " else:\n", + " action = np.random.choice(self.n_actions) # 随机选择动作\n", + " return action\n", + " def predict_action(self,state):\n", + " ''' 预测或选择动作,测试时用\n", + " '''\n", + " action = np.argmax(self.Q_table[str(state)])\n", + " return action\n", + " def update(self, state, action, reward, next_state, terminated):\n", + " Q_predict = self.Q_table[str(state)][action] \n", + " if terminated: # 终止状态\n", + " Q_target = reward \n", + " else:\n", + " Q_target = reward + self.gamma * np.max(self.Q_table[str(next_state)]) \n", + " self.Q_table[str(state)][action] += self.lr * (Q_target - Q_predict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2、定义训练\n", + "强化学习算法的训练方式也比较固定,如下:\n", + "```python\n", + "for i_ep in range(train_eps): # 遍历每个回合\n", + " state = env.reset() # 重置环境,即开始新的回合\n", + " while True: # 对于一些比较复杂的游戏可以设置每回合最大的步长,例如while ep_step<100,就是每回合最大步长为100。\n", + " action = agent.sample(state) # 根据算法采样一个动作\n", + " next_state, reward, terminated, _ = env.step(action) # 与环境进行一次动作交互\n", + " agent.memory.push(state, action, reward, next_state, terminated) # 记录memory\n", + " agent.update(state, action, reward, next_state, terminated) # 算法更新\n", + " state = next_state # 更新状态\n", + " if terminated:\n", + " break\n", + "```\n", + "首先对于每个回合,回合开始时环境需要重置,好比我们每次开一把游戏需要从头再来一样。我们可以设置智能体在每回合数的最大步长,尤其是对于比较复杂的游戏,这样做的好处之一就是帮助智能体在训练中快速收敛,比如我们先验地知道最优解的大概步数,那么理论上智能体收敛时也应该是这个步数附近,设置最大步数可以方便智能体接近这个最优解。在每个回合中,智能体首先需要采样(sample),或者说采用探索策略例如常见的$\\varepsilon$-greedy策略或者UCB探索策略等等。采样的过程是将当前的状态state作为输入,智能体采样输出动作action。然后环境根据采样出来的动作反馈出下一个状态以及相应的reward等信息。接下来对于具有memory的智能体例如包含replay memory的DQN来说,需要将相应的transition(记住这个词,中文不好翻译,通常是状态、动作、奖励等信息)。紧接着就是智能体更新,对于深度强化学习此时一般从memory中随机采样一些transition进行更新,对于Q learning一般是采样上一次的transition。更新公式是比较关键的部分,但是也很通用,一般基于值的算法更新公式都是一个套路如下:\n", + "$$\n", + "y_{j}= \\begin{cases}r_{j} & \\text { for terminal } s_{t+1} \\\\ r_{j}+\\gamma \\max _{a^{\\prime}} Q\\left(s_{t+1}, a^{\\prime} ; \\theta\\right) & \\text { for non-terminal } s_{t+1}\\end{cases}\n", + "$$\n", + "智能体更新完之后,通常需要更新状态,即```state = next_state```,然后会检查是否完成了这一回合的游戏,即```terminated==True```,注意完成并不代表这回合成功,也有可能是失败的太离谱,等同学们有了自定义强化学习环境的经验就知道了(等你长大就知道了XD)。\n", + "如果需要记录奖励、损失等等的话可以再加上,如下方代码,实际项目中更多地使用tensorboard来记录相应的数据,甚至于笔者就在这些教学代码中使用过,但是看起来有些繁琐,容易给大家增加不必要的学习难度,因此学有余力以及需要在项目研究中做强化学习的可以去看看,也很简单。\n", + "此外稍微复杂一些的强化学习不是一次性写完代码就能收敛的,这时需要我们做一个调参侠。为了检查我们参数调得好不好,可以在终端print出奖励、损失以及epsilon等随着回合数的变化,这点说明一下强化学习的训练过程一般都是先探索然后收敛的,官方的话就是权衡exploration and exploitation。e-greedy策略的做法就是前期探索,然后逐渐减小探索率至慢慢收敛,也就是这个epsilon。这个值越大比如0.9就说明智能体90%的概率在随机探索,通常情况下会设置三个值,epsilon_start、epsilon_end以及epsilon_decay,即初始值、终止值和衰减率,其中初始值一般是0.95不变,终止值是0.01,也就是说即使在收敛阶段也让智能体保持很小概率的探索,这样做的原因就是智能体已经学出了一个不错的策略,但是保不齐还有更好的策略,好比我们知道要出人头地学历高比较重要,但是“人还是要有梦想的,万一实现了呢”,总是存在意外的可能,对吧。回归正题,比较关键的是epsilon_decay这个衰减率,这个epsilon衰减太快了学来的策略往往过拟合,好比一条只能选择一朵花的花道上,你早早选择了一朵看起来还可以的花,却错过了后面更多的好花。但是衰减的太慢会影响收敛的速度,好比你走过了花道的尽头也还没选出一朵花来,相比前者不如更甚。当然强化学习的调参相比于深度学习只能说是有过之无不及,比较复杂,不止epsilon这一个,这就需要同学们的耐心学习了。\n", + "强化学习测试的代码跟训练基本上是一样的,因此我放到同一个代码段里。相比于训练代码,测试代码主要有以下几点不同:1、测试模型的过程是不需要更新的,这个是不言而喻的;2、测试代码不需要采样(sample)动作,相比之代替的是预测(sample)动作,其区别就是采样动作时可能会使用各种策略例如$\\varepsilon$-greedy策略,而预测动作不需要,只需要根据训练时学习好的Q表或者网络模型代入状态得到动作即可;3、测试过程终端一般只需要看奖励,不需要看epislon等,反正它在测试中也是无意义的。" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "def train(cfg,env,agent):\n", + " print('开始训练!')\n", + " print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')\n", + " rewards = [] # 记录奖励\n", + " for i_ep in range(cfg.train_eps):\n", + " ep_reward = 0 # 记录每个回合的奖励\n", + " state = env.reset(seed=cfg.seed) # 重置环境,即开始新的回合\n", + " while True:\n", + " action = agent.sample_action(state) # 根据算法采样一个动作\n", + " next_state, reward, terminated, info = env.step(action) # 与环境进行一次动作交互\n", + " agent.update(state, action, reward, next_state, terminated) # Q学习算法更新\n", + " state = next_state # 更新状态\n", + " ep_reward += reward\n", + " if terminated:\n", + " break\n", + " rewards.append(ep_reward)\n", + " if (i_ep+1)%20==0:\n", + " print(f\"回合:{i_ep+1}/{cfg.train_eps},奖励:{ep_reward:.1f},Epsilon:{agent.epsilon:.3f}\")\n", + " print('完成训练!')\n", + " return {\"rewards\":rewards}\n", + "def test(cfg,env,agent):\n", + " print('开始测试!')\n", + " print(f'环境:{cfg.env_name}, 算法:{cfg.algo_name}, 设备:{cfg.device}')\n", + " rewards = [] # 记录所有回合的奖励\n", + " for i_ep in range(cfg.test_eps):\n", + " ep_reward = 0 # 记录每个episode的reward\n", + " state = env.reset(seed=cfg.seed) # 重置环境, 重新开一局(即开始新的一个回合)\n", + " while True:\n", + " action = agent.predict_action(state) # 根据算法选择一个动作\n", + " next_state, reward, terminated, info = env.step(action) # 与环境进行一个交互\n", + " state = next_state # 更新状态\n", + " ep_reward += reward\n", + " if terminated:\n", + " break\n", + " rewards.append(ep_reward)\n", + " print(f\"回合数:{i_ep+1}/{cfg.test_eps}, 奖励:{ep_reward:.1f}\")\n", + " print('完成测试!')\n", + " return {\"rewards\":rewards}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3、定义环境\n", + "\n", + "OpenAI Gym中其实集成了很多强化学习环境,足够大家学习了,但是在做强化学习的应用中免不了要自己创建环境,比如在本项目中其实不太好找到Qlearning能学出来的环境,Qlearning实在是太弱了,需要足够简单的环境才行,因此本项目写了一个环境,大家感兴趣的话可以看一下,一般环境接口最关键的部分即使reset和step。" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "import gym\n", + "import turtle\n", + "import numpy as np\n", + "\n", + "# turtle tutorial : https://docs.python.org/3.3/library/turtle.html\n", + "\n", + "class CliffWalkingWapper(gym.Wrapper):\n", + " def __init__(self, env):\n", + " gym.Wrapper.__init__(self, env)\n", + " self.t = None\n", + " self.unit = 50\n", + " self.max_x = 12\n", + " self.max_y = 4\n", + "\n", + " def draw_x_line(self, y, x0, x1, color='gray'):\n", + " assert x1 > x0\n", + " self.t.color(color)\n", + " self.t.setheading(0)\n", + " self.t.up()\n", + " self.t.goto(x0, y)\n", + " self.t.down()\n", + " self.t.forward(x1 - x0)\n", + "\n", + " def draw_y_line(self, x, y0, y1, color='gray'):\n", + " assert y1 > y0\n", + " self.t.color(color)\n", + " self.t.setheading(90)\n", + " self.t.up()\n", + " self.t.goto(x, y0)\n", + " self.t.down()\n", + " self.t.forward(y1 - y0)\n", + "\n", + " def draw_box(self, x, y, fillcolor='', line_color='gray'):\n", + " self.t.up()\n", + " self.t.goto(x * self.unit, y * self.unit)\n", + " self.t.color(line_color)\n", + " self.t.fillcolor(fillcolor)\n", + " self.t.setheading(90)\n", + " self.t.down()\n", + " self.t.begin_fill()\n", + " for i in range(4):\n", + " self.t.forward(self.unit)\n", + " self.t.right(90)\n", + " self.t.end_fill()\n", + "\n", + " def move_player(self, x, y):\n", + " self.t.up()\n", + " self.t.setheading(90)\n", + " self.t.fillcolor('red')\n", + " self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit)\n", + "\n", + " def render(self):\n", + " if self.t == None:\n", + " self.t = turtle.Turtle()\n", + " self.wn = turtle.Screen()\n", + " self.wn.setup(self.unit * self.max_x + 100,\n", + " self.unit * self.max_y + 100)\n", + " self.wn.setworldcoordinates(0, 0, self.unit * self.max_x,\n", + " self.unit * self.max_y)\n", + " self.t.shape('circle')\n", + " self.t.width(2)\n", + " self.t.speed(0)\n", + " self.t.color('gray')\n", + " for _ in range(2):\n", + " self.t.forward(self.max_x * self.unit)\n", + " self.t.left(90)\n", + " self.t.forward(self.max_y * self.unit)\n", + " self.t.left(90)\n", + " for i in range(1, self.max_y):\n", + " self.draw_x_line(\n", + " y=i * self.unit, x0=0, x1=self.max_x * self.unit)\n", + " for i in range(1, self.max_x):\n", + " self.draw_y_line(\n", + " x=i * self.unit, y0=0, y1=self.max_y * self.unit)\n", + "\n", + " for i in range(1, self.max_x - 1):\n", + " self.draw_box(i, 0, 'black')\n", + " self.draw_box(self.max_x - 1, 0, 'yellow')\n", + " self.t.shape('turtle')\n", + "\n", + " x_pos = self.s % self.max_x\n", + " y_pos = self.max_y - 1 - int(self.s / self.max_x)\n", + " self.move_player(x_pos, y_pos)" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "import gym\n", + "def env_agent_config(cfg,seed=1):\n", + " '''创建环境和智能体\n", + " ''' \n", + " env = gym.make(cfg.env_name,new_step_api=True) \n", + " env = CliffWalkingWapper(env)\n", + " n_states = env.observation_space.n # 状态维度\n", + " n_actions = env.action_space.n # 动作维度\n", + " agent = QLearning(n_states,n_actions,cfg)\n", + " return env,agent" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4、设置参数\n", + "\n", + "到这里所有qlearning模块就算完成了,下面需要设置一些参数,方便大家“炼丹”,其中默认的是笔者已经调好的~。另外为了定义了一个画图函数,用来描述奖励的变化。" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "import datetime\n", + "import argparse\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "class Config:\n", + " '''配置参数\n", + " '''\n", + " def __init__(self):\n", + " self.env_name = 'CliffWalking-v0' # 环境名称\n", + " self.algo_name = 'Q-Learning' # 算法名称\n", + " self.train_eps = 400 # 训练回合数\n", + " self.test_eps = 20 # 测试回合数\n", + " self.max_steps = 200 # 每个回合最大步数\n", + " self.epsilon_start = 0.95 # e-greedy策略中epsilon的初始值\n", + " self.epsilon_end = 0.01 # e-greedy策略中epsilon的最终值\n", + " self.epsilon_decay = 300 # e-greedy策略中epsilon的衰减率\n", + " self.gamma = 0.9 # 折扣因子\n", + " self.lr = 0.1 # 学习率\n", + " self.seed = 1 # 随机种子\n", + " if torch.cuda.is_available(): # 是否使用GPUs\n", + " self.device = torch.device('cuda')\n", + " else:\n", + " self.device = torch.device('cpu')\n", + "\n", + "def smooth(data, weight=0.9): \n", + " '''用于平滑曲线\n", + " '''\n", + " last = data[0] # First value in the plot (first timestep)\n", + " smoothed = list()\n", + " for point in data:\n", + " smoothed_val = last * weight + (1 - weight) * point # 计算平滑值\n", + " smoothed.append(smoothed_val) \n", + " last = smoothed_val \n", + " return smoothed\n", + "\n", + "def plot_rewards(rewards,title=\"learning curve\"):\n", + " sns.set()\n", + " plt.figure() # 创建一个图形实例,方便同时多画几个图\n", + " plt.title(f\"{title}\")\n", + " plt.xlim(0, len(rewards), 10) # 设置x轴的范围\n", + " plt.xlabel('epsiodes')\n", + " plt.plot(rewards, label='rewards')\n", + " plt.plot(smooth(rewards), label='smoothed')\n", + " plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5、我准备好了!\n", + "\n", + "到现在我们真的可以像海绵宝宝那样大声说出来“我准备好了!“,跟着注释来看下效果吧~。" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\24438\\anaconda3\\envs\\easyrl\\lib\\site-packages\\gym\\core.py:318: DeprecationWarning: \u001b[33mWARN: Initializing wrapper in old step API which returns one bool instead of two. It is recommended to set `new_step_api=True` to use new step API. This will be the default behaviour in future.\u001b[0m\n", + " \"Initializing wrapper in old step API which returns one bool instead of two. It is recommended to set `new_step_api=True` to use new step API. This will be the default behaviour in future.\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "开始训练!\n", + "环境:CliffWalking-v0, 算法:Q-Learning, 设备:cuda\n", + "回合:20/400,奖励:-126.0,Epsilon:0.010\n", + "回合:40/400,奖励:-43.0,Epsilon:0.010\n", + "回合:60/400,奖励:-37.0,Epsilon:0.010\n", + "回合:80/400,奖励:-52.0,Epsilon:0.010\n", + "回合:100/400,奖励:-49.0,Epsilon:0.010\n", + "回合:120/400,奖励:-38.0,Epsilon:0.010\n", + "回合:140/400,奖励:-26.0,Epsilon:0.010\n", + "回合:160/400,奖励:-23.0,Epsilon:0.010\n", + "回合:180/400,奖励:-17.0,Epsilon:0.010\n", + "回合:200/400,奖励:-36.0,Epsilon:0.010\n", + "回合:220/400,奖励:-18.0,Epsilon:0.010\n", + "回合:240/400,奖励:-29.0,Epsilon:0.010\n", + "回合:260/400,奖励:-13.0,Epsilon:0.010\n", + "回合:280/400,奖励:-16.0,Epsilon:0.010\n", + "回合:300/400,奖励:-13.0,Epsilon:0.010\n", + "回合:320/400,奖励:-14.0,Epsilon:0.010\n", + "回合:340/400,奖励:-13.0,Epsilon:0.010\n", + "回合:360/400,奖励:-13.0,Epsilon:0.010\n", + "回合:380/400,奖励:-13.0,Epsilon:0.010\n", + "回合:400/400,奖励:-13.0,Epsilon:0.010\n", + "完成训练!\n", + "开始测试!\n", + "环境:CliffWalking-v0, 算法:Q-Learning, 设备:cuda\n", + "回合数:1/20, 奖励:-13.0\n", + "回合数:2/20, 奖励:-13.0\n", + "回合数:3/20, 奖励:-13.0\n", + "回合数:4/20, 奖励:-13.0\n", + "回合数:5/20, 奖励:-13.0\n", + "回合数:6/20, 奖励:-13.0\n", + "回合数:7/20, 奖励:-13.0\n", + "回合数:8/20, 奖励:-13.0\n", + "回合数:9/20, 奖励:-13.0\n", + "回合数:10/20, 奖励:-13.0\n", + "回合数:11/20, 奖励:-13.0\n", + "回合数:12/20, 奖励:-13.0\n", + "回合数:13/20, 奖励:-13.0\n", + "回合数:14/20, 奖励:-13.0\n", + "回合数:15/20, 奖励:-13.0\n", + "回合数:16/20, 奖励:-13.0\n", + "回合数:17/20, 奖励:-13.0\n", + "回合数:18/20, 奖励:-13.0\n", + "回合数:19/20, 奖励:-13.0\n", + "回合数:20/20, 奖励:-13.0\n", + "完成测试!\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\24438\\anaconda3\\envs\\easyrl\\lib\\site-packages\\seaborn\\rcmod.py:400: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.\n", + " if LooseVersion(mpl.__version__) >= \"3.0\":\n", + "c:\\Users\\24438\\anaconda3\\envs\\easyrl\\lib\\site-packages\\setuptools\\_distutils\\version.py:346: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.\n", + " other = LooseVersion(other)\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkgAAAHJCAYAAAB+GsZPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAACFiElEQVR4nO3dd3hUZcLG4d+Zkt6BJFTpofcWQVB0BRXRRV1dERXFrqhYwBU72CgWFLF3XVfFCvYC6kcHAUF6bwkhjfTMzPn+mMwwkwIBEkIyz31dXpJzzpx536nPvO0YpmmaiIiIiIiXpaYLICIiInKyUUASERERKUUBSURERKQUBSQRERGRUhSQREREREpRQBIREREpRQFJREREpBQFJBEREZFSFJBqMa3xKSIiUj0UkGqpn376ifHjx1fJuWbPnk1SUhK7du2q1ttI7ZCUlMSMGTNOyH2tX7+eCy+8kE6dOnHuuece8dj//Oc/DB48mC5dunD66aczbtw4Vq5cWan72rVrF0lJScyePbsqil6tJkyYwODBg0/IfeXk5HDjjTfStWtXevfuzbZt26rlflJSUnj66acZOnQoXbt2ZcCAAdx4440sXbrU77hRo0YxatQo79+lX49z5szhjDPOoFOnTjz44IPs27ePkSNH0rlzZ/r06UO7du148skny9z/o48+SlJSEg899FCZfY899hjdunWjqKioUnXxLdOiRYtISkpi0aJFFR4/ePBgJkyYUKlznyirV69m1KhRdO/enQEDBjB9+vRK1z9Q2Gq6AHJs3nrrrSo71+mnn85HH31EfHx8td5GpLQXX3yRPXv28OKLLxIXF1fhcZ9//jkPPPAAHTp04LbbbqNx48bs27ePTz75hH//+9/cc889jB49+gSWvHrdfPPNXHnllSfkvj7//HN++eUXHnzwQdq0aUOTJk2q/D6WLVvGLbfcQmxsLFdeeSUtWrQgMzOTjz76iFGjRvHEE09w4YUXlnvbjz76iMTERO/fjz76KM2bN+fJJ58kISGBt99+mz///JMpU6aQkJDA008/zYoVK8qc57fffiMmJobff/+9zL4lS5bQq1cvgoKCqqzOvl544QUiIiKq5dzHYufOnYwePZpu3brx7LPPsnnzZp555hkyMzN59NFHa7p4Jw0FJCEuLu6wX05VdRuR0jIyMmjbti2DBg2q8Jh169YxceJEhg0bxuOPP47Fcqjhe/jw4UyePJmnnnqKpKQkTj311BNR7GrXrFmzE3ZfmZmZAFx++eUYhlEt57/jjjto3rw5b775JqGhod59Q4YM4frrr+fBBx9kwIAB1K9fv8ztu3XrVuZ8/fv3p2/fvt6/4+PjvS2Q/fr14/XXX6ewsJDg4GAAduzYwY4dO7jrrruYNm0aW7ZsoWXLlgBkZ2ezceNG/vnPf1Z53T06dOhQbec+Fq+++irh4eHMnDmToKAgBg0aREhICI899hg33ngjjRo1qukinhTUxVYLjRo1isWLF7N48WJv066nmfe///0vZ5xxBj169OCPP/4A4OOPP2bEiBF069aNLl26cMEFF/DNN994z1e6u2zChAlcffXVfPrppwwZMoROnTpxwQUXMH/+/OO6DcCKFSsYOXIk3bp14/TTT+ftt9/m6quvPmLz859//sk111xDjx496NevH+PGjSMlJaXcsniUbtZOSkrihRdeYMSIEXTp0oUXXniB9u3b89577/ndLj09nY4dO3pb6VwuF6+88gr/+Mc/6NSpE0OGDOHdd9894vN08OBBnnjiCc466yw6d+7MsGHD+OSTT8qU8fnnn+epp57i1FNPpUuXLlx77bVH7OYoKiri2Wef5cwzz6RLly4MGzaMzz77rMK6V/Q4LV68mEsvvZSuXbsyZMgQ/u///q/Mfe3atYt7772XAQMG0LFjR5KTk7n33nvJyMg4bBlTU1O57777GDRoEF26dOHiiy/mp59+8u5PSkpi8eLFLFmy5LBdX6+++iphYWE8+OCDfuHI45577qFhw4a8+OKLhy1PZVXm+XY6nbzyyisMGzaMLl260K1bNy677DIWLlzoPWbGjBn84x//4IUXXqBPnz4MGDCArKysSj3npbvYKvs6+eyzzzj33HPp3Lkzw4cPZ8GCBXTo0KHCx3bUqFHerqJ27dp5XzOVfe0+/vjjXHXVVXTp0oX777+/3Pv4/PPPSU1N5T//+Y9fOAKwWCzcfffdjBw5kpycnHJv7+nO8nzGgbvlMSkpicGDBzN79mz27NnjPe7UU0+luLiY1atXe8/x22+/ERUVxRVXXEFoaKhfK9KyZctwuVzecH2sr3ePoqIirrnmGvr27cvff//tfaw8j62nq/ebb75h7NixdO/enT59+jBx4kTy8vK85ykuLmbq1KkMHDjQ+3x//vnnRxzaMGTIEMaOHVtm+wUXXMBNN90EwO+//86gQYP8WsyGDh2Ky+Uqt4UtUKkFqRZ66KGHuOeee7z/bt26NWvWrAHcTbkTJ06koKCA7t278/777zNp0iRuu+02evbsSVZWFq+++ip333033bt392u69vXXX3+RmprK2LFjiYiI4LnnnuO2225j/vz5REdHH9NtNm/ezNVXX02nTp2YPn06GRkZTJ8+nezsbM4777wK67t27VquuOIKunbtytNPP43T6WTatGneD4yjMWvWLO666y5atGhB48aNWbJkCXPmzOGKK67wHvPtt99imqa3TA8//DCzZ8/mhhtuoHv37ixZsoTHH3+c7OxsbrnllnLvp6CggMsvv5wDBw4wduxYGjduzI8//sj9999PWloaN954o/fYd955h549e/LEE0+QlZXF5MmTGT9+PB999FGF9bj77ruZN28eN910E127dmXevHlMmDABu93OsGHDKvVYrFmzhmuuuYZ+/frx/PPPs2vXLsaNG+d3TH5+PldeeSWxsbE89NBDREZGsmLFCl544QVCQkIqbI5PS0vj4osvJjg4mDvvvJPY2Fhmz57NLbfcwtNPP83w4cP56KOPeOSRRwD367iiVpNffvmFQYMGERYWVu7+oKAgzjrrLN59910yMjKIjY2tVP0rUpnne+rUqXz44YfcddddJCUlkZKSwosvvsjtt9/Or7/+6g0Ce/bsYd68ed7uC89751ie8yPd5vPPP2fChAlccskl3HfffaxatYqbb74Zp9NZ4Tkfeugh3nzzTT755BM++ugj4uLijuq1+/777zN69Giuu+46wsPDy72P3377jfr169OlS5dy97dr14527dod5hlx69ixIx999BGXXnopF198MZdccgmGYfDiiy+ydu1aXnjhBRITE4mLiyMkJITly5fTq1cvbxmSk5MJCwujd+/e/Pbbb94uzCVLltCgQQOSkpKO+fXu4XA4uPPOO/nrr7948803ad++fYXHPvTQQ1x00UXMnDmTVatW8cwzzxAbG8tdd90FwIMPPsjXX3/NbbfdRvv27fn666954IEHjvg4DR8+nFdeeYWcnBxvt97mzZtZt24dN910EwUFBezevZsWLVr43S4uLo6IiAi2bt16xPsIFApItVDr1q29L/zSzc+XX345Q4cO9f69c+dOrr32Wm6+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wurVq8ttWfn777+58MILue+++7j66quPurzl6dChAzExMfz5558sWLDA23rkceqpp7Js2TIsFgtt27b1BsJjfb2Dey2lPn36cM455/DII48wc+bMYy6/J1ylpaX5fcb4fg527NixzOvcM67onHPOYdKkSfz4449s2bKFxo0bez8XwsPDSUhIKPMcHzhwgNzcXFq1anXM5a5r1MVWS5U3m6e0jIwMtm7dysUXX0znzp2x2dx52DOz7EhNrVXNMziysLDQu23t2rVHbB3o1asXf/zxh18T99q1a7n++utZs2aN9xfRvn37vPs9YaEyPNOL33nnHdasWePtXvPcN7gfy86dO3v/S09P57nnnqvwPnr37s3u3bvLrMfy5ZdfYrfbKxywWhmeD7qff/7Zb/vUqVOZPHky4P6V6Pt4AGW6A5OTk5k/f75ft85vv/1GcXGx322ioqIYM2aM98siNzfXO/OnIr1792bFihXs3r3bb/uXX35JgwYNOOWUUypbXW644QYKCgp45JFHvPf5119/ceGFF3LDDTfwxBNPsGPHDu8A6tjYWL/nqnPnzpVe36Yyz/eWLVvIzMzkyiuvpHXr1t73Yk29r8AdkJo1a8YPP/zgt/37778/6nNV9Wt3+PDhNGjQgCeeeIKCggK/fU6nk6lTp2K32znnnHOOuqwVsVgs9O3blwULFrBu3boyAWnAgAGsW7eO5cuX+7UeHevrHdwtbA0aNGDcuHH89NNPfjOFj1bPnj2xWq2HfT4jIiLKvM49n4VRUVGcccYZ/PTTT3z33XcMHz7cr+usf//+/Prrr36fqd999x1Wq5V+/fodc7nrGrUg1VJRUVGsWLHCO423PPXq1aNx48a8//77JCYmEhUVxW+//cY777wDHH68Q3W48cYbmTt3LmPGjOGaa64hOzub5557DovFcth+75tvvplLL72UG264gSuvvJKCggKeffZZunTpQv/+/SkoKCAkJIQnn3yS22+/ndzcXJ5//nnvQNIjsVqtnHfeebz33nskJCR411cB9xTj4cOH88ADD7B79246derE1q1beeaZZ2jSpAnNmzcv95wjRozggw8+4JZbbmHs2LE0adKEn3/+mU8//ZRbb73V21JxLNq1a8fQoUOZMmUKBQUFtG/fnvnz5/PLL7/wwgsvAO5Wl5dffpmXX36Zrl278vPPP/tNQQe45ZZb+PHHH7n22msZM2YM6enpPPvss35jkrp06cKHH37Ik08+yRlnnEFqaiqvv/46aWlpFc5mBBg9ejRffvklV199NbfeeisxMTF8/vnnLFy4sMxaRkfStm1bnnzySe677z527NjBZZddRpMmTbjjjjt47rnncDqdJCcnV3rl6T/++KPcLr5zzjmnUs93Xl4eERERzJo1C5vNhs1m47vvvvP+mj/R7ytwd2ePHTuWu+++m4ceeoh//OMfrFu3zrv0wdE83lX92o2MjOTJJ5/k1ltv5ZJLLuGKK66gefPm7Nu3j/fff59Vq1Yxbdq0I3ZJHa1+/frx+OOPY7Va6dOnj9++5ORkcnJyWLp0Kddee613+7G+3n1ddtllfP7550yePJlTTz210rfz1bRpUy666CKmT59OcXEx7dq144cffuCXX34BKvd8Dh8+nLFjx+J0Ov1+9AGMGTPGO6xg9OjRbNu2jenTp/Ovf/1LayD5UECqpUaOHMlff/3FddddxxNPPFHhitYzZ85k8uTJTJgwgaCgIFq3bs1LL73E448/ztKlS/1m4VS3U045hddff52nn36asWPHUq9ePW644QZeeumlCqcIg7u5/N1332XatGnccccdREREMGjQIO6++26CgoIICgpixowZTJs2jVtuuYXGjRtz6623HtUSABdccAFvv/02w4YNK/Ph88QTT/Dyyy/z3//+l3379lGvXj3OPfdc7rjjDr9Bs75CQ0O9ZX7uuefIycmhZcuWTJ48mYsvvrjS5arIlClTeOGFF3j77bfJyMigVatWPP/8896xUzfccAPp6em8/vrrFBcXc/rppzN58mTvOigAzZs357333uPJJ5/kzjvvpF69eowfP97vMg3//Oc/2bVrF59++ikffPABCQkJDBo0iMsvv5wHHniAzZs3l9sk36BBAz788EOmTZvGpEmTvB/yM2fO5Mwzzzzq+p533nm0bduWt956i+eff579+/cTExPjXafntdde46KLLmLSpElHXJTv66+/5uuvvy6zvVOnTiQkJBzx+Y6MjGTmzJk8/fTT3H777YSHh3vX07ruuutYunTpCbtMiK/zzz+fvLw8Xn/9dT799FPatGnD/fffz/3331+psUIe1fHaHTBgAB9//DFvvPEGL7/8MmlpacTExNCpUyc++ugjunbtekznPZzk5GSKi4s59dRT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2IIwbEHlHyQiIiJ1ggJSKRXNYjMLctz7gyNOZHFERESkBigglfBO869of0kLkhESfkLKIyIiIjVHAamUiqb5ewOSWpBERETqPAWkUo7cxaYWJBERkbpOAamUI3axqQVJRESkzlNAKqXCFqTCkhYkjUESERGp8xSQPI4wSluz2ERERAKHAlIpR+5iUwuSiIhIXaeAVMqRutgIUQuSiIhIXaeAVKLS6yCpBUlERKTOU0AqpcJ1kDQGSUREJGAoIJVSXhebabqgMM+9X7PYRERE6jwFpMooysfTCacWJBERkbpPAakUSzldbJ7uNewhGFbbiS2QiIiInHAKSKWV18WmAdoiIiIBRQGplPIGaXtX0VZAEhERCQgKSCXMknn+RjkT/U3PAG0FJBERkYCggORVMgi73Bakki62oLATWSARERGpIQpIpZS3DJJZ5GlBUkASEREJBApIpZS7DlJJFxvqYhMREQkICkillLuSdpG62ERERAKJAlIleAdpKyCJiIgEBAWkUsrtYivKd+/TGCQREZGAoIBUymFnsSkgiYiIBAQFpFION4uNIA3SFhERCQQKSCVK1okst4uNQk3zFxERCSQKSB6elbRL5SPTNA+tg6RB2iIiIgFBAelIigvAdAG61IiIiEigUEAqxVKqCck7/shiA6u9BkokIiIiJ5oCUmmlu9h8xh+VOz5JRERE6hwFpFIMym9B0vgjERGRwKGAVEqZQdolayChGWwiIiIBQwGplDKdaGpBEhERCTgKSCXMknn+pccZHRqDpBlsIiIigUIBqbQKutjUgiQiIhI4FJA8ShaKtJQOSEVqQRIREQk0CkhlVLAOklqQREREAoYCUillljrSddhEREQCjgJSKWUGaRcpIImIiAQaBaRSSjcgaZC2iIhI4FFAKlEyRruchSK1DpKIiEigUUAqpcJLjWgWm4iISMBQQCrNJx+ZLicUF7j/0BgkERGRgKGAVIpfF1tR/qHt6mITEREJGApIpfh2sXnXQLKHYFisNVQiEREROdEUkDxKRmn7tiBpBpuIiEhgUkAqxT8gaQ0kERGRQKSAVEp5XWxqQRIREQksCkglylsHydPFpuuwiYiIBBYFpNL8ZrFpDSQREZFApIBUisWnCUljkERERAKTAtJhaAySiIhIYFJA8nKPQtIsNhEREVFAKsV/FpvWQRIREQlECkillNeC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jHTv/sLCQtat+5vmzVsCFQewirRs2Zrc3FyKi4tp0qSp97/333+b33+fB0CbNm1ZtWql3+3Wrfv7qO5HREQCmwKSDyM6saaLUK3Cw8OZPftjZs58nl27drJlyyZ+/PF7mjRpRkxMzFGf79//HsXs2f/js88+YdeunXz//be88cYrDB/+TyIiIvjHP4YSHR3DAw9M4O+/17Bp00YefXQi+fn5XHDBCMDdjQfuAFNYWHDE++zbN5k2bdry0EP3sXz5Unbt2smMGdOZO/crb+i64oqrmT//Fz744B127tzBJ5/8l19//emo6yciIoFL/Q4+Qho0PfJBtVjz5i2YPHkKb775Kp999jEWi4VevfowbdrzpKTsO+rz/fvfVxAUZOejjz7gueemEh+fwMiRV3H55aMAiIiIYMaMl3nhhWe5/fabAejSpSsvvfQ6jRo1BqBHj9506NCJm266hgceeOyI92m1WnnmmZnMnPkcDz44gfz8fJo3b8nkyVPo2bM3AKeeOoCHHprEG2+8wmuvzaJjx85cdtkV/PDDt0ddRxERCUyGqZX6ACjMzyevwIXD4Sqzr7i4iAMH9lKvXkPs9rq10rbNZim3znVdefWuy88zuOscGxtORkZuQD3nqrfqHQgCtd5xceFYrdXTGaYuthLBJV09IiIiIgpIIiIiIqUoIImIiIiUooAkIiIiUooCkoiIiEgpCkhHQRP+6jY9vyIi4qGAVAlWq/uyGEVFhTVcEqlOnufXatXyYCIigU7fBJVgsVgJDY0gJ8d9OY6goOCjvkTGycrlMnA6A6/lxLfepmlSVFRITk4GoaERh70WnIiIBAYFpEqKiooD8IakusJiseByBc6iYh7l1Ts0NML7PIuISGBTQKokwzCIjq5HZGQsTqejpotTJaxWg+joMLKy8gKqFam8elutNrUciYiIlwLSUbJYLFgsdeMyFDabhZCQEPLznQG1NH2g1ltERCpPP5lFRERESlFAEhERESlFAUlERESkFMPU6nheTmfgjUexWi2qdwBRvQOL6h1YArHeFotRbcvuKCCJiIiIlKIuNhEREZFSFJBERERESlFAEhERESlFAUlERESkFAUkERERkVIUkERERERKUUASERERKUUBSURERKQUBSQRERGRUhSQREREREpRQBIREREpRQFJREREpBQFJBEREZFSAjoguVwunn/+eU477TS6devGddddx86dO2u6WFUuJSWFpKSkMv/Nnj0bgL///psrrriCbt26MXjwYN55550aLvHxe/nllxk1apTftiPVsy68Hsqr98SJE8s894MHD/bur631zszM5MEHH2TgwIH06NGDf//73yxdutS7f8GCBYwYMYKuXbsydOhQ5syZ43f7wsJCHnnkEZKTk+nevTt33XUX6enpJ7oaR+1I9R49enSZ59v3NVFb633gwAHuuece+vXrR/fu3bn++uvZvHmzd39dfX8fqd519f3ta+vWrXTv3t37nQUn6Pk2A9iMGTPMvn37mr/88ov5999/m9dcc4159tlnm4WFhTVdtCr166+/mp07dzZTUlLM1NRU73/5+flmenq62bdvX/O+++4zN23aZH7yySdm586dzU8++aSmi33M3nvvPbNdu3bmFVdc4d1WmXrW9tdDefU2TdO8+OKLzenTp/s99wcOHPDur631Hj16tDls2DBzyZIl5pYtW8xHHnnE7NKli7l582Zz06ZNZufOnc3p06ebmzZtMl977TWzQ4cO5v/93/95bz9hwgTzrLPOMpcsWWKuXLnSvPDCC82RI0fWYI0q53D1Nk3TTE5ONj/44AO/5zsjI8N7+9pa70svvdS85JJLzJUrV5qbNm0yb7vtNnPAgAFmXl5enX5/H67epll3398eRUVF5ogRI8y2bduan376qWmaJ+7zPGADUmFhodm9e3fz/fff927Lysoyu3TpYn711Vc1WLKq98orr5jnn39+uftmzZplDhgwwCwuLvZumzZtmnn22WefqOJVmX379pk33HCD2a1bN3Po0KF+QeFI9azNr4fD1dvlcpndunUzv//++3JvW1vrvW3bNrNt27bm0qVLvdtcLpd51llnmc8++6z5wAMPmBdffLHfbcaNG2dec801pmm6H7N27dqZv/76q3f/li1bzLZt25rLly8/MZU4Bkeqd1pamtm2bVtzzZo15d6+ttY7MzPTHDdunLl+/Xrvtr///tts27atuXLlyjr7/j5Svevq+9vXtGnTzCuvvNIvIJ2o5ztgu9jWrVtHbm4uycnJ3m1RUVF06NCBJUuW1GDJqt769etp1apVufuWLl1Knz59sNls3m39+vVj27ZtpKWlnagiVok1a9Zgt9v58ssv6dq1q9++I9WzNr8eDlfvHTt2kJeXR8uWLcu9bW2td2xsLK+88gqdO3f2bjMMA8MwyM7OZunSpX51AvfzvWzZMkzTZNmyZd5tHi1atCAhIaFW13v9+vUYhkGLFi3KvX1trXd0dDTTpk2jbdu2AKSnp/PWW2+RmJhI69at6+z7+0j1rqvvb48lS5bw0Ucf8eSTT/ptP1HPt+3Ih9RN+/btA6Bhw4Z+2+Pj47376ooNGzYQGxvLyJEj2bp1K6eccgo33XQTAwcOZN++fd43n0d8fDwAe/fupX79+jVR5GMyePBgv753X0eqZ21+PRyu3hs2bADg3XffZf78+VgsFgYOHMidd95JZGRkra13VFQUgwYN8tv23XffsX37dv7zn//w2WefkZiY6Lc/Pj6e/Px8MjIySElJITY2luDg4DLH1OZ6b9iwgcjISB599FH++OMPwsLCGDp0KDfffDNBQUG1tt6+HnjgAf73v/8RFBTESy+9RFhYWJ1+f3uUV++6+v4GyM7O5t5772XixIllyn+inu+AbUHKz88HICgoyG97cHAwhYWFNVGkauFwONiyZQtZWVncdtttvPLKK3Tr1o3rr7+eBQsWUFBQUO5jANSpx+FI9ayrr4cNGzZgsViIj49n1qxZTJgwgd9//52bb74Zl8tVZ+q9fPly7rvvPs4++2xOP/30cp9vz99FRUXk5+eX2Q+1v94bNmygsLCQLl268Nprr3HTTTfx8ccfM3HiRIA6Ue+rrrqKTz/9lGHDhnHLLbewZs2agHh/l1fvuvz+fvjhh+nevTvnn39+mX0n6vkO2BakkJAQwP1h6fk3uB/c0NDQmipWlbPZbCxatAir1eqtZ6dOndi4cSOvv/46ISEhFBUV+d3G8wIKCws74eWtLkeqZ119Pdx0001cfvnlxMbGAtC2bVsaNGjAv/71L1avXl0n6v3jjz9y991306NHD6ZOnQq4PwhLP9+ev0NDQ8t9PUDtr/ejjz7K+PHjiY6OBtzPt91u58477+Tee++tE/Vu3bo1AJMnT2blypW89957AfH+Lq/ekydPrpPv788//5ylS5fy1Vdflbv/RD3fAduC5Gl6S01N9duemppKQkJCTRSp2oSHh/u9SADatGlDSkoKiYmJ5T4GQJ16HI5Uz7r6erBYLN4PT482bdoA7mbq2l7v9957j9tuu40zzjiDWbNmeX9FNmzYsNw6hYWFERkZSWJiIpmZmWU+ZGt7vW02mzccefg+37W13unp6cyZMweHw+HdZrFYaN26NampqXX2/X2ketfV9/enn37KgQMHOP300+nevTvdu3cH4KGHHmLMmDEn7PkO2IDUrl07IiIiWLRokXdbdnY2a9eupXfv3jVYsqq1ceNGevTo4VdPgL/++ovWrVvTu3dvli1bhtPp9O5buHAhLVq0oF69eie6uNXmSPWsq6+He++9l6uvvtpv2+rVqwH3L9LaXO8PPviAxx57jJEjRzJ9+nS/5vRevXqxePFiv+MXLlxIjx49sFgs9OzZE5fL5R20DO61VlJSUmp1vUeNGsV9993nd/zq1aux2+00b9681tY7LS2NcePGsWDBAu+24uJi1q5dS6tWrers+/tI9a6r7++pU6cyd+5cPv/8c+9/AGPHjmXy5Mkn7vmumol4tdP06dPNPn36mD/++KPfOglFRUU1XbQq43Q6zYsuusg899xzzSVLlpibNm0yH3/8cbNTp07m+vXrzbS0NLN3797m+PHjzY0bN5qffvqp2blzZ3P27Nk1XfTjMn78eL/p7pWpZ114PZSu948//mi2bdvWnDFjhrl9+3bz119/NQcPHmyOGzfOe0xtrPeWLVvMjh07mrfccovf+i+pqalmdna2uWHDBrNjx47mlClTzE2bNpmvv/56mXWQxo0bZw4ePNhcuHChdz2g0mtInWyOVO93333XbN++vfnBBx+YO3bsMOfMmWP27dvXnD59uvcctbHepmmaY8aMMc8++2xz8eLF5vr1681x48aZvXv3Nnfv3l2n39+Hq3ddfX+Xx3ea/4l6vgM6IDkcDvPpp582+/XrZ3br1s287rrrzJ07d9Z0sarc/v37zQkTJpj9+/c3O3fubF566aXmkiVLvPtXrlxp/utf/zI7depknnHGGea7775bg6WtGqWDgmkeuZ514fVQXr3nzp1rXnjhhWaXLl3M/v37m08++aRZUFDg3V8b6/3SSy+Zbdu2Lfe/8ePHm6ZpmvPmzTOHDRtmdurUyRw6dKg5Z84cv3Pk5uaa999/v9mrVy+zV69e5rhx48z09PSaqE6lVabe7733nnnOOed4X+cvvfSS6XQ6veeojfU2TdPMzs42H3roIbN///5mly5dzGuuucbcsGGDd39dfX8fqd518f1dHt+AZJon5vk2TNM0q6pZTERERKQuCNgxSCIiIiIVUUASERERKUUBSURERKQUBSQRERGRUhSQREREREpRQBIREREpRQFJREREpBQFJBEREZFSFJBEpE7YtWsXSUlJzJ49+7jPNWHCBAYPHlwFpRKR2spW0wUQEakK8fHxfPTRRzRr1qymiyIidYACkojUCUFBQXTr1q2miyEidYS62ETkhPj4448577zz6NSpE6effjozZszA6XQC7i6tUaNG8cknn3DGGWfQvXt3rrrqKtatW+e9vcvl4plnnmHw4MF06tSJwYMHM23aNIqLi4Hyu9i2bdvG2LFj6d+/P926dWPUqFEsW7bMr1xZWVncd9999OnTh969ezNlyhRcLleZ8v/444+MGDGCzp07079/fyZNmkReXp53f0FBAQ8//DADBw6kU6dODB06lNdff71KH0MROXHUgiQi1e7ll1/mmWee4YorruC+++7j77//ZsaMGezdu5fHH38cgL///pstW7Ywbtw4oqOjef7557niiiuYO3cu8fHxvPrqq3z44YeMHz+epk2bsnLlSp555hnsdjtjx44tc5+bNm3iX//6F82bN2fixInY7XbeeecdrrrqKt544w369OmDy+VizJgx7N69m/HjxxMTE8Nrr73G6tWriY+P957rq6++4u677+b888/njjvuYPfu3TzzzDNs2rSJN998E8MwePzxx/n9998ZP3489evXZ/78+Tz99NPExMRw0UUXnbDHWkSqhgKSiFSrgwcPMnPmTC699FImTpwIwIABA4iJiWHixImMHj3ae9ysWbPo1asXAF26dOGss87inXfe4e6772bx4sV06tTJGzb69OlDaGgokZGR5d7vCy+8QFBQEO+88w4REREAnH766QwbNoynn36aTz75hPnz57Nq1SpeffVVBg4cCEBycrLfAG3TNJk6dSqnnXYaU6dO9W5v3rw5V199NfPmzeP0009n8eLF9O/fn/POOw+Avn37EhYWRr169ary4RSRE0RdbCJSrVasWEFBQQGDBw/G4XB4//OEkD/++AOAJk2aeMMRuAddd+/enSVLlgDuwPHHH39w+eWX89prr7Fp0yauuOIKLrjggnLvd/HixZxxxhnecARgs9k477zz+Ouvv8jNzWXp0qXY7XZOO+007zFhYWEMGjTI+/eWLVvYt29fmfL37t2biIgIb/n79u3L//73P6677jree+89du7cyS233MLpp59eNQ+kiJxQakESkWqVmZkJwPXXX1/u/tTUVAASEhLK7KtXrx5r1qwBYMyYMYSHh/Ppp58ydepUpkyZQps2bZg4cSL9+vUrc9usrCzq169fZnv9+vUxTZOcnByysrKIiYnBMAy/Yxo0aFCm/I888giPPPJIheW///77SUxM5Msvv+Sxxx7jscceo3v37jz88MO0a9eu3LqLyMlLAUlEqlVUVBQAU6dOpXnz5mX2169fn+eee46MjIwy+9LS0rxdVBaLhZEjRzJy5EgOHDjAvHnzmDVrFrfddpu3FcdXdHQ0aWlpZbbv378fgNjYWGJjY8nIyMDpdGK1Wr3HeEKRb/nvvfde+vTpU+79gHsW3U033cRNN93Enj17+OWXX5g5cyZ33XUXc+bMqejhEZGTlLrYRKRade3aFbvdTkpKCp07d/b+Z7PZmD59Ort27QLcM842b97svV1KSgorVqwgOTkZgMsuu4xJkyYB7palESNGMHLkSLKzs8nJySlzv7179+aXX37x2+d0OpkzZw6dO3cmKCiI5ORkHA4HP/74o/eYoqIiv8DVsmVL6tWrx65du/zKn5CQwLRp01i7di0FBQUMGTKEN954A4BGjRoxcuRIzjvvPPbs2VOFj6aInChqQRKRahUbG8uYMWN47rnnyMnJoW/fvqSkpPDcc89hGIa3+8k0TW688UbuvPNOrFYrL7zwAtHR0YwaNQpwB5433niD+vXr0717d1JSUnjzzTfp06cPcXFxflPuAW699Vbmz5/PlVdeyfXXX4/dbveODXrttdcA94DsAQMGMHHiRA4cOEDjxo155513SE9P97ZcWa1W7rzzTh588EGsVitnnHEG2dnZzJw5k5SUFDp27EhISAgdO3bkhRdewG63k5SUxNatW/nss88YMmTICXy0RaSqGKZpmjVdCBGp+95//30++OADtm/fTnR0NMnJyYwbN45GjRoxYcIEFi9ezHXXXceLL75Ifn4+p556KuPHj6dJkyYAOBwOXnrpJb788kv27dtHZGQkgwcP5q677iI2NpZdu3Zx5pln8sQTTzBixAjAvXTA9OnTWbp0KYZh0KVLF2699Va/weD5+flMnTqVOXPmUFhYyLnnnktYWBg//fQTP//8s/e4uXPn8tprr7Fx40bCwsLo0aMHd9xxB0lJSQDk5OTw7LPP8tNPP7F//37q1avHueeey+23305ISMgJfKRFpCooIIlIjfMEJN9AIiJSkzQGSURERKQUBSQRERGRUtTFJiIiIlKKWpBERERESlFAEhERESlFAUlERESkFAUkERERkVIUkERERERKUUASERERKUUBSURERKQUBSQRERGRUv4fwQ4H0Ypddl0AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# 获取参数\n", + "cfg = Config() \n", + "# 训练\n", + "env, agent = env_agent_config(cfg)\n", + "res_dic = train(cfg, env, agent)\n", + " \n", + "plot_rewards(res_dic['rewards'], title=f\"training curve on {cfg.device} of {cfg.algo_name} for {cfg.env_name}\") \n", + "# 测试\n", + "res_dic = test(cfg, env, agent)\n", + "plot_rewards(res_dic['rewards'], title=f\"testing curve on {cfg.device} of {cfg.algo_name} for {cfg.env_name}\") # 画出结果" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.12 ('easyrl')", + "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.7.12" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "f5a9629e9f3b9957bf68a43815f911e93447d47b3d065b6a8a04975e44c504d9" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/projects/notebooks/Value Iteration/README.md b/projects/notebooks/Value Iteration/README.md new file mode 100644 index 0000000..e69de29 diff --git a/projects/requirements.txt b/projects/requirements.txt index 7dbd44a..5cda89e 100644 --- a/projects/requirements.txt +++ b/projects/requirements.txt @@ -1,10 +1,11 @@ pyyaml==6.0 ipykernel==6.15.1 jupyter==1.0.0 -matplotlib==3.5.2 -seaborn==0.11.2 +matplotlib==3.5.3 +seaborn==0.12.1 dill==0.3.5.1 argparse==1.4.0 pandas==1.3.5 pyglet==1.5.26 -importlib-metadata<5.0 \ No newline at end of file +importlib-metadata<5.0 +setuptools==65.2.0 \ No newline at end of file