value-based 实践:Q-Learning 智能体(FrozenLake + Taxi) + 回放视频 + 评估分数
Browse files- .gitattributes +9 -0
- README.md +96 -0
- code/build_hub_package.py +286 -0
- code/evaluate_and_record.py +542 -0
- code/make_combined_video.py +142 -0
- code/train_qlearning.py +604 -0
- code/upload_to_hub.py +104 -0
- eval_results/eval_frozenlake4x4.json +727 -0
- eval_results/eval_frozenlake4x4_slippery.json +727 -0
- eval_results/eval_frozenlake8x8.json +727 -0
- eval_results/eval_taxi.json +724 -0
- logs/frozenlake4x4/progress.csv +0 -0
- logs/frozenlake4x4/train_console.log +79 -0
- logs/frozenlake4x4/train_curve.png +3 -0
- logs/frozenlake4x4_slippery/progress.csv +0 -0
- logs/frozenlake4x4_slippery/train_console.log +79 -0
- logs/frozenlake4x4_slippery/train_curve.png +3 -0
- logs/frozenlake8x8/progress.csv +0 -0
- logs/frozenlake8x8/train_console.log +79 -0
- logs/frozenlake8x8/train_curve.png +3 -0
- logs/taxi/progress.csv +0 -0
- logs/taxi/train_console.log +84 -0
- logs/taxi/train_curve.png +3 -0
- metrics.json +58 -0
- models/qtable_frozenlake4x4.pkl +3 -0
- models/qtable_frozenlake4x4_slippery.pkl +3 -0
- models/qtable_frozenlake8x8.pkl +3 -0
- models/qtable_taxi.pkl +3 -0
- requirements.txt +7 -0
- videos/replay_frozenlake4x4.mp4 +3 -0
- videos/replay_frozenlake4x4_slippery.mp4 +3 -0
- videos/replay_frozenlake8x8.mp4 +3 -0
- videos/replay_taxi.mp4 +3 -0
- videos/replay_value_based_all.mp4 +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,12 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
logs/frozenlake4x4/train_curve.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
logs/frozenlake4x4_slippery/train_curve.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
logs/frozenlake8x8/train_curve.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
logs/taxi/train_curve.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
videos/replay_frozenlake4x4.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
videos/replay_frozenlake4x4_slippery.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
videos/replay_frozenlake8x8.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
videos/replay_taxi.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
videos/replay_value_based_all.mp4 filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Value-based 实践 · Q-Learning(FrozenLake-v1 + Taxi-v3)
|
| 2 |
+
|
| 3 |
+
> 《第3周-深度强化学习原理实践》PPT 第 27–40 页 value-based 实践产物:**从零手写 Q-Learning**(Q 表 + epsilon-greedy + Bellman 更新),训练好的智能体 + 训练代码 + 回放视频 + 评估分数。
|
| 4 |
+
|
| 5 |
+
## 1. 评估分数
|
| 6 |
+
|
| 7 |
+
| 智能体 | 环境 | 平均回报(100 局) | 成功率 | 平均步数 | 训练回合 |
|
| 8 |
+
|---|---|---|---|---|---|
|
| 9 |
+
| FrozenLake-v1 · 4x4 不滑 | `FrozenLake-v1` | **1.00 ± 0.00** | 100% | 6.0 | 10000 |
|
| 10 |
+
| FrozenLake-v1 · 4x4 滑冰版 | `FrozenLake-v1` | **0.74 ± 0.44** | 74% | 39.4 | 20000 |
|
| 11 |
+
| FrozenLake-v1 · 8x8 | `FrozenLake-v1` | **1.00 ± 0.00** | 100% | 14.0 | 60000 |
|
| 12 |
+
| Taxi-v3 | `Taxi-v3` | **7.56 ± 2.71** | 100% | 13.4 | 25000 |
|
| 13 |
+
|
| 14 |
+
> 评估方式:独立环境、贪心策略 `argmax_a Q(s,a)`、每局最多 99 步,跑 100 局;FrozenLake 的回报是「是否到达目标」(0/1),Taxi 的回报是「每步 −1,成功送达 +20」。
|
| 15 |
+
|
| 16 |
+
## 2. 回放视频
|
| 17 |
+
|
| 18 |
+
**总回放(三个智能体合集)**
|
| 19 |
+
|
| 20 |
+
<video controls width="100%" src="videos/replay_value_based_all.mp4"></video>
|
| 21 |
+
|
| 22 |
+
**FrozenLake-v1 · 4x4 不滑**
|
| 23 |
+
|
| 24 |
+
<video controls width="100%" src="videos/replay_frozenlake4x4.mp4"></video>
|
| 25 |
+
|
| 26 |
+
**FrozenLake-v1 · 4x4 滑冰版**
|
| 27 |
+
|
| 28 |
+
<video controls width="100%" src="videos/replay_frozenlake4x4_slippery.mp4"></video>
|
| 29 |
+
|
| 30 |
+
**FrozenLake-v1 · 8x8**
|
| 31 |
+
|
| 32 |
+
<video controls width="100%" src="videos/replay_frozenlake8x8.mp4"></video>
|
| 33 |
+
|
| 34 |
+
**Taxi-v3**
|
| 35 |
+
|
| 36 |
+
<video controls width="100%" src="videos/replay_taxi.mp4"></video>
|
| 37 |
+
|
| 38 |
+
## 3. 学到的策略(Q 表可视化)
|
| 39 |
+
|
| 40 |
+
## 4. 训练曲线
|
| 41 |
+
|
| 42 |
+

|
| 43 |
+
|
| 44 |
+

|
| 45 |
+
|
| 46 |
+

|
| 47 |
+
|
| 48 |
+

|
| 49 |
+
|
| 50 |
+
## 5. 怎么复现
|
| 51 |
+
|
| 52 |
+
```powershell
|
| 53 |
+
# 环境(本机已有):conda activate DRL
|
| 54 |
+
conda activate DRL
|
| 55 |
+
|
| 56 |
+
# 训练(每个实验 1~30 秒)
|
| 57 |
+
python train_qlearning.py --env frozenlake4x4
|
| 58 |
+
python train_qlearning.py --env frozenlake4x4_slippery
|
| 59 |
+
python train_qlearning.py --env frozenlake8x8
|
| 60 |
+
python train_qlearning.py --env taxi
|
| 61 |
+
|
| 62 |
+
# 评估 + 录视频(生成 eval_results/*.json 和 videos/*.mp4)
|
| 63 |
+
python evaluate_and_record.py --model models/qtable_frozenlake4x4.pkl
|
| 64 |
+
python evaluate_and_record.py --model models/qtable_frozenlake4x4_slippery.pkl --video-episodes 5 --slowmo 4
|
| 65 |
+
python evaluate_and_record.py --model models/qtable_frozenlake8x8.pkl
|
| 66 |
+
python evaluate_and_record.py --model models/qtable_taxi.pkl
|
| 67 |
+
|
| 68 |
+
# Q 表可视化 + 总回放 + 打包
|
| 69 |
+
python visualize_qtable.py --all
|
| 70 |
+
python make_combined_video.py
|
| 71 |
+
python build_hub_package.py
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
## 6. 文件说明
|
| 75 |
+
|
| 76 |
+
- `models/qtable_*.pkl`:模型文件。pickle 格式,内含 Q 表、超参数、训练种子和评估指标;
|
| 77 |
+
`evaluate_and_record.py` 可以直接加载(不需要重新训练)。
|
| 78 |
+
- `videos/*.mp4`:回放,每帧标注步数/动作/奖励/Q 值条形图,片头片尾是标题卡和分数卡。
|
| 79 |
+
- `eval_results/*.json`:评估分数 + 逐局明细(起点种子、回报、步数、是否成功)。
|
| 80 |
+
- `logs/<run>/train_console.log`:完整训练日志(环境自检、超参数、每 N 回合进度、每次评估)。
|
| 81 |
+
- `code/`:全部代码(训练 / 评估录像 / 可视化 / 打包 / 上传 / 一键脚本)。
|
| 82 |
+
|
| 83 |
+
## 7. 对应 PPT 页码
|
| 84 |
+
|
| 85 |
+
| PPT 页 | 内容 | 对应实现 |
|
| 86 |
+
|---|---|---|
|
| 87 |
+
| 29 | Q 表 / Q 函数 / 最优策略 | `train_qlearning.py` 的 `initialize_q_table` / `greedy_policy` |
|
| 88 |
+
| 31–32 | FrozenLake 观测/动作/奖励 | 训练日志里的「环境自检」 |
|
| 89 |
+
| 33 | Q 表初始化 + 贪心策略 | `initialize_q_table` / `greedy_policy` |
|
| 90 |
+
| 34 | epsilon-greedy + 超参数 | `epsilon_greedy_policy` + `EXPERIMENTS` 配置 |
|
| 91 |
+
| 35 | 训练循环(Bellman 更新) | `train_qlearning.py::train` 里的 `Q[s][a] += lr*(...)` |
|
| 92 |
+
| 36–37 | 训练、Q 表可视化、评估、保存模型 | 训练日志 / `visualize_qtable.py` / `evaluate_and_record.py` / `models/*.pkl` |
|
| 93 |
+
| 38–40 | Taxi-v3(500 状态 × 6 动作) | `--env taxi`(含 PPT 的 100 个官方评估种子) |
|
| 94 |
+
| 28 | 上传 Hub + 视频 + 分数 | `build_hub_package.py` + `upload_to_hub.py` + README |
|
| 95 |
+
|
| 96 |
+
- 生成时间:2026-10-30 23:05
|
code/build_hub_package.py
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
把训练好的智能体 + 代码 + 视频 + 评估分数打包成"可以直接上传 Hub"的文件夹。
|
| 4 |
+
================================================================
|
| 5 |
+
对应 PPT 第 28 页学习目标第 4 条:
|
| 6 |
+
"能够将训练好的智能体和代码上传到 Hub,并附上一个漂亮的视频回放和评估分数"
|
| 7 |
+
|
| 8 |
+
产物 hub_package/ 结构:
|
| 9 |
+
README.md 自动填好分数 + 内嵌视频的模型卡
|
| 10 |
+
metrics.json 三/四个智能体的评估分数汇总
|
| 11 |
+
requirements.txt
|
| 12 |
+
models/qtable_*.pkl 训练出的模型文件(Q 表 + 超参 + 指标)
|
| 13 |
+
videos/replay_*.mp4 回放视频(含总回放 replay_value_based_all.mp4)
|
| 14 |
+
eval_results/eval_*.json 评估分数(逐局明细)
|
| 15 |
+
logs/<run>/train_console.log 训练日志
|
| 16 |
+
logs/<run>/train_curve.png 训练曲线
|
| 17 |
+
assets/qtable_policy_*.png 学到的策略可视化
|
| 18 |
+
code/ 训练 + 评估 + 可视化 + 上传脚本(可复现)
|
| 19 |
+
run_all.ps1 一键复现脚本
|
| 20 |
+
|
| 21 |
+
用法:
|
| 22 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe build_hub_package.py
|
| 23 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe build_hub_package.py --repo-id 你的用户名/value-based-qlearning
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
import argparse
|
| 27 |
+
import json
|
| 28 |
+
import os
|
| 29 |
+
import shutil
|
| 30 |
+
from datetime import datetime
|
| 31 |
+
|
| 32 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 33 |
+
|
| 34 |
+
# 要打包的智能体(按 PPT 顺序)
|
| 35 |
+
AGENTS = [
|
| 36 |
+
dict(run="frozenlake4x4", title="FrozenLake-v1 · 4x4 不滑",
|
| 37 |
+
desc="PPT 第一部分主实验:确定性冰面,从零手写 Q 表,10,000 回合"),
|
| 38 |
+
dict(run="frozenlake4x4_slippery", title="FrozenLake-v1 · 4x4 滑冰版",
|
| 39 |
+
desc="对照实验:只改 is_slippery=True,冰面会打滑,20,000 回合"),
|
| 40 |
+
dict(run="frozenlake8x8", title="FrozenLake-v1 · 8x8",
|
| 41 |
+
desc="进阶实验:地图 8x8 + 拉长探索期,60,000 回合"),
|
| 42 |
+
dict(run="taxi", title="Taxi-v3",
|
| 43 |
+
desc="PPT 第二部分主实验:500 状态 × 6 动作,25,000 回合,官方 100 个评估种子"),
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
+
CODE_FILES = [
|
| 47 |
+
"train_qlearning.py",
|
| 48 |
+
"evaluate_and_record.py",
|
| 49 |
+
"visualize_qtable.py",
|
| 50 |
+
"make_combined_video.py",
|
| 51 |
+
"build_hub_package.py",
|
| 52 |
+
"upload_to_hub.py",
|
| 53 |
+
"run_all.ps1",
|
| 54 |
+
"01_实践3说明.md",
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
REQUIREMENTS = """gymnasium>=1.0
|
| 58 |
+
numpy>=1.24
|
| 59 |
+
imageio>=2.31
|
| 60 |
+
imageio-ffmpeg>=0.4
|
| 61 |
+
Pillow>=9.0
|
| 62 |
+
matplotlib>=3.7
|
| 63 |
+
tqdm>=4.65
|
| 64 |
+
"""
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def read_json(path):
|
| 68 |
+
if not os.path.exists(path):
|
| 69 |
+
return None
|
| 70 |
+
with open(path, encoding="utf-8") as f:
|
| 71 |
+
return json.load(f)
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def build_readme(repo_id=None, scores=None, now=None):
|
| 75 |
+
raw = f"https://huggingface.co/{repo_id}/resolve/main/" if repo_id else ""
|
| 76 |
+
link = (lambda p: raw + p) if repo_id else (lambda p: p)
|
| 77 |
+
|
| 78 |
+
lines = []
|
| 79 |
+
lines.append("# Value-based 实践 · Q-Learning(FrozenLake-v1 + Taxi-v3)")
|
| 80 |
+
lines.append("")
|
| 81 |
+
lines.append("> 《第3周-深度强化学习原理实践》PPT 第 27–40 页 value-based 实践产物:"
|
| 82 |
+
"**从零手写 Q-Learning**(Q 表 + epsilon-greedy + Bellman 更新),"
|
| 83 |
+
"训练好的智能体 + 训练代码 + 回放视频 + 评估分数。")
|
| 84 |
+
lines.append("")
|
| 85 |
+
lines.append("## 1. 评估分数")
|
| 86 |
+
lines.append("")
|
| 87 |
+
lines.append("| 智能体 | 环境 | 平均回报(100 局) | 成功率 | 平均步数 | 训练回合 |")
|
| 88 |
+
lines.append("|---|---|---|---|---|---|")
|
| 89 |
+
for agent in AGENTS:
|
| 90 |
+
s = (scores or {}).get(agent["run"])
|
| 91 |
+
if s:
|
| 92 |
+
lines.append(
|
| 93 |
+
f"| {agent['title']} | `{s['env_id']}` | **{s['mean_reward']:.2f} ± "
|
| 94 |
+
f"{s['std_reward']:.2f}** | {s['success_rate'] * 100:.0f}% | "
|
| 95 |
+
f"{s['mean_steps']:.1f} | {s.get('n_training_episodes', '—')} |"
|
| 96 |
+
)
|
| 97 |
+
else:
|
| 98 |
+
lines.append(f"| {agent['title']} | — | 待运行 | — | — | — |")
|
| 99 |
+
lines.append("")
|
| 100 |
+
lines.append("> 评估方式:独立环境、贪心策略 `argmax_a Q(s,a)`、每局最多 99 步,跑 100 局;"
|
| 101 |
+
"FrozenLake 的回报是「是否到达目标」(0/1),Taxi 的回报是"
|
| 102 |
+
"「每步 −1,成功送达 +20」。")
|
| 103 |
+
lines.append("")
|
| 104 |
+
|
| 105 |
+
lines.append("## 2. 回放视频")
|
| 106 |
+
lines.append("")
|
| 107 |
+
if os.path.exists(os.path.join(BASE_DIR, "videos", "replay_value_based_all.mp4")):
|
| 108 |
+
lines.append("**总回放(三个智能体合集)**")
|
| 109 |
+
lines.append("")
|
| 110 |
+
lines.append(f'<video controls width="100%" src="{link("videos/replay_value_based_all.mp4")}"></video>')
|
| 111 |
+
lines.append("")
|
| 112 |
+
for agent in AGENTS:
|
| 113 |
+
video = f"videos/replay_{agent['run']}.mp4"
|
| 114 |
+
if os.path.exists(os.path.join(BASE_DIR, video)):
|
| 115 |
+
lines.append(f"**{agent['title']}**")
|
| 116 |
+
lines.append("")
|
| 117 |
+
lines.append(f'<video controls width="100%" src="{link(video)}"></video>')
|
| 118 |
+
lines.append("")
|
| 119 |
+
|
| 120 |
+
lines.append("## 3. 学到的策略���Q 表可视化)")
|
| 121 |
+
lines.append("")
|
| 122 |
+
for agent in AGENTS:
|
| 123 |
+
fig = f"assets/qtable_policy_{agent['run']}.png"
|
| 124 |
+
if os.path.exists(os.path.join(BASE_DIR, fig)):
|
| 125 |
+
lines.append(f"![{agent['title']}]({link(fig)})")
|
| 126 |
+
lines.append("")
|
| 127 |
+
|
| 128 |
+
lines.append("## 4. 训练曲线")
|
| 129 |
+
lines.append("")
|
| 130 |
+
for agent in AGENTS:
|
| 131 |
+
fig = f"logs/{agent['run']}/train_curve.png"
|
| 132 |
+
if os.path.exists(os.path.join(BASE_DIR, fig)):
|
| 133 |
+
lines.append(f"![{agent['title']} 训练曲线]({link(fig)})")
|
| 134 |
+
lines.append("")
|
| 135 |
+
|
| 136 |
+
lines.append("## 5. 怎么复现")
|
| 137 |
+
lines.append("")
|
| 138 |
+
lines.append("```powershell")
|
| 139 |
+
lines.append("# 环境(本机已有):conda activate DRL")
|
| 140 |
+
lines.append("conda activate DRL")
|
| 141 |
+
lines.append("")
|
| 142 |
+
lines.append("# 训练(每个实验 1~30 秒)")
|
| 143 |
+
lines.append("python train_qlearning.py --env frozenlake4x4")
|
| 144 |
+
lines.append("python train_qlearning.py --env frozenlake4x4_slippery")
|
| 145 |
+
lines.append("python train_qlearning.py --env frozenlake8x8")
|
| 146 |
+
lines.append("python train_qlearning.py --env taxi")
|
| 147 |
+
lines.append("")
|
| 148 |
+
lines.append("# 评估 + 录视频(生成 eval_results/*.json 和 videos/*.mp4)")
|
| 149 |
+
lines.append("python evaluate_and_record.py --model models/qtable_frozenlake4x4.pkl")
|
| 150 |
+
lines.append("python evaluate_and_record.py --model models/qtable_frozenlake4x4_slippery.pkl --video-episodes 5 --slowmo 4")
|
| 151 |
+
lines.append("python evaluate_and_record.py --model models/qtable_frozenlake8x8.pkl")
|
| 152 |
+
lines.append("python evaluate_and_record.py --model models/qtable_taxi.pkl")
|
| 153 |
+
lines.append("")
|
| 154 |
+
lines.append("# Q 表可视化 + 总回放 + 打包")
|
| 155 |
+
lines.append("python visualize_qtable.py --all")
|
| 156 |
+
lines.append("python make_combined_video.py")
|
| 157 |
+
lines.append("python build_hub_package.py")
|
| 158 |
+
lines.append("```")
|
| 159 |
+
lines.append("")
|
| 160 |
+
lines.append("## 6. 文件说明")
|
| 161 |
+
lines.append("")
|
| 162 |
+
lines.append("- `models/qtable_*.pkl`:模型文件。pickle 格式,内含 Q 表、超参数、训练种子和评估指标;")
|
| 163 |
+
lines.append(" `evaluate_and_record.py` 可以直接加载(不需要重新训练)。")
|
| 164 |
+
lines.append("- `videos/*.mp4`:回放,每帧标注步数/动作/奖励/Q 值条形图,片头片尾是标题卡和分数卡。")
|
| 165 |
+
lines.append("- `eval_results/*.json`:评估分数 + 逐局明细(起点种子、回报、步数、是否成功)。")
|
| 166 |
+
lines.append("- `logs/<run>/train_console.log`:完整训练日志(环境自检、超参数、每 N 回合进度、每次评估)。")
|
| 167 |
+
lines.append("- `code/`:全部代码(训练 / 评估录像 / 可视化 / 打包 / 上传 / 一键脚本)。")
|
| 168 |
+
lines.append("")
|
| 169 |
+
lines.append("## 7. 对应 PPT 页码")
|
| 170 |
+
lines.append("")
|
| 171 |
+
lines.append("| PPT 页 | 内容 | 对应实现 |")
|
| 172 |
+
lines.append("|---|---|---|")
|
| 173 |
+
lines.append("| 29 | Q 表 / Q 函数 / 最优策略 | `train_qlearning.py` 的 `initialize_q_table` / `greedy_policy` |")
|
| 174 |
+
lines.append("| 31–32 | FrozenLake 观测/动作/奖励 | 训练日志里的「环境自检」 |")
|
| 175 |
+
lines.append("| 33 | Q 表初始化 + 贪心策略 | `initialize_q_table` / `greedy_policy` |")
|
| 176 |
+
lines.append("| 34 | epsilon-greedy + 超参数 | `epsilon_greedy_policy` + `EXPERIMENTS` 配置 |")
|
| 177 |
+
lines.append("| 35 | 训练循环(Bellman 更新) | `train_qlearning.py::train` 里的 `Q[s][a] += lr*(...)` |")
|
| 178 |
+
lines.append("| 36–37 | 训练、Q 表可视化、评估、保存模型 | 训练日志 / `visualize_qtable.py` / `evaluate_and_record.py` / `models/*.pkl` |")
|
| 179 |
+
lines.append("| 38–40 | Taxi-v3(500 状态 × 6 动作) | `--env taxi`(含 PPT 的 100 个官方评估种子) |")
|
| 180 |
+
lines.append("| 28 | 上传 Hub + 视频 + 分数 | `build_hub_package.py` + `upload_to_hub.py` + README |")
|
| 181 |
+
lines.append("")
|
| 182 |
+
lines.append(f"- 生成时间:{now:%Y-%m-%d %H:%M}")
|
| 183 |
+
lines.append("")
|
| 184 |
+
return "\n".join(lines)
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def copy_file(src, dst):
|
| 188 |
+
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
| 189 |
+
shutil.copy2(src, dst)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def main():
|
| 193 |
+
parser = argparse.ArgumentParser(description="打包成可上传 Hub 的文件夹")
|
| 194 |
+
parser.add_argument("--repo-id", type=str, default=None,
|
| 195 |
+
help="你的 HF 用户名/仓库名,例如 zhangsan/value-based-qlearning")
|
| 196 |
+
parser.add_argument("--out", type=str, default=os.path.join(BASE_DIR, "hub_package"))
|
| 197 |
+
args = parser.parse_args()
|
| 198 |
+
|
| 199 |
+
out = args.out
|
| 200 |
+
if os.path.exists(out):
|
| 201 |
+
shutil.rmtree(out)
|
| 202 |
+
os.makedirs(out)
|
| 203 |
+
now = datetime.now()
|
| 204 |
+
|
| 205 |
+
# 1) 读取所有评估分数
|
| 206 |
+
scores = {}
|
| 207 |
+
for agent in AGENTS:
|
| 208 |
+
run = agent["run"]
|
| 209 |
+
s = read_json(os.path.join(BASE_DIR, "eval_results", f"eval_{run}.json"))
|
| 210 |
+
if s is None:
|
| 211 |
+
print(f"[警告] 缺少 eval_results/eval_{run}.json,"
|
| 212 |
+
f"请先跑 evaluate_and_record.py --model models/qtable_{run}.pkl")
|
| 213 |
+
continue
|
| 214 |
+
scores[run] = s
|
| 215 |
+
metrics = {}
|
| 216 |
+
for run, s in scores.items():
|
| 217 |
+
metrics[run] = {k: s[k] for k in
|
| 218 |
+
("env_id", "n_episodes", "mean_reward", "std_reward",
|
| 219 |
+
"success_rate", "mean_steps", "qtable_shape",
|
| 220 |
+
"qtable_nonzero", "evaluated_at")}
|
| 221 |
+
|
| 222 |
+
# 2) 拷模型
|
| 223 |
+
for agent in AGENTS:
|
| 224 |
+
src = os.path.join(BASE_DIR, "models", f"qtable_{agent['run']}.pkl")
|
| 225 |
+
if os.path.exists(src):
|
| 226 |
+
copy_file(src, os.path.join(out, "models", os.path.basename(src)))
|
| 227 |
+
else:
|
| 228 |
+
print(f"[警告] 缺少模型 {src}")
|
| 229 |
+
|
| 230 |
+
# 3) 拷视频(含总回放)
|
| 231 |
+
video_dir = os.path.join(BASE_DIR, "videos")
|
| 232 |
+
if os.path.isdir(video_dir):
|
| 233 |
+
for name in sorted(os.listdir(video_dir)):
|
| 234 |
+
if name.endswith(".mp4"):
|
| 235 |
+
copy_file(os.path.join(video_dir, name),
|
| 236 |
+
os.path.join(out, "videos", name))
|
| 237 |
+
|
| 238 |
+
# 4) 拷评估 json
|
| 239 |
+
for agent in AGENTS:
|
| 240 |
+
src = os.path.join(BASE_DIR, "eval_results", f"eval_{agent['run']}.json")
|
| 241 |
+
if os.path.exists(src):
|
| 242 |
+
copy_file(src, os.path.join(out, "eval_results", os.path.basename(src)))
|
| 243 |
+
|
| 244 |
+
# 5) 拷日志 + 训练曲线
|
| 245 |
+
for agent in AGENTS:
|
| 246 |
+
run_dir = os.path.join(BASE_DIR, "logs", agent["run"])
|
| 247 |
+
for name in ("train_console.log", "train_curve.png", "progress.csv"):
|
| 248 |
+
src = os.path.join(run_dir, name)
|
| 249 |
+
if os.path.exists(src):
|
| 250 |
+
copy_file(src, os.path.join(out, "logs", agent["run"], name))
|
| 251 |
+
|
| 252 |
+
# 6) 拷 Q 表可视化
|
| 253 |
+
for agent in AGENTS:
|
| 254 |
+
src = os.path.join(BASE_DIR, "assets", f"qtable_policy_{agent['run']}.png")
|
| 255 |
+
if os.path.exists(src):
|
| 256 |
+
copy_file(src, os.path.join(out, "assets", os.path.basename(src)))
|
| 257 |
+
|
| 258 |
+
# 7) 拷代码
|
| 259 |
+
for name in CODE_FILES:
|
| 260 |
+
src = os.path.join(BASE_DIR, name)
|
| 261 |
+
if os.path.exists(src):
|
| 262 |
+
copy_file(src, os.path.join(out, "code", name))
|
| 263 |
+
|
| 264 |
+
# 8) 写 README / metrics / requirements
|
| 265 |
+
with open(os.path.join(out, "README.md"), "w", encoding="utf-8") as f:
|
| 266 |
+
f.write(build_readme(repo_id=args.repo_id, scores=scores, now=now))
|
| 267 |
+
with open(os.path.join(out, "metrics.json"), "w", encoding="utf-8") as f:
|
| 268 |
+
json.dump(metrics, f, ensure_ascii=False, indent=2)
|
| 269 |
+
with open(os.path.join(out, "requirements.txt"), "w", encoding="utf-8") as f:
|
| 270 |
+
f.write(REQUIREMENTS)
|
| 271 |
+
|
| 272 |
+
n_files = sum(len(files) for _, _, files in os.walk(out))
|
| 273 |
+
print(f"[完成] hub_package/ 共 {n_files} 个文件")
|
| 274 |
+
for root, dirs, files in os.walk(out):
|
| 275 |
+
rel = os.path.relpath(root, out)
|
| 276 |
+
for name in sorted(files):
|
| 277 |
+
path = os.path.join(root, name)
|
| 278 |
+
print(f" {os.path.join(rel, name) if rel != '.' else name}"
|
| 279 |
+
f" ({os.path.getsize(path) / 1024:.0f} KB)")
|
| 280 |
+
print("\n下一步上传:")
|
| 281 |
+
print(" hf auth login # 粘贴你的 write token")
|
| 282 |
+
print(" python upload_to_hub.py --repo-id 你的用户名/value-based-qlearning")
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
if __name__ == "__main__":
|
| 286 |
+
main()
|
code/evaluate_and_record.py
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
第3周 · 实战3(value-based / Q-Learning)—— 评估 + 录视频脚本
|
| 4 |
+
=============================================================
|
| 5 |
+
对应 PPT 第 36–37 页(评估方法、Q 表可视化、模型文件)与第 28 页学习目标第 4 条:
|
| 6 |
+
"能够将训练好的智能体和代码上传到 Hub,并附上一个漂亮的视频回放和评估分数"
|
| 7 |
+
|
| 8 |
+
做三件事:
|
| 9 |
+
1) 加载训练好的模型文件(models/qtable_*.pkl,里面同时存着 Q 表和全套配置)
|
| 10 |
+
2) 用贪婪策略独立评估 N 局,输出评估分数(平均回报 ± 标准差、成功率、平均步数)
|
| 11 |
+
-> eval_results/eval_<run>.json
|
| 12 |
+
3) 回放录像:每一帧都标注"第几局/第几步/动作/奖励/Q 值条形图/累计回报",
|
| 13 |
+
片头有标题卡,片尾有分数卡
|
| 14 |
+
-> videos/replay_<run>.mp4
|
| 15 |
+
|
| 16 |
+
用法:
|
| 17 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe evaluate_and_record.py --model models/qtable_frozenlake4x4.pkl
|
| 18 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe evaluate_and_record.py --model models/qtable_taxi.pkl --episodes 100
|
| 19 |
+
# 想录得更慢/更多局:
|
| 20 |
+
python evaluate_and_record.py --model models/qtable_taxi.pkl --video-episodes 10 --slowmo 8
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
import argparse
|
| 24 |
+
import json
|
| 25 |
+
import os
|
| 26 |
+
import pickle
|
| 27 |
+
import time
|
| 28 |
+
from datetime import datetime
|
| 29 |
+
|
| 30 |
+
import gymnasium as gym
|
| 31 |
+
import imageio
|
| 32 |
+
import numpy as np
|
| 33 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 34 |
+
|
| 35 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 36 |
+
EVAL_DIR = os.path.join(BASE_DIR, "eval_results")
|
| 37 |
+
VIDEO_DIR = os.path.join(BASE_DIR, "videos")
|
| 38 |
+
|
| 39 |
+
# ----------------------------------------------------------------------
|
| 40 |
+
# 录像画面参数(1280x720 / 30fps,B 站、Hub、PPT 里都合适)
|
| 41 |
+
# ----------------------------------------------------------------------
|
| 42 |
+
WIDTH, HEIGHT = 1280, 720
|
| 43 |
+
HEADER_H = 78
|
| 44 |
+
FOOTER_H = 52
|
| 45 |
+
FPS = 30
|
| 46 |
+
SLOWMO = 6 # 每个动作帧重复次数(让 Q-Learning 这种短回合看得清)
|
| 47 |
+
HOLD_LAST = 1.2 # 每局结束后的定格秒数
|
| 48 |
+
TITLE_SECONDS = 2.5
|
| 49 |
+
END_SECONDS = 4.0
|
| 50 |
+
|
| 51 |
+
# 配色
|
| 52 |
+
BG = (15, 23, 42)
|
| 53 |
+
PANEL = (30, 41, 59)
|
| 54 |
+
PANEL_EDGE = (51, 65, 85)
|
| 55 |
+
TEXT = (226, 232, 240)
|
| 56 |
+
MUTED = (148, 163, 184)
|
| 57 |
+
ACCENT = (56, 189, 248)
|
| 58 |
+
GREEN = (34, 197, 94)
|
| 59 |
+
RED = (239, 68, 68)
|
| 60 |
+
AMBER = (245, 158, 11)
|
| 61 |
+
|
| 62 |
+
FONT_DIR = r"C:\Windows\Fonts"
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def load_font(size, bold=False):
|
| 66 |
+
"""优先微软雅黑,找不到再退回黑体/默认字体。"""
|
| 67 |
+
names = ["msyhbd.ttc", "msyh.ttc"] if bold else ["msyh.ttc", "simhei.ttf"]
|
| 68 |
+
for name in names:
|
| 69 |
+
path = os.path.join(FONT_DIR, name)
|
| 70 |
+
if os.path.exists(path):
|
| 71 |
+
try:
|
| 72 |
+
return ImageFont.truetype(path, size)
|
| 73 |
+
except Exception:
|
| 74 |
+
pass
|
| 75 |
+
return ImageFont.load_default()
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
FONT_TITLE = load_font(40, bold=True)
|
| 79 |
+
FONT_H1 = load_font(28, bold=True)
|
| 80 |
+
FONT_H2 = load_font(22, bold=True)
|
| 81 |
+
FONT_BODY = load_font(20)
|
| 82 |
+
FONT_SMALL = load_font(16)
|
| 83 |
+
FONT_TINY = load_font(14)
|
| 84 |
+
|
| 85 |
+
# 动作名称(PPT 第 32 页 / 第 38 页)
|
| 86 |
+
ACTION_NAMES = {
|
| 87 |
+
"FrozenLake-v1": ["← 向左 (0)", "↓ 向下 (1)", "→ 向右 (2)", "↑ 向上 (3)"],
|
| 88 |
+
"Taxi-v3": ["↓ 向南 (0)", "↑ 向北 (1)", "→ 向东 (2)", "← 向西 (3)",
|
| 89 |
+
"P 搭载乘客 (4)", "D 送达乘客 (5)"],
|
| 90 |
+
}
|
| 91 |
+
ACTION_SHORT = {
|
| 92 |
+
"FrozenLake-v1": ["←", "↓", "→", "↑"],
|
| 93 |
+
"Taxi-v3": ["南", "北", "东", "西", "载", "送"],
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
# Taxi-v3 地图上的四个上下客点(R 红 / G 绿 / Y 黄 / B 蓝)
|
| 97 |
+
TAXI_LOCS = [(0, 0), (0, 4), (4, 0), (4, 3)]
|
| 98 |
+
TAXI_LOC_NAMES = ["R 红", "G 绿", "Y 黄", "B 蓝"]
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# ======================================================================
|
| 102 |
+
# 模型 / 环境
|
| 103 |
+
# ======================================================================
|
| 104 |
+
def load_model(path):
|
| 105 |
+
with open(path, "rb") as f:
|
| 106 |
+
model = pickle.load(f)
|
| 107 |
+
if "qtable" not in model:
|
| 108 |
+
raise ValueError(f"{path} 里没有 qtable 字段,不是本脚本保存的模型")
|
| 109 |
+
return model
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def make_env(model, render_mode="rgb_array"):
|
| 113 |
+
kwargs = dict(model.get("env_kwargs") or {})
|
| 114 |
+
kwargs.pop("render_mode", None)
|
| 115 |
+
return gym.make(model["env_id"], render_mode=render_mode, **kwargs)
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def greedy_action(q_table, state):
|
| 119 |
+
return int(np.argmax(q_table[state]))
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
# ======================================================================
|
| 123 |
+
# 评估:贪婪策略跑 N 局(PPT 第 36 页 evaluate_agent 的同一件事)
|
| 124 |
+
# ======================================================================
|
| 125 |
+
def evaluate(env, model, n_episodes, seeds):
|
| 126 |
+
q = model["qtable"]
|
| 127 |
+
max_steps = model["max_steps"]
|
| 128 |
+
rows = []
|
| 129 |
+
for i in range(n_episodes):
|
| 130 |
+
if seeds is not None and i < len(seeds):
|
| 131 |
+
state, _ = env.reset(seed=int(seeds[i]))
|
| 132 |
+
else:
|
| 133 |
+
state, _ = env.reset()
|
| 134 |
+
total, steps = 0.0, 0
|
| 135 |
+
for step in range(max_steps):
|
| 136 |
+
action = greedy_action(q, state)
|
| 137 |
+
state, reward, terminated, truncated, _ = env.step(action)
|
| 138 |
+
total += float(reward)
|
| 139 |
+
steps = step + 1
|
| 140 |
+
if terminated or truncated:
|
| 141 |
+
break
|
| 142 |
+
rows.append(dict(episode=i + 1, seed=None if seeds is None else int(seeds[i]),
|
| 143 |
+
reward=round(total, 4), steps=steps, success=int(total > 0)))
|
| 144 |
+
rewards = np.array([r["reward"] for r in rows], dtype=float)
|
| 145 |
+
success = np.array([r["success"] for r in rows], dtype=float)
|
| 146 |
+
steps = np.array([r["steps"] for r in rows], dtype=float)
|
| 147 |
+
result = dict(
|
| 148 |
+
run=model.get("run_name", "unknown"),
|
| 149 |
+
env_id=model["env_id"],
|
| 150 |
+
env_kwargs=model.get("env_kwargs", {}),
|
| 151 |
+
n_training_episodes=model.get("n_training_episodes"),
|
| 152 |
+
n_episodes=n_episodes,
|
| 153 |
+
mean_reward=float(rewards.mean()),
|
| 154 |
+
std_reward=float(rewards.std()),
|
| 155 |
+
min_reward=float(rewards.min()),
|
| 156 |
+
max_reward=float(rewards.max()),
|
| 157 |
+
success_rate=float(success.mean()),
|
| 158 |
+
mean_steps=float(steps.mean()),
|
| 159 |
+
policy="greedy (argmax Q)",
|
| 160 |
+
model_file=os.path.relpath(model["_path"], BASE_DIR) if "_path" in model else None,
|
| 161 |
+
qtable_shape=list(q.shape),
|
| 162 |
+
qtable_nonzero=int(np.count_nonzero(q)),
|
| 163 |
+
evaluated_at=datetime.now().isoformat(timespec="seconds"),
|
| 164 |
+
episodes=rows,
|
| 165 |
+
)
|
| 166 |
+
return result
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
# ======================================================================
|
| 170 |
+
# 画面工具
|
| 171 |
+
# ======================================================================
|
| 172 |
+
def rounded_rect(draw, box, radius=16, fill=PANEL, outline=PANEL_EDGE, width=2):
|
| 173 |
+
draw.rounded_rectangle(box, radius=radius, fill=fill, outline=outline, width=width)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def draw_text(draw, xy, text, font=FONT_BODY, fill=TEXT, anchor="la"):
|
| 177 |
+
draw.text(xy, text, font=font, fill=fill, anchor=anchor)
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def fit_image(frame, max_w, max_h, nearest=True):
|
| 181 |
+
"""把 env.render() 的一帧缩放后居中贴到画布上(像素风用最近邻更清晰)。"""
|
| 182 |
+
img = Image.fromarray(np.asarray(frame, dtype=np.uint8))
|
| 183 |
+
scale = min(max_w / img.width, max_h / img.height)
|
| 184 |
+
new_size = (max(1, int(img.width * scale)), max(1, int(img.height * scale)))
|
| 185 |
+
resample = Image.NEAREST if nearest else Image.LANCZOS
|
| 186 |
+
return img.resize(new_size, resample)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def base_canvas():
|
| 190 |
+
canvas = Image.new("RGB", (WIDTH, HEIGHT), BG)
|
| 191 |
+
draw = ImageDraw.Draw(canvas)
|
| 192 |
+
# 顶栏
|
| 193 |
+
draw.rectangle([0, 0, WIDTH, HEADER_H], fill=(15, 23, 42))
|
| 194 |
+
draw.line([0, HEADER_H, WIDTH, HEADER_H], fill=PANEL_EDGE, width=2)
|
| 195 |
+
# 底栏
|
| 196 |
+
draw.rectangle([0, HEIGHT - FOOTER_H, WIDTH, HEIGHT], fill=(15, 23, 42))
|
| 197 |
+
draw.line([0, HEIGHT - FOOTER_H, WIDTH, HEIGHT - FOOTER_H], fill=PANEL_EDGE, width=2)
|
| 198 |
+
return canvas, draw
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def title_card(model, result):
|
| 202 |
+
"""片头标题卡。"""
|
| 203 |
+
canvas, draw = base_canvas()
|
| 204 |
+
draw_text(draw, (WIDTH // 2, 150), "Q-Learning 智能体 · 训练后回放", FONT_TITLE,
|
| 205 |
+
fill=ACCENT, anchor="mm")
|
| 206 |
+
draw_text(draw, (WIDTH // 2, 215), model.get("title", model["env_id"]), FONT_H1,
|
| 207 |
+
fill=TEXT, anchor="mm")
|
| 208 |
+
draw.line([WIDTH // 2 - 220, 260, WIDTH // 2 + 220, 260], fill=PANEL_EDGE, width=2)
|
| 209 |
+
|
| 210 |
+
# 中间:三个信息块
|
| 211 |
+
blocks = [
|
| 212 |
+
("算法", "Q-Learning(从零手写 Q 表)"),
|
| 213 |
+
("训练规模", f"{model['n_training_episodes']:,} 回合"),
|
| 214 |
+
("Q 表", f"{model['qtable'].shape[0]} 状态 × {model['qtable'].shape[1]} 动作"),
|
| 215 |
+
("超参数", f"lr={model['learning_rate']} γ={model['gamma']} "
|
| 216 |
+
f"ε {model['max_epsilon']}→{model['min_epsilon']}"),
|
| 217 |
+
]
|
| 218 |
+
y = 310
|
| 219 |
+
for k, v in blocks:
|
| 220 |
+
draw_text(draw, (WIDTH // 2 - 300, y), f"{k}", FONT_SMALL, fill=MUTED)
|
| 221 |
+
draw_text(draw, (WIDTH // 2 - 160, y), f"{v}", FONT_BODY, fill=TEXT)
|
| 222 |
+
y += 46
|
| 223 |
+
|
| 224 |
+
draw_text(draw, (WIDTH // 2, 570),
|
| 225 |
+
f"独立评估 {result['n_episodes']} 局:"
|
| 226 |
+
f"平均回报 {result['mean_reward']:.2f} ± {result['std_reward']:.2f} "
|
| 227 |
+
f"成功率 {result['success_rate'] * 100:.0f}%",
|
| 228 |
+
FONT_H2, fill=GREEN, anchor="mm")
|
| 229 |
+
draw_text(draw, (WIDTH // 2, 615),
|
| 230 |
+
"对应《第3周-深度强化学习原理实践》PPT 第 27–40 页 · value-based 实践",
|
| 231 |
+
FONT_SMALL, fill=MUTED, anchor="mm")
|
| 232 |
+
draw_text(draw, (WIDTH // 2, 640), "模型文件:models/" + os.path.basename(model["_path"]),
|
| 233 |
+
FONT_SMALL, fill=MUTED, anchor="mm")
|
| 234 |
+
return canvas
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
def score_card(model, result):
|
| 238 |
+
"""片尾分数卡。"""
|
| 239 |
+
canvas, draw = base_canvas()
|
| 240 |
+
draw_text(draw, (WIDTH // 2, 120), "评估结果", FONT_TITLE, fill=ACCENT, anchor="mm")
|
| 241 |
+
draw_text(draw, (WIDTH // 2, 185), model.get("title", model["env_id"]), FONT_H1,
|
| 242 |
+
fill=TEXT, anchor="mm")
|
| 243 |
+
|
| 244 |
+
# 大号分数
|
| 245 |
+
mean, std = result["mean_reward"], result["std_reward"]
|
| 246 |
+
draw_text(draw, (WIDTH // 2 - 200, 300), "平均回报", FONT_BODY, fill=MUTED, anchor="mm")
|
| 247 |
+
draw_text(draw, (WIDTH // 2 - 200, 360), f"{mean:.2f}", load_font(64, bold=True),
|
| 248 |
+
fill=GREEN if mean > 0 else RED, anchor="mm")
|
| 249 |
+
draw_text(draw, (WIDTH // 2 - 200, 410), f"± {std:.2f}", FONT_H2, fill=MUTED, anchor="mm")
|
| 250 |
+
|
| 251 |
+
draw_text(draw, (WIDTH // 2 + 60, 300), "成功率", FONT_BODY, fill=MUTED, anchor="mm")
|
| 252 |
+
draw_text(draw, (WIDTH // 2 + 60, 360), f"{result['success_rate'] * 100:.0f}%",
|
| 253 |
+
load_font(64, bold=True), fill=ACCENT, anchor="mm")
|
| 254 |
+
|
| 255 |
+
draw_text(draw, (WIDTH // 2 + 300, 300), "平均步数", FONT_BODY, fill=MUTED, anchor="mm")
|
| 256 |
+
draw_text(draw, (WIDTH // 2 + 300, 360), f"{result['mean_steps']:.1f}",
|
| 257 |
+
load_font(64, bold=True), fill=AMBER, anchor="mm")
|
| 258 |
+
|
| 259 |
+
draw_text(draw, (WIDTH // 2, 505),
|
| 260 |
+
f"{result['n_episodes']} 局独立评估 · 贪婪策略 argmax_a Q(s,a)",
|
| 261 |
+
FONT_BODY, fill=TEXT, anchor="mm")
|
| 262 |
+
# 迷你分数分布
|
| 263 |
+
rewards = [e["reward"] for e in result["episodes"]]
|
| 264 |
+
values, counts = np.unique(np.round(rewards, 2), return_counts=True)
|
| 265 |
+
draw_text(draw, (WIDTH // 2, 555),
|
| 266 |
+
"逐局回报分布:" + " ".join(f"{v:g}×{c}" for v, c in zip(values[:8], counts[:8]))
|
| 267 |
+
+ (" …" if len(values) > 8 else ""),
|
| 268 |
+
FONT_SMALL, fill=MUTED, anchor="mm")
|
| 269 |
+
draw_text(draw, (WIDTH // 2, 620),
|
| 270 |
+
"模型与代码已打包上传 Hub:附视频回放 + 评估分数",
|
| 271 |
+
FONT_SMALL, fill=MUTED, anchor="mm")
|
| 272 |
+
return canvas
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
def draw_q_bars(draw, q_row, action_names, chosen_action, x, y, width):
|
| 276 |
+
"""把当前状态各动作的 Q 值画成水平条形图(直观看出贪心策略选了什么)。"""
|
| 277 |
+
q = np.asarray(q_row, dtype=float)
|
| 278 |
+
lo, hi = float(q.min()), float(q.max())
|
| 279 |
+
span = hi - lo if hi - lo > 1e-9 else 1.0
|
| 280 |
+
bar_h = 26
|
| 281 |
+
gap = 10
|
| 282 |
+
for a in range(len(q)):
|
| 283 |
+
yy = y + a * (bar_h + gap)
|
| 284 |
+
chosen = a == chosen_action
|
| 285 |
+
fill = ACCENT if chosen else (71, 85, 105)
|
| 286 |
+
# 动作标签
|
| 287 |
+
draw_text(draw, (x, yy + bar_h // 2), action_names[a], FONT_SMALL,
|
| 288 |
+
fill=TEXT if chosen else MUTED, anchor="lm")
|
| 289 |
+
# 条形
|
| 290 |
+
left = x + 150
|
| 291 |
+
draw.rectangle([left, yy, left + width, yy + bar_h], fill=(51, 65, 85))
|
| 292 |
+
frac = (q[a] - lo) / span
|
| 293 |
+
draw.rectangle([left, yy, left + max(3, int(width * frac)), yy + bar_h], fill=fill)
|
| 294 |
+
# 数值
|
| 295 |
+
draw_text(draw, (left + width + 12, yy + bar_h // 2), f"{q[a]:.3f}", FONT_SMALL,
|
| 296 |
+
fill=ACCENT if chosen else MUTED, anchor="lm")
|
| 297 |
+
if chosen:
|
| 298 |
+
draw_text(draw, (left + width + 78, yy + bar_h // 2), "← 最优", FONT_SMALL,
|
| 299 |
+
fill=ACCENT, anchor="lm")
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
def game_frame(model, env, state, step, episode_idx, n_video_eps, total_reward,
|
| 303 |
+
last_reward, action, ended, success, eval_result):
|
| 304 |
+
"""合成一帧:左边是环境画面,右边是 Q 值/动作/奖励信息。"""
|
| 305 |
+
canvas, draw = base_canvas()
|
| 306 |
+
|
| 307 |
+
title = model.get("title", model["env_id"])
|
| 308 |
+
draw_text(draw, (32, HEADER_H // 2), f"Q-Learning 智能体回放 · {title}",
|
| 309 |
+
FONT_H2, fill=TEXT, anchor="lm")
|
| 310 |
+
draw_text(draw, (WIDTH - 32, HEADER_H // 2),
|
| 311 |
+
"PPT 第 27–40 页 · value-based", FONT_SMALL, fill=MUTED, anchor="rm")
|
| 312 |
+
|
| 313 |
+
# ---------- 左边:环境画面 ----------
|
| 314 |
+
box = [32, HEADER_H + 22, 672, HEIGHT - FOOTER_H - 22]
|
| 315 |
+
rounded_rect(draw, box)
|
| 316 |
+
raw = env.render()
|
| 317 |
+
if raw is not None:
|
| 318 |
+
inner_w = box[2] - box[0] - 24
|
| 319 |
+
inner_h = box[3] - box[1] - 24
|
| 320 |
+
img = fit_image(raw, inner_w, inner_h)
|
| 321 |
+
px = box[0] + (box[2] - box[0] - img.width) // 2
|
| 322 |
+
py = box[1] + (box[3] - box[1] - img.height) // 2
|
| 323 |
+
canvas.paste(img, (px, py))
|
| 324 |
+
|
| 325 |
+
# ---------- 右边:信息面板 ----------
|
| 326 |
+
px0, px1 = 700, WIDTH - 32
|
| 327 |
+
rounded_rect(draw, [px0, HEADER_H + 22, px1, HEIGHT - FOOTER_H - 22])
|
| 328 |
+
|
| 329 |
+
x = px0 + 24
|
| 330 |
+
y = HEADER_H + 50
|
| 331 |
+
draw_text(draw, (x, y), f"第 {episode_idx + 1} / {n_video_eps} 局", FONT_H2, fill=TEXT)
|
| 332 |
+
y += 34
|
| 333 |
+
|
| 334 |
+
# Taxi 额外显示乘客/目的地
|
| 335 |
+
if model["env_id"] == "Taxi-v3":
|
| 336 |
+
taxi_row, taxi_col, pass_idx, dest_idx = env.unwrapped.decode(int(state))
|
| 337 |
+
pass_text = "在车上" if pass_idx == 4 else TAXI_LOC_NAMES[pass_idx] + " 处"
|
| 338 |
+
draw_text(draw, (x, y), f"出租车 ({taxi_row},{taxi_col}) 乘客 {pass_text} "
|
| 339 |
+
f"目的地 {TAXI_LOC_NAMES[dest_idx]}", FONT_SMALL, fill=MUTED)
|
| 340 |
+
y += 30
|
| 341 |
+
else:
|
| 342 |
+
draw_text(draw, (x, y), f"状态编号 s = {int(state)}", FONT_SMALL, fill=MUTED)
|
| 343 |
+
y += 30
|
| 344 |
+
|
| 345 |
+
# 步数 / 动作 / 奖励
|
| 346 |
+
draw_text(draw, (x, y), "步数", FONT_SMALL, fill=MUTED)
|
| 347 |
+
draw_text(draw, (x + 70, y), f"{step}", FONT_H2, fill=TEXT)
|
| 348 |
+
draw_text(draw, (x + 180, y), "动作", FONT_SMALL, fill=MUTED)
|
| 349 |
+
draw_text(draw, (x + 250, y),
|
| 350 |
+
ACTION_NAMES[model["env_id"]][action] if action is not None else "—",
|
| 351 |
+
FONT_H2, fill=ACCENT)
|
| 352 |
+
y += 38
|
| 353 |
+
|
| 354 |
+
draw_text(draw, (x, y), "单步奖励", FONT_SMALL, fill=MUTED)
|
| 355 |
+
draw_text(draw, (x + 120, y), f"{last_reward:+.2f}" if last_reward is not None else "—",
|
| 356 |
+
FONT_H2, fill=GREEN if (last_reward or 0) > 0 else TEXT)
|
| 357 |
+
draw_text(draw, (x + 260, y), "累计回报", FONT_SMALL, fill=MUTED)
|
| 358 |
+
draw_text(draw, (x + 360, y), f"{total_reward:+.2f}", FONT_H2,
|
| 359 |
+
fill=GREEN if total_reward > 0 else TEXT)
|
| 360 |
+
y += 44
|
| 361 |
+
|
| 362 |
+
# Q 值条形图(终局状态不再更新 Q,改成提示文字)
|
| 363 |
+
if ended:
|
| 364 |
+
draw_text(draw, (x, y), "终局状态:回合结束,Q 表在这一帧不再更新", FONT_SMALL, fill=MUTED)
|
| 365 |
+
else:
|
| 366 |
+
draw_text(draw, (x, y), f"Q(s={int(state)}, ·) ← 贪心策略从这里选动作", FONT_SMALL, fill=MUTED)
|
| 367 |
+
y += 30
|
| 368 |
+
q = model["qtable"][int(state)]
|
| 369 |
+
chosen = int(np.argmax(q))
|
| 370 |
+
bars_width = 180
|
| 371 |
+
draw_q_bars(draw, q, ACTION_SHORT[model["env_id"]], chosen, x, y, bars_width)
|
| 372 |
+
|
| 373 |
+
# 回合结束横幅
|
| 374 |
+
if ended:
|
| 375 |
+
banner_y = HEIGHT - FOOTER_H - 105
|
| 376 |
+
if model["env_id"] == "Taxi-v3":
|
| 377 |
+
text, color = ("√ 成功送达乘客(+20 奖励)", GREEN) if success else \
|
| 378 |
+
("× 超时 / 未送达(回合结束)", RED)
|
| 379 |
+
else:
|
| 380 |
+
text, color = ("√ 成功到达目标(+1 奖励)", GREEN) if success else \
|
| 381 |
+
("× 掉进冰洞(奖励 0,回合结束)", RED)
|
| 382 |
+
draw.rounded_rectangle([px0 + 20, banner_y, px1 - 20, banner_y + 62],
|
| 383 |
+
radius=12, fill=(color[0] // 4, color[1] // 4, color[2] // 4),
|
| 384 |
+
outline=color, width=2)
|
| 385 |
+
draw_text(draw, ((px0 + px1) // 2, banner_y + 31), text, FONT_H2, fill=color, anchor="mm")
|
| 386 |
+
|
| 387 |
+
# ---------- 底栏:总体评估分数 ----------
|
| 388 |
+
draw_text(draw, (32, HEIGHT - FOOTER_H // 2),
|
| 389 |
+
f"评估 {eval_result['n_episodes']} 局:平均回报 "
|
| 390 |
+
f"{eval_result['mean_reward']:.2f} ± {eval_result['std_reward']:.2f} "
|
| 391 |
+
f"成功率 {eval_result['success_rate'] * 100:.0f}% "
|
| 392 |
+
f"平均步数 {eval_result['mean_steps']:.1f}",
|
| 393 |
+
FONT_SMALL, fill=MUTED, anchor="lm")
|
| 394 |
+
draw_text(draw, (WIDTH - 32, HEIGHT - FOOTER_H // 2), "贪心策略 argmax_a Q(s,a)",
|
| 395 |
+
FONT_SMALL, fill=MUTED, anchor="rm")
|
| 396 |
+
return canvas
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
# ======================================================================
|
| 400 |
+
# 录像
|
| 401 |
+
# ======================================================================
|
| 402 |
+
def record_video(env, model, result, out_path, n_video_episodes, slowmo, fps):
|
| 403 |
+
q = model["qtable"]
|
| 404 |
+
max_steps = model["max_steps"]
|
| 405 |
+
seeds = model.get("eval_seed")
|
| 406 |
+
writer = imageio.get_writer(out_path, fps=fps, codec="libx264", quality=8,
|
| 407 |
+
macro_block_size=2)
|
| 408 |
+
n_frames = 0
|
| 409 |
+
|
| 410 |
+
def push(img, repeat=1):
|
| 411 |
+
nonlocal n_frames
|
| 412 |
+
frame = np.asarray(img, dtype=np.uint8)
|
| 413 |
+
for _ in range(repeat):
|
| 414 |
+
writer.append_data(frame)
|
| 415 |
+
n_frames += 1
|
| 416 |
+
|
| 417 |
+
# 片头
|
| 418 |
+
push(title_card(model, result), int(TITLE_SECONDS * fps))
|
| 419 |
+
hold_end = int(HOLD_LAST * fps)
|
| 420 |
+
|
| 421 |
+
for ep in range(n_video_episodes):
|
| 422 |
+
if seeds is not None and ep < len(seeds):
|
| 423 |
+
state, _ = env.reset(seed=int(seeds[ep]))
|
| 424 |
+
else:
|
| 425 |
+
state, _ = env.reset()
|
| 426 |
+
|
| 427 |
+
total_reward = 0.0
|
| 428 |
+
last_reward = None
|
| 429 |
+
prev_reward = None
|
| 430 |
+
last_action = None
|
| 431 |
+
step = 0
|
| 432 |
+
for step in range(max_steps):
|
| 433 |
+
action = greedy_action(q, state)
|
| 434 |
+
last_action = action
|
| 435 |
+
new_state, reward, terminated, truncated, _ = env.step(action)
|
| 436 |
+
done = terminated or truncated
|
| 437 |
+
total_reward += float(reward)
|
| 438 |
+
success = total_reward > 0
|
| 439 |
+
last_reward = float(reward)
|
| 440 |
+
# 这一步的"决策画面":画面里的状态是"还没执行这个动作之前"的状态,
|
| 441 |
+
# 所以累计回报用执行前的值,单步奖励显示上一步拿到的奖励
|
| 442 |
+
push(game_frame(model, env, state, step, ep, n_video_episodes,
|
| 443 |
+
total_reward - last_reward, prev_reward, action, False, success, result),
|
| 444 |
+
slowmo)
|
| 445 |
+
prev_reward = last_reward
|
| 446 |
+
state = new_state
|
| 447 |
+
if done:
|
| 448 |
+
break
|
| 449 |
+
# 回合结束:定格 + 结束横幅
|
| 450 |
+
ended_frame = game_frame(model, env, state, step + 1, ep, n_video_episodes,
|
| 451 |
+
total_reward, last_reward, last_action, True,
|
| 452 |
+
total_reward > 0, result)
|
| 453 |
+
push(ended_frame, hold_end)
|
| 454 |
+
print(f" [录像] 第 {ep + 1}/{n_video_episodes} 局:回报={total_reward:+.2f},"
|
| 455 |
+
f"步数={step + 1},{'√ 成功' if total_reward > 0 else '× 失败'}")
|
| 456 |
+
|
| 457 |
+
# 片尾分数卡
|
| 458 |
+
push(score_card(model, result), int(END_SECONDS * fps))
|
| 459 |
+
writer.close()
|
| 460 |
+
return n_frames
|
| 461 |
+
|
| 462 |
+
|
| 463 |
+
# ======================================================================
|
| 464 |
+
# 主流程
|
| 465 |
+
# ======================================================================
|
| 466 |
+
def main():
|
| 467 |
+
parser = argparse.ArgumentParser(description="评估 Q-Learning 智能体并录制回放视频")
|
| 468 |
+
parser.add_argument("--model", type=str, required=True, help="models/qtable_*.pkl")
|
| 469 |
+
parser.add_argument("--episodes", type=int, default=None,
|
| 470 |
+
help="评估局数(默认用模型里记录的 n_eval_episodes)")
|
| 471 |
+
parser.add_argument("--video-episodes", type=int, default=8, help="录几局回放(默认 8)")
|
| 472 |
+
parser.add_argument("--slowmo", type=int, default=SLOWMO, help="每个动作帧重复几次(默认 6)")
|
| 473 |
+
parser.add_argument("--fps", type=int, default=FPS, help="视频帧率(默认 30)")
|
| 474 |
+
parser.add_argument("--out-video", type=str, default=None, help="视频输出路径(.mp4)")
|
| 475 |
+
parser.add_argument("--out-json", type=str, default=None, help="评估结果输出路径(.json)")
|
| 476 |
+
parser.add_argument("--skip-video", action="store_true",
|
| 477 |
+
help="只评估、不录视频(改完分数想快速重算时用)")
|
| 478 |
+
args = parser.parse_args()
|
| 479 |
+
|
| 480 |
+
model = load_model(args.model)
|
| 481 |
+
model["_path"] = os.path.abspath(args.model)
|
| 482 |
+
model["run_name"] = os.path.splitext(os.path.basename(args.model))[0].replace("qtable_", "")
|
| 483 |
+
if not model.get("title"):
|
| 484 |
+
model["title"] = model["env_id"]
|
| 485 |
+
|
| 486 |
+
os.makedirs(EVAL_DIR, exist_ok=True)
|
| 487 |
+
os.makedirs(VIDEO_DIR, exist_ok=True)
|
| 488 |
+
|
| 489 |
+
run = model["run_name"]
|
| 490 |
+
out_json = args.out_json or os.path.join(EVAL_DIR, f"eval_{run}.json")
|
| 491 |
+
out_video = args.out_video or os.path.join(VIDEO_DIR, f"replay_{run}.mp4")
|
| 492 |
+
|
| 493 |
+
n_eval = args.episodes or model.get("n_eval_episodes", 100)
|
| 494 |
+
seeds = model.get("eval_seed")
|
| 495 |
+
if seeds is not None and len(seeds) < n_eval:
|
| 496 |
+
seeds = None # 种子不够就不指定,退回随机起点
|
| 497 |
+
|
| 498 |
+
print("=" * 78)
|
| 499 |
+
print(f"评估 + 录像 · {model['title']}")
|
| 500 |
+
print(f"模型文件:{os.path.relpath(model['_path'], BASE_DIR)}")
|
| 501 |
+
print(f"贪婪策略:argmax_a Q(s,a) Q 表形状:{model['qtable'].shape}")
|
| 502 |
+
print("=" * 78)
|
| 503 |
+
|
| 504 |
+
env = make_env(model)
|
| 505 |
+
print(f"\n[评估] 用贪婪策略跑 {n_eval} 局(独立环境,起点种子:"
|
| 506 |
+
f"{'模型自带的 ' + str(len(seeds)) + ' 个种子' if seeds is not None else '随机'})")
|
| 507 |
+
started = time.time()
|
| 508 |
+
result = evaluate(env, model, n_eval, seeds)
|
| 509 |
+
result["evaluation_seconds"] = round(time.time() - started, 2)
|
| 510 |
+
print(f" Mean_reward = {result['mean_reward']:.2f} +/- {result['std_reward']:.2f}")
|
| 511 |
+
print(f" 成功率 = {result['success_rate'] * 100:.0f}%")
|
| 512 |
+
print(f" 平均步数 = {result['mean_steps']:.1f}")
|
| 513 |
+
print(f" 回报范围 = [{result['min_reward']:.2f}, {result['max_reward']:.2f}]")
|
| 514 |
+
with open(out_json, "w", encoding="utf-8") as f:
|
| 515 |
+
json.dump(result, f, ensure_ascii=False, indent=2)
|
| 516 |
+
print(f"[输出] 评估分数 = {os.path.relpath(out_json, BASE_DIR)}")
|
| 517 |
+
|
| 518 |
+
if args.skip_video:
|
| 519 |
+
print("\n[跳过录像](--skip-video)")
|
| 520 |
+
env.close()
|
| 521 |
+
print("\n" + "=" * 78)
|
| 522 |
+
print(f"完成。评估分数 {result['mean_reward']:.2f} ± {result['std_reward']:.2f},"
|
| 523 |
+
f"成功率 {result['success_rate'] * 100:.0f}%")
|
| 524 |
+
print("=" * 78)
|
| 525 |
+
return
|
| 526 |
+
|
| 527 |
+
print(f"\n[录像] 录 {args.video_episodes} 局回放,每帧慢放 ×{args.slowmo},{args.fps}fps")
|
| 528 |
+
n_frames = record_video(env, model, result, out_video, args.video_episodes,
|
| 529 |
+
args.slowmo, args.fps)
|
| 530 |
+
secs = n_frames / args.fps
|
| 531 |
+
print(f"[输出] 回放视频 = {os.path.relpath(out_video, BASE_DIR)} "
|
| 532 |
+
f"({n_frames} 帧 / {secs:.1f} 秒 / {os.path.getsize(out_video) / 1024:.0f} KB)")
|
| 533 |
+
env.close()
|
| 534 |
+
|
| 535 |
+
print("\n" + "=" * 78)
|
| 536 |
+
print(f"完成。评估分数 {result['mean_reward']:.2f} ± {result['std_reward']:.2f},"
|
| 537 |
+
f"成功率 {result['success_rate'] * 100:.0f}%")
|
| 538 |
+
print("=" * 78)
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
if __name__ == "__main__":
|
| 542 |
+
main()
|
code/make_combined_video.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
把三个智能体的回放视频拼成一支"总回放"视频(方便上传 Hub / 交作业)。
|
| 4 |
+
==============================================================
|
| 5 |
+
输入:videos/replay_frozenlake4x4.mp4、replay_frozenlake8x8.mp4、replay_taxi.mp4
|
| 6 |
+
输出:videos/replay_value_based_all.mp4(1280x720 / 30fps,开头有总览卡,结尾有分数汇总卡)
|
| 7 |
+
|
| 8 |
+
用法:
|
| 9 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe make_combined_video.py
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import json
|
| 13 |
+
import os
|
| 14 |
+
|
| 15 |
+
import imageio.v2 as imageio
|
| 16 |
+
import numpy as np
|
| 17 |
+
|
| 18 |
+
import evaluate_and_record as ev # 复用录像脚本里的画布/字体/配色
|
| 19 |
+
|
| 20 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 21 |
+
VIDEO_DIR = os.path.join(BASE_DIR, "videos")
|
| 22 |
+
EVAL_DIR = os.path.join(BASE_DIR, "eval_results")
|
| 23 |
+
|
| 24 |
+
FPS = ev.FPS
|
| 25 |
+
RUNS = [
|
| 26 |
+
("frozenlake4x4", "FrozenLake-v1 · 4x4 不滑", "PPT 第一部分(10,000 回合)"),
|
| 27 |
+
("frozenlake8x8", "FrozenLake-v1 · 8x8", "进阶:地图变大 + 探索调度"),
|
| 28 |
+
("taxi", "Taxi-v3", "PPT 第二部分(25,000 回合)"),
|
| 29 |
+
]
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def load_scores():
|
| 33 |
+
scores = {}
|
| 34 |
+
for run, _, _ in RUNS:
|
| 35 |
+
path = os.path.join(EVAL_DIR, f"eval_{run}.json")
|
| 36 |
+
if os.path.exists(path):
|
| 37 |
+
with open(path, encoding="utf-8") as f:
|
| 38 |
+
scores[run] = json.load(f)
|
| 39 |
+
return scores
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def intro_card(scores):
|
| 43 |
+
canvas, draw = ev.base_canvas()
|
| 44 |
+
ev.draw_text(draw, (ev.WIDTH // 2, 110), "value-based 实践 · Q-Learning 智能体回放合集",
|
| 45 |
+
ev.FONT_TITLE, fill=ev.ACCENT, anchor="mm")
|
| 46 |
+
ev.draw_text(draw, (ev.WIDTH // 2, 165),
|
| 47 |
+
"从零手写 Q 表 + epsilon-greedy + Bellman 更新(PPT 第 27–40 页)",
|
| 48 |
+
ev.FONT_BODY, fill=ev.TEXT, anchor="mm")
|
| 49 |
+
draw.line([120, 205, ev.WIDTH - 120, 205], fill=ev.PANEL_EDGE, width=2)
|
| 50 |
+
|
| 51 |
+
y = 265
|
| 52 |
+
for i, (run, name, note) in enumerate(RUNS):
|
| 53 |
+
s = scores.get(run)
|
| 54 |
+
ev.draw_text(draw, (110, y), f"{i + 1}. {name}", ev.FONT_H2, fill=ev.TEXT)
|
| 55 |
+
ev.draw_text(draw, (110, y + 34), note, ev.FONT_SMALL, fill=ev.MUTED)
|
| 56 |
+
if s:
|
| 57 |
+
score_text = f"{s['mean_reward']:.2f} ± {s['std_reward']:.2f}"
|
| 58 |
+
ev.draw_text(draw, (ev.WIDTH - 110, y + 16), score_text, ev.FONT_H1,
|
| 59 |
+
fill=ev.GREEN if s["mean_reward"] > 0 else ev.RED, anchor="rm")
|
| 60 |
+
ev.draw_text(draw, (ev.WIDTH - 110, y + 46),
|
| 61 |
+
f"成功率 {s['success_rate'] * 100:.0f}% "
|
| 62 |
+
f"平均步数 {s['mean_steps']:.1f}",
|
| 63 |
+
ev.FONT_SMALL, fill=ev.MUTED, anchor="rm")
|
| 64 |
+
y += 95
|
| 65 |
+
|
| 66 |
+
ev.draw_text(draw, (ev.WIDTH // 2, 620),
|
| 67 |
+
"每段回放都标注了步数 / 动作 / Q 值条形图,片尾有该智能体的评估分数",
|
| 68 |
+
ev.FONT_SMALL, fill=ev.MUTED, anchor="mm")
|
| 69 |
+
return canvas
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def end_card(scores):
|
| 73 |
+
canvas, draw = ev.base_canvas()
|
| 74 |
+
ev.draw_text(draw, (ev.WIDTH // 2, 105), "三个智能体评估分数汇总", ev.FONT_TITLE,
|
| 75 |
+
fill=ev.ACCENT, anchor="mm")
|
| 76 |
+
ev.draw_text(draw, (ev.WIDTH // 2, 155),
|
| 77 |
+
"独立环境 · 贪婪策略 argmax_a Q(s,a) · 100 局", ev.FONT_BODY,
|
| 78 |
+
fill=ev.MUTED, anchor="mm")
|
| 79 |
+
draw.line([120, 195, ev.WIDTH - 120, 195], fill=ev.PANEL_EDGE, width=2)
|
| 80 |
+
|
| 81 |
+
y = 265
|
| 82 |
+
for run, name, _ in RUNS:
|
| 83 |
+
s = scores.get(run)
|
| 84 |
+
if not s:
|
| 85 |
+
continue
|
| 86 |
+
ev.draw_text(draw, (120, y), name, ev.FONT_H2, fill=ev.TEXT)
|
| 87 |
+
ev.draw_text(draw, (560, y), f"回报 {s['mean_reward']:.2f} ± {s['std_reward']:.2f}",
|
| 88 |
+
ev.FONT_H2, fill=ev.GREEN if s["mean_reward"] > 0 else ev.RED)
|
| 89 |
+
ev.draw_text(draw, (880, y), f"成功率 {s['success_rate'] * 100:.0f}%",
|
| 90 |
+
ev.FONT_H2, fill=ev.ACCENT)
|
| 91 |
+
y += 90
|
| 92 |
+
|
| 93 |
+
ev.draw_text(draw, (ev.WIDTH // 2, 610),
|
| 94 |
+
"模型文件(Q 表 pkl)+ 训练代码 + 日志 已打包上传 Hub",
|
| 95 |
+
ev.FONT_BODY, fill=ev.TEXT, anchor="mm")
|
| 96 |
+
return canvas
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def main():
|
| 100 |
+
scores = load_scores()
|
| 101 |
+
clips = []
|
| 102 |
+
for run, _, _ in RUNS:
|
| 103 |
+
path = os.path.join(VIDEO_DIR, f"replay_{run}.mp4")
|
| 104 |
+
if not os.path.exists(path):
|
| 105 |
+
print(f"[跳过] 找不到 {path},请先跑 evaluate_and_record.py --model models/qtable_{run}.pkl")
|
| 106 |
+
continue
|
| 107 |
+
clips.append(path)
|
| 108 |
+
if not clips:
|
| 109 |
+
raise SystemExit("没有可拼接的视频。")
|
| 110 |
+
|
| 111 |
+
out_path = os.path.join(VIDEO_DIR, "replay_value_based_all.mp4")
|
| 112 |
+
writer = imageio.get_writer(out_path, fps=FPS, codec="libx264", quality=8,
|
| 113 |
+
macro_block_size=2)
|
| 114 |
+
frames = 0
|
| 115 |
+
|
| 116 |
+
def push(img, repeat=1):
|
| 117 |
+
nonlocal frames
|
| 118 |
+
arr = np.asarray(img, dtype=np.uint8)
|
| 119 |
+
for _ in range(repeat):
|
| 120 |
+
writer.append_data(arr)
|
| 121 |
+
frames += 1
|
| 122 |
+
|
| 123 |
+
push(intro_card(scores), int(3.0 * FPS))
|
| 124 |
+
for path in clips:
|
| 125 |
+
reader = imageio.get_reader(path)
|
| 126 |
+
n = 0
|
| 127 |
+
for frame in reader:
|
| 128 |
+
writer.append_data(frame)
|
| 129 |
+
frames += 1
|
| 130 |
+
n += 1
|
| 131 |
+
reader.close()
|
| 132 |
+
print(f" [拼接] {os.path.basename(path)}:{n} 帧")
|
| 133 |
+
push(end_card(scores), int(5.0 * FPS))
|
| 134 |
+
|
| 135 |
+
writer.close()
|
| 136 |
+
size_mb = os.path.getsize(out_path) / (1024 * 1024)
|
| 137 |
+
print(f"[输出] 总回放视频 = videos/{os.path.basename(out_path)} "
|
| 138 |
+
f"({frames} 帧 / {frames / FPS:.1f} 秒 / {size_mb:.1f} MB)")
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
if __name__ == "__main__":
|
| 142 |
+
main()
|
code/train_qlearning.py
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
第3周 · 实战3(value-based / Q-Learning)—— 训练脚本
|
| 4 |
+
=====================================================
|
| 5 |
+
对应 PPT《第3周-深度强化学习原理实践》第 27–40 页:
|
| 6 |
+
· 第 29 页:Q 表 / Q 函数 / 最优策略 pi*(s) = argmax_a Q*(s,a)
|
| 7 |
+
· 第 31–32 页:FrozenLake-v1(4x4 不滑版)观测/动作/奖励
|
| 8 |
+
· 第 33 页:Q 表初始化 + 贪心策略
|
| 9 |
+
· 第 34 页:epsilon-greedy 行为策略 + 超参数
|
| 10 |
+
· 第 35 页:Q-Learning 训练循环(Bellman 更新)
|
| 11 |
+
· 第 36–37 页:训练、Q 表可视化、评估
|
| 12 |
+
· 第 38–40 页:Taxi-v3
|
| 13 |
+
|
| 14 |
+
本脚本从零手写 Q-Learning(不依赖 stable-baselines3),一次跑通三个环境:
|
| 15 |
+
frozenlake4x4 FrozenLake-v1 4x4,is_slippery=False(PPT 第一部分,确定性)
|
| 16 |
+
frozenlake8x8 FrozenLake-v1 8x8,is_slippery=True (PPT 第 31 页提到的进阶版本,随机性)
|
| 17 |
+
taxi Taxi-v3(PPT 第二部分,500 个状态 × 6 个动作)
|
| 18 |
+
|
| 19 |
+
输出(全部落在本目录下):
|
| 20 |
+
logs/<run>/train_console.log 完整控制台日志(含环境自检/超参/每 N 回合进度/每次评估)
|
| 21 |
+
logs/<run>/progress.csv 结构化进度数据(画曲线 / 写报告用)
|
| 22 |
+
logs/<run>/train_curve.png 训练曲线(回报、epsilon、成功率、评估)
|
| 23 |
+
models/qtable_<run>.pkl 训练出的模型文件(Q 表 + 全套配置,可被 evaluate_and_record.py 直接加载)
|
| 24 |
+
|
| 25 |
+
用法(本机已装好 DRL 环境,无需再装包):
|
| 26 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe train_qlearning.py --env frozenlake4x4
|
| 27 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe train_qlearning.py --env frozenlake8x8
|
| 28 |
+
D:\\study\\robot\\pyenv\\DRL\\python.exe train_qlearning.py --env taxi
|
| 29 |
+
|
| 30 |
+
只改一个变量做对照实验(例如演示"epsilon 衰减太慢"):
|
| 31 |
+
python train_qlearning.py --env frozenlake4x4 --decay-rate 0.0001 --run-name fl4x4_slow_decay
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
import argparse
|
| 35 |
+
import csv
|
| 36 |
+
import os
|
| 37 |
+
import pickle
|
| 38 |
+
import random
|
| 39 |
+
import sys
|
| 40 |
+
import time
|
| 41 |
+
from datetime import datetime
|
| 42 |
+
|
| 43 |
+
import gymnasium as gym
|
| 44 |
+
import matplotlib
|
| 45 |
+
matplotlib.use("Agg") # 不弹窗,直接存 png
|
| 46 |
+
import matplotlib.pyplot as plt
|
| 47 |
+
import numpy as np
|
| 48 |
+
|
| 49 |
+
# ======================================================================
|
| 50 |
+
# 全局路径
|
| 51 |
+
# ======================================================================
|
| 52 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 53 |
+
LOG_ROOT = os.path.join(BASE_DIR, "logs")
|
| 54 |
+
MODEL_ROOT = os.path.join(BASE_DIR, "models")
|
| 55 |
+
|
| 56 |
+
# 中文字体:Windows 自带的微软雅黑 / 黑体
|
| 57 |
+
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "DejaVu Sans"]
|
| 58 |
+
plt.rcParams["axes.unicode_minus"] = False
|
| 59 |
+
|
| 60 |
+
# ======================================================================
|
| 61 |
+
# 第 38–39 页:Taxi-v3 官方评估种子(PPT 原文:请勿修改 EVAL_SEED)
|
| 62 |
+
# 作用:让所有同学都在相同的出租车起始位置上评估,班级分数才可比。
|
| 63 |
+
# ======================================================================
|
| 64 |
+
EVAL_SEED_TAXI = [
|
| 65 |
+
16, 54, 165, 177, 191, 191, 120, 80, 149, 178, 48, 38, 6, 125, 174, 73, 50,
|
| 66 |
+
172, 100, 148, 146, 6, 25, 40, 68, 148, 49, 167, 9, 97, 164, 176, 61, 7, 54,
|
| 67 |
+
55, 161, 131, 184, 51, 170, 12, 120, 113, 95, 126, 51, 98, 36, 135, 54, 82,
|
| 68 |
+
45, 95, 89, 59, 95, 124, 9, 113, 58, 85, 51, 134, 121, 169, 105, 21, 30, 11,
|
| 69 |
+
50, 65, 12, 43, 82, 145, 152, 97, 106, 55, 31, 85, 38, 112, 102, 168, 123, 97,
|
| 70 |
+
21, 83, 158, 26, 80, 63, 5, 81, 32, 11, 28, 148,
|
| 71 |
+
]
|
| 72 |
+
|
| 73 |
+
# ======================================================================
|
| 74 |
+
# 环境 + 超参数配置(严格对应 PPT 第 34 页与第 39 页)
|
| 75 |
+
# ======================================================================
|
| 76 |
+
EXPERIMENTS = {
|
| 77 |
+
# ---- 第一部分:冰冻湖 4x4,不滑(确定性) -------------------------
|
| 78 |
+
"frozenlake4x4": dict(
|
| 79 |
+
title="FrozenLake-v1(4x4,is_slippery=False)",
|
| 80 |
+
env_id="FrozenLake-v1",
|
| 81 |
+
env_kwargs=dict(map_name="4x4", is_slippery=False),
|
| 82 |
+
n_training_episodes=10000, # 第 34 页:总训练回合数
|
| 83 |
+
learning_rate=0.7, # 第 34 页:学习率
|
| 84 |
+
gamma=0.95, # 第 34 页:折扣率
|
| 85 |
+
max_steps=99, # 第 34 页:每回合最大步数
|
| 86 |
+
max_epsilon=1.0, # 第 34 页:开始时探索概率
|
| 87 |
+
min_epsilon=0.05, # 第 34 页:最小探索概率
|
| 88 |
+
decay_rate=0.0005, # 第 34 页:探索概率指数衰减率
|
| 89 |
+
n_eval_episodes=100, # 第 34 页:评估回合数
|
| 90 |
+
eval_seed=None, # 第 34 页 eval_seed = []
|
| 91 |
+
eval_every=1000,
|
| 92 |
+
log_every=500,
|
| 93 |
+
),
|
| 94 |
+
# ---- 第 31 页提到的另一种模式:4x4 + 滑冰(is_slippery=True) ------
|
| 95 |
+
# 与第一部分只差一个变量 is_slippery,但冰面会以 1/3 概率把智能体推偏,
|
| 96 |
+
# 所以同样的超参数明显更难学:这里把探索期拉长(min_epsilon 0.1 / decay 0.0003)
|
| 97 |
+
# 并多训一倍回合,成功率才能从 ~20% 提到 ~75%。
|
| 98 |
+
"frozenlake4x4_slippery": dict(
|
| 99 |
+
title="FrozenLake-v1(4x4,is_slippery=True)",
|
| 100 |
+
env_id="FrozenLake-v1",
|
| 101 |
+
env_kwargs=dict(map_name="4x4", is_slippery=True),
|
| 102 |
+
n_training_episodes=20000,
|
| 103 |
+
learning_rate=0.7,
|
| 104 |
+
gamma=0.95,
|
| 105 |
+
max_steps=99,
|
| 106 |
+
max_epsilon=1.0,
|
| 107 |
+
min_epsilon=0.1,
|
| 108 |
+
decay_rate=0.0003,
|
| 109 |
+
n_eval_episodes=100,
|
| 110 |
+
eval_seed=list(range(100)),
|
| 111 |
+
eval_every=2000,
|
| 112 |
+
log_every=1000,
|
| 113 |
+
),
|
| 114 |
+
# ---- 第 31 页提到的进阶版:冰冻湖 8x8(地图变大) -----------------
|
| 115 |
+
# 8x8 最优路径约 14 步,比 4x4 长一倍多;Q 表从 16x4 变成 64x4。
|
| 116 |
+
# 注意:8x8 的稀疏奖励让"随机探索"很难碰到终点,如果沿用 4x4 的快速 epsilon 衰减,
|
| 117 |
+
# Q 表会一直是全 0(这一点在实验报告里作为对照实验记录)。
|
| 118 |
+
# 所以这里把探索期拉长(min_epsilon 0.3 / decay 0.00003),让智能体先"逛遍"地图。
|
| 119 |
+
"frozenlake8x8": dict(
|
| 120 |
+
title="FrozenLake-v1(8x8,is_slippery=False)",
|
| 121 |
+
env_id="FrozenLake-v1",
|
| 122 |
+
env_kwargs=dict(map_name="8x8", is_slippery=False),
|
| 123 |
+
n_training_episodes=60000,
|
| 124 |
+
learning_rate=0.8,
|
| 125 |
+
gamma=0.95,
|
| 126 |
+
max_steps=200,
|
| 127 |
+
max_epsilon=1.0,
|
| 128 |
+
min_epsilon=0.3,
|
| 129 |
+
decay_rate=0.00003,
|
| 130 |
+
n_eval_episodes=100,
|
| 131 |
+
eval_seed=list(range(100)),
|
| 132 |
+
eval_every=6000,
|
| 133 |
+
log_every=3000,
|
| 134 |
+
),
|
| 135 |
+
# ---- 第二部分:Taxi-v3 -------------------------------------------
|
| 136 |
+
"taxi": dict(
|
| 137 |
+
title="Taxi-v3",
|
| 138 |
+
env_id="Taxi-v3",
|
| 139 |
+
env_kwargs=dict(),
|
| 140 |
+
n_training_episodes=25000, # 第 39 页:总训练回合数
|
| 141 |
+
learning_rate=0.7,
|
| 142 |
+
gamma=0.95,
|
| 143 |
+
max_steps=99,
|
| 144 |
+
max_epsilon=1.0,
|
| 145 |
+
min_epsilon=0.05,
|
| 146 |
+
decay_rate=0.005, # 第 39 页:0.005(比冰冻湖衰减快,因为回合更长)
|
| 147 |
+
n_eval_episodes=100,
|
| 148 |
+
eval_seed=EVAL_SEED_TAXI, # 第 39 页:官方评估种子
|
| 149 |
+
eval_every=2500,
|
| 150 |
+
log_every=1000,
|
| 151 |
+
),
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
# ======================================================================
|
| 156 |
+
# 工具:同时写控制台 + 日志文件(这就是"有日志输出的训练代码")
|
| 157 |
+
# ======================================================================
|
| 158 |
+
class Tee:
|
| 159 |
+
"""把 print 的内容同时写进 stdout 和日志文件。"""
|
| 160 |
+
|
| 161 |
+
def __init__(self, log_path):
|
| 162 |
+
self.terminal = sys.stdout
|
| 163 |
+
self.log_file = open(log_path, "w", encoding="utf-8")
|
| 164 |
+
|
| 165 |
+
def write(self, message):
|
| 166 |
+
self.terminal.write(message)
|
| 167 |
+
self.log_file.write(message)
|
| 168 |
+
self.log_file.flush()
|
| 169 |
+
|
| 170 |
+
def flush(self):
|
| 171 |
+
self.terminal.flush()
|
| 172 |
+
self.log_file.flush()
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def timestamp():
|
| 176 |
+
return datetime.now().strftime("%H:%M:%S")
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
# ======================================================================
|
| 180 |
+
# 第 33 页:创建并初始化 Q 表
|
| 181 |
+
# Q 表大小 = (状态数, 动作数),初始全 0("在开始时 Q 表是无用的")
|
| 182 |
+
# ======================================================================
|
| 183 |
+
def initialize_q_table(state_space, action_space):
|
| 184 |
+
return np.zeros((state_space, action_space))
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
# ======================================================================
|
| 188 |
+
# 第 33 页:贪婪策略(更新策略 / 最终策略)
|
| 189 |
+
# pi*(s) = argmax_a Q(s,a)
|
| 190 |
+
# ======================================================================
|
| 191 |
+
def greedy_policy(q_table, state):
|
| 192 |
+
return int(np.argmax(q_table[state]))
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
# ======================================================================
|
| 196 |
+
# 第 34 页:epsilon-greedy 策略(行为策略)
|
| 197 |
+
# 以 epsilon 的概率探索(随机动作),否则利用(贪心动作)
|
| 198 |
+
# —— Q-Learning 是离线策略(off-policy):行动用 epsilon-greedy,
|
| 199 |
+
# 更新时却用 max_a Q(s', a),两套策略。
|
| 200 |
+
# ======================================================================
|
| 201 |
+
def epsilon_greedy_policy(q_table, state, epsilon, action_space):
|
| 202 |
+
if random.random() > epsilon:
|
| 203 |
+
return greedy_policy(q_table, state) # 利用
|
| 204 |
+
return int(action_space.sample()) # 探索
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
# ======================================================================
|
| 208 |
+
# 第 35 页:训练循环
|
| 209 |
+
# Q(s,a) <- Q(s,a) + lr * [ r + gamma * max_a' Q(s',a') - Q(s,a) ]
|
| 210 |
+
# ======================================================================
|
| 211 |
+
def train(
|
| 212 |
+
env,
|
| 213 |
+
q_table,
|
| 214 |
+
n_training_episodes,
|
| 215 |
+
max_steps,
|
| 216 |
+
learning_rate,
|
| 217 |
+
gamma,
|
| 218 |
+
max_epsilon,
|
| 219 |
+
min_epsilon,
|
| 220 |
+
decay_rate,
|
| 221 |
+
train_seed=0,
|
| 222 |
+
log_every=500,
|
| 223 |
+
eval_every=None,
|
| 224 |
+
eval_kwargs=None,
|
| 225 |
+
):
|
| 226 |
+
"""
|
| 227 |
+
返回:q_table、每回合数据、评估历史
|
| 228 |
+
"""
|
| 229 |
+
episode_rewards = []
|
| 230 |
+
episode_steps = []
|
| 231 |
+
episode_success = [] # 是否到达目标(FrozenLake 的 reward==1 / Taxi 的 reward==20)
|
| 232 |
+
epsilons = []
|
| 233 |
+
eval_history = [] # [(episode, mean, std, success_rate), ...]
|
| 234 |
+
|
| 235 |
+
started = time.time()
|
| 236 |
+
eval_kwargs = eval_kwargs or {}
|
| 237 |
+
|
| 238 |
+
for episode in range(n_training_episodes):
|
| 239 |
+
# ---- epsilon 指数衰减:越往后越少探索 ----
|
| 240 |
+
epsilon = min_epsilon + (max_epsilon - min_epsilon) * np.exp(-decay_rate * episode)
|
| 241 |
+
epsilons.append(epsilon)
|
| 242 |
+
|
| 243 |
+
# ---- 重置环境 ----
|
| 244 |
+
# 每回合都用固定种子 reset(seed=train_seed+episode):
|
| 245 |
+
# 同一个 --seed 重跑,起点序列、滑冰随机性和探索随机性完全一致 -> 分数可复现。
|
| 246 |
+
# 注意:gymnasium 的 env.reset(seed=...) 只给 env 播种,不给 action_space 播种,
|
| 247 |
+
# 而 epsilon-greedy 的"探索"要用 env.action_space.sample(),
|
| 248 |
+
# 所以这里再单独给 action_space 播种一次(这一行是可复现的关键)。
|
| 249 |
+
if train_seed is not None:
|
| 250 |
+
state, _ = env.reset(seed=train_seed + episode)
|
| 251 |
+
env.action_space.seed(train_seed + episode)
|
| 252 |
+
else:
|
| 253 |
+
state, _ = env.reset()
|
| 254 |
+
|
| 255 |
+
total_reward = 0.0
|
| 256 |
+
reached_goal = False
|
| 257 |
+
|
| 258 |
+
for step in range(max_steps):
|
| 259 |
+
# 1) 用 epsilon-greedy 选择动作 At
|
| 260 |
+
action = epsilon_greedy_policy(q_table, state, epsilon, env.action_space)
|
| 261 |
+
|
| 262 |
+
# 2) 执行动作,观察 Rt+1 和 St+1
|
| 263 |
+
new_state, reward, terminated, truncated, _ = env.step(action)
|
| 264 |
+
done = terminated or truncated
|
| 265 |
+
|
| 266 |
+
# 3) Bellman 更新(Q-Learning 的核心这一行)
|
| 267 |
+
# 注意:真实终止状态没有未来价值,next_q 取 0;
|
| 268 |
+
# PPT 截图里没做这个掩码,这里修正后结果更稳(FrozenLake 两者等价)。
|
| 269 |
+
next_q = 0.0 if terminated else float(np.max(q_table[new_state]))
|
| 270 |
+
q_table[state][action] += learning_rate * (
|
| 271 |
+
reward + gamma * next_q - q_table[state][action]
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
total_reward += reward
|
| 275 |
+
state = new_state
|
| 276 |
+
if done:
|
| 277 |
+
reached_goal = reward > 0
|
| 278 |
+
break
|
| 279 |
+
|
| 280 |
+
episode_rewards.append(total_reward)
|
| 281 |
+
episode_steps.append(step + 1)
|
| 282 |
+
episode_success.append(1 if reached_goal else 0)
|
| 283 |
+
|
| 284 |
+
# ---- 每 log_every 回合打印一行进度(可直接粘进实验报告)----
|
| 285 |
+
if (episode + 1) % log_every == 0 or episode == 0:
|
| 286 |
+
window = episode_rewards[-min(100, len(episode_rewards)):]
|
| 287 |
+
window_success = episode_success[-min(100, len(episode_success)):]
|
| 288 |
+
window_steps = episode_steps[-min(100, len(episode_steps)):]
|
| 289 |
+
elapsed_min = (time.time() - started) / 60.0
|
| 290 |
+
print(
|
| 291 |
+
f"[train] ep={episode + 1:>6}/{n_training_episodes} | "
|
| 292 |
+
f"eps={epsilon:.3f} | "
|
| 293 |
+
f"最近100回合平均回报={np.mean(window):6.2f} | "
|
| 294 |
+
f"成功率={np.mean(window_success) * 100:5.1f}% | "
|
| 295 |
+
f"平均步数={np.mean(window_steps):5.1f} | "
|
| 296 |
+
f"Q非零项={np.count_nonzero(q_table):5d} | "
|
| 297 |
+
f"用时={elapsed_min:5.2f}min"
|
| 298 |
+
)
|
| 299 |
+
|
| 300 |
+
# ---- 周期评估(用贪婪策略跑独立回合)----
|
| 301 |
+
if eval_every and (episode + 1) % eval_every == 0:
|
| 302 |
+
mean_r, std_r, succ = evaluate_agent(
|
| 303 |
+
env, q_table, max_steps, eval_kwargs.get("n_eval", 20),
|
| 304 |
+
eval_kwargs.get("eval_seed"),
|
| 305 |
+
)
|
| 306 |
+
eval_history.append((episode + 1, mean_r, std_r, succ))
|
| 307 |
+
print(
|
| 308 |
+
f"[eval ] ep={episode + 1:>6} | 贪婪策略 {eval_kwargs.get('n_eval', 20)} 局: "
|
| 309 |
+
f"回报={mean_r:6.2f} ± {std_r:5.2f} | 成功率={succ * 100:5.1f}%"
|
| 310 |
+
)
|
| 311 |
+
|
| 312 |
+
return q_table, episode_rewards, episode_steps, episode_success, epsilons, eval_history
|
| 313 |
+
|
| 314 |
+
|
| 315 |
+
# ======================================================================
|
| 316 |
+
# 第 36 页:评估智能体(贪婪策略,返回平均回报 ± 标准差)
|
| 317 |
+
# ======================================================================
|
| 318 |
+
def evaluate_agent(env, q_table, max_steps, n_episodes, seeds=None):
|
| 319 |
+
rewards = []
|
| 320 |
+
successes = []
|
| 321 |
+
lengths = []
|
| 322 |
+
for i in range(n_episodes):
|
| 323 |
+
if seeds is not None and i < len(seeds):
|
| 324 |
+
state, _ = env.reset(seed=int(seeds[i]))
|
| 325 |
+
else:
|
| 326 |
+
state, _ = env.reset()
|
| 327 |
+
total_reward = 0.0
|
| 328 |
+
for step in range(max_steps):
|
| 329 |
+
action = greedy_policy(q_table, state)
|
| 330 |
+
state, reward, terminated, truncated, _ = env.step(action)
|
| 331 |
+
total_reward += reward
|
| 332 |
+
if terminated or truncated:
|
| 333 |
+
break
|
| 334 |
+
rewards.append(total_reward)
|
| 335 |
+
lengths.append(step + 1)
|
| 336 |
+
successes.append(1 if total_reward > 0 else 0)
|
| 337 |
+
return float(np.mean(rewards)), float(np.std(rewards)), float(np.mean(successes))
|
| 338 |
+
|
| 339 |
+
|
| 340 |
+
# ======================================================================
|
| 341 |
+
# 画训练曲线
|
| 342 |
+
# ======================================================================
|
| 343 |
+
def moving_average(values, window=100):
|
| 344 |
+
values = np.asarray(values, dtype=float)
|
| 345 |
+
if len(values) < window:
|
| 346 |
+
return values
|
| 347 |
+
kernel = np.ones(window) / window
|
| 348 |
+
return np.convolve(values, kernel, mode="valid")
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
def plot_curve(run_dir, title, episode_rewards, epsilons, episode_success,
|
| 352 |
+
eval_history, n_training_episodes):
|
| 353 |
+
fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=False)
|
| 354 |
+
|
| 355 |
+
# 上图:每回合回报 + 100 回合滑动平均 + 周期评估
|
| 356 |
+
ax = axes[0]
|
| 357 |
+
ax.plot(np.arange(1, len(episode_rewards) + 1), episode_rewards,
|
| 358 |
+
color="#93c5fd", linewidth=0.5, alpha=0.6, label="每回合回报")
|
| 359 |
+
ma = moving_average(episode_rewards, 100)
|
| 360 |
+
ax.plot(np.arange(100, 100 + len(ma)), ma,
|
| 361 |
+
color="#1d4ed8", linewidth=2, label="100 回合滑动平均")
|
| 362 |
+
if eval_history:
|
| 363 |
+
xs = [h[0] for h in eval_history]
|
| 364 |
+
ys = [h[1] for h in eval_history]
|
| 365 |
+
errs = [h[2] for h in eval_history]
|
| 366 |
+
ax.errorbar(xs, ys, yerr=errs, fmt="o--", color="#dc2626", markersize=4,
|
| 367 |
+
linewidth=1.2, capsize=3, label="周期评估(贪婪策略)")
|
| 368 |
+
ax.set_xlabel("训练回合 episode")
|
| 369 |
+
ax.set_ylabel("回报 reward")
|
| 370 |
+
ax.set_title(f"{title} · 训练曲线(共 {n_training_episodes} 回合)")
|
| 371 |
+
# 早期有几局极端负分(例如 Taxi 乱按上下客被 -10 罚到 -400),会把曲线压扁,
|
| 372 |
+
# 这里按 0.5%~99.5% 分位数裁一下 y 轴,极端点仍在图外但趋势看得清。
|
| 373 |
+
rewards_arr = np.asarray(episode_rewards, dtype=float)
|
| 374 |
+
low = min(float(np.percentile(rewards_arr, 0.5)), 0.0) - 2
|
| 375 |
+
high = max(float(np.percentile(rewards_arr, 99.5)), 1.0) + 1
|
| 376 |
+
if high - low > 5:
|
| 377 |
+
ax.set_ylim(low, high)
|
| 378 |
+
ax.legend(loc="lower right", fontsize=9)
|
| 379 |
+
ax.grid(alpha=0.3)
|
| 380 |
+
|
| 381 |
+
# 下图:epsilon 衰减 + 探索/利用的阶段
|
| 382 |
+
ax2 = axes[1]
|
| 383 |
+
ax2.plot(np.arange(1, len(epsilons) + 1), epsilons, color="#f59e0b", linewidth=2,
|
| 384 |
+
label="epsilon(探索概率)")
|
| 385 |
+
ax2.fill_between(np.arange(1, len(epsilons) + 1), 0, epsilons, color="#f59e0b", alpha=0.15)
|
| 386 |
+
ax2.set_xlabel("训练回合 episode")
|
| 387 |
+
ax2.set_ylabel("epsilon")
|
| 388 |
+
ax2.set_title("epsilon 指数衰减:从\"大胆探索\"到\"相信 Q 表\"")
|
| 389 |
+
ax2.grid(alpha=0.3)
|
| 390 |
+
ax2.legend(loc="upper right", fontsize=9)
|
| 391 |
+
|
| 392 |
+
fig.tight_layout()
|
| 393 |
+
path = os.path.join(run_dir, "train_curve.png")
|
| 394 |
+
fig.savefig(path, dpi=130)
|
| 395 |
+
plt.close(fig)
|
| 396 |
+
return path
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
def write_progress_csv(run_dir, rewards, steps, success, epsilons, eval_history):
|
| 400 |
+
path = os.path.join(run_dir, "progress.csv")
|
| 401 |
+
with open(path, "w", newline="", encoding="utf-8-sig") as f:
|
| 402 |
+
writer = csv.writer(f)
|
| 403 |
+
writer.writerow(["episode", "epsilon", "episode_reward", "episode_steps", "success"])
|
| 404 |
+
for i, (r, s, ok, eps) in enumerate(zip(rewards, steps, success, epsilons), start=1):
|
| 405 |
+
writer.writerow([i, f"{eps:.6f}", f"{r:.6f}", s, ok])
|
| 406 |
+
writer.writerow([])
|
| 407 |
+
writer.writerow(["eval_episode", "eval_mean_reward", "eval_std_reward", "eval_success_rate"])
|
| 408 |
+
for ep, mean_r, std_r, succ in eval_history:
|
| 409 |
+
writer.writerow([ep, f"{mean_r:.6f}", f"{std_r:.6f}", f"{succ:.4f}"])
|
| 410 |
+
return path
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
# ======================================================================
|
| 414 |
+
# 主流程
|
| 415 |
+
# ======================================================================
|
| 416 |
+
def main():
|
| 417 |
+
parser = argparse.ArgumentParser(description="Q-Learning 训练(FrozenLake / Taxi)")
|
| 418 |
+
parser.add_argument("--env", choices=list(EXPERIMENTS.keys()), default="frozenlake4x4",
|
| 419 |
+
help="用哪个环境训练")
|
| 420 |
+
parser.add_argument("--episodes", type=int, default=None, help="覆盖总训练回合数")
|
| 421 |
+
parser.add_argument("--learning-rate", type=float, default=None, help="覆盖学习率 lr")
|
| 422 |
+
parser.add_argument("--gamma", type=float, default=None, help="覆盖折扣率 gamma")
|
| 423 |
+
parser.add_argument("--decay-rate", type=float, default=None, help="覆盖 epsilon 衰减率")
|
| 424 |
+
parser.add_argument("--min-epsilon", type=float, default=None, help="覆盖最小探索概率")
|
| 425 |
+
parser.add_argument("--max-steps", type=int, default=None, help="覆盖每回合最大步数")
|
| 426 |
+
parser.add_argument("--eval-episodes", type=int, default=None, help="覆盖最终评估回合数")
|
| 427 |
+
parser.add_argument("--eval-every", type=int, default=None, help="每多少回合评估一次")
|
| 428 |
+
parser.add_argument("--log-every", type=int, default=None, help="每多少回合打印一行日志")
|
| 429 |
+
parser.add_argument("--seed", type=int, default=0, help="训练随机种子(默认 0)")
|
| 430 |
+
parser.add_argument("--run-name", type=str, default=None, help="日志/模型文件名前缀")
|
| 431 |
+
parser.add_argument("--slippery", action="store_true",
|
| 432 |
+
help="把 FrozenLake 的冰面切换成滑冰版(is_slippery=True,随机转移)")
|
| 433 |
+
args = parser.parse_args()
|
| 434 |
+
|
| 435 |
+
cfg = dict(EXPERIMENTS[args.env])
|
| 436 |
+
if args.slippery:
|
| 437 |
+
cfg["env_kwargs"] = dict(cfg["env_kwargs"], is_slippery=True)
|
| 438 |
+
cfg["title"] += " · 滑冰版"
|
| 439 |
+
# 滑冰版起点随机性大,固定 100 个起点种子才能公平比较
|
| 440 |
+
cfg["eval_seed"] = list(range(100))
|
| 441 |
+
# 命令行覆盖(方便做"一次只改一个变量"的对照实验)
|
| 442 |
+
if args.episodes is not None:
|
| 443 |
+
cfg["n_training_episodes"] = args.episodes
|
| 444 |
+
if args.learning_rate is not None:
|
| 445 |
+
cfg["learning_rate"] = args.learning_rate
|
| 446 |
+
if args.gamma is not None:
|
| 447 |
+
cfg["gamma"] = args.gamma
|
| 448 |
+
if args.decay_rate is not None:
|
| 449 |
+
cfg["decay_rate"] = args.decay_rate
|
| 450 |
+
if args.min_epsilon is not None:
|
| 451 |
+
cfg["min_epsilon"] = args.min_epsilon
|
| 452 |
+
if args.max_steps is not None:
|
| 453 |
+
cfg["max_steps"] = args.max_steps
|
| 454 |
+
if args.eval_episodes is not None:
|
| 455 |
+
cfg["n_eval_episodes"] = args.eval_episodes
|
| 456 |
+
if args.eval_every is not None:
|
| 457 |
+
cfg["eval_every"] = args.eval_every
|
| 458 |
+
if args.log_every is not None:
|
| 459 |
+
cfg["log_every"] = args.log_every
|
| 460 |
+
cfg["train_seed"] = args.seed
|
| 461 |
+
|
| 462 |
+
run_name = args.run_name or args.env
|
| 463 |
+
run_dir = os.path.join(LOG_ROOT, run_name)
|
| 464 |
+
os.makedirs(run_dir, exist_ok=True)
|
| 465 |
+
os.makedirs(MODEL_ROOT, exist_ok=True)
|
| 466 |
+
|
| 467 |
+
# 每次运行先设置随机种子:Python random 管探索、np 管 Q 表初始化
|
| 468 |
+
random.seed(args.seed)
|
| 469 |
+
np.random.seed(args.seed)
|
| 470 |
+
|
| 471 |
+
tee = Tee(os.path.join(run_dir, "train_console.log"))
|
| 472 |
+
sys.stdout = tee
|
| 473 |
+
try:
|
| 474 |
+
print("=" * 78)
|
| 475 |
+
print(f"Q-Learning 训练 · {cfg['title']}")
|
| 476 |
+
print(f"运行名称: {run_name} 开始时间: {datetime.now():%Y-%m-%d %H:%M:%S}")
|
| 477 |
+
print("=" * 78)
|
| 478 |
+
|
| 479 |
+
# ---------------- 第 31–32 页:创建并理解环境 ----------------
|
| 480 |
+
env = gym.make(cfg["env_id"], render_mode="rgb_array", **cfg["env_kwargs"])
|
| 481 |
+
state_space = env.observation_space.n
|
| 482 |
+
action_space = env.action_space.n
|
| 483 |
+
sample_state, _ = env.reset(seed=args.seed)
|
| 484 |
+
|
| 485 |
+
print("\n[环境自检]")
|
| 486 |
+
print(f" env_id = {cfg['env_id']}")
|
| 487 |
+
print(f" env_kwargs = {cfg['env_kwargs']}")
|
| 488 |
+
print(f" 观测空间 = {env.observation_space} -> {state_space} 个状态")
|
| 489 |
+
print(f" 动作空间 = {env.action_space} -> {action_space} 个动作")
|
| 490 |
+
if cfg["env_id"] == "FrozenLake-v1":
|
| 491 |
+
ncol = env.unwrapped.ncol
|
| 492 |
+
print(f" 一次 reset 的观测 = {sample_state}"
|
| 493 |
+
f"(整数 = 状态编号,{env.unwrapped.nrow}x{ncol} 地图按 row*{ncol}+col 编码)")
|
| 494 |
+
else:
|
| 495 |
+
print(f" 一次 reset 的观测 = {sample_state}(整数 = 状态编号,共 500 个)")
|
| 496 |
+
print(f" 每回合最大步数 = {cfg['max_steps']}")
|
| 497 |
+
|
| 498 |
+
# ---------------- 第 33 页:Q 表 ----------------
|
| 499 |
+
q_table = initialize_q_table(state_space, action_space)
|
| 500 |
+
print("\n[Q 表初始化]")
|
| 501 |
+
print(f" Q 表形状 = {q_table.shape}(= (状态数, 动作数)),初始值全为 0")
|
| 502 |
+
print(f" 需要学习的参数个数 = {state_space * action_space}")
|
| 503 |
+
|
| 504 |
+
# ---------------- 第 34 页:超参数 ----------------
|
| 505 |
+
print("\n[超参数]")
|
| 506 |
+
print(f" n_training_episodes = {cfg['n_training_episodes']}")
|
| 507 |
+
print(f" learning_rate = {cfg['learning_rate']}")
|
| 508 |
+
print(f" gamma = {cfg['gamma']}")
|
| 509 |
+
print(f" max_steps = {cfg['max_steps']}")
|
| 510 |
+
print(f" max_epsilon = {cfg['max_epsilon']}")
|
| 511 |
+
print(f" min_epsilon = {cfg['min_epsilon']}")
|
| 512 |
+
print(f" decay_rate = {cfg['decay_rate']}")
|
| 513 |
+
print(f" n_eval_episodes = {cfg['n_eval_episodes']}")
|
| 514 |
+
print(f" eval_seed = {'官方 100 个种子' if cfg['eval_seed'] else '[](不指定)'}")
|
| 515 |
+
print(f" train_seed = {args.seed}")
|
| 516 |
+
|
| 517 |
+
# ---------------- 第 35 页:训练 ----------------
|
| 518 |
+
print(f"\n[开始训练] {timestamp()} 每 {cfg['log_every']} 回合打印一行,"
|
| 519 |
+
f"每 {cfg['eval_every']} 回合评估一次")
|
| 520 |
+
print(f" 可复现性:每回合 env.reset(seed={args.seed}+episode),同 --seed 重跑分数一致")
|
| 521 |
+
started = time.time()
|
| 522 |
+
(q_table, rewards, steps, success, epsilons, eval_history) = train(
|
| 523 |
+
env=env,
|
| 524 |
+
q_table=q_table,
|
| 525 |
+
n_training_episodes=cfg["n_training_episodes"],
|
| 526 |
+
max_steps=cfg["max_steps"],
|
| 527 |
+
learning_rate=cfg["learning_rate"],
|
| 528 |
+
gamma=cfg["gamma"],
|
| 529 |
+
max_epsilon=cfg["max_epsilon"],
|
| 530 |
+
min_epsilon=cfg["min_epsilon"],
|
| 531 |
+
decay_rate=cfg["decay_rate"],
|
| 532 |
+
train_seed=args.seed,
|
| 533 |
+
log_every=cfg["log_every"],
|
| 534 |
+
eval_every=cfg["eval_every"],
|
| 535 |
+
eval_kwargs=dict(
|
| 536 |
+
n_eval=20,
|
| 537 |
+
eval_seed=cfg["eval_seed"],
|
| 538 |
+
),
|
| 539 |
+
)
|
| 540 |
+
elapsed = (time.time() - started) / 60.0
|
| 541 |
+
print(f"\n[训练完成] {timestamp()} 总用时 = {elapsed:.2f} 分钟")
|
| 542 |
+
|
| 543 |
+
# ---------------- 第 36 页:最终评估 ----------------
|
| 544 |
+
print(f"\n[最终评估] 用贪婪策略跑 {cfg['n_eval_episodes']} 局(独立于训练)")
|
| 545 |
+
mean_r, std_r, succ = evaluate_agent(
|
| 546 |
+
env, q_table, cfg["max_steps"], cfg["n_eval_episodes"], cfg["eval_seed"]
|
| 547 |
+
)
|
| 548 |
+
print(f" Mean_reward = {mean_r:.2f} +/- {std_r:.2f}")
|
| 549 |
+
print(f" 成功率 = {succ * 100:.0f}%")
|
| 550 |
+
if eval_history:
|
| 551 |
+
best = max(eval_history, key=lambda h: h[1])
|
| 552 |
+
print(f" 训练途中最好的周期评估:{best[1]:.2f} ± {best[2]:.2f} @ 第 {best[0]} 回合")
|
| 553 |
+
print(f" Q 表非零项 = {np.count_nonzero(q_table)} / {q_table.size}")
|
| 554 |
+
print(f" Q 表最大价值 = {q_table.max():.4f}")
|
| 555 |
+
|
| 556 |
+
# ---------------- 第 36–37 页:Q 表可视化 + 训练曲线 ----------------
|
| 557 |
+
curve_path = plot_curve(run_dir, cfg["title"], rewards, epsilons, success,
|
| 558 |
+
eval_history, cfg["n_training_episodes"])
|
| 559 |
+
csv_path = write_progress_csv(run_dir, rewards, steps, success, epsilons, eval_history)
|
| 560 |
+
print(f"\n[输出] 训练曲线 = {os.path.relpath(curve_path, BASE_DIR)}")
|
| 561 |
+
print(f"[输出] 进度 CSV = {os.path.relpath(csv_path, BASE_DIR)}")
|
| 562 |
+
|
| 563 |
+
# ---------------- 第 37 页:保存模型(= "训练出的模型文件") ----------------
|
| 564 |
+
model = {
|
| 565 |
+
"run_name": run_name,
|
| 566 |
+
"title": cfg["title"],
|
| 567 |
+
"env_id": cfg["env_id"],
|
| 568 |
+
"env_kwargs": cfg["env_kwargs"],
|
| 569 |
+
"max_steps": cfg["max_steps"],
|
| 570 |
+
"n_training_episodes": cfg["n_training_episodes"],
|
| 571 |
+
"n_eval_episodes": cfg["n_eval_episodes"],
|
| 572 |
+
"eval_seed": cfg["eval_seed"],
|
| 573 |
+
"learning_rate": cfg["learning_rate"],
|
| 574 |
+
"gamma": cfg["gamma"],
|
| 575 |
+
"max_epsilon": cfg["max_epsilon"],
|
| 576 |
+
"min_epsilon": cfg["min_epsilon"],
|
| 577 |
+
"decay_rate": cfg["decay_rate"],
|
| 578 |
+
"train_seed": args.seed,
|
| 579 |
+
"qtable": q_table,
|
| 580 |
+
"metrics": {
|
| 581 |
+
"mean_reward": mean_r,
|
| 582 |
+
"std_reward": std_r,
|
| 583 |
+
"success_rate": succ,
|
| 584 |
+
"training_minutes": elapsed,
|
| 585 |
+
},
|
| 586 |
+
"trained_at": datetime.now().isoformat(timespec="seconds"),
|
| 587 |
+
}
|
| 588 |
+
model_path = os.path.join(MODEL_ROOT, f"qtable_{run_name}.pkl")
|
| 589 |
+
with open(model_path, "wb") as f:
|
| 590 |
+
pickle.dump(model, f)
|
| 591 |
+
print(f"[输出] 模型文件 = {os.path.relpath(model_path, BASE_DIR)} "
|
| 592 |
+
f"({os.path.getsize(model_path) / 1024:.1f} KB)")
|
| 593 |
+
|
| 594 |
+
print("\n" + "=" * 78)
|
| 595 |
+
print(f"完成。下一步:python evaluate_and_record.py --model models/qtable_{run_name}.pkl")
|
| 596 |
+
print("=" * 78)
|
| 597 |
+
env.close()
|
| 598 |
+
finally:
|
| 599 |
+
sys.stdout = tee.terminal
|
| 600 |
+
tee.log_file.close()
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
if __name__ == "__main__":
|
| 604 |
+
main()
|
code/upload_to_hub.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
把 hub_package/ 上传到 Hugging Face Hub(对应 PPT 第 28 页第 4 条学习目标)。
|
| 4 |
+
================================================================
|
| 5 |
+
等价于 PPT 里的 package_to_hub(...),只是拆成"先打包、再上传"两步,更透明。
|
| 6 |
+
|
| 7 |
+
准备:
|
| 8 |
+
1) 注册 https://huggingface.co ,在 Settings -> Access Tokens 建一个 write token
|
| 9 |
+
2) 登录(二选一):
|
| 10 |
+
hf auth login # 交互式粘贴 token
|
| 11 |
+
或者直接设环境变量:$env:HF_TOKEN = "hf_xxx"
|
| 12 |
+
3) 打包:python build_hub_package.py --repo-id 你的用户名/value-based-qlearning
|
| 13 |
+
|
| 14 |
+
上传:
|
| 15 |
+
python upload_to_hub.py --repo-id 你的用户名/value-based-qlearning
|
| 16 |
+
python upload_to_hub.py --repo-id 你的用户名/value-based-qlearning --private
|
| 17 |
+
|
| 18 |
+
如果本机连不上 huggingface.co(本机实测会超时),有三条路:
|
| 19 |
+
A) 开代理后重试本脚本;
|
| 20 |
+
B) 换镜像(只能下载不能上传,不适用于上传);
|
| 21 |
+
C) 浏览器手动上传:https://huggingface.co/new 建仓库,把 hub_package/ 里的文件拖进去。
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
import argparse
|
| 25 |
+
import os
|
| 26 |
+
import sys
|
| 27 |
+
|
| 28 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def list_files(folder):
|
| 32 |
+
rows = []
|
| 33 |
+
for root, _, files in os.walk(folder):
|
| 34 |
+
for name in sorted(files):
|
| 35 |
+
path = os.path.join(root, name)
|
| 36 |
+
rows.append((os.path.relpath(path, folder), os.path.getsize(path)))
|
| 37 |
+
return rows
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def main():
|
| 41 |
+
parser = argparse.ArgumentParser(description="上传 hub_package 到 Hugging Face Hub")
|
| 42 |
+
parser.add_argument("--repo-id", required=True, help="用户名/仓库名,例如 zhangsan/value-based-qlearning")
|
| 43 |
+
parser.add_argument("--folder", default=os.path.join(BASE_DIR, "hub_package"))
|
| 44 |
+
parser.add_argument("--token", default=os.environ.get("HF_TOKEN"), help="默认读环境变量 HF_TOKEN")
|
| 45 |
+
parser.add_argument("--private", action="store_true", help="创建私有仓库")
|
| 46 |
+
parser.add_argument("--endpoint", default=os.environ.get("HF_ENDPOINT"),
|
| 47 |
+
help="默认 huggingface.co,可用环境变量 HF_ENDPOINT 覆盖")
|
| 48 |
+
parser.add_argument("--dry-run", action="store_true", help="只列出要上传的文件,不真的上传")
|
| 49 |
+
args = parser.parse_args()
|
| 50 |
+
|
| 51 |
+
if not os.path.isdir(args.folder):
|
| 52 |
+
raise SystemExit(f"找不到 {args.folder},请先运行 python build_hub_package.py")
|
| 53 |
+
|
| 54 |
+
files = list_files(args.folder)
|
| 55 |
+
total_mb = sum(size for _, size in files) / (1024 * 1024)
|
| 56 |
+
print(f"准备上传 {len(files)} 个文件(共 {total_mb:.1f} MB)到仓库 {args.repo_id}")
|
| 57 |
+
for rel, size in files:
|
| 58 |
+
print(f" {rel} ({size / 1024:.0f} KB)")
|
| 59 |
+
|
| 60 |
+
if args.dry_run:
|
| 61 |
+
print("\n[--dry-run] 不上传。")
|
| 62 |
+
return
|
| 63 |
+
|
| 64 |
+
if not args.token:
|
| 65 |
+
print("\n[错误] 没有 token。请先执行 hf auth login,或设置 $env:HF_TOKEN。")
|
| 66 |
+
print(" 也可以去掉 --token 参数让 huggingface_hub 读本机缓存的登录信息。")
|
| 67 |
+
return
|
| 68 |
+
|
| 69 |
+
try:
|
| 70 |
+
from huggingface_hub import HfApi
|
| 71 |
+
except ImportError:
|
| 72 |
+
print("\n[错误] 缺 huggingface_hub,请先:pip install huggingface_hub")
|
| 73 |
+
return
|
| 74 |
+
|
| 75 |
+
api = HfApi(endpoint=args.endpoint, token=args.token) if args.endpoint else HfApi(token=args.token)
|
| 76 |
+
|
| 77 |
+
try:
|
| 78 |
+
print(f"\n[1/2] 创建/确认仓库 {args.repo_id} ...")
|
| 79 |
+
api.create_repo(repo_id=args.repo_id, repo_type="model",
|
| 80 |
+
private=args.private, exist_ok=True)
|
| 81 |
+
print("[2/2] 上传文件 ...")
|
| 82 |
+
api.upload_folder(
|
| 83 |
+
repo_id=args.repo_id,
|
| 84 |
+
repo_type="model",
|
| 85 |
+
folder_path=args.folder,
|
| 86 |
+
commit_message="value-based 实践:Q-Learning 智能体(FrozenLake + Taxi)"
|
| 87 |
+
" + 回放视频 + 评估分数",
|
| 88 |
+
)
|
| 89 |
+
except Exception as exc: # noqa: BLE001
|
| 90 |
+
print(f"\n[上传失败] {type(exc).__name__}: {exc}")
|
| 91 |
+
print("\n常见原因与对策:")
|
| 92 |
+
print(" 1) 网络连不上 huggingface.co(本机常见)-> 开代理后重试,或浏览器手动上传;")
|
| 93 |
+
print(" 2) token 没有 write 权限 -> 重新建一个 write token;")
|
| 94 |
+
print(" 3) 仓库名格式不对 -> 必须是 用户名/仓库名。")
|
| 95 |
+
print(f"\n手动上传入口:https://huggingface.co/new (仓库名建议 value-based-qlearning)")
|
| 96 |
+
return
|
| 97 |
+
|
| 98 |
+
url = f"https://huggingface.co/{args.repo_id}"
|
| 99 |
+
print(f"\n[完成] 仓库地址:{url}")
|
| 100 |
+
print(f" 视频和评估分数已经写进 README.md,打开仓库就能看到。")
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
if __name__ == "__main__":
|
| 104 |
+
sys.exit(main())
|
eval_results/eval_frozenlake4x4.json
ADDED
|
@@ -0,0 +1,727 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run": "frozenlake4x4",
|
| 3 |
+
"env_id": "FrozenLake-v1",
|
| 4 |
+
"env_kwargs": {
|
| 5 |
+
"map_name": "4x4",
|
| 6 |
+
"is_slippery": false
|
| 7 |
+
},
|
| 8 |
+
"n_training_episodes": 10000,
|
| 9 |
+
"n_episodes": 100,
|
| 10 |
+
"mean_reward": 1.0,
|
| 11 |
+
"std_reward": 0.0,
|
| 12 |
+
"min_reward": 1.0,
|
| 13 |
+
"max_reward": 1.0,
|
| 14 |
+
"success_rate": 1.0,
|
| 15 |
+
"mean_steps": 6.0,
|
| 16 |
+
"policy": "greedy (argmax Q)",
|
| 17 |
+
"model_file": "models\\qtable_frozenlake4x4.pkl",
|
| 18 |
+
"qtable_shape": [
|
| 19 |
+
16,
|
| 20 |
+
4
|
| 21 |
+
],
|
| 22 |
+
"qtable_nonzero": 35,
|
| 23 |
+
"evaluated_at": "2026-10-30T22:46:48",
|
| 24 |
+
"episodes": [
|
| 25 |
+
{
|
| 26 |
+
"episode": 1,
|
| 27 |
+
"seed": null,
|
| 28 |
+
"reward": 1.0,
|
| 29 |
+
"steps": 6,
|
| 30 |
+
"success": 1
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"episode": 2,
|
| 34 |
+
"seed": null,
|
| 35 |
+
"reward": 1.0,
|
| 36 |
+
"steps": 6,
|
| 37 |
+
"success": 1
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"episode": 3,
|
| 41 |
+
"seed": null,
|
| 42 |
+
"reward": 1.0,
|
| 43 |
+
"steps": 6,
|
| 44 |
+
"success": 1
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"episode": 4,
|
| 48 |
+
"seed": null,
|
| 49 |
+
"reward": 1.0,
|
| 50 |
+
"steps": 6,
|
| 51 |
+
"success": 1
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"episode": 5,
|
| 55 |
+
"seed": null,
|
| 56 |
+
"reward": 1.0,
|
| 57 |
+
"steps": 6,
|
| 58 |
+
"success": 1
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"episode": 6,
|
| 62 |
+
"seed": null,
|
| 63 |
+
"reward": 1.0,
|
| 64 |
+
"steps": 6,
|
| 65 |
+
"success": 1
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"episode": 7,
|
| 69 |
+
"seed": null,
|
| 70 |
+
"reward": 1.0,
|
| 71 |
+
"steps": 6,
|
| 72 |
+
"success": 1
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"episode": 8,
|
| 76 |
+
"seed": null,
|
| 77 |
+
"reward": 1.0,
|
| 78 |
+
"steps": 6,
|
| 79 |
+
"success": 1
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"episode": 9,
|
| 83 |
+
"seed": null,
|
| 84 |
+
"reward": 1.0,
|
| 85 |
+
"steps": 6,
|
| 86 |
+
"success": 1
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"episode": 10,
|
| 90 |
+
"seed": null,
|
| 91 |
+
"reward": 1.0,
|
| 92 |
+
"steps": 6,
|
| 93 |
+
"success": 1
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"episode": 11,
|
| 97 |
+
"seed": null,
|
| 98 |
+
"reward": 1.0,
|
| 99 |
+
"steps": 6,
|
| 100 |
+
"success": 1
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"episode": 12,
|
| 104 |
+
"seed": null,
|
| 105 |
+
"reward": 1.0,
|
| 106 |
+
"steps": 6,
|
| 107 |
+
"success": 1
|
| 108 |
+
},
|
| 109 |
+
{
|
| 110 |
+
"episode": 13,
|
| 111 |
+
"seed": null,
|
| 112 |
+
"reward": 1.0,
|
| 113 |
+
"steps": 6,
|
| 114 |
+
"success": 1
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"episode": 14,
|
| 118 |
+
"seed": null,
|
| 119 |
+
"reward": 1.0,
|
| 120 |
+
"steps": 6,
|
| 121 |
+
"success": 1
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"episode": 15,
|
| 125 |
+
"seed": null,
|
| 126 |
+
"reward": 1.0,
|
| 127 |
+
"steps": 6,
|
| 128 |
+
"success": 1
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"episode": 16,
|
| 132 |
+
"seed": null,
|
| 133 |
+
"reward": 1.0,
|
| 134 |
+
"steps": 6,
|
| 135 |
+
"success": 1
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"episode": 17,
|
| 139 |
+
"seed": null,
|
| 140 |
+
"reward": 1.0,
|
| 141 |
+
"steps": 6,
|
| 142 |
+
"success": 1
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"episode": 18,
|
| 146 |
+
"seed": null,
|
| 147 |
+
"reward": 1.0,
|
| 148 |
+
"steps": 6,
|
| 149 |
+
"success": 1
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"episode": 19,
|
| 153 |
+
"seed": null,
|
| 154 |
+
"reward": 1.0,
|
| 155 |
+
"steps": 6,
|
| 156 |
+
"success": 1
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"episode": 20,
|
| 160 |
+
"seed": null,
|
| 161 |
+
"reward": 1.0,
|
| 162 |
+
"steps": 6,
|
| 163 |
+
"success": 1
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"episode": 21,
|
| 167 |
+
"seed": null,
|
| 168 |
+
"reward": 1.0,
|
| 169 |
+
"steps": 6,
|
| 170 |
+
"success": 1
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"episode": 22,
|
| 174 |
+
"seed": null,
|
| 175 |
+
"reward": 1.0,
|
| 176 |
+
"steps": 6,
|
| 177 |
+
"success": 1
|
| 178 |
+
},
|
| 179 |
+
{
|
| 180 |
+
"episode": 23,
|
| 181 |
+
"seed": null,
|
| 182 |
+
"reward": 1.0,
|
| 183 |
+
"steps": 6,
|
| 184 |
+
"success": 1
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"episode": 24,
|
| 188 |
+
"seed": null,
|
| 189 |
+
"reward": 1.0,
|
| 190 |
+
"steps": 6,
|
| 191 |
+
"success": 1
|
| 192 |
+
},
|
| 193 |
+
{
|
| 194 |
+
"episode": 25,
|
| 195 |
+
"seed": null,
|
| 196 |
+
"reward": 1.0,
|
| 197 |
+
"steps": 6,
|
| 198 |
+
"success": 1
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"episode": 26,
|
| 202 |
+
"seed": null,
|
| 203 |
+
"reward": 1.0,
|
| 204 |
+
"steps": 6,
|
| 205 |
+
"success": 1
|
| 206 |
+
},
|
| 207 |
+
{
|
| 208 |
+
"episode": 27,
|
| 209 |
+
"seed": null,
|
| 210 |
+
"reward": 1.0,
|
| 211 |
+
"steps": 6,
|
| 212 |
+
"success": 1
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"episode": 28,
|
| 216 |
+
"seed": null,
|
| 217 |
+
"reward": 1.0,
|
| 218 |
+
"steps": 6,
|
| 219 |
+
"success": 1
|
| 220 |
+
},
|
| 221 |
+
{
|
| 222 |
+
"episode": 29,
|
| 223 |
+
"seed": null,
|
| 224 |
+
"reward": 1.0,
|
| 225 |
+
"steps": 6,
|
| 226 |
+
"success": 1
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
"episode": 30,
|
| 230 |
+
"seed": null,
|
| 231 |
+
"reward": 1.0,
|
| 232 |
+
"steps": 6,
|
| 233 |
+
"success": 1
|
| 234 |
+
},
|
| 235 |
+
{
|
| 236 |
+
"episode": 31,
|
| 237 |
+
"seed": null,
|
| 238 |
+
"reward": 1.0,
|
| 239 |
+
"steps": 6,
|
| 240 |
+
"success": 1
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"episode": 32,
|
| 244 |
+
"seed": null,
|
| 245 |
+
"reward": 1.0,
|
| 246 |
+
"steps": 6,
|
| 247 |
+
"success": 1
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"episode": 33,
|
| 251 |
+
"seed": null,
|
| 252 |
+
"reward": 1.0,
|
| 253 |
+
"steps": 6,
|
| 254 |
+
"success": 1
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"episode": 34,
|
| 258 |
+
"seed": null,
|
| 259 |
+
"reward": 1.0,
|
| 260 |
+
"steps": 6,
|
| 261 |
+
"success": 1
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"episode": 35,
|
| 265 |
+
"seed": null,
|
| 266 |
+
"reward": 1.0,
|
| 267 |
+
"steps": 6,
|
| 268 |
+
"success": 1
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"episode": 36,
|
| 272 |
+
"seed": null,
|
| 273 |
+
"reward": 1.0,
|
| 274 |
+
"steps": 6,
|
| 275 |
+
"success": 1
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"episode": 37,
|
| 279 |
+
"seed": null,
|
| 280 |
+
"reward": 1.0,
|
| 281 |
+
"steps": 6,
|
| 282 |
+
"success": 1
|
| 283 |
+
},
|
| 284 |
+
{
|
| 285 |
+
"episode": 38,
|
| 286 |
+
"seed": null,
|
| 287 |
+
"reward": 1.0,
|
| 288 |
+
"steps": 6,
|
| 289 |
+
"success": 1
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"episode": 39,
|
| 293 |
+
"seed": null,
|
| 294 |
+
"reward": 1.0,
|
| 295 |
+
"steps": 6,
|
| 296 |
+
"success": 1
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"episode": 40,
|
| 300 |
+
"seed": null,
|
| 301 |
+
"reward": 1.0,
|
| 302 |
+
"steps": 6,
|
| 303 |
+
"success": 1
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"episode": 41,
|
| 307 |
+
"seed": null,
|
| 308 |
+
"reward": 1.0,
|
| 309 |
+
"steps": 6,
|
| 310 |
+
"success": 1
|
| 311 |
+
},
|
| 312 |
+
{
|
| 313 |
+
"episode": 42,
|
| 314 |
+
"seed": null,
|
| 315 |
+
"reward": 1.0,
|
| 316 |
+
"steps": 6,
|
| 317 |
+
"success": 1
|
| 318 |
+
},
|
| 319 |
+
{
|
| 320 |
+
"episode": 43,
|
| 321 |
+
"seed": null,
|
| 322 |
+
"reward": 1.0,
|
| 323 |
+
"steps": 6,
|
| 324 |
+
"success": 1
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"episode": 44,
|
| 328 |
+
"seed": null,
|
| 329 |
+
"reward": 1.0,
|
| 330 |
+
"steps": 6,
|
| 331 |
+
"success": 1
|
| 332 |
+
},
|
| 333 |
+
{
|
| 334 |
+
"episode": 45,
|
| 335 |
+
"seed": null,
|
| 336 |
+
"reward": 1.0,
|
| 337 |
+
"steps": 6,
|
| 338 |
+
"success": 1
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"episode": 46,
|
| 342 |
+
"seed": null,
|
| 343 |
+
"reward": 1.0,
|
| 344 |
+
"steps": 6,
|
| 345 |
+
"success": 1
|
| 346 |
+
},
|
| 347 |
+
{
|
| 348 |
+
"episode": 47,
|
| 349 |
+
"seed": null,
|
| 350 |
+
"reward": 1.0,
|
| 351 |
+
"steps": 6,
|
| 352 |
+
"success": 1
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"episode": 48,
|
| 356 |
+
"seed": null,
|
| 357 |
+
"reward": 1.0,
|
| 358 |
+
"steps": 6,
|
| 359 |
+
"success": 1
|
| 360 |
+
},
|
| 361 |
+
{
|
| 362 |
+
"episode": 49,
|
| 363 |
+
"seed": null,
|
| 364 |
+
"reward": 1.0,
|
| 365 |
+
"steps": 6,
|
| 366 |
+
"success": 1
|
| 367 |
+
},
|
| 368 |
+
{
|
| 369 |
+
"episode": 50,
|
| 370 |
+
"seed": null,
|
| 371 |
+
"reward": 1.0,
|
| 372 |
+
"steps": 6,
|
| 373 |
+
"success": 1
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"episode": 51,
|
| 377 |
+
"seed": null,
|
| 378 |
+
"reward": 1.0,
|
| 379 |
+
"steps": 6,
|
| 380 |
+
"success": 1
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"episode": 52,
|
| 384 |
+
"seed": null,
|
| 385 |
+
"reward": 1.0,
|
| 386 |
+
"steps": 6,
|
| 387 |
+
"success": 1
|
| 388 |
+
},
|
| 389 |
+
{
|
| 390 |
+
"episode": 53,
|
| 391 |
+
"seed": null,
|
| 392 |
+
"reward": 1.0,
|
| 393 |
+
"steps": 6,
|
| 394 |
+
"success": 1
|
| 395 |
+
},
|
| 396 |
+
{
|
| 397 |
+
"episode": 54,
|
| 398 |
+
"seed": null,
|
| 399 |
+
"reward": 1.0,
|
| 400 |
+
"steps": 6,
|
| 401 |
+
"success": 1
|
| 402 |
+
},
|
| 403 |
+
{
|
| 404 |
+
"episode": 55,
|
| 405 |
+
"seed": null,
|
| 406 |
+
"reward": 1.0,
|
| 407 |
+
"steps": 6,
|
| 408 |
+
"success": 1
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"episode": 56,
|
| 412 |
+
"seed": null,
|
| 413 |
+
"reward": 1.0,
|
| 414 |
+
"steps": 6,
|
| 415 |
+
"success": 1
|
| 416 |
+
},
|
| 417 |
+
{
|
| 418 |
+
"episode": 57,
|
| 419 |
+
"seed": null,
|
| 420 |
+
"reward": 1.0,
|
| 421 |
+
"steps": 6,
|
| 422 |
+
"success": 1
|
| 423 |
+
},
|
| 424 |
+
{
|
| 425 |
+
"episode": 58,
|
| 426 |
+
"seed": null,
|
| 427 |
+
"reward": 1.0,
|
| 428 |
+
"steps": 6,
|
| 429 |
+
"success": 1
|
| 430 |
+
},
|
| 431 |
+
{
|
| 432 |
+
"episode": 59,
|
| 433 |
+
"seed": null,
|
| 434 |
+
"reward": 1.0,
|
| 435 |
+
"steps": 6,
|
| 436 |
+
"success": 1
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
"episode": 60,
|
| 440 |
+
"seed": null,
|
| 441 |
+
"reward": 1.0,
|
| 442 |
+
"steps": 6,
|
| 443 |
+
"success": 1
|
| 444 |
+
},
|
| 445 |
+
{
|
| 446 |
+
"episode": 61,
|
| 447 |
+
"seed": null,
|
| 448 |
+
"reward": 1.0,
|
| 449 |
+
"steps": 6,
|
| 450 |
+
"success": 1
|
| 451 |
+
},
|
| 452 |
+
{
|
| 453 |
+
"episode": 62,
|
| 454 |
+
"seed": null,
|
| 455 |
+
"reward": 1.0,
|
| 456 |
+
"steps": 6,
|
| 457 |
+
"success": 1
|
| 458 |
+
},
|
| 459 |
+
{
|
| 460 |
+
"episode": 63,
|
| 461 |
+
"seed": null,
|
| 462 |
+
"reward": 1.0,
|
| 463 |
+
"steps": 6,
|
| 464 |
+
"success": 1
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"episode": 64,
|
| 468 |
+
"seed": null,
|
| 469 |
+
"reward": 1.0,
|
| 470 |
+
"steps": 6,
|
| 471 |
+
"success": 1
|
| 472 |
+
},
|
| 473 |
+
{
|
| 474 |
+
"episode": 65,
|
| 475 |
+
"seed": null,
|
| 476 |
+
"reward": 1.0,
|
| 477 |
+
"steps": 6,
|
| 478 |
+
"success": 1
|
| 479 |
+
},
|
| 480 |
+
{
|
| 481 |
+
"episode": 66,
|
| 482 |
+
"seed": null,
|
| 483 |
+
"reward": 1.0,
|
| 484 |
+
"steps": 6,
|
| 485 |
+
"success": 1
|
| 486 |
+
},
|
| 487 |
+
{
|
| 488 |
+
"episode": 67,
|
| 489 |
+
"seed": null,
|
| 490 |
+
"reward": 1.0,
|
| 491 |
+
"steps": 6,
|
| 492 |
+
"success": 1
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"episode": 68,
|
| 496 |
+
"seed": null,
|
| 497 |
+
"reward": 1.0,
|
| 498 |
+
"steps": 6,
|
| 499 |
+
"success": 1
|
| 500 |
+
},
|
| 501 |
+
{
|
| 502 |
+
"episode": 69,
|
| 503 |
+
"seed": null,
|
| 504 |
+
"reward": 1.0,
|
| 505 |
+
"steps": 6,
|
| 506 |
+
"success": 1
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"episode": 70,
|
| 510 |
+
"seed": null,
|
| 511 |
+
"reward": 1.0,
|
| 512 |
+
"steps": 6,
|
| 513 |
+
"success": 1
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"episode": 71,
|
| 517 |
+
"seed": null,
|
| 518 |
+
"reward": 1.0,
|
| 519 |
+
"steps": 6,
|
| 520 |
+
"success": 1
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"episode": 72,
|
| 524 |
+
"seed": null,
|
| 525 |
+
"reward": 1.0,
|
| 526 |
+
"steps": 6,
|
| 527 |
+
"success": 1
|
| 528 |
+
},
|
| 529 |
+
{
|
| 530 |
+
"episode": 73,
|
| 531 |
+
"seed": null,
|
| 532 |
+
"reward": 1.0,
|
| 533 |
+
"steps": 6,
|
| 534 |
+
"success": 1
|
| 535 |
+
},
|
| 536 |
+
{
|
| 537 |
+
"episode": 74,
|
| 538 |
+
"seed": null,
|
| 539 |
+
"reward": 1.0,
|
| 540 |
+
"steps": 6,
|
| 541 |
+
"success": 1
|
| 542 |
+
},
|
| 543 |
+
{
|
| 544 |
+
"episode": 75,
|
| 545 |
+
"seed": null,
|
| 546 |
+
"reward": 1.0,
|
| 547 |
+
"steps": 6,
|
| 548 |
+
"success": 1
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"episode": 76,
|
| 552 |
+
"seed": null,
|
| 553 |
+
"reward": 1.0,
|
| 554 |
+
"steps": 6,
|
| 555 |
+
"success": 1
|
| 556 |
+
},
|
| 557 |
+
{
|
| 558 |
+
"episode": 77,
|
| 559 |
+
"seed": null,
|
| 560 |
+
"reward": 1.0,
|
| 561 |
+
"steps": 6,
|
| 562 |
+
"success": 1
|
| 563 |
+
},
|
| 564 |
+
{
|
| 565 |
+
"episode": 78,
|
| 566 |
+
"seed": null,
|
| 567 |
+
"reward": 1.0,
|
| 568 |
+
"steps": 6,
|
| 569 |
+
"success": 1
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"episode": 79,
|
| 573 |
+
"seed": null,
|
| 574 |
+
"reward": 1.0,
|
| 575 |
+
"steps": 6,
|
| 576 |
+
"success": 1
|
| 577 |
+
},
|
| 578 |
+
{
|
| 579 |
+
"episode": 80,
|
| 580 |
+
"seed": null,
|
| 581 |
+
"reward": 1.0,
|
| 582 |
+
"steps": 6,
|
| 583 |
+
"success": 1
|
| 584 |
+
},
|
| 585 |
+
{
|
| 586 |
+
"episode": 81,
|
| 587 |
+
"seed": null,
|
| 588 |
+
"reward": 1.0,
|
| 589 |
+
"steps": 6,
|
| 590 |
+
"success": 1
|
| 591 |
+
},
|
| 592 |
+
{
|
| 593 |
+
"episode": 82,
|
| 594 |
+
"seed": null,
|
| 595 |
+
"reward": 1.0,
|
| 596 |
+
"steps": 6,
|
| 597 |
+
"success": 1
|
| 598 |
+
},
|
| 599 |
+
{
|
| 600 |
+
"episode": 83,
|
| 601 |
+
"seed": null,
|
| 602 |
+
"reward": 1.0,
|
| 603 |
+
"steps": 6,
|
| 604 |
+
"success": 1
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"episode": 84,
|
| 608 |
+
"seed": null,
|
| 609 |
+
"reward": 1.0,
|
| 610 |
+
"steps": 6,
|
| 611 |
+
"success": 1
|
| 612 |
+
},
|
| 613 |
+
{
|
| 614 |
+
"episode": 85,
|
| 615 |
+
"seed": null,
|
| 616 |
+
"reward": 1.0,
|
| 617 |
+
"steps": 6,
|
| 618 |
+
"success": 1
|
| 619 |
+
},
|
| 620 |
+
{
|
| 621 |
+
"episode": 86,
|
| 622 |
+
"seed": null,
|
| 623 |
+
"reward": 1.0,
|
| 624 |
+
"steps": 6,
|
| 625 |
+
"success": 1
|
| 626 |
+
},
|
| 627 |
+
{
|
| 628 |
+
"episode": 87,
|
| 629 |
+
"seed": null,
|
| 630 |
+
"reward": 1.0,
|
| 631 |
+
"steps": 6,
|
| 632 |
+
"success": 1
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"episode": 88,
|
| 636 |
+
"seed": null,
|
| 637 |
+
"reward": 1.0,
|
| 638 |
+
"steps": 6,
|
| 639 |
+
"success": 1
|
| 640 |
+
},
|
| 641 |
+
{
|
| 642 |
+
"episode": 89,
|
| 643 |
+
"seed": null,
|
| 644 |
+
"reward": 1.0,
|
| 645 |
+
"steps": 6,
|
| 646 |
+
"success": 1
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"episode": 90,
|
| 650 |
+
"seed": null,
|
| 651 |
+
"reward": 1.0,
|
| 652 |
+
"steps": 6,
|
| 653 |
+
"success": 1
|
| 654 |
+
},
|
| 655 |
+
{
|
| 656 |
+
"episode": 91,
|
| 657 |
+
"seed": null,
|
| 658 |
+
"reward": 1.0,
|
| 659 |
+
"steps": 6,
|
| 660 |
+
"success": 1
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"episode": 92,
|
| 664 |
+
"seed": null,
|
| 665 |
+
"reward": 1.0,
|
| 666 |
+
"steps": 6,
|
| 667 |
+
"success": 1
|
| 668 |
+
},
|
| 669 |
+
{
|
| 670 |
+
"episode": 93,
|
| 671 |
+
"seed": null,
|
| 672 |
+
"reward": 1.0,
|
| 673 |
+
"steps": 6,
|
| 674 |
+
"success": 1
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"episode": 94,
|
| 678 |
+
"seed": null,
|
| 679 |
+
"reward": 1.0,
|
| 680 |
+
"steps": 6,
|
| 681 |
+
"success": 1
|
| 682 |
+
},
|
| 683 |
+
{
|
| 684 |
+
"episode": 95,
|
| 685 |
+
"seed": null,
|
| 686 |
+
"reward": 1.0,
|
| 687 |
+
"steps": 6,
|
| 688 |
+
"success": 1
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"episode": 96,
|
| 692 |
+
"seed": null,
|
| 693 |
+
"reward": 1.0,
|
| 694 |
+
"steps": 6,
|
| 695 |
+
"success": 1
|
| 696 |
+
},
|
| 697 |
+
{
|
| 698 |
+
"episode": 97,
|
| 699 |
+
"seed": null,
|
| 700 |
+
"reward": 1.0,
|
| 701 |
+
"steps": 6,
|
| 702 |
+
"success": 1
|
| 703 |
+
},
|
| 704 |
+
{
|
| 705 |
+
"episode": 98,
|
| 706 |
+
"seed": null,
|
| 707 |
+
"reward": 1.0,
|
| 708 |
+
"steps": 6,
|
| 709 |
+
"success": 1
|
| 710 |
+
},
|
| 711 |
+
{
|
| 712 |
+
"episode": 99,
|
| 713 |
+
"seed": null,
|
| 714 |
+
"reward": 1.0,
|
| 715 |
+
"steps": 6,
|
| 716 |
+
"success": 1
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"episode": 100,
|
| 720 |
+
"seed": null,
|
| 721 |
+
"reward": 1.0,
|
| 722 |
+
"steps": 6,
|
| 723 |
+
"success": 1
|
| 724 |
+
}
|
| 725 |
+
],
|
| 726 |
+
"evaluation_seconds": 0.01
|
| 727 |
+
}
|
eval_results/eval_frozenlake4x4_slippery.json
ADDED
|
@@ -0,0 +1,727 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run": "frozenlake4x4_slippery",
|
| 3 |
+
"env_id": "FrozenLake-v1",
|
| 4 |
+
"env_kwargs": {
|
| 5 |
+
"map_name": "4x4",
|
| 6 |
+
"is_slippery": true
|
| 7 |
+
},
|
| 8 |
+
"n_training_episodes": 20000,
|
| 9 |
+
"n_episodes": 100,
|
| 10 |
+
"mean_reward": 0.74,
|
| 11 |
+
"std_reward": 0.4386342439892262,
|
| 12 |
+
"min_reward": 0.0,
|
| 13 |
+
"max_reward": 1.0,
|
| 14 |
+
"success_rate": 0.74,
|
| 15 |
+
"mean_steps": 39.41,
|
| 16 |
+
"policy": "greedy (argmax Q)",
|
| 17 |
+
"model_file": "models\\qtable_frozenlake4x4_slippery.pkl",
|
| 18 |
+
"qtable_shape": [
|
| 19 |
+
16,
|
| 20 |
+
4
|
| 21 |
+
],
|
| 22 |
+
"qtable_nonzero": 44,
|
| 23 |
+
"evaluated_at": "2026-10-30T22:46:59",
|
| 24 |
+
"episodes": [
|
| 25 |
+
{
|
| 26 |
+
"episode": 1,
|
| 27 |
+
"seed": 0,
|
| 28 |
+
"reward": 0.0,
|
| 29 |
+
"steps": 54,
|
| 30 |
+
"success": 0
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"episode": 2,
|
| 34 |
+
"seed": 1,
|
| 35 |
+
"reward": 1.0,
|
| 36 |
+
"steps": 41,
|
| 37 |
+
"success": 1
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"episode": 3,
|
| 41 |
+
"seed": 2,
|
| 42 |
+
"reward": 0.0,
|
| 43 |
+
"steps": 99,
|
| 44 |
+
"success": 0
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"episode": 4,
|
| 48 |
+
"seed": 3,
|
| 49 |
+
"reward": 1.0,
|
| 50 |
+
"steps": 27,
|
| 51 |
+
"success": 1
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"episode": 5,
|
| 55 |
+
"seed": 4,
|
| 56 |
+
"reward": 1.0,
|
| 57 |
+
"steps": 98,
|
| 58 |
+
"success": 1
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"episode": 6,
|
| 62 |
+
"seed": 5,
|
| 63 |
+
"reward": 1.0,
|
| 64 |
+
"steps": 78,
|
| 65 |
+
"success": 1
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"episode": 7,
|
| 69 |
+
"seed": 6,
|
| 70 |
+
"reward": 1.0,
|
| 71 |
+
"steps": 24,
|
| 72 |
+
"success": 1
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"episode": 8,
|
| 76 |
+
"seed": 7,
|
| 77 |
+
"reward": 1.0,
|
| 78 |
+
"steps": 16,
|
| 79 |
+
"success": 1
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"episode": 9,
|
| 83 |
+
"seed": 8,
|
| 84 |
+
"reward": 1.0,
|
| 85 |
+
"steps": 42,
|
| 86 |
+
"success": 1
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"episode": 10,
|
| 90 |
+
"seed": 9,
|
| 91 |
+
"reward": 1.0,
|
| 92 |
+
"steps": 23,
|
| 93 |
+
"success": 1
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"episode": 11,
|
| 97 |
+
"seed": 10,
|
| 98 |
+
"reward": 1.0,
|
| 99 |
+
"steps": 96,
|
| 100 |
+
"success": 1
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"episode": 12,
|
| 104 |
+
"seed": 11,
|
| 105 |
+
"reward": 0.0,
|
| 106 |
+
"steps": 30,
|
| 107 |
+
"success": 0
|
| 108 |
+
},
|
| 109 |
+
{
|
| 110 |
+
"episode": 13,
|
| 111 |
+
"seed": 12,
|
| 112 |
+
"reward": 1.0,
|
| 113 |
+
"steps": 17,
|
| 114 |
+
"success": 1
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"episode": 14,
|
| 118 |
+
"seed": 13,
|
| 119 |
+
"reward": 0.0,
|
| 120 |
+
"steps": 13,
|
| 121 |
+
"success": 0
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"episode": 15,
|
| 125 |
+
"seed": 14,
|
| 126 |
+
"reward": 1.0,
|
| 127 |
+
"steps": 18,
|
| 128 |
+
"success": 1
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"episode": 16,
|
| 132 |
+
"seed": 15,
|
| 133 |
+
"reward": 1.0,
|
| 134 |
+
"steps": 25,
|
| 135 |
+
"success": 1
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"episode": 17,
|
| 139 |
+
"seed": 16,
|
| 140 |
+
"reward": 1.0,
|
| 141 |
+
"steps": 37,
|
| 142 |
+
"success": 1
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"episode": 18,
|
| 146 |
+
"seed": 17,
|
| 147 |
+
"reward": 1.0,
|
| 148 |
+
"steps": 24,
|
| 149 |
+
"success": 1
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"episode": 19,
|
| 153 |
+
"seed": 18,
|
| 154 |
+
"reward": 1.0,
|
| 155 |
+
"steps": 22,
|
| 156 |
+
"success": 1
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"episode": 20,
|
| 160 |
+
"seed": 19,
|
| 161 |
+
"reward": 0.0,
|
| 162 |
+
"steps": 76,
|
| 163 |
+
"success": 0
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"episode": 21,
|
| 167 |
+
"seed": 20,
|
| 168 |
+
"reward": 1.0,
|
| 169 |
+
"steps": 34,
|
| 170 |
+
"success": 1
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"episode": 22,
|
| 174 |
+
"seed": 21,
|
| 175 |
+
"reward": 1.0,
|
| 176 |
+
"steps": 26,
|
| 177 |
+
"success": 1
|
| 178 |
+
},
|
| 179 |
+
{
|
| 180 |
+
"episode": 23,
|
| 181 |
+
"seed": 22,
|
| 182 |
+
"reward": 1.0,
|
| 183 |
+
"steps": 19,
|
| 184 |
+
"success": 1
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"episode": 24,
|
| 188 |
+
"seed": 23,
|
| 189 |
+
"reward": 1.0,
|
| 190 |
+
"steps": 23,
|
| 191 |
+
"success": 1
|
| 192 |
+
},
|
| 193 |
+
{
|
| 194 |
+
"episode": 25,
|
| 195 |
+
"seed": 24,
|
| 196 |
+
"reward": 1.0,
|
| 197 |
+
"steps": 22,
|
| 198 |
+
"success": 1
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"episode": 26,
|
| 202 |
+
"seed": 25,
|
| 203 |
+
"reward": 1.0,
|
| 204 |
+
"steps": 17,
|
| 205 |
+
"success": 1
|
| 206 |
+
},
|
| 207 |
+
{
|
| 208 |
+
"episode": 27,
|
| 209 |
+
"seed": 26,
|
| 210 |
+
"reward": 1.0,
|
| 211 |
+
"steps": 23,
|
| 212 |
+
"success": 1
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"episode": 28,
|
| 216 |
+
"seed": 27,
|
| 217 |
+
"reward": 0.0,
|
| 218 |
+
"steps": 30,
|
| 219 |
+
"success": 0
|
| 220 |
+
},
|
| 221 |
+
{
|
| 222 |
+
"episode": 29,
|
| 223 |
+
"seed": 28,
|
| 224 |
+
"reward": 1.0,
|
| 225 |
+
"steps": 9,
|
| 226 |
+
"success": 1
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
"episode": 30,
|
| 230 |
+
"seed": 29,
|
| 231 |
+
"reward": 1.0,
|
| 232 |
+
"steps": 32,
|
| 233 |
+
"success": 1
|
| 234 |
+
},
|
| 235 |
+
{
|
| 236 |
+
"episode": 31,
|
| 237 |
+
"seed": 30,
|
| 238 |
+
"reward": 0.0,
|
| 239 |
+
"steps": 31,
|
| 240 |
+
"success": 0
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"episode": 32,
|
| 244 |
+
"seed": 31,
|
| 245 |
+
"reward": 0.0,
|
| 246 |
+
"steps": 10,
|
| 247 |
+
"success": 0
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"episode": 33,
|
| 251 |
+
"seed": 32,
|
| 252 |
+
"reward": 0.0,
|
| 253 |
+
"steps": 46,
|
| 254 |
+
"success": 0
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"episode": 34,
|
| 258 |
+
"seed": 33,
|
| 259 |
+
"reward": 0.0,
|
| 260 |
+
"steps": 99,
|
| 261 |
+
"success": 0
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"episode": 35,
|
| 265 |
+
"seed": 34,
|
| 266 |
+
"reward": 1.0,
|
| 267 |
+
"steps": 16,
|
| 268 |
+
"success": 1
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"episode": 36,
|
| 272 |
+
"seed": 35,
|
| 273 |
+
"reward": 0.0,
|
| 274 |
+
"steps": 69,
|
| 275 |
+
"success": 0
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"episode": 37,
|
| 279 |
+
"seed": 36,
|
| 280 |
+
"reward": 1.0,
|
| 281 |
+
"steps": 13,
|
| 282 |
+
"success": 1
|
| 283 |
+
},
|
| 284 |
+
{
|
| 285 |
+
"episode": 38,
|
| 286 |
+
"seed": 37,
|
| 287 |
+
"reward": 0.0,
|
| 288 |
+
"steps": 30,
|
| 289 |
+
"success": 0
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"episode": 39,
|
| 293 |
+
"seed": 38,
|
| 294 |
+
"reward": 1.0,
|
| 295 |
+
"steps": 27,
|
| 296 |
+
"success": 1
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"episode": 40,
|
| 300 |
+
"seed": 39,
|
| 301 |
+
"reward": 1.0,
|
| 302 |
+
"steps": 26,
|
| 303 |
+
"success": 1
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"episode": 41,
|
| 307 |
+
"seed": 40,
|
| 308 |
+
"reward": 1.0,
|
| 309 |
+
"steps": 9,
|
| 310 |
+
"success": 1
|
| 311 |
+
},
|
| 312 |
+
{
|
| 313 |
+
"episode": 42,
|
| 314 |
+
"seed": 41,
|
| 315 |
+
"reward": 1.0,
|
| 316 |
+
"steps": 37,
|
| 317 |
+
"success": 1
|
| 318 |
+
},
|
| 319 |
+
{
|
| 320 |
+
"episode": 43,
|
| 321 |
+
"seed": 42,
|
| 322 |
+
"reward": 1.0,
|
| 323 |
+
"steps": 7,
|
| 324 |
+
"success": 1
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"episode": 44,
|
| 328 |
+
"seed": 43,
|
| 329 |
+
"reward": 1.0,
|
| 330 |
+
"steps": 47,
|
| 331 |
+
"success": 1
|
| 332 |
+
},
|
| 333 |
+
{
|
| 334 |
+
"episode": 45,
|
| 335 |
+
"seed": 44,
|
| 336 |
+
"reward": 1.0,
|
| 337 |
+
"steps": 48,
|
| 338 |
+
"success": 1
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"episode": 46,
|
| 342 |
+
"seed": 45,
|
| 343 |
+
"reward": 1.0,
|
| 344 |
+
"steps": 53,
|
| 345 |
+
"success": 1
|
| 346 |
+
},
|
| 347 |
+
{
|
| 348 |
+
"episode": 47,
|
| 349 |
+
"seed": 46,
|
| 350 |
+
"reward": 1.0,
|
| 351 |
+
"steps": 27,
|
| 352 |
+
"success": 1
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"episode": 48,
|
| 356 |
+
"seed": 47,
|
| 357 |
+
"reward": 1.0,
|
| 358 |
+
"steps": 27,
|
| 359 |
+
"success": 1
|
| 360 |
+
},
|
| 361 |
+
{
|
| 362 |
+
"episode": 49,
|
| 363 |
+
"seed": 48,
|
| 364 |
+
"reward": 1.0,
|
| 365 |
+
"steps": 16,
|
| 366 |
+
"success": 1
|
| 367 |
+
},
|
| 368 |
+
{
|
| 369 |
+
"episode": 50,
|
| 370 |
+
"seed": 49,
|
| 371 |
+
"reward": 1.0,
|
| 372 |
+
"steps": 90,
|
| 373 |
+
"success": 1
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"episode": 51,
|
| 377 |
+
"seed": 50,
|
| 378 |
+
"reward": 1.0,
|
| 379 |
+
"steps": 48,
|
| 380 |
+
"success": 1
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"episode": 52,
|
| 384 |
+
"seed": 51,
|
| 385 |
+
"reward": 0.0,
|
| 386 |
+
"steps": 17,
|
| 387 |
+
"success": 0
|
| 388 |
+
},
|
| 389 |
+
{
|
| 390 |
+
"episode": 53,
|
| 391 |
+
"seed": 52,
|
| 392 |
+
"reward": 1.0,
|
| 393 |
+
"steps": 88,
|
| 394 |
+
"success": 1
|
| 395 |
+
},
|
| 396 |
+
{
|
| 397 |
+
"episode": 54,
|
| 398 |
+
"seed": 53,
|
| 399 |
+
"reward": 1.0,
|
| 400 |
+
"steps": 25,
|
| 401 |
+
"success": 1
|
| 402 |
+
},
|
| 403 |
+
{
|
| 404 |
+
"episode": 55,
|
| 405 |
+
"seed": 54,
|
| 406 |
+
"reward": 0.0,
|
| 407 |
+
"steps": 25,
|
| 408 |
+
"success": 0
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"episode": 56,
|
| 412 |
+
"seed": 55,
|
| 413 |
+
"reward": 1.0,
|
| 414 |
+
"steps": 18,
|
| 415 |
+
"success": 1
|
| 416 |
+
},
|
| 417 |
+
{
|
| 418 |
+
"episode": 57,
|
| 419 |
+
"seed": 56,
|
| 420 |
+
"reward": 1.0,
|
| 421 |
+
"steps": 46,
|
| 422 |
+
"success": 1
|
| 423 |
+
},
|
| 424 |
+
{
|
| 425 |
+
"episode": 58,
|
| 426 |
+
"seed": 57,
|
| 427 |
+
"reward": 1.0,
|
| 428 |
+
"steps": 29,
|
| 429 |
+
"success": 1
|
| 430 |
+
},
|
| 431 |
+
{
|
| 432 |
+
"episode": 59,
|
| 433 |
+
"seed": 58,
|
| 434 |
+
"reward": 1.0,
|
| 435 |
+
"steps": 43,
|
| 436 |
+
"success": 1
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
"episode": 60,
|
| 440 |
+
"seed": 59,
|
| 441 |
+
"reward": 1.0,
|
| 442 |
+
"steps": 46,
|
| 443 |
+
"success": 1
|
| 444 |
+
},
|
| 445 |
+
{
|
| 446 |
+
"episode": 61,
|
| 447 |
+
"seed": 60,
|
| 448 |
+
"reward": 0.0,
|
| 449 |
+
"steps": 99,
|
| 450 |
+
"success": 0
|
| 451 |
+
},
|
| 452 |
+
{
|
| 453 |
+
"episode": 62,
|
| 454 |
+
"seed": 61,
|
| 455 |
+
"reward": 1.0,
|
| 456 |
+
"steps": 22,
|
| 457 |
+
"success": 1
|
| 458 |
+
},
|
| 459 |
+
{
|
| 460 |
+
"episode": 63,
|
| 461 |
+
"seed": 62,
|
| 462 |
+
"reward": 1.0,
|
| 463 |
+
"steps": 7,
|
| 464 |
+
"success": 1
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"episode": 64,
|
| 468 |
+
"seed": 63,
|
| 469 |
+
"reward": 1.0,
|
| 470 |
+
"steps": 29,
|
| 471 |
+
"success": 1
|
| 472 |
+
},
|
| 473 |
+
{
|
| 474 |
+
"episode": 65,
|
| 475 |
+
"seed": 64,
|
| 476 |
+
"reward": 0.0,
|
| 477 |
+
"steps": 26,
|
| 478 |
+
"success": 0
|
| 479 |
+
},
|
| 480 |
+
{
|
| 481 |
+
"episode": 66,
|
| 482 |
+
"seed": 65,
|
| 483 |
+
"reward": 1.0,
|
| 484 |
+
"steps": 26,
|
| 485 |
+
"success": 1
|
| 486 |
+
},
|
| 487 |
+
{
|
| 488 |
+
"episode": 67,
|
| 489 |
+
"seed": 66,
|
| 490 |
+
"reward": 1.0,
|
| 491 |
+
"steps": 33,
|
| 492 |
+
"success": 1
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"episode": 68,
|
| 496 |
+
"seed": 67,
|
| 497 |
+
"reward": 1.0,
|
| 498 |
+
"steps": 55,
|
| 499 |
+
"success": 1
|
| 500 |
+
},
|
| 501 |
+
{
|
| 502 |
+
"episode": 69,
|
| 503 |
+
"seed": 68,
|
| 504 |
+
"reward": 1.0,
|
| 505 |
+
"steps": 19,
|
| 506 |
+
"success": 1
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"episode": 70,
|
| 510 |
+
"seed": 69,
|
| 511 |
+
"reward": 1.0,
|
| 512 |
+
"steps": 17,
|
| 513 |
+
"success": 1
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"episode": 71,
|
| 517 |
+
"seed": 70,
|
| 518 |
+
"reward": 1.0,
|
| 519 |
+
"steps": 84,
|
| 520 |
+
"success": 1
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"episode": 72,
|
| 524 |
+
"seed": 71,
|
| 525 |
+
"reward": 0.0,
|
| 526 |
+
"steps": 42,
|
| 527 |
+
"success": 0
|
| 528 |
+
},
|
| 529 |
+
{
|
| 530 |
+
"episode": 73,
|
| 531 |
+
"seed": 72,
|
| 532 |
+
"reward": 0.0,
|
| 533 |
+
"steps": 62,
|
| 534 |
+
"success": 0
|
| 535 |
+
},
|
| 536 |
+
{
|
| 537 |
+
"episode": 74,
|
| 538 |
+
"seed": 73,
|
| 539 |
+
"reward": 0.0,
|
| 540 |
+
"steps": 99,
|
| 541 |
+
"success": 0
|
| 542 |
+
},
|
| 543 |
+
{
|
| 544 |
+
"episode": 75,
|
| 545 |
+
"seed": 74,
|
| 546 |
+
"reward": 1.0,
|
| 547 |
+
"steps": 39,
|
| 548 |
+
"success": 1
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"episode": 76,
|
| 552 |
+
"seed": 75,
|
| 553 |
+
"reward": 1.0,
|
| 554 |
+
"steps": 16,
|
| 555 |
+
"success": 1
|
| 556 |
+
},
|
| 557 |
+
{
|
| 558 |
+
"episode": 77,
|
| 559 |
+
"seed": 76,
|
| 560 |
+
"reward": 1.0,
|
| 561 |
+
"steps": 21,
|
| 562 |
+
"success": 1
|
| 563 |
+
},
|
| 564 |
+
{
|
| 565 |
+
"episode": 78,
|
| 566 |
+
"seed": 77,
|
| 567 |
+
"reward": 0.0,
|
| 568 |
+
"steps": 20,
|
| 569 |
+
"success": 0
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"episode": 79,
|
| 573 |
+
"seed": 78,
|
| 574 |
+
"reward": 1.0,
|
| 575 |
+
"steps": 14,
|
| 576 |
+
"success": 1
|
| 577 |
+
},
|
| 578 |
+
{
|
| 579 |
+
"episode": 80,
|
| 580 |
+
"seed": 79,
|
| 581 |
+
"reward": 1.0,
|
| 582 |
+
"steps": 23,
|
| 583 |
+
"success": 1
|
| 584 |
+
},
|
| 585 |
+
{
|
| 586 |
+
"episode": 81,
|
| 587 |
+
"seed": 80,
|
| 588 |
+
"reward": 0.0,
|
| 589 |
+
"steps": 12,
|
| 590 |
+
"success": 0
|
| 591 |
+
},
|
| 592 |
+
{
|
| 593 |
+
"episode": 82,
|
| 594 |
+
"seed": 81,
|
| 595 |
+
"reward": 1.0,
|
| 596 |
+
"steps": 58,
|
| 597 |
+
"success": 1
|
| 598 |
+
},
|
| 599 |
+
{
|
| 600 |
+
"episode": 83,
|
| 601 |
+
"seed": 82,
|
| 602 |
+
"reward": 1.0,
|
| 603 |
+
"steps": 12,
|
| 604 |
+
"success": 1
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"episode": 84,
|
| 608 |
+
"seed": 83,
|
| 609 |
+
"reward": 1.0,
|
| 610 |
+
"steps": 31,
|
| 611 |
+
"success": 1
|
| 612 |
+
},
|
| 613 |
+
{
|
| 614 |
+
"episode": 85,
|
| 615 |
+
"seed": 84,
|
| 616 |
+
"reward": 0.0,
|
| 617 |
+
"steps": 11,
|
| 618 |
+
"success": 0
|
| 619 |
+
},
|
| 620 |
+
{
|
| 621 |
+
"episode": 86,
|
| 622 |
+
"seed": 85,
|
| 623 |
+
"reward": 0.0,
|
| 624 |
+
"steps": 73,
|
| 625 |
+
"success": 0
|
| 626 |
+
},
|
| 627 |
+
{
|
| 628 |
+
"episode": 87,
|
| 629 |
+
"seed": 86,
|
| 630 |
+
"reward": 1.0,
|
| 631 |
+
"steps": 14,
|
| 632 |
+
"success": 1
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"episode": 88,
|
| 636 |
+
"seed": 87,
|
| 637 |
+
"reward": 0.0,
|
| 638 |
+
"steps": 99,
|
| 639 |
+
"success": 0
|
| 640 |
+
},
|
| 641 |
+
{
|
| 642 |
+
"episode": 89,
|
| 643 |
+
"seed": 88,
|
| 644 |
+
"reward": 1.0,
|
| 645 |
+
"steps": 82,
|
| 646 |
+
"success": 1
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"episode": 90,
|
| 650 |
+
"seed": 89,
|
| 651 |
+
"reward": 0.0,
|
| 652 |
+
"steps": 99,
|
| 653 |
+
"success": 0
|
| 654 |
+
},
|
| 655 |
+
{
|
| 656 |
+
"episode": 91,
|
| 657 |
+
"seed": 90,
|
| 658 |
+
"reward": 1.0,
|
| 659 |
+
"steps": 14,
|
| 660 |
+
"success": 1
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"episode": 92,
|
| 664 |
+
"seed": 91,
|
| 665 |
+
"reward": 0.0,
|
| 666 |
+
"steps": 72,
|
| 667 |
+
"success": 0
|
| 668 |
+
},
|
| 669 |
+
{
|
| 670 |
+
"episode": 93,
|
| 671 |
+
"seed": 92,
|
| 672 |
+
"reward": 1.0,
|
| 673 |
+
"steps": 59,
|
| 674 |
+
"success": 1
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"episode": 94,
|
| 678 |
+
"seed": 93,
|
| 679 |
+
"reward": 1.0,
|
| 680 |
+
"steps": 76,
|
| 681 |
+
"success": 1
|
| 682 |
+
},
|
| 683 |
+
{
|
| 684 |
+
"episode": 95,
|
| 685 |
+
"seed": 94,
|
| 686 |
+
"reward": 1.0,
|
| 687 |
+
"steps": 26,
|
| 688 |
+
"success": 1
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"episode": 96,
|
| 692 |
+
"seed": 95,
|
| 693 |
+
"reward": 1.0,
|
| 694 |
+
"steps": 43,
|
| 695 |
+
"success": 1
|
| 696 |
+
},
|
| 697 |
+
{
|
| 698 |
+
"episode": 97,
|
| 699 |
+
"seed": 96,
|
| 700 |
+
"reward": 1.0,
|
| 701 |
+
"steps": 40,
|
| 702 |
+
"success": 1
|
| 703 |
+
},
|
| 704 |
+
{
|
| 705 |
+
"episode": 98,
|
| 706 |
+
"seed": 97,
|
| 707 |
+
"reward": 1.0,
|
| 708 |
+
"steps": 44,
|
| 709 |
+
"success": 1
|
| 710 |
+
},
|
| 711 |
+
{
|
| 712 |
+
"episode": 99,
|
| 713 |
+
"seed": 98,
|
| 714 |
+
"reward": 1.0,
|
| 715 |
+
"steps": 47,
|
| 716 |
+
"success": 1
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"episode": 100,
|
| 720 |
+
"seed": 99,
|
| 721 |
+
"reward": 1.0,
|
| 722 |
+
"steps": 68,
|
| 723 |
+
"success": 1
|
| 724 |
+
}
|
| 725 |
+
],
|
| 726 |
+
"evaluation_seconds": 0.04
|
| 727 |
+
}
|
eval_results/eval_frozenlake8x8.json
ADDED
|
@@ -0,0 +1,727 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run": "frozenlake8x8",
|
| 3 |
+
"env_id": "FrozenLake-v1",
|
| 4 |
+
"env_kwargs": {
|
| 5 |
+
"map_name": "8x8",
|
| 6 |
+
"is_slippery": false
|
| 7 |
+
},
|
| 8 |
+
"n_training_episodes": 60000,
|
| 9 |
+
"n_episodes": 100,
|
| 10 |
+
"mean_reward": 1.0,
|
| 11 |
+
"std_reward": 0.0,
|
| 12 |
+
"min_reward": 1.0,
|
| 13 |
+
"max_reward": 1.0,
|
| 14 |
+
"success_rate": 1.0,
|
| 15 |
+
"mean_steps": 14.0,
|
| 16 |
+
"policy": "greedy (argmax Q)",
|
| 17 |
+
"model_file": "models\\qtable_frozenlake8x8.pkl",
|
| 18 |
+
"qtable_shape": [
|
| 19 |
+
64,
|
| 20 |
+
4
|
| 21 |
+
],
|
| 22 |
+
"qtable_nonzero": 179,
|
| 23 |
+
"evaluated_at": "2026-10-30T22:47:24",
|
| 24 |
+
"episodes": [
|
| 25 |
+
{
|
| 26 |
+
"episode": 1,
|
| 27 |
+
"seed": 0,
|
| 28 |
+
"reward": 1.0,
|
| 29 |
+
"steps": 14,
|
| 30 |
+
"success": 1
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"episode": 2,
|
| 34 |
+
"seed": 1,
|
| 35 |
+
"reward": 1.0,
|
| 36 |
+
"steps": 14,
|
| 37 |
+
"success": 1
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
"episode": 3,
|
| 41 |
+
"seed": 2,
|
| 42 |
+
"reward": 1.0,
|
| 43 |
+
"steps": 14,
|
| 44 |
+
"success": 1
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"episode": 4,
|
| 48 |
+
"seed": 3,
|
| 49 |
+
"reward": 1.0,
|
| 50 |
+
"steps": 14,
|
| 51 |
+
"success": 1
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"episode": 5,
|
| 55 |
+
"seed": 4,
|
| 56 |
+
"reward": 1.0,
|
| 57 |
+
"steps": 14,
|
| 58 |
+
"success": 1
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"episode": 6,
|
| 62 |
+
"seed": 5,
|
| 63 |
+
"reward": 1.0,
|
| 64 |
+
"steps": 14,
|
| 65 |
+
"success": 1
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"episode": 7,
|
| 69 |
+
"seed": 6,
|
| 70 |
+
"reward": 1.0,
|
| 71 |
+
"steps": 14,
|
| 72 |
+
"success": 1
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"episode": 8,
|
| 76 |
+
"seed": 7,
|
| 77 |
+
"reward": 1.0,
|
| 78 |
+
"steps": 14,
|
| 79 |
+
"success": 1
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"episode": 9,
|
| 83 |
+
"seed": 8,
|
| 84 |
+
"reward": 1.0,
|
| 85 |
+
"steps": 14,
|
| 86 |
+
"success": 1
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"episode": 10,
|
| 90 |
+
"seed": 9,
|
| 91 |
+
"reward": 1.0,
|
| 92 |
+
"steps": 14,
|
| 93 |
+
"success": 1
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"episode": 11,
|
| 97 |
+
"seed": 10,
|
| 98 |
+
"reward": 1.0,
|
| 99 |
+
"steps": 14,
|
| 100 |
+
"success": 1
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"episode": 12,
|
| 104 |
+
"seed": 11,
|
| 105 |
+
"reward": 1.0,
|
| 106 |
+
"steps": 14,
|
| 107 |
+
"success": 1
|
| 108 |
+
},
|
| 109 |
+
{
|
| 110 |
+
"episode": 13,
|
| 111 |
+
"seed": 12,
|
| 112 |
+
"reward": 1.0,
|
| 113 |
+
"steps": 14,
|
| 114 |
+
"success": 1
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"episode": 14,
|
| 118 |
+
"seed": 13,
|
| 119 |
+
"reward": 1.0,
|
| 120 |
+
"steps": 14,
|
| 121 |
+
"success": 1
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"episode": 15,
|
| 125 |
+
"seed": 14,
|
| 126 |
+
"reward": 1.0,
|
| 127 |
+
"steps": 14,
|
| 128 |
+
"success": 1
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"episode": 16,
|
| 132 |
+
"seed": 15,
|
| 133 |
+
"reward": 1.0,
|
| 134 |
+
"steps": 14,
|
| 135 |
+
"success": 1
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"episode": 17,
|
| 139 |
+
"seed": 16,
|
| 140 |
+
"reward": 1.0,
|
| 141 |
+
"steps": 14,
|
| 142 |
+
"success": 1
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"episode": 18,
|
| 146 |
+
"seed": 17,
|
| 147 |
+
"reward": 1.0,
|
| 148 |
+
"steps": 14,
|
| 149 |
+
"success": 1
|
| 150 |
+
},
|
| 151 |
+
{
|
| 152 |
+
"episode": 19,
|
| 153 |
+
"seed": 18,
|
| 154 |
+
"reward": 1.0,
|
| 155 |
+
"steps": 14,
|
| 156 |
+
"success": 1
|
| 157 |
+
},
|
| 158 |
+
{
|
| 159 |
+
"episode": 20,
|
| 160 |
+
"seed": 19,
|
| 161 |
+
"reward": 1.0,
|
| 162 |
+
"steps": 14,
|
| 163 |
+
"success": 1
|
| 164 |
+
},
|
| 165 |
+
{
|
| 166 |
+
"episode": 21,
|
| 167 |
+
"seed": 20,
|
| 168 |
+
"reward": 1.0,
|
| 169 |
+
"steps": 14,
|
| 170 |
+
"success": 1
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"episode": 22,
|
| 174 |
+
"seed": 21,
|
| 175 |
+
"reward": 1.0,
|
| 176 |
+
"steps": 14,
|
| 177 |
+
"success": 1
|
| 178 |
+
},
|
| 179 |
+
{
|
| 180 |
+
"episode": 23,
|
| 181 |
+
"seed": 22,
|
| 182 |
+
"reward": 1.0,
|
| 183 |
+
"steps": 14,
|
| 184 |
+
"success": 1
|
| 185 |
+
},
|
| 186 |
+
{
|
| 187 |
+
"episode": 24,
|
| 188 |
+
"seed": 23,
|
| 189 |
+
"reward": 1.0,
|
| 190 |
+
"steps": 14,
|
| 191 |
+
"success": 1
|
| 192 |
+
},
|
| 193 |
+
{
|
| 194 |
+
"episode": 25,
|
| 195 |
+
"seed": 24,
|
| 196 |
+
"reward": 1.0,
|
| 197 |
+
"steps": 14,
|
| 198 |
+
"success": 1
|
| 199 |
+
},
|
| 200 |
+
{
|
| 201 |
+
"episode": 26,
|
| 202 |
+
"seed": 25,
|
| 203 |
+
"reward": 1.0,
|
| 204 |
+
"steps": 14,
|
| 205 |
+
"success": 1
|
| 206 |
+
},
|
| 207 |
+
{
|
| 208 |
+
"episode": 27,
|
| 209 |
+
"seed": 26,
|
| 210 |
+
"reward": 1.0,
|
| 211 |
+
"steps": 14,
|
| 212 |
+
"success": 1
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"episode": 28,
|
| 216 |
+
"seed": 27,
|
| 217 |
+
"reward": 1.0,
|
| 218 |
+
"steps": 14,
|
| 219 |
+
"success": 1
|
| 220 |
+
},
|
| 221 |
+
{
|
| 222 |
+
"episode": 29,
|
| 223 |
+
"seed": 28,
|
| 224 |
+
"reward": 1.0,
|
| 225 |
+
"steps": 14,
|
| 226 |
+
"success": 1
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
"episode": 30,
|
| 230 |
+
"seed": 29,
|
| 231 |
+
"reward": 1.0,
|
| 232 |
+
"steps": 14,
|
| 233 |
+
"success": 1
|
| 234 |
+
},
|
| 235 |
+
{
|
| 236 |
+
"episode": 31,
|
| 237 |
+
"seed": 30,
|
| 238 |
+
"reward": 1.0,
|
| 239 |
+
"steps": 14,
|
| 240 |
+
"success": 1
|
| 241 |
+
},
|
| 242 |
+
{
|
| 243 |
+
"episode": 32,
|
| 244 |
+
"seed": 31,
|
| 245 |
+
"reward": 1.0,
|
| 246 |
+
"steps": 14,
|
| 247 |
+
"success": 1
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"episode": 33,
|
| 251 |
+
"seed": 32,
|
| 252 |
+
"reward": 1.0,
|
| 253 |
+
"steps": 14,
|
| 254 |
+
"success": 1
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"episode": 34,
|
| 258 |
+
"seed": 33,
|
| 259 |
+
"reward": 1.0,
|
| 260 |
+
"steps": 14,
|
| 261 |
+
"success": 1
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"episode": 35,
|
| 265 |
+
"seed": 34,
|
| 266 |
+
"reward": 1.0,
|
| 267 |
+
"steps": 14,
|
| 268 |
+
"success": 1
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"episode": 36,
|
| 272 |
+
"seed": 35,
|
| 273 |
+
"reward": 1.0,
|
| 274 |
+
"steps": 14,
|
| 275 |
+
"success": 1
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"episode": 37,
|
| 279 |
+
"seed": 36,
|
| 280 |
+
"reward": 1.0,
|
| 281 |
+
"steps": 14,
|
| 282 |
+
"success": 1
|
| 283 |
+
},
|
| 284 |
+
{
|
| 285 |
+
"episode": 38,
|
| 286 |
+
"seed": 37,
|
| 287 |
+
"reward": 1.0,
|
| 288 |
+
"steps": 14,
|
| 289 |
+
"success": 1
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"episode": 39,
|
| 293 |
+
"seed": 38,
|
| 294 |
+
"reward": 1.0,
|
| 295 |
+
"steps": 14,
|
| 296 |
+
"success": 1
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"episode": 40,
|
| 300 |
+
"seed": 39,
|
| 301 |
+
"reward": 1.0,
|
| 302 |
+
"steps": 14,
|
| 303 |
+
"success": 1
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"episode": 41,
|
| 307 |
+
"seed": 40,
|
| 308 |
+
"reward": 1.0,
|
| 309 |
+
"steps": 14,
|
| 310 |
+
"success": 1
|
| 311 |
+
},
|
| 312 |
+
{
|
| 313 |
+
"episode": 42,
|
| 314 |
+
"seed": 41,
|
| 315 |
+
"reward": 1.0,
|
| 316 |
+
"steps": 14,
|
| 317 |
+
"success": 1
|
| 318 |
+
},
|
| 319 |
+
{
|
| 320 |
+
"episode": 43,
|
| 321 |
+
"seed": 42,
|
| 322 |
+
"reward": 1.0,
|
| 323 |
+
"steps": 14,
|
| 324 |
+
"success": 1
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"episode": 44,
|
| 328 |
+
"seed": 43,
|
| 329 |
+
"reward": 1.0,
|
| 330 |
+
"steps": 14,
|
| 331 |
+
"success": 1
|
| 332 |
+
},
|
| 333 |
+
{
|
| 334 |
+
"episode": 45,
|
| 335 |
+
"seed": 44,
|
| 336 |
+
"reward": 1.0,
|
| 337 |
+
"steps": 14,
|
| 338 |
+
"success": 1
|
| 339 |
+
},
|
| 340 |
+
{
|
| 341 |
+
"episode": 46,
|
| 342 |
+
"seed": 45,
|
| 343 |
+
"reward": 1.0,
|
| 344 |
+
"steps": 14,
|
| 345 |
+
"success": 1
|
| 346 |
+
},
|
| 347 |
+
{
|
| 348 |
+
"episode": 47,
|
| 349 |
+
"seed": 46,
|
| 350 |
+
"reward": 1.0,
|
| 351 |
+
"steps": 14,
|
| 352 |
+
"success": 1
|
| 353 |
+
},
|
| 354 |
+
{
|
| 355 |
+
"episode": 48,
|
| 356 |
+
"seed": 47,
|
| 357 |
+
"reward": 1.0,
|
| 358 |
+
"steps": 14,
|
| 359 |
+
"success": 1
|
| 360 |
+
},
|
| 361 |
+
{
|
| 362 |
+
"episode": 49,
|
| 363 |
+
"seed": 48,
|
| 364 |
+
"reward": 1.0,
|
| 365 |
+
"steps": 14,
|
| 366 |
+
"success": 1
|
| 367 |
+
},
|
| 368 |
+
{
|
| 369 |
+
"episode": 50,
|
| 370 |
+
"seed": 49,
|
| 371 |
+
"reward": 1.0,
|
| 372 |
+
"steps": 14,
|
| 373 |
+
"success": 1
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"episode": 51,
|
| 377 |
+
"seed": 50,
|
| 378 |
+
"reward": 1.0,
|
| 379 |
+
"steps": 14,
|
| 380 |
+
"success": 1
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
"episode": 52,
|
| 384 |
+
"seed": 51,
|
| 385 |
+
"reward": 1.0,
|
| 386 |
+
"steps": 14,
|
| 387 |
+
"success": 1
|
| 388 |
+
},
|
| 389 |
+
{
|
| 390 |
+
"episode": 53,
|
| 391 |
+
"seed": 52,
|
| 392 |
+
"reward": 1.0,
|
| 393 |
+
"steps": 14,
|
| 394 |
+
"success": 1
|
| 395 |
+
},
|
| 396 |
+
{
|
| 397 |
+
"episode": 54,
|
| 398 |
+
"seed": 53,
|
| 399 |
+
"reward": 1.0,
|
| 400 |
+
"steps": 14,
|
| 401 |
+
"success": 1
|
| 402 |
+
},
|
| 403 |
+
{
|
| 404 |
+
"episode": 55,
|
| 405 |
+
"seed": 54,
|
| 406 |
+
"reward": 1.0,
|
| 407 |
+
"steps": 14,
|
| 408 |
+
"success": 1
|
| 409 |
+
},
|
| 410 |
+
{
|
| 411 |
+
"episode": 56,
|
| 412 |
+
"seed": 55,
|
| 413 |
+
"reward": 1.0,
|
| 414 |
+
"steps": 14,
|
| 415 |
+
"success": 1
|
| 416 |
+
},
|
| 417 |
+
{
|
| 418 |
+
"episode": 57,
|
| 419 |
+
"seed": 56,
|
| 420 |
+
"reward": 1.0,
|
| 421 |
+
"steps": 14,
|
| 422 |
+
"success": 1
|
| 423 |
+
},
|
| 424 |
+
{
|
| 425 |
+
"episode": 58,
|
| 426 |
+
"seed": 57,
|
| 427 |
+
"reward": 1.0,
|
| 428 |
+
"steps": 14,
|
| 429 |
+
"success": 1
|
| 430 |
+
},
|
| 431 |
+
{
|
| 432 |
+
"episode": 59,
|
| 433 |
+
"seed": 58,
|
| 434 |
+
"reward": 1.0,
|
| 435 |
+
"steps": 14,
|
| 436 |
+
"success": 1
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
"episode": 60,
|
| 440 |
+
"seed": 59,
|
| 441 |
+
"reward": 1.0,
|
| 442 |
+
"steps": 14,
|
| 443 |
+
"success": 1
|
| 444 |
+
},
|
| 445 |
+
{
|
| 446 |
+
"episode": 61,
|
| 447 |
+
"seed": 60,
|
| 448 |
+
"reward": 1.0,
|
| 449 |
+
"steps": 14,
|
| 450 |
+
"success": 1
|
| 451 |
+
},
|
| 452 |
+
{
|
| 453 |
+
"episode": 62,
|
| 454 |
+
"seed": 61,
|
| 455 |
+
"reward": 1.0,
|
| 456 |
+
"steps": 14,
|
| 457 |
+
"success": 1
|
| 458 |
+
},
|
| 459 |
+
{
|
| 460 |
+
"episode": 63,
|
| 461 |
+
"seed": 62,
|
| 462 |
+
"reward": 1.0,
|
| 463 |
+
"steps": 14,
|
| 464 |
+
"success": 1
|
| 465 |
+
},
|
| 466 |
+
{
|
| 467 |
+
"episode": 64,
|
| 468 |
+
"seed": 63,
|
| 469 |
+
"reward": 1.0,
|
| 470 |
+
"steps": 14,
|
| 471 |
+
"success": 1
|
| 472 |
+
},
|
| 473 |
+
{
|
| 474 |
+
"episode": 65,
|
| 475 |
+
"seed": 64,
|
| 476 |
+
"reward": 1.0,
|
| 477 |
+
"steps": 14,
|
| 478 |
+
"success": 1
|
| 479 |
+
},
|
| 480 |
+
{
|
| 481 |
+
"episode": 66,
|
| 482 |
+
"seed": 65,
|
| 483 |
+
"reward": 1.0,
|
| 484 |
+
"steps": 14,
|
| 485 |
+
"success": 1
|
| 486 |
+
},
|
| 487 |
+
{
|
| 488 |
+
"episode": 67,
|
| 489 |
+
"seed": 66,
|
| 490 |
+
"reward": 1.0,
|
| 491 |
+
"steps": 14,
|
| 492 |
+
"success": 1
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"episode": 68,
|
| 496 |
+
"seed": 67,
|
| 497 |
+
"reward": 1.0,
|
| 498 |
+
"steps": 14,
|
| 499 |
+
"success": 1
|
| 500 |
+
},
|
| 501 |
+
{
|
| 502 |
+
"episode": 69,
|
| 503 |
+
"seed": 68,
|
| 504 |
+
"reward": 1.0,
|
| 505 |
+
"steps": 14,
|
| 506 |
+
"success": 1
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"episode": 70,
|
| 510 |
+
"seed": 69,
|
| 511 |
+
"reward": 1.0,
|
| 512 |
+
"steps": 14,
|
| 513 |
+
"success": 1
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"episode": 71,
|
| 517 |
+
"seed": 70,
|
| 518 |
+
"reward": 1.0,
|
| 519 |
+
"steps": 14,
|
| 520 |
+
"success": 1
|
| 521 |
+
},
|
| 522 |
+
{
|
| 523 |
+
"episode": 72,
|
| 524 |
+
"seed": 71,
|
| 525 |
+
"reward": 1.0,
|
| 526 |
+
"steps": 14,
|
| 527 |
+
"success": 1
|
| 528 |
+
},
|
| 529 |
+
{
|
| 530 |
+
"episode": 73,
|
| 531 |
+
"seed": 72,
|
| 532 |
+
"reward": 1.0,
|
| 533 |
+
"steps": 14,
|
| 534 |
+
"success": 1
|
| 535 |
+
},
|
| 536 |
+
{
|
| 537 |
+
"episode": 74,
|
| 538 |
+
"seed": 73,
|
| 539 |
+
"reward": 1.0,
|
| 540 |
+
"steps": 14,
|
| 541 |
+
"success": 1
|
| 542 |
+
},
|
| 543 |
+
{
|
| 544 |
+
"episode": 75,
|
| 545 |
+
"seed": 74,
|
| 546 |
+
"reward": 1.0,
|
| 547 |
+
"steps": 14,
|
| 548 |
+
"success": 1
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"episode": 76,
|
| 552 |
+
"seed": 75,
|
| 553 |
+
"reward": 1.0,
|
| 554 |
+
"steps": 14,
|
| 555 |
+
"success": 1
|
| 556 |
+
},
|
| 557 |
+
{
|
| 558 |
+
"episode": 77,
|
| 559 |
+
"seed": 76,
|
| 560 |
+
"reward": 1.0,
|
| 561 |
+
"steps": 14,
|
| 562 |
+
"success": 1
|
| 563 |
+
},
|
| 564 |
+
{
|
| 565 |
+
"episode": 78,
|
| 566 |
+
"seed": 77,
|
| 567 |
+
"reward": 1.0,
|
| 568 |
+
"steps": 14,
|
| 569 |
+
"success": 1
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"episode": 79,
|
| 573 |
+
"seed": 78,
|
| 574 |
+
"reward": 1.0,
|
| 575 |
+
"steps": 14,
|
| 576 |
+
"success": 1
|
| 577 |
+
},
|
| 578 |
+
{
|
| 579 |
+
"episode": 80,
|
| 580 |
+
"seed": 79,
|
| 581 |
+
"reward": 1.0,
|
| 582 |
+
"steps": 14,
|
| 583 |
+
"success": 1
|
| 584 |
+
},
|
| 585 |
+
{
|
| 586 |
+
"episode": 81,
|
| 587 |
+
"seed": 80,
|
| 588 |
+
"reward": 1.0,
|
| 589 |
+
"steps": 14,
|
| 590 |
+
"success": 1
|
| 591 |
+
},
|
| 592 |
+
{
|
| 593 |
+
"episode": 82,
|
| 594 |
+
"seed": 81,
|
| 595 |
+
"reward": 1.0,
|
| 596 |
+
"steps": 14,
|
| 597 |
+
"success": 1
|
| 598 |
+
},
|
| 599 |
+
{
|
| 600 |
+
"episode": 83,
|
| 601 |
+
"seed": 82,
|
| 602 |
+
"reward": 1.0,
|
| 603 |
+
"steps": 14,
|
| 604 |
+
"success": 1
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"episode": 84,
|
| 608 |
+
"seed": 83,
|
| 609 |
+
"reward": 1.0,
|
| 610 |
+
"steps": 14,
|
| 611 |
+
"success": 1
|
| 612 |
+
},
|
| 613 |
+
{
|
| 614 |
+
"episode": 85,
|
| 615 |
+
"seed": 84,
|
| 616 |
+
"reward": 1.0,
|
| 617 |
+
"steps": 14,
|
| 618 |
+
"success": 1
|
| 619 |
+
},
|
| 620 |
+
{
|
| 621 |
+
"episode": 86,
|
| 622 |
+
"seed": 85,
|
| 623 |
+
"reward": 1.0,
|
| 624 |
+
"steps": 14,
|
| 625 |
+
"success": 1
|
| 626 |
+
},
|
| 627 |
+
{
|
| 628 |
+
"episode": 87,
|
| 629 |
+
"seed": 86,
|
| 630 |
+
"reward": 1.0,
|
| 631 |
+
"steps": 14,
|
| 632 |
+
"success": 1
|
| 633 |
+
},
|
| 634 |
+
{
|
| 635 |
+
"episode": 88,
|
| 636 |
+
"seed": 87,
|
| 637 |
+
"reward": 1.0,
|
| 638 |
+
"steps": 14,
|
| 639 |
+
"success": 1
|
| 640 |
+
},
|
| 641 |
+
{
|
| 642 |
+
"episode": 89,
|
| 643 |
+
"seed": 88,
|
| 644 |
+
"reward": 1.0,
|
| 645 |
+
"steps": 14,
|
| 646 |
+
"success": 1
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"episode": 90,
|
| 650 |
+
"seed": 89,
|
| 651 |
+
"reward": 1.0,
|
| 652 |
+
"steps": 14,
|
| 653 |
+
"success": 1
|
| 654 |
+
},
|
| 655 |
+
{
|
| 656 |
+
"episode": 91,
|
| 657 |
+
"seed": 90,
|
| 658 |
+
"reward": 1.0,
|
| 659 |
+
"steps": 14,
|
| 660 |
+
"success": 1
|
| 661 |
+
},
|
| 662 |
+
{
|
| 663 |
+
"episode": 92,
|
| 664 |
+
"seed": 91,
|
| 665 |
+
"reward": 1.0,
|
| 666 |
+
"steps": 14,
|
| 667 |
+
"success": 1
|
| 668 |
+
},
|
| 669 |
+
{
|
| 670 |
+
"episode": 93,
|
| 671 |
+
"seed": 92,
|
| 672 |
+
"reward": 1.0,
|
| 673 |
+
"steps": 14,
|
| 674 |
+
"success": 1
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"episode": 94,
|
| 678 |
+
"seed": 93,
|
| 679 |
+
"reward": 1.0,
|
| 680 |
+
"steps": 14,
|
| 681 |
+
"success": 1
|
| 682 |
+
},
|
| 683 |
+
{
|
| 684 |
+
"episode": 95,
|
| 685 |
+
"seed": 94,
|
| 686 |
+
"reward": 1.0,
|
| 687 |
+
"steps": 14,
|
| 688 |
+
"success": 1
|
| 689 |
+
},
|
| 690 |
+
{
|
| 691 |
+
"episode": 96,
|
| 692 |
+
"seed": 95,
|
| 693 |
+
"reward": 1.0,
|
| 694 |
+
"steps": 14,
|
| 695 |
+
"success": 1
|
| 696 |
+
},
|
| 697 |
+
{
|
| 698 |
+
"episode": 97,
|
| 699 |
+
"seed": 96,
|
| 700 |
+
"reward": 1.0,
|
| 701 |
+
"steps": 14,
|
| 702 |
+
"success": 1
|
| 703 |
+
},
|
| 704 |
+
{
|
| 705 |
+
"episode": 98,
|
| 706 |
+
"seed": 97,
|
| 707 |
+
"reward": 1.0,
|
| 708 |
+
"steps": 14,
|
| 709 |
+
"success": 1
|
| 710 |
+
},
|
| 711 |
+
{
|
| 712 |
+
"episode": 99,
|
| 713 |
+
"seed": 98,
|
| 714 |
+
"reward": 1.0,
|
| 715 |
+
"steps": 14,
|
| 716 |
+
"success": 1
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"episode": 100,
|
| 720 |
+
"seed": 99,
|
| 721 |
+
"reward": 1.0,
|
| 722 |
+
"steps": 14,
|
| 723 |
+
"success": 1
|
| 724 |
+
}
|
| 725 |
+
],
|
| 726 |
+
"evaluation_seconds": 0.02
|
| 727 |
+
}
|
eval_results/eval_taxi.json
ADDED
|
@@ -0,0 +1,724 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run": "taxi",
|
| 3 |
+
"env_id": "Taxi-v3",
|
| 4 |
+
"env_kwargs": {},
|
| 5 |
+
"n_training_episodes": 25000,
|
| 6 |
+
"n_episodes": 100,
|
| 7 |
+
"mean_reward": 7.56,
|
| 8 |
+
"std_reward": 2.706732347314747,
|
| 9 |
+
"min_reward": 3.0,
|
| 10 |
+
"max_reward": 15.0,
|
| 11 |
+
"success_rate": 1.0,
|
| 12 |
+
"mean_steps": 13.44,
|
| 13 |
+
"policy": "greedy (argmax Q)",
|
| 14 |
+
"model_file": "models\\qtable_taxi.pkl",
|
| 15 |
+
"qtable_shape": [
|
| 16 |
+
500,
|
| 17 |
+
6
|
| 18 |
+
],
|
| 19 |
+
"qtable_nonzero": 2398,
|
| 20 |
+
"evaluated_at": "2026-10-30T22:47:35",
|
| 21 |
+
"episodes": [
|
| 22 |
+
{
|
| 23 |
+
"episode": 1,
|
| 24 |
+
"seed": 16,
|
| 25 |
+
"reward": 6.0,
|
| 26 |
+
"steps": 15,
|
| 27 |
+
"success": 1
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"episode": 2,
|
| 31 |
+
"seed": 54,
|
| 32 |
+
"reward": 12.0,
|
| 33 |
+
"steps": 9,
|
| 34 |
+
"success": 1
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"episode": 3,
|
| 38 |
+
"seed": 165,
|
| 39 |
+
"reward": 12.0,
|
| 40 |
+
"steps": 9,
|
| 41 |
+
"success": 1
|
| 42 |
+
},
|
| 43 |
+
{
|
| 44 |
+
"episode": 4,
|
| 45 |
+
"seed": 177,
|
| 46 |
+
"reward": 11.0,
|
| 47 |
+
"steps": 10,
|
| 48 |
+
"success": 1
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"episode": 5,
|
| 52 |
+
"seed": 191,
|
| 53 |
+
"reward": 7.0,
|
| 54 |
+
"steps": 14,
|
| 55 |
+
"success": 1
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"episode": 6,
|
| 59 |
+
"seed": 191,
|
| 60 |
+
"reward": 7.0,
|
| 61 |
+
"steps": 14,
|
| 62 |
+
"success": 1
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"episode": 7,
|
| 66 |
+
"seed": 120,
|
| 67 |
+
"reward": 4.0,
|
| 68 |
+
"steps": 17,
|
| 69 |
+
"success": 1
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"episode": 8,
|
| 73 |
+
"seed": 80,
|
| 74 |
+
"reward": 7.0,
|
| 75 |
+
"steps": 14,
|
| 76 |
+
"success": 1
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"episode": 9,
|
| 80 |
+
"seed": 149,
|
| 81 |
+
"reward": 5.0,
|
| 82 |
+
"steps": 16,
|
| 83 |
+
"success": 1
|
| 84 |
+
},
|
| 85 |
+
{
|
| 86 |
+
"episode": 10,
|
| 87 |
+
"seed": 178,
|
| 88 |
+
"reward": 4.0,
|
| 89 |
+
"steps": 17,
|
| 90 |
+
"success": 1
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"episode": 11,
|
| 94 |
+
"seed": 48,
|
| 95 |
+
"reward": 5.0,
|
| 96 |
+
"steps": 16,
|
| 97 |
+
"success": 1
|
| 98 |
+
},
|
| 99 |
+
{
|
| 100 |
+
"episode": 12,
|
| 101 |
+
"seed": 38,
|
| 102 |
+
"reward": 11.0,
|
| 103 |
+
"steps": 10,
|
| 104 |
+
"success": 1
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"episode": 13,
|
| 108 |
+
"seed": 6,
|
| 109 |
+
"reward": 11.0,
|
| 110 |
+
"steps": 10,
|
| 111 |
+
"success": 1
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"episode": 14,
|
| 115 |
+
"seed": 125,
|
| 116 |
+
"reward": 4.0,
|
| 117 |
+
"steps": 17,
|
| 118 |
+
"success": 1
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"episode": 15,
|
| 122 |
+
"seed": 174,
|
| 123 |
+
"reward": 4.0,
|
| 124 |
+
"steps": 17,
|
| 125 |
+
"success": 1
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"episode": 16,
|
| 129 |
+
"seed": 73,
|
| 130 |
+
"reward": 7.0,
|
| 131 |
+
"steps": 14,
|
| 132 |
+
"success": 1
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"episode": 17,
|
| 136 |
+
"seed": 50,
|
| 137 |
+
"reward": 5.0,
|
| 138 |
+
"steps": 16,
|
| 139 |
+
"success": 1
|
| 140 |
+
},
|
| 141 |
+
{
|
| 142 |
+
"episode": 18,
|
| 143 |
+
"seed": 172,
|
| 144 |
+
"reward": 11.0,
|
| 145 |
+
"steps": 10,
|
| 146 |
+
"success": 1
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"episode": 19,
|
| 150 |
+
"seed": 100,
|
| 151 |
+
"reward": 7.0,
|
| 152 |
+
"steps": 14,
|
| 153 |
+
"success": 1
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"episode": 20,
|
| 157 |
+
"seed": 148,
|
| 158 |
+
"reward": 6.0,
|
| 159 |
+
"steps": 15,
|
| 160 |
+
"success": 1
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"episode": 21,
|
| 164 |
+
"seed": 146,
|
| 165 |
+
"reward": 7.0,
|
| 166 |
+
"steps": 14,
|
| 167 |
+
"success": 1
|
| 168 |
+
},
|
| 169 |
+
{
|
| 170 |
+
"episode": 22,
|
| 171 |
+
"seed": 6,
|
| 172 |
+
"reward": 11.0,
|
| 173 |
+
"steps": 10,
|
| 174 |
+
"success": 1
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"episode": 23,
|
| 178 |
+
"seed": 25,
|
| 179 |
+
"reward": 3.0,
|
| 180 |
+
"steps": 18,
|
| 181 |
+
"success": 1
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"episode": 24,
|
| 185 |
+
"seed": 40,
|
| 186 |
+
"reward": 6.0,
|
| 187 |
+
"steps": 15,
|
| 188 |
+
"success": 1
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"episode": 25,
|
| 192 |
+
"seed": 68,
|
| 193 |
+
"reward": 11.0,
|
| 194 |
+
"steps": 10,
|
| 195 |
+
"success": 1
|
| 196 |
+
},
|
| 197 |
+
{
|
| 198 |
+
"episode": 26,
|
| 199 |
+
"seed": 148,
|
| 200 |
+
"reward": 6.0,
|
| 201 |
+
"steps": 15,
|
| 202 |
+
"success": 1
|
| 203 |
+
},
|
| 204 |
+
{
|
| 205 |
+
"episode": 27,
|
| 206 |
+
"seed": 49,
|
| 207 |
+
"reward": 4.0,
|
| 208 |
+
"steps": 17,
|
| 209 |
+
"success": 1
|
| 210 |
+
},
|
| 211 |
+
{
|
| 212 |
+
"episode": 28,
|
| 213 |
+
"seed": 167,
|
| 214 |
+
"reward": 9.0,
|
| 215 |
+
"steps": 12,
|
| 216 |
+
"success": 1
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"episode": 29,
|
| 220 |
+
"seed": 9,
|
| 221 |
+
"reward": 6.0,
|
| 222 |
+
"steps": 15,
|
| 223 |
+
"success": 1
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"episode": 30,
|
| 227 |
+
"seed": 97,
|
| 228 |
+
"reward": 9.0,
|
| 229 |
+
"steps": 12,
|
| 230 |
+
"success": 1
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"episode": 31,
|
| 234 |
+
"seed": 164,
|
| 235 |
+
"reward": 6.0,
|
| 236 |
+
"steps": 15,
|
| 237 |
+
"success": 1
|
| 238 |
+
},
|
| 239 |
+
{
|
| 240 |
+
"episode": 32,
|
| 241 |
+
"seed": 176,
|
| 242 |
+
"reward": 6.0,
|
| 243 |
+
"steps": 15,
|
| 244 |
+
"success": 1
|
| 245 |
+
},
|
| 246 |
+
{
|
| 247 |
+
"episode": 33,
|
| 248 |
+
"seed": 61,
|
| 249 |
+
"reward": 10.0,
|
| 250 |
+
"steps": 11,
|
| 251 |
+
"success": 1
|
| 252 |
+
},
|
| 253 |
+
{
|
| 254 |
+
"episode": 34,
|
| 255 |
+
"seed": 7,
|
| 256 |
+
"reward": 10.0,
|
| 257 |
+
"steps": 11,
|
| 258 |
+
"success": 1
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
"episode": 35,
|
| 262 |
+
"seed": 54,
|
| 263 |
+
"reward": 12.0,
|
| 264 |
+
"steps": 9,
|
| 265 |
+
"success": 1
|
| 266 |
+
},
|
| 267 |
+
{
|
| 268 |
+
"episode": 36,
|
| 269 |
+
"seed": 55,
|
| 270 |
+
"reward": 5.0,
|
| 271 |
+
"steps": 16,
|
| 272 |
+
"success": 1
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"episode": 37,
|
| 276 |
+
"seed": 161,
|
| 277 |
+
"reward": 9.0,
|
| 278 |
+
"steps": 12,
|
| 279 |
+
"success": 1
|
| 280 |
+
},
|
| 281 |
+
{
|
| 282 |
+
"episode": 38,
|
| 283 |
+
"seed": 131,
|
| 284 |
+
"reward": 11.0,
|
| 285 |
+
"steps": 10,
|
| 286 |
+
"success": 1
|
| 287 |
+
},
|
| 288 |
+
{
|
| 289 |
+
"episode": 39,
|
| 290 |
+
"seed": 184,
|
| 291 |
+
"reward": 6.0,
|
| 292 |
+
"steps": 15,
|
| 293 |
+
"success": 1
|
| 294 |
+
},
|
| 295 |
+
{
|
| 296 |
+
"episode": 40,
|
| 297 |
+
"seed": 51,
|
| 298 |
+
"reward": 8.0,
|
| 299 |
+
"steps": 13,
|
| 300 |
+
"success": 1
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"episode": 41,
|
| 304 |
+
"seed": 170,
|
| 305 |
+
"reward": 5.0,
|
| 306 |
+
"steps": 16,
|
| 307 |
+
"success": 1
|
| 308 |
+
},
|
| 309 |
+
{
|
| 310 |
+
"episode": 42,
|
| 311 |
+
"seed": 12,
|
| 312 |
+
"reward": 5.0,
|
| 313 |
+
"steps": 16,
|
| 314 |
+
"success": 1
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"episode": 43,
|
| 318 |
+
"seed": 120,
|
| 319 |
+
"reward": 4.0,
|
| 320 |
+
"steps": 17,
|
| 321 |
+
"success": 1
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"episode": 44,
|
| 325 |
+
"seed": 113,
|
| 326 |
+
"reward": 6.0,
|
| 327 |
+
"steps": 15,
|
| 328 |
+
"success": 1
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"episode": 45,
|
| 332 |
+
"seed": 95,
|
| 333 |
+
"reward": 10.0,
|
| 334 |
+
"steps": 11,
|
| 335 |
+
"success": 1
|
| 336 |
+
},
|
| 337 |
+
{
|
| 338 |
+
"episode": 46,
|
| 339 |
+
"seed": 126,
|
| 340 |
+
"reward": 15.0,
|
| 341 |
+
"steps": 6,
|
| 342 |
+
"success": 1
|
| 343 |
+
},
|
| 344 |
+
{
|
| 345 |
+
"episode": 47,
|
| 346 |
+
"seed": 51,
|
| 347 |
+
"reward": 8.0,
|
| 348 |
+
"steps": 13,
|
| 349 |
+
"success": 1
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"episode": 48,
|
| 353 |
+
"seed": 98,
|
| 354 |
+
"reward": 4.0,
|
| 355 |
+
"steps": 17,
|
| 356 |
+
"success": 1
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"episode": 49,
|
| 360 |
+
"seed": 36,
|
| 361 |
+
"reward": 7.0,
|
| 362 |
+
"steps": 14,
|
| 363 |
+
"success": 1
|
| 364 |
+
},
|
| 365 |
+
{
|
| 366 |
+
"episode": 50,
|
| 367 |
+
"seed": 135,
|
| 368 |
+
"reward": 7.0,
|
| 369 |
+
"steps": 14,
|
| 370 |
+
"success": 1
|
| 371 |
+
},
|
| 372 |
+
{
|
| 373 |
+
"episode": 51,
|
| 374 |
+
"seed": 54,
|
| 375 |
+
"reward": 12.0,
|
| 376 |
+
"steps": 9,
|
| 377 |
+
"success": 1
|
| 378 |
+
},
|
| 379 |
+
{
|
| 380 |
+
"episode": 52,
|
| 381 |
+
"seed": 82,
|
| 382 |
+
"reward": 11.0,
|
| 383 |
+
"steps": 10,
|
| 384 |
+
"success": 1
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"episode": 53,
|
| 388 |
+
"seed": 45,
|
| 389 |
+
"reward": 9.0,
|
| 390 |
+
"steps": 12,
|
| 391 |
+
"success": 1
|
| 392 |
+
},
|
| 393 |
+
{
|
| 394 |
+
"episode": 54,
|
| 395 |
+
"seed": 95,
|
| 396 |
+
"reward": 10.0,
|
| 397 |
+
"steps": 11,
|
| 398 |
+
"success": 1
|
| 399 |
+
},
|
| 400 |
+
{
|
| 401 |
+
"episode": 55,
|
| 402 |
+
"seed": 89,
|
| 403 |
+
"reward": 9.0,
|
| 404 |
+
"steps": 12,
|
| 405 |
+
"success": 1
|
| 406 |
+
},
|
| 407 |
+
{
|
| 408 |
+
"episode": 56,
|
| 409 |
+
"seed": 59,
|
| 410 |
+
"reward": 6.0,
|
| 411 |
+
"steps": 15,
|
| 412 |
+
"success": 1
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"episode": 57,
|
| 416 |
+
"seed": 95,
|
| 417 |
+
"reward": 10.0,
|
| 418 |
+
"steps": 11,
|
| 419 |
+
"success": 1
|
| 420 |
+
},
|
| 421 |
+
{
|
| 422 |
+
"episode": 58,
|
| 423 |
+
"seed": 124,
|
| 424 |
+
"reward": 4.0,
|
| 425 |
+
"steps": 17,
|
| 426 |
+
"success": 1
|
| 427 |
+
},
|
| 428 |
+
{
|
| 429 |
+
"episode": 59,
|
| 430 |
+
"seed": 9,
|
| 431 |
+
"reward": 6.0,
|
| 432 |
+
"steps": 15,
|
| 433 |
+
"success": 1
|
| 434 |
+
},
|
| 435 |
+
{
|
| 436 |
+
"episode": 60,
|
| 437 |
+
"seed": 113,
|
| 438 |
+
"reward": 6.0,
|
| 439 |
+
"steps": 15,
|
| 440 |
+
"success": 1
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"episode": 61,
|
| 444 |
+
"seed": 58,
|
| 445 |
+
"reward": 7.0,
|
| 446 |
+
"steps": 14,
|
| 447 |
+
"success": 1
|
| 448 |
+
},
|
| 449 |
+
{
|
| 450 |
+
"episode": 62,
|
| 451 |
+
"seed": 85,
|
| 452 |
+
"reward": 14.0,
|
| 453 |
+
"steps": 7,
|
| 454 |
+
"success": 1
|
| 455 |
+
},
|
| 456 |
+
{
|
| 457 |
+
"episode": 63,
|
| 458 |
+
"seed": 51,
|
| 459 |
+
"reward": 8.0,
|
| 460 |
+
"steps": 13,
|
| 461 |
+
"success": 1
|
| 462 |
+
},
|
| 463 |
+
{
|
| 464 |
+
"episode": 64,
|
| 465 |
+
"seed": 134,
|
| 466 |
+
"reward": 4.0,
|
| 467 |
+
"steps": 17,
|
| 468 |
+
"success": 1
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"episode": 65,
|
| 472 |
+
"seed": 121,
|
| 473 |
+
"reward": 6.0,
|
| 474 |
+
"steps": 15,
|
| 475 |
+
"success": 1
|
| 476 |
+
},
|
| 477 |
+
{
|
| 478 |
+
"episode": 66,
|
| 479 |
+
"seed": 169,
|
| 480 |
+
"reward": 10.0,
|
| 481 |
+
"steps": 11,
|
| 482 |
+
"success": 1
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"episode": 67,
|
| 486 |
+
"seed": 105,
|
| 487 |
+
"reward": 6.0,
|
| 488 |
+
"steps": 15,
|
| 489 |
+
"success": 1
|
| 490 |
+
},
|
| 491 |
+
{
|
| 492 |
+
"episode": 68,
|
| 493 |
+
"seed": 21,
|
| 494 |
+
"reward": 8.0,
|
| 495 |
+
"steps": 13,
|
| 496 |
+
"success": 1
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"episode": 69,
|
| 500 |
+
"seed": 30,
|
| 501 |
+
"reward": 8.0,
|
| 502 |
+
"steps": 13,
|
| 503 |
+
"success": 1
|
| 504 |
+
},
|
| 505 |
+
{
|
| 506 |
+
"episode": 70,
|
| 507 |
+
"seed": 11,
|
| 508 |
+
"reward": 5.0,
|
| 509 |
+
"steps": 16,
|
| 510 |
+
"success": 1
|
| 511 |
+
},
|
| 512 |
+
{
|
| 513 |
+
"episode": 71,
|
| 514 |
+
"seed": 50,
|
| 515 |
+
"reward": 5.0,
|
| 516 |
+
"steps": 16,
|
| 517 |
+
"success": 1
|
| 518 |
+
},
|
| 519 |
+
{
|
| 520 |
+
"episode": 72,
|
| 521 |
+
"seed": 65,
|
| 522 |
+
"reward": 11.0,
|
| 523 |
+
"steps": 10,
|
| 524 |
+
"success": 1
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"episode": 73,
|
| 528 |
+
"seed": 12,
|
| 529 |
+
"reward": 5.0,
|
| 530 |
+
"steps": 16,
|
| 531 |
+
"success": 1
|
| 532 |
+
},
|
| 533 |
+
{
|
| 534 |
+
"episode": 74,
|
| 535 |
+
"seed": 43,
|
| 536 |
+
"reward": 5.0,
|
| 537 |
+
"steps": 16,
|
| 538 |
+
"success": 1
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"episode": 75,
|
| 542 |
+
"seed": 82,
|
| 543 |
+
"reward": 11.0,
|
| 544 |
+
"steps": 10,
|
| 545 |
+
"success": 1
|
| 546 |
+
},
|
| 547 |
+
{
|
| 548 |
+
"episode": 76,
|
| 549 |
+
"seed": 145,
|
| 550 |
+
"reward": 8.0,
|
| 551 |
+
"steps": 13,
|
| 552 |
+
"success": 1
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"episode": 77,
|
| 556 |
+
"seed": 152,
|
| 557 |
+
"reward": 7.0,
|
| 558 |
+
"steps": 14,
|
| 559 |
+
"success": 1
|
| 560 |
+
},
|
| 561 |
+
{
|
| 562 |
+
"episode": 78,
|
| 563 |
+
"seed": 97,
|
| 564 |
+
"reward": 9.0,
|
| 565 |
+
"steps": 12,
|
| 566 |
+
"success": 1
|
| 567 |
+
},
|
| 568 |
+
{
|
| 569 |
+
"episode": 79,
|
| 570 |
+
"seed": 106,
|
| 571 |
+
"reward": 7.0,
|
| 572 |
+
"steps": 14,
|
| 573 |
+
"success": 1
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"episode": 80,
|
| 577 |
+
"seed": 55,
|
| 578 |
+
"reward": 5.0,
|
| 579 |
+
"steps": 16,
|
| 580 |
+
"success": 1
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"episode": 81,
|
| 584 |
+
"seed": 31,
|
| 585 |
+
"reward": 9.0,
|
| 586 |
+
"steps": 12,
|
| 587 |
+
"success": 1
|
| 588 |
+
},
|
| 589 |
+
{
|
| 590 |
+
"episode": 82,
|
| 591 |
+
"seed": 85,
|
| 592 |
+
"reward": 14.0,
|
| 593 |
+
"steps": 7,
|
| 594 |
+
"success": 1
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"episode": 83,
|
| 598 |
+
"seed": 38,
|
| 599 |
+
"reward": 11.0,
|
| 600 |
+
"steps": 10,
|
| 601 |
+
"success": 1
|
| 602 |
+
},
|
| 603 |
+
{
|
| 604 |
+
"episode": 84,
|
| 605 |
+
"seed": 112,
|
| 606 |
+
"reward": 9.0,
|
| 607 |
+
"steps": 12,
|
| 608 |
+
"success": 1
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"episode": 85,
|
| 612 |
+
"seed": 102,
|
| 613 |
+
"reward": 8.0,
|
| 614 |
+
"steps": 13,
|
| 615 |
+
"success": 1
|
| 616 |
+
},
|
| 617 |
+
{
|
| 618 |
+
"episode": 86,
|
| 619 |
+
"seed": 168,
|
| 620 |
+
"reward": 7.0,
|
| 621 |
+
"steps": 14,
|
| 622 |
+
"success": 1
|
| 623 |
+
},
|
| 624 |
+
{
|
| 625 |
+
"episode": 87,
|
| 626 |
+
"seed": 123,
|
| 627 |
+
"reward": 6.0,
|
| 628 |
+
"steps": 15,
|
| 629 |
+
"success": 1
|
| 630 |
+
},
|
| 631 |
+
{
|
| 632 |
+
"episode": 88,
|
| 633 |
+
"seed": 97,
|
| 634 |
+
"reward": 9.0,
|
| 635 |
+
"steps": 12,
|
| 636 |
+
"success": 1
|
| 637 |
+
},
|
| 638 |
+
{
|
| 639 |
+
"episode": 89,
|
| 640 |
+
"seed": 21,
|
| 641 |
+
"reward": 8.0,
|
| 642 |
+
"steps": 13,
|
| 643 |
+
"success": 1
|
| 644 |
+
},
|
| 645 |
+
{
|
| 646 |
+
"episode": 90,
|
| 647 |
+
"seed": 83,
|
| 648 |
+
"reward": 10.0,
|
| 649 |
+
"steps": 11,
|
| 650 |
+
"success": 1
|
| 651 |
+
},
|
| 652 |
+
{
|
| 653 |
+
"episode": 91,
|
| 654 |
+
"seed": 158,
|
| 655 |
+
"reward": 4.0,
|
| 656 |
+
"steps": 17,
|
| 657 |
+
"success": 1
|
| 658 |
+
},
|
| 659 |
+
{
|
| 660 |
+
"episode": 92,
|
| 661 |
+
"seed": 26,
|
| 662 |
+
"reward": 7.0,
|
| 663 |
+
"steps": 14,
|
| 664 |
+
"success": 1
|
| 665 |
+
},
|
| 666 |
+
{
|
| 667 |
+
"episode": 93,
|
| 668 |
+
"seed": 80,
|
| 669 |
+
"reward": 7.0,
|
| 670 |
+
"steps": 14,
|
| 671 |
+
"success": 1
|
| 672 |
+
},
|
| 673 |
+
{
|
| 674 |
+
"episode": 94,
|
| 675 |
+
"seed": 63,
|
| 676 |
+
"reward": 5.0,
|
| 677 |
+
"steps": 16,
|
| 678 |
+
"success": 1
|
| 679 |
+
},
|
| 680 |
+
{
|
| 681 |
+
"episode": 95,
|
| 682 |
+
"seed": 5,
|
| 683 |
+
"reward": 11.0,
|
| 684 |
+
"steps": 10,
|
| 685 |
+
"success": 1
|
| 686 |
+
},
|
| 687 |
+
{
|
| 688 |
+
"episode": 96,
|
| 689 |
+
"seed": 81,
|
| 690 |
+
"reward": 9.0,
|
| 691 |
+
"steps": 12,
|
| 692 |
+
"success": 1
|
| 693 |
+
},
|
| 694 |
+
{
|
| 695 |
+
"episode": 97,
|
| 696 |
+
"seed": 32,
|
| 697 |
+
"reward": 3.0,
|
| 698 |
+
"steps": 18,
|
| 699 |
+
"success": 1
|
| 700 |
+
},
|
| 701 |
+
{
|
| 702 |
+
"episode": 98,
|
| 703 |
+
"seed": 11,
|
| 704 |
+
"reward": 5.0,
|
| 705 |
+
"steps": 16,
|
| 706 |
+
"success": 1
|
| 707 |
+
},
|
| 708 |
+
{
|
| 709 |
+
"episode": 99,
|
| 710 |
+
"seed": 28,
|
| 711 |
+
"reward": 4.0,
|
| 712 |
+
"steps": 17,
|
| 713 |
+
"success": 1
|
| 714 |
+
},
|
| 715 |
+
{
|
| 716 |
+
"episode": 100,
|
| 717 |
+
"seed": 148,
|
| 718 |
+
"reward": 6.0,
|
| 719 |
+
"steps": 15,
|
| 720 |
+
"success": 1
|
| 721 |
+
}
|
| 722 |
+
],
|
| 723 |
+
"evaluation_seconds": 0.02
|
| 724 |
+
}
|
logs/frozenlake4x4/progress.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
logs/frozenlake4x4/train_console.log
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
==============================================================================
|
| 2 |
+
Q-Learning 训练 · FrozenLake-v1(4x4,is_slippery=False)
|
| 3 |
+
运行名称: frozenlake4x4 开始时间: 2026-10-30 22:29:00
|
| 4 |
+
==============================================================================
|
| 5 |
+
|
| 6 |
+
[环境自检]
|
| 7 |
+
env_id = FrozenLake-v1
|
| 8 |
+
env_kwargs = {'map_name': '4x4', 'is_slippery': False}
|
| 9 |
+
观测空间 = Discrete(16) -> 16 个状态
|
| 10 |
+
动作空间 = Discrete(4) -> 4 个动作
|
| 11 |
+
一次 reset 的观测 = 0(整数 = 状态编号,4x4 地图按 row*4+col 编码)
|
| 12 |
+
每回合最大步数 = 99
|
| 13 |
+
|
| 14 |
+
[Q 表初始化]
|
| 15 |
+
Q 表形状 = (16, 4)(= (状态数, 动作数)),初始值全为 0
|
| 16 |
+
需要学习的参数个数 = 64
|
| 17 |
+
|
| 18 |
+
[超参数]
|
| 19 |
+
n_training_episodes = 10000
|
| 20 |
+
learning_rate = 0.7
|
| 21 |
+
gamma = 0.95
|
| 22 |
+
max_steps = 99
|
| 23 |
+
max_epsilon = 1.0
|
| 24 |
+
min_epsilon = 0.05
|
| 25 |
+
decay_rate = 0.0005
|
| 26 |
+
n_eval_episodes = 100
|
| 27 |
+
eval_seed = [](不指定)
|
| 28 |
+
train_seed = 0
|
| 29 |
+
|
| 30 |
+
[开始训练] 22:29:00 每 500 回合打印一行,每 1000 回合评估一次
|
| 31 |
+
可复现性:每回合 env.reset(seed=0+episode),同 --seed 重跑分数一致
|
| 32 |
+
[train] ep= 1/10000 | eps=1.000 | 最近100回合平均回报= 0.00 | 成功率= 0.0% | 平均步数= 11.0 | Q非零项= 0 | 用时= 0.00min
|
| 33 |
+
[train] ep= 500/10000 | eps=0.790 | 最近100回合平均回报= 0.06 | 成功率= 6.0% | 平均步数= 7.6 | Q非零项= 35 | 用时= 0.00min
|
| 34 |
+
[train] ep= 1000/10000 | eps=0.626 | 最近100回合平均回报= 0.26 | 成功率= 26.0% | 平均步数= 7.4 | Q非零项= 35 | 用时= 0.00min
|
| 35 |
+
[eval ] ep= 1000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 36 |
+
[train] ep= 1500/10000 | eps=0.499 | 最近100回合平均回报= 0.47 | 成功率= 47.0% | 平均步数= 7.1 | Q非零项= 35 | 用时= 0.00min
|
| 37 |
+
[train] ep= 2000/10000 | eps=0.400 | 最近100回合平均回报= 0.54 | 成功率= 54.0% | 平均步数= 7.1 | Q非零项= 35 | 用时= 0.01min
|
| 38 |
+
[eval ] ep= 2000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 39 |
+
[train] ep= 2500/10000 | eps=0.322 | 最近100回合平均回报= 0.66 | 成功率= 66.0% | 平均步数= 7.0 | Q非零项= 35 | 用时= 0.01min
|
| 40 |
+
[train] ep= 3000/10000 | eps=0.262 | 最近100回合平均回报= 0.69 | 成功率= 69.0% | 平均步数= 6.7 | Q非零项= 35 | 用时= 0.01min
|
| 41 |
+
[eval ] ep= 3000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 42 |
+
[train] ep= 3500/10000 | eps=0.215 | 最近100回合平均回报= 0.77 | 成功率= 77.0% | 平均步数= 6.7 | Q非零项= 35 | 用时= 0.01min
|
| 43 |
+
[train] ep= 4000/10000 | eps=0.179 | 最近100回合平均回报= 0.84 | 成功率= 84.0% | 平均步数= 6.3 | Q非零项= 35 | 用时= 0.01min
|
| 44 |
+
[eval ] ep= 4000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 45 |
+
[train] ep= 4500/10000 | eps=0.150 | 最近100回合平均回报= 0.86 | 成功率= 86.0% | 平均步数= 6.5 | Q非零项= 35 | 用时= 0.01min
|
| 46 |
+
[train] ep= 5000/10000 | eps=0.128 | 最近100回合平均回报= 0.83 | 成功率= 83.0% | 平均步数= 6.2 | Q非零项= 35 | 用时= 0.01min
|
| 47 |
+
[eval ] ep= 5000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 48 |
+
[train] ep= 5500/10000 | eps=0.111 | 最近100回合平均回报= 0.85 | 成功率= 85.0% | 平均步数= 6.2 | Q非零项= 35 | 用时= 0.01min
|
| 49 |
+
[train] ep= 6000/10000 | eps=0.097 | 最近100回合平均回报= 0.94 | 成功率= 94.0% | 平均步数= 6.3 | Q非零项= 35 | 用时= 0.01min
|
| 50 |
+
[eval ] ep= 6000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 51 |
+
[train] ep= 6500/10000 | eps=0.087 | 最近100回合平均回报= 0.92 | 成功率= 92.0% | 平均步数= 6.1 | Q非零项= 35 | 用时= 0.02min
|
| 52 |
+
[train] ep= 7000/10000 | eps=0.079 | 最近100回合平均回报= 0.88 | 成功率= 88.0% | 平均步数= 6.2 | Q非零项= 35 | 用时= 0.02min
|
| 53 |
+
[eval ] ep= 7000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 54 |
+
[train] ep= 7500/10000 | eps=0.072 | 最近100回合平均回报= 0.92 | 成功率= 92.0% | 平均步数= 6.1 | Q非零项= 35 | 用时= 0.02min
|
| 55 |
+
[train] ep= 8000/10000 | eps=0.067 | 最近100回合平均回报= 0.88 | 成功率= 88.0% | 平均步数= 6.0 | Q非零项= 35 | 用时= 0.02min
|
| 56 |
+
[eval ] ep= 8000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 57 |
+
[train] ep= 8500/10000 | eps=0.064 | 最近100回合平均回报= 0.92 | 成功率= 92.0% | 平均步数= 6.2 | Q非零项= 35 | 用时= 0.02min
|
| 58 |
+
[train] ep= 9000/10000 | eps=0.061 | 最近100回合平均回报= 0.92 | 成功率= 92.0% | 平均步数= 6.0 | Q非零项= 35 | 用时= 0.02min
|
| 59 |
+
[eval ] ep= 9000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 60 |
+
[train] ep= 9500/10000 | eps=0.058 | 最近100回合平均回报= 0.92 | 成功率= 92.0% | 平均步数= 6.0 | Q非零项= 35 | 用时= 0.02min
|
| 61 |
+
[train] ep= 10000/10000 | eps=0.056 | 最近100回合平均回报= 0.93 | 成功率= 93.0% | 平均步数= 6.1 | Q非零项= 35 | 用时= 0.02min
|
| 62 |
+
[eval ] ep= 10000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 63 |
+
|
| 64 |
+
[训练完成] 22:29:01 总用时 = 0.02 分钟
|
| 65 |
+
|
| 66 |
+
[最终评估] 用贪婪策略跑 100 局(独立于训练)
|
| 67 |
+
Mean_reward = 1.00 +/- 0.00
|
| 68 |
+
成功率 = 100%
|
| 69 |
+
训练途中最好的周期评估:1.00 ± 0.00 @ 第 1000 回合
|
| 70 |
+
Q 表非零项 = 35 / 64
|
| 71 |
+
Q 表最大价值 = 1.0000
|
| 72 |
+
|
| 73 |
+
[输出] 训练曲线 = logs\frozenlake4x4\train_curve.png
|
| 74 |
+
[输出] 进度 CSV = logs\frozenlake4x4\progress.csv
|
| 75 |
+
[输出] 模型文件 = models\qtable_frozenlake4x4.pkl (1.1 KB)
|
| 76 |
+
|
| 77 |
+
==============================================================================
|
| 78 |
+
完成。下一步:python evaluate_and_record.py --model models/qtable_frozenlake4x4.pkl
|
| 79 |
+
==============================================================================
|
logs/frozenlake4x4/train_curve.png
ADDED
|
Git LFS Details
|
logs/frozenlake4x4_slippery/progress.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
logs/frozenlake4x4_slippery/train_console.log
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
==============================================================================
|
| 2 |
+
Q-Learning 训练 · FrozenLake-v1(4x4,is_slippery=True)
|
| 3 |
+
运行名称: frozenlake4x4_slippery 开始时间: 2026-10-30 22:29:40
|
| 4 |
+
==============================================================================
|
| 5 |
+
|
| 6 |
+
[环境自检]
|
| 7 |
+
env_id = FrozenLake-v1
|
| 8 |
+
env_kwargs = {'map_name': '4x4', 'is_slippery': True}
|
| 9 |
+
观测空间 = Discrete(16) -> 16 个状态
|
| 10 |
+
动作空间 = Discrete(4) -> 4 个动作
|
| 11 |
+
一次 reset 的观测 = 0(整数 = 状态编号,4x4 地图按 row*4+col 编码)
|
| 12 |
+
每回合最大步数 = 99
|
| 13 |
+
|
| 14 |
+
[Q 表初始化]
|
| 15 |
+
Q 表形状 = (16, 4)(= (状态数, 动作数)),初始值全为 0
|
| 16 |
+
需要学习的参数个数 = 64
|
| 17 |
+
|
| 18 |
+
[超参数]
|
| 19 |
+
n_training_episodes = 20000
|
| 20 |
+
learning_rate = 0.7
|
| 21 |
+
gamma = 0.95
|
| 22 |
+
max_steps = 99
|
| 23 |
+
max_epsilon = 1.0
|
| 24 |
+
min_epsilon = 0.1
|
| 25 |
+
decay_rate = 0.0003
|
| 26 |
+
n_eval_episodes = 100
|
| 27 |
+
eval_seed = 官方 100 个种子
|
| 28 |
+
train_seed = 0
|
| 29 |
+
|
| 30 |
+
[开始训练] 22:29:40 每 1000 回合打印一行,每 2000 回合评估一次
|
| 31 |
+
可复现性:每回合 env.reset(seed=0+episode),同 --seed 重跑分数一致
|
| 32 |
+
[train] ep= 1/20000 | eps=1.000 | 最近100回合平均回报= 0.00 | 成功率= 0.0% | 平均步数= 2.0 | Q非零项= 0 | 用时= 0.00min
|
| 33 |
+
[train] ep= 1000/20000 | eps=0.767 | 最近100回合平均回报= 0.01 | 成功率= 1.0% | 平均步数= 8.2 | Q非零项= 44 | 用时= 0.00min
|
| 34 |
+
[train] ep= 2000/20000 | eps=0.594 | 最近100回合平均回报= 0.05 | 成功率= 5.0% | 平均步数= 9.6 | Q非零项= 44 | 用时= 0.01min
|
| 35 |
+
[eval ] ep= 2000 | 贪婪策略 20 局: 回报= 0.00 ± 0.00 | 成功率= 0.0%
|
| 36 |
+
[train] ep= 3000/20000 | eps=0.466 | 最近100回合平均回报= 0.04 | 成功率= 4.0% | 平均步数= 10.5 | Q非零项= 44 | 用时= 0.01min
|
| 37 |
+
[train] ep= 4000/20000 | eps=0.371 | 最近100回合平均回报= 0.03 | 成功率= 3.0% | 平均步数= 11.7 | Q非零项= 44 | 用时= 0.01min
|
| 38 |
+
[eval ] ep= 4000 | 贪婪策略 20 局: 回报= 0.10 ± 0.30 | 成功率= 10.0%
|
| 39 |
+
[train] ep= 5000/20000 | eps=0.301 | 最近100回合平均回报= 0.04 | 成功率= 4.0% | 平均步数= 13.2 | Q非零项= 44 | 用时= 0.02min
|
| 40 |
+
[train] ep= 6000/20000 | eps=0.249 | 最近100回合平均回报= 0.06 | 成功率= 6.0% | 平均步数= 13.1 | Q非零项= 44 | 用时= 0.02min
|
| 41 |
+
[eval ] ep= 6000 | 贪婪策略 20 局: 回报= 0.30 ± 0.46 | 成功率= 30.0%
|
| 42 |
+
[train] ep= 7000/20000 | eps=0.210 | 最近100回合平均回报= 0.10 | 成功率= 10.0% | 平均步数= 15.9 | Q非零项= 44 | 用时= 0.02min
|
| 43 |
+
[train] ep= 8000/20000 | eps=0.182 | 最近100回合平均回报= 0.10 | 成功率= 10.0% | 平均步数= 17.3 | Q非零项= 44 | 用时= 0.03min
|
| 44 |
+
[eval ] ep= 8000 | 贪婪策略 20 局: 回报= 0.10 ± 0.30 | 成功率= 10.0%
|
| 45 |
+
[train] ep= 9000/20000 | eps=0.161 | 最近100回合平均回报= 0.09 | 成功率= 9.0% | 平均步数= 17.4 | Q非零项= 44 | 用时= 0.03min
|
| 46 |
+
[train] ep= 10000/20000 | eps=0.145 | 最近100回合平均回报= 0.12 | 成功率= 12.0% | 平均步数= 16.9 | Q非零项= 44 | 用时= 0.04min
|
| 47 |
+
[eval ] ep= 10000 | 贪婪策略 20 局: 回报= 0.65 ± 0.48 | 成功率= 65.0%
|
| 48 |
+
[train] ep= 11000/20000 | eps=0.133 | 最近100回合平均回报= 0.06 | 成功率= 6.0% | 平均步数= 16.5 | Q非零项= 44 | 用时= 0.04min
|
| 49 |
+
[train] ep= 12000/20000 | eps=0.125 | 最近100回合平均回报= 0.09 | 成功率= 9.0% | 平均步数= 17.4 | Q非零项= 44 | 用时= 0.05min
|
| 50 |
+
[eval ] ep= 12000 | 贪婪策略 20 局: 回报= 0.10 ± 0.30 | 成功率= 10.0%
|
| 51 |
+
[train] ep= 13000/20000 | eps=0.118 | 最近100回合平均回报= 0.09 | 成功率= 9.0% | 平均步数= 18.2 | Q非零项= 44 | 用时= 0.05min
|
| 52 |
+
[train] ep= 14000/20000 | eps=0.114 | 最近100回合平均回报= 0.22 | 成功率= 22.0% | 平均步数= 18.9 | Q非零项= 44 | 用时= 0.06min
|
| 53 |
+
[eval ] ep= 14000 | 贪婪策略 20 局: 回报= 0.65 ± 0.48 | 成功率= 65.0%
|
| 54 |
+
[train] ep= 15000/20000 | eps=0.110 | 最近100回合平均回报= 0.16 | 成功率= 16.0% | 平均步数= 19.4 | Q非零项= 44 | 用时= 0.07min
|
| 55 |
+
[train] ep= 16000/20000 | eps=0.107 | 最近100回合平均回报= 0.21 | 成功率= 21.0% | 平均步数= 21.4 | Q非零项= 44 | 用时= 0.07min
|
| 56 |
+
[eval ] ep= 16000 | 贪婪策略 20 局: 回报= 0.55 ± 0.50 | 成功率= 55.0%
|
| 57 |
+
[train] ep= 17000/20000 | eps=0.105 | 最近100回合平均回报= 0.23 | 成功率= 23.0% | 平均步数= 20.5 | Q非零项= 44 | 用时= 0.08min
|
| 58 |
+
[train] ep= 18000/20000 | eps=0.104 | 最近100回合平均回报= 0.24 | 成功率= 24.0% | 平均步数= 19.9 | Q非零项= 44 | 用时= 0.08min
|
| 59 |
+
[eval ] ep= 18000 | 贪婪策略 20 局: 回报= 0.65 ± 0.48 | 成功率= 65.0%
|
| 60 |
+
[train] ep= 19000/20000 | eps=0.103 | 最近100回合平均回报= 0.18 | 成功率= 18.0% | 平均步数= 20.9 | Q非零项= 44 | 用时= 0.09min
|
| 61 |
+
[train] ep= 20000/20000 | eps=0.102 | 最近100回合平均回报= 0.17 | 成功率= 17.0% | 平均步数= 19.4 | Q非零项= 44 | 用时= 0.09min
|
| 62 |
+
[eval ] ep= 20000 | 贪婪策略 20 局: 回报= 0.75 ± 0.43 | 成功率= 75.0%
|
| 63 |
+
|
| 64 |
+
[训练完成] 22:29:46 总用时 = 0.10 分钟
|
| 65 |
+
|
| 66 |
+
[最终评估] 用贪婪策略跑 100 局(独立于训练)
|
| 67 |
+
Mean_reward = 0.74 +/- 0.44
|
| 68 |
+
成功率 = 74%
|
| 69 |
+
训练途中最好的周期评估:0.75 ± 0.43 @ 第 20000 回合
|
| 70 |
+
Q 表非零项 = 44 / 64
|
| 71 |
+
Q 表最大价值 = 0.8458
|
| 72 |
+
|
| 73 |
+
[输出] 训练曲线 = logs\frozenlake4x4_slippery\train_curve.png
|
| 74 |
+
[输出] 进度 CSV = logs\frozenlake4x4_slippery\progress.csv
|
| 75 |
+
[输出] 模型文件 = models\qtable_frozenlake4x4_slippery.pkl (1.4 KB)
|
| 76 |
+
|
| 77 |
+
==============================================================================
|
| 78 |
+
完成。下一步:python evaluate_and_record.py --model models/qtable_frozenlake4x4_slippery.pkl
|
| 79 |
+
==============================================================================
|
logs/frozenlake4x4_slippery/train_curve.png
ADDED
|
Git LFS Details
|
logs/frozenlake8x8/progress.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
logs/frozenlake8x8/train_console.log
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
==============================================================================
|
| 2 |
+
Q-Learning 训练 · FrozenLake-v1(8x8,is_slippery=False)
|
| 3 |
+
运行名称: frozenlake8x8 开始时间: 2026-10-30 22:30:02
|
| 4 |
+
==============================================================================
|
| 5 |
+
|
| 6 |
+
[环境自检]
|
| 7 |
+
env_id = FrozenLake-v1
|
| 8 |
+
env_kwargs = {'map_name': '8x8', 'is_slippery': False}
|
| 9 |
+
观测空间 = Discrete(64) -> 64 个状态
|
| 10 |
+
动作空间 = Discrete(4) -> 4 个动作
|
| 11 |
+
一次 reset 的观测 = 0(整数 = 状态编号,8x8 地图按 row*8+col 编码)
|
| 12 |
+
每回合最大步数 = 200
|
| 13 |
+
|
| 14 |
+
[Q 表初始化]
|
| 15 |
+
Q 表形状 = (64, 4)(= (状态数, 动作数)),初始值全为 0
|
| 16 |
+
需要学习的参数个数 = 256
|
| 17 |
+
|
| 18 |
+
[超参数]
|
| 19 |
+
n_training_episodes = 60000
|
| 20 |
+
learning_rate = 0.8
|
| 21 |
+
gamma = 0.95
|
| 22 |
+
max_steps = 200
|
| 23 |
+
max_epsilon = 1.0
|
| 24 |
+
min_epsilon = 0.3
|
| 25 |
+
decay_rate = 3e-05
|
| 26 |
+
n_eval_episodes = 100
|
| 27 |
+
eval_seed = 官方 100 个种子
|
| 28 |
+
train_seed = 0
|
| 29 |
+
|
| 30 |
+
[开始训练] 22:30:02 每 3000 回合打印一行,每 6000 回合评估一次
|
| 31 |
+
可复现性:每回合 env.reset(seed=0+episode),同 --seed 重跑分数一致
|
| 32 |
+
[train] ep= 1/60000 | eps=1.000 | 最近100回合平均回报= 0.00 | 成功率= 0.0% | 平均步数= 42.0 | Q非零项= 0 | 用时= 0.00min
|
| 33 |
+
[train] ep= 3000/60000 | eps=0.940 | 最近100回合平均回报= 0.00 | 成功率= 0.0% | 平均步数= 23.9 | Q非零项= 161 | 用时= 0.02min
|
| 34 |
+
[train] ep= 6000/60000 | eps=0.885 | 最近100回合平均回报= 0.00 | 成功率= 0.0% | 平均步数= 23.6 | Q非零项= 171 | 用时= 0.05min
|
| 35 |
+
[eval ] ep= 6000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 36 |
+
[train] ep= 9000/60000 | eps=0.834 | 最近100回合平均回报= 0.02 | 成功率= 2.0% | 平均步数= 22.6 | Q非零项= 175 | 用时= 0.06min
|
| 37 |
+
[train] ep= 12000/60000 | eps=0.788 | 最近100回合平均回报= 0.02 | 成功率= 2.0% | 平均步数= 21.0 | Q非零项= 175 | 用时= 0.08min
|
| 38 |
+
[eval ] ep= 12000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 39 |
+
[train] ep= 15000/60000 | eps=0.746 | 最近100回合平均回报= 0.01 | 成功率= 1.0% | 平均步数= 18.5 | Q非零项= 175 | 用时= 0.10min
|
| 40 |
+
[train] ep= 18000/60000 | eps=0.708 | 最近100回合平均回报= 0.01 | 成功率= 1.0% | 平均步数= 18.1 | Q非零项= 175 | 用时= 0.11min
|
| 41 |
+
[eval ] ep= 18000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 42 |
+
[train] ep= 21000/60000 | eps=0.673 | 最近100回合平均回报= 0.04 | 成功率= 4.0% | 平均步数= 19.2 | Q非零项= 176 | 用时= 0.13min
|
| 43 |
+
[train] ep= 24000/60000 | eps=0.641 | 最近100回合平均回报= 0.03 | 成功率= 3.0% | 平均步数= 18.1 | Q非零项= 178 | 用时= 0.14min
|
| 44 |
+
[eval ] ep= 24000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 45 |
+
[train] ep= 27000/60000 | eps=0.611 | 最近100回合平均回报= 0.08 | 成功率= 8.0% | 平均步数= 17.6 | Q非零项= 179 | 用时= 0.16min
|
| 46 |
+
[train] ep= 30000/60000 | eps=0.585 | 最近100回合平均回报= 0.08 | 成功率= 8.0% | 平均步数= 16.5 | Q非零项= 179 | 用时= 0.17min
|
| 47 |
+
[eval ] ep= 30000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 48 |
+
[train] ep= 33000/60000 | eps=0.560 | 最近100回合平均回报= 0.10 | 成功率= 10.0% | 平均步数= 17.6 | Q非零项= 179 | 用时= 0.18min
|
| 49 |
+
[train] ep= 36000/60000 | eps=0.538 | 最近100回合平均回报= 0.07 | 成功率= 7.0% | 平均步数= 14.5 | Q非零项= 179 | 用时= 0.20min
|
| 50 |
+
[eval ] ep= 36000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 51 |
+
[train] ep= 39000/60000 | eps=0.517 | 最近100回合平均回报= 0.08 | 成功率= 8.0% | 平均步数= 16.6 | Q非零项= 179 | 用时= 0.21min
|
| 52 |
+
[train] ep= 42000/60000 | eps=0.499 | 最近100回合平均回报= 0.16 | 成功率= 16.0% | 平均步数= 16.7 | Q非零项= 179 | 用时= 0.23min
|
| 53 |
+
[eval ] ep= 42000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 54 |
+
[train] ep= 45000/60000 | eps=0.481 | 最近100回合平均回报= 0.16 | 成功率= 16.0% | 平均步数= 16.2 | Q非零项= 179 | 用时= 0.24min
|
| 55 |
+
[train] ep= 48000/60000 | eps=0.466 | 最近100回合平均回报= 0.12 | 成功率= 12.0% | 平均步数= 15.4 | Q非零项= 179 | 用时= 0.26min
|
| 56 |
+
[eval ] ep= 48000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 57 |
+
[train] ep= 51000/60000 | eps=0.452 | 最近100回合平均回报= 0.14 | 成功率= 14.0% | 平均步数= 15.0 | Q非零项= 179 | 用时= 0.27min
|
| 58 |
+
[train] ep= 54000/60000 | eps=0.439 | 最近100回合平均回报= 0.17 | 成功率= 17.0% | 平均步数= 14.4 | Q非零项= 179 | 用时= 0.28min
|
| 59 |
+
[eval ] ep= 54000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 60 |
+
[train] ep= 57000/60000 | eps=0.427 | 最近100回合平均回报= 0.25 | 成功率= 25.0% | 平均步数= 14.7 | Q非零项= 179 | ��时= 0.30min
|
| 61 |
+
[train] ep= 60000/60000 | eps=0.416 | 最近100回合平均回报= 0.22 | 成功率= 22.0% | 平均步数= 16.1 | Q非零项= 179 | 用时= 0.31min
|
| 62 |
+
[eval ] ep= 60000 | 贪婪策略 20 局: 回报= 1.00 ± 0.00 | 成功率=100.0%
|
| 63 |
+
|
| 64 |
+
[训练完成] 22:30:20 总用时 = 0.31 分钟
|
| 65 |
+
|
| 66 |
+
[最终评估] 用贪婪策略跑 100 局(独立于训练)
|
| 67 |
+
Mean_reward = 1.00 +/- 0.00
|
| 68 |
+
成功率 = 100%
|
| 69 |
+
训练途中最好的周期评估:1.00 ± 0.00 @ 第 6000 回合
|
| 70 |
+
Q 表非零项 = 179 / 256
|
| 71 |
+
Q 表最大价值 = 1.0000
|
| 72 |
+
|
| 73 |
+
[输出] 训练曲线 = logs\frozenlake8x8\train_curve.png
|
| 74 |
+
[输出] 进度 CSV = logs\frozenlake8x8\progress.csv
|
| 75 |
+
[输出] 模型文件 = models\qtable_frozenlake8x8.pkl (2.8 KB)
|
| 76 |
+
|
| 77 |
+
==============================================================================
|
| 78 |
+
完成。下一步:python evaluate_and_record.py --model models/qtable_frozenlake8x8.pkl
|
| 79 |
+
==============================================================================
|
logs/frozenlake8x8/train_curve.png
ADDED
|
Git LFS Details
|
logs/taxi/progress.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
logs/taxi/train_console.log
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
==============================================================================
|
| 2 |
+
Q-Learning 训练 · Taxi-v3
|
| 3 |
+
运行名称: taxi 开始时间: 2026-10-30 22:45:31
|
| 4 |
+
==============================================================================
|
| 5 |
+
|
| 6 |
+
[环境自检]
|
| 7 |
+
env_id = Taxi-v3
|
| 8 |
+
env_kwargs = {}
|
| 9 |
+
观测空间 = Discrete(500) -> 500 个状态
|
| 10 |
+
动作空间 = Discrete(6) -> 6 个动作
|
| 11 |
+
一次 reset 的观测 = 314(整数 = 状态编号,共 500 个)
|
| 12 |
+
每回合最大步数 = 99
|
| 13 |
+
|
| 14 |
+
[Q 表初始化]
|
| 15 |
+
Q 表形状 = (500, 6)(= (状态数, 动作数)),初始值全为 0
|
| 16 |
+
需要学习的参数个数 = 3000
|
| 17 |
+
|
| 18 |
+
[超参数]
|
| 19 |
+
n_training_episodes = 25000
|
| 20 |
+
learning_rate = 0.7
|
| 21 |
+
gamma = 0.95
|
| 22 |
+
max_steps = 99
|
| 23 |
+
max_epsilon = 1.0
|
| 24 |
+
min_epsilon = 0.05
|
| 25 |
+
decay_rate = 0.005
|
| 26 |
+
n_eval_episodes = 100
|
| 27 |
+
eval_seed = 官方 100 个种子
|
| 28 |
+
train_seed = 0
|
| 29 |
+
|
| 30 |
+
[开始训练] 22:45:31 每 1000 回合打印一行,每 2500 回合评估一次
|
| 31 |
+
可复现性:每回合 env.reset(seed=0+episode),同 --seed 重跑分数一致
|
| 32 |
+
[train] ep= 1/25000 | eps=1.000 | 最近100回合平均回报=-405.00 | 成功率= 0.0% | 平均步数= 99.0 | Q非零项= 29 | 用时= 0.00min
|
| 33 |
+
[train] ep= 1000/25000 | eps=0.056 | 最近100回合平均回报= 4.96 | 成功率=100.0% | 平均步数= 14.1 | Q非零项= 2393 | 用时= 0.01min
|
| 34 |
+
[train] ep= 2000/25000 | eps=0.050 | 最近100回合平均回报= 4.12 | 成功率=100.0% | 平均步数= 14.5 | Q非零项= 2393 | 用时= 0.01min
|
| 35 |
+
[eval ] ep= 2500 | 贪婪策略 20 局: 回报= 7.20 ± 2.93 | 成功率=100.0%
|
| 36 |
+
[train] ep= 3000/25000 | eps=0.050 | 最近100回合平均回报= 5.34 | 成功率=100.0% | 平均步数= 13.8 | Q非零项= 2393 | 用时= 0.02min
|
| 37 |
+
[train] ep= 4000/25000 | eps=0.050 | 最近100回合平均回报= 4.83 | 成功率=100.0% | 平均步数= 14.1 | Q非零项= 2393 | 用时= 0.02min
|
| 38 |
+
[train] ep= 5000/25000 | eps=0.050 | 最近100回合平均回报= 4.12 | 成功率=100.0% | 平均步数= 14.7 | Q非零项= 2393 | 用时= 0.03min
|
| 39 |
+
[eval ] ep= 5000 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 40 |
+
[train] ep= 6000/25000 | eps=0.050 | 最近100回合平均回报= 4.99 | 成功率=100.0% | 平均步数= 13.8 | Q非零项= 2393 | 用时= 0.03min
|
| 41 |
+
[train] ep= 7000/25000 | eps=0.050 | 最近100回合平均回报= 4.21 | 成功率=100.0% | 平均步数= 14.3 | Q非零项= 2393 | 用时= 0.04min
|
| 42 |
+
[eval ] ep= 7500 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 43 |
+
[train] ep= 8000/25000 | eps=0.050 | 最近100回合平均回报= 4.63 | 成功率=100.0% | 平均步数= 13.9 | Q非零项= 2393 | 用时= 0.04min
|
| 44 |
+
[train] ep= 9000/25000 | eps=0.050 | 最近100回合平均回报= 5.26 | 成功率=100.0% | 平均步数= 13.8 | Q非零项= 2393 | 用时= 0.05min
|
| 45 |
+
[train] ep= 10000/25000 | eps=0.050 | 最近100回合平均回报= 4.50 | 成功率=100.0% | 平均步数= 14.0 | Q非零项= 2394 | 用时= 0.05min
|
| 46 |
+
[eval ] ep= 10000 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 47 |
+
[train] ep= 11000/25000 | eps=0.050 | 最近100回合平均回报= 5.30 | 成功率=100.0% | 平均步数= 13.6 | Q非零项= 2394 | 用时= 0.06min
|
| 48 |
+
[train] ep= 12000/25000 | eps=0.050 | 最近100回合平均回报= 5.68 | 成功率=100.0% | 平均步数= 13.9 | Q非零项= 2394 | 用时= 0.06min
|
| 49 |
+
[eval ] ep= 12500 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 50 |
+
[train] ep= 13000/25000 | eps=0.050 | 最近100回合平均回报= 6.05 | 成功率=100.0% | 平均步数= 13.6 | Q非零项= 2394 | 用时= 0.07min
|
| 51 |
+
[train] ep= 14000/25000 | eps=0.050 | 最近100回合平均回报= 5.30 | 成功率=100.0% | 平均步数= 13.7 | Q非零项= 2394 | 用时= 0.07min
|
| 52 |
+
[train] ep= 15000/25000 | eps=0.050 | 最近100回合平均回报= 5.02 | 成功率=100.0% | 平均步数= 13.9 | Q非零项= 2396 | 用时= 0.07min
|
| 53 |
+
[eval ] ep= 15000 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 54 |
+
[train] ep= 16000/25000 | eps=0.050 | 最近100回合平均回报= 5.16 | 成功率=100.0% | 平均步数= 13.6 | Q非零项= 2396 | 用时= 0.08min
|
| 55 |
+
[train] ep= 17000/25000 | eps=0.050 | 最近100回合平均回报= 4.64 | 成功率=100.0% | 平均步数= 14.0 | Q非零项= 2396 | 用时= 0.08min
|
| 56 |
+
[eval ] ep= 17500 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 57 |
+
[train] ep= 18000/25000 | eps=0.050 | 最近100回合平均回报= 4.51 | 成功率=100.0% | 平均步数= 14.2 | Q非零项= 2397 | 用时= 0.09min
|
| 58 |
+
[train] ep= 19000/25000 | eps=0.050 | 最近100回合平均回报= 6.06 | 成功率=100.0% | 平均步数= 13.8 | Q非零项= 2397 | 用时= 0.09min
|
| 59 |
+
[train] ep= 20000/25000 | eps=0.050 | 最近100回合平均回报= 4.73 | 成功率=100.0% | 平均步数= 13.8 | Q非零项= 2398 | 用时= 0.10min
|
| 60 |
+
[eval ] ep= 20000 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 61 |
+
[train] ep= 21000/25000 | eps=0.050 | 最近100回合平均回报= 4.93 | 成功率=100.0% | 平均步数= 14.1 | Q非零项= 2398 | 用时= 0.10min
|
| 62 |
+
[train] ep= 22000/25000 | eps=0.050 | 最近100回合平均回报= 5.22 | 成功率=100.0% | 平均步数= 14.4 | Q非零项= 2398 | 用时= 0.11min
|
| 63 |
+
[eval ] ep= 22500 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 64 |
+
[train] ep= 23000/25000 | eps=0.050 | 最近100回合平均回报= 5.73 | 成功率=100.0% | 平均步数= 13.5 | Q非零项= 2398 | 用时= 0.11min
|
| 65 |
+
[train] ep= 24000/25000 | eps=0.050 | 最近100回合平均回报= 5.22 | 成功率=100.0% | 平均步数= 14.0 | Q非零项= 2398 | 用时= 0.12min
|
| 66 |
+
[train] ep= 25000/25000 | eps=0.050 | 最近100回合平均回报= 4.43 | 成功率=100.0% | 平均步数= 14.0 | Q非零项= 2398 | 用时= 0.12min
|
| 67 |
+
[eval ] ep= 25000 | 贪婪策略 20 局: 回报= 7.30 ± 2.85 | 成功率=100.0%
|
| 68 |
+
|
| 69 |
+
[训练完成] 22:45:38 总用时 = 0.12 分钟
|
| 70 |
+
|
| 71 |
+
[最终评估] 用贪婪策略跑 100 局(独立于训练)
|
| 72 |
+
Mean_reward = 7.56 +/- 2.71
|
| 73 |
+
成功率 = 100%
|
| 74 |
+
训练途中最好的周期评估:7.30 ± 2.85 @ 第 5000 回合
|
| 75 |
+
Q 表非零项 = 2398 / 3000
|
| 76 |
+
Q 表最大价值 = 20.0000
|
| 77 |
+
|
| 78 |
+
[输出] 训练曲线 = logs\taxi\train_curve.png
|
| 79 |
+
[输出] 进度 CSV = logs\taxi\progress.csv
|
| 80 |
+
[输出] 模型文件 = models\qtable_taxi.pkl (24.2 KB)
|
| 81 |
+
|
| 82 |
+
==============================================================================
|
| 83 |
+
完成。下一步:python evaluate_and_record.py --model models/qtable_taxi.pkl
|
| 84 |
+
==============================================================================
|
logs/taxi/train_curve.png
ADDED
|
Git LFS Details
|
metrics.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"frozenlake4x4": {
|
| 3 |
+
"env_id": "FrozenLake-v1",
|
| 4 |
+
"n_episodes": 100,
|
| 5 |
+
"mean_reward": 1.0,
|
| 6 |
+
"std_reward": 0.0,
|
| 7 |
+
"success_rate": 1.0,
|
| 8 |
+
"mean_steps": 6.0,
|
| 9 |
+
"qtable_shape": [
|
| 10 |
+
16,
|
| 11 |
+
4
|
| 12 |
+
],
|
| 13 |
+
"qtable_nonzero": 35,
|
| 14 |
+
"evaluated_at": "2026-10-30T22:46:48"
|
| 15 |
+
},
|
| 16 |
+
"frozenlake4x4_slippery": {
|
| 17 |
+
"env_id": "FrozenLake-v1",
|
| 18 |
+
"n_episodes": 100,
|
| 19 |
+
"mean_reward": 0.74,
|
| 20 |
+
"std_reward": 0.4386342439892262,
|
| 21 |
+
"success_rate": 0.74,
|
| 22 |
+
"mean_steps": 39.41,
|
| 23 |
+
"qtable_shape": [
|
| 24 |
+
16,
|
| 25 |
+
4
|
| 26 |
+
],
|
| 27 |
+
"qtable_nonzero": 44,
|
| 28 |
+
"evaluated_at": "2026-10-30T22:46:59"
|
| 29 |
+
},
|
| 30 |
+
"frozenlake8x8": {
|
| 31 |
+
"env_id": "FrozenLake-v1",
|
| 32 |
+
"n_episodes": 100,
|
| 33 |
+
"mean_reward": 1.0,
|
| 34 |
+
"std_reward": 0.0,
|
| 35 |
+
"success_rate": 1.0,
|
| 36 |
+
"mean_steps": 14.0,
|
| 37 |
+
"qtable_shape": [
|
| 38 |
+
64,
|
| 39 |
+
4
|
| 40 |
+
],
|
| 41 |
+
"qtable_nonzero": 179,
|
| 42 |
+
"evaluated_at": "2026-10-30T22:47:24"
|
| 43 |
+
},
|
| 44 |
+
"taxi": {
|
| 45 |
+
"env_id": "Taxi-v3",
|
| 46 |
+
"n_episodes": 100,
|
| 47 |
+
"mean_reward": 7.56,
|
| 48 |
+
"std_reward": 2.706732347314747,
|
| 49 |
+
"success_rate": 1.0,
|
| 50 |
+
"mean_steps": 13.44,
|
| 51 |
+
"qtable_shape": [
|
| 52 |
+
500,
|
| 53 |
+
6
|
| 54 |
+
],
|
| 55 |
+
"qtable_nonzero": 2398,
|
| 56 |
+
"evaluated_at": "2026-10-30T22:47:35"
|
| 57 |
+
}
|
| 58 |
+
}
|
models/qtable_frozenlake4x4.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:15783f0650b3ecdbf19a79372c3e8e505de805e775f3f3b3283ce4cd2485b011
|
| 3 |
+
size 1175
|
models/qtable_frozenlake4x4_slippery.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:355c6ee182cb716493c9f7ea9518986b11b9c211cdd07e5564690ca995b863b5
|
| 3 |
+
size 1386
|
models/qtable_frozenlake8x8.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:56b229bccb1b7ae4b5518dd78e0aae8ededf2b766f7d832393a51f4fca295b09
|
| 3 |
+
size 2914
|
models/qtable_taxi.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:42512445ebaa03b152ca4b9f5dc084f363b6a16c5a9d70db18f084625a0ab390
|
| 3 |
+
size 24775
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gymnasium>=1.0
|
| 2 |
+
numpy>=1.24
|
| 3 |
+
imageio>=2.31
|
| 4 |
+
imageio-ffmpeg>=0.4
|
| 5 |
+
Pillow>=9.0
|
| 6 |
+
matplotlib>=3.7
|
| 7 |
+
tqdm>=4.65
|
videos/replay_frozenlake4x4.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8f02fda66c2195fd108a330c70e8da165ff0ed144bedffc7f2a4ab5723824e5e
|
| 3 |
+
size 970642
|
videos/replay_frozenlake4x4_slippery.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a84a49c1451716a0315a6b2620eec47809bbd98030e2c70978d2af1686e915ac
|
| 3 |
+
size 1963828
|
videos/replay_frozenlake8x8.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5a170d8acedfb336a15dc6c1ba368a22681ef21d46ab59f6f7a5e264822be340
|
| 3 |
+
size 1624987
|
videos/replay_taxi.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b80e69b55c62c9007c2086b6a651a4f9871a2b9fd7ac5220152aa8af9d815c35
|
| 3 |
+
size 1973514
|
videos/replay_value_based_all.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5bba48c8275925470d1dd4873246b6ed7318a642b4159af1af1224df78f385d7
|
| 3 |
+
size 4782880
|