mathisweil commited on
Commit
f3010d9
·
verified ·
1 Parent(s): b502fdb

Upload MiniHack ReMDM planner checkpoints

Browse files
README.md CHANGED
@@ -12,39 +12,32 @@ tags:
12
  - pytorch
13
  ---
14
 
15
- # ReMDM Planner MiniHack checkpoints
16
 
17
  Trained weights accompanying *The Double Intractability of Reinforcement Learning for Discrete Diffusion Planners*: a remasking discrete diffusion model
18
  (ReMDM) used as an action-sequence planner in
19
- [MiniHack](https://github.com/facebookresearch/minihack).
 
20
 
21
  Code, configs and evaluation harness: https://github.com/mathisweil/minihack-ReMDM-planner
22
 
23
  ## Contents
24
 
25
- | Path | Role | Architecture | Params | Trained to | Full state |
26
- |---|---|---|---|---|---|
27
- | `checkpoints/offline/Minihack-OfflineDiffusion-BC-82M` | Diffusion planner (offline BC) | 4L, d_model 256, 4 heads, horizon 64 | 5.2M | 40,000 gradient steps, 81,920,000 sample-equivalents | 80 MB |
28
- | `checkpoints/online/Minihack-Online-Diffusion-DAgger-100M` | Diffusion planner (online DAgger) | 4L, d_model 256, 4 heads, horizon 64 | 5.2M | DAgger iteration 563, 5,654,965 env steps | 80 MB |
 
29
 
30
- Each directory holds three things: the original `.pth` training state (weights,
31
  EMA shadow, optimiser, scheduler, and for the DAgger run the curriculum and RNG
32
- state, so training can be resumed exactly), a `model.safetensors` export of the
33
- EMA weights for inference, and the YAML config snapshot the run was trained
34
- under. Paths mirror the source repository, so a snapshot can be dropped
35
- straight into a working copy.
36
 
37
- Both files are best-checkpoint selections rather than final-step dumps: each
38
- trainer evaluates every periodic checkpoint on 50 episodes per environment
39
- using EMA weights, and the highest-scoring one is published (the metric behind that selection is not recorded in this release).
40
- Each directory's `selection.json` records the selected step, the candidate
41
- cadence and the eval protocol. Directory suffixes
42
- are the sample-equivalents the published model consumed (gradient steps x batch
43
- size, rounded); file names carry each trainer's own counter, DAgger iterations
44
- online and gradient steps offline. The offline run was given the
45
- DAgger-matched budget of 60,000 gradient steps and its best checkpoint fell at
46
- 40,000, so the two published models sit at different points on a matched
47
- budget.
48
 
49
  `results/` holds the evaluation and ablation tables reported in the paper, as
50
  produced by `experiments/rl_finetuning`. Figures and raw logs stay in the code
@@ -55,14 +48,14 @@ repository.
55
  ```python
56
  from huggingface_hub import snapshot_download
57
 
58
- # everything
59
  snapshot_download(repo_id="mathisweil/remdm-minihack-checkpoints", local_dir=".")
60
 
61
- # inference weights only
62
  snapshot_download(
63
  repo_id="mathisweil/remdm-minihack-checkpoints",
64
  local_dir=".",
65
- allow_patterns=["**/model.safetensors", "**/config*.yaml"],
66
  )
67
  ```
68
 
@@ -76,7 +69,8 @@ uv run python main.py --mode inference \
76
  --config $DIR/config_iter600.yaml --checkpoint $DIR/iter600.pth
77
  ```
78
 
79
- Programmatic loading, using the safetensors export:
 
80
 
81
  ```python
82
  from safetensors.torch import load_file
@@ -89,18 +83,29 @@ model.load_state_dict(load_file(f"{DIR}/model.safetensors"))
89
  model.eval()
90
  ```
91
 
92
- Architecture arguments must come from the checkpoint's own config snapshot
93
  rather than from `configs/defaults.yaml`, which tracks the current code.
94
 
95
  ## Training
96
 
97
  The planners are bidirectional transformers that denoise a masked action plan
98
  conditioned on a cropped MiniHack glyph observation, trained either by offline
99
- behaviour cloning on oracle rollouts or by online DAgger against the oracle
100
- with a dynamic environment curriculum. In-distribution and out-of-distribution
101
- environment sets, remasking strategy, sampling settings and every
102
- hyperparameter are recorded in the per-checkpoint config snapshots, which are
103
- the authoritative record.
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  ## Limitations
106
 
 
12
  - pytorch
13
  ---
14
 
15
+ # ReMDM Planner: MiniHack checkpoints
16
 
17
  Trained weights accompanying *The Double Intractability of Reinforcement Learning for Discrete Diffusion Planners*: a remasking discrete diffusion model
18
  (ReMDM) used as an action-sequence planner in
19
+ [MiniHack](https://github.com/facebookresearch/minihack), together with the BFS
20
+ oracle rollouts that supervise it.
21
 
22
  Code, configs and evaluation harness: https://github.com/mathisweil/minihack-ReMDM-planner
23
 
24
  ## Contents
25
 
26
+ | Path | Role | Environment | Architecture | Selected at | Training | Size |
27
+ |---|---|---|---|---|---|---|
28
+ | `checkpoints` | minihack-ReMDM-planner | `MiniHack` | 4L, d_model 256, 4 heads, horizon 64, 5M params | iteration 5 | 2,835 env steps | 260 MB |
29
+ | `checkpoints/offline/Minihack-OfflineDiffusion-BC-82M` | Diffusion planner (offline BC) | `MiniHack` | 4L, d_model 256, 4 heads, horizon 64, 5M params | gradient step 40,000 | 81,920,000 sample-equivalents | 100 MB |
30
+ | `checkpoints/online/Minihack-Online-Diffusion-DAgger-100M` | Diffusion planner (online DAgger) | `MiniHack` | 4L, d_model 256, 4 heads, horizon 64, 5M params | iteration 563 | 5,654,965 env steps | 100 MB |
31
 
32
+ Each checkpoint ships the `.pth` training state it was published from (weights,
33
  EMA shadow, optimiser, scheduler, and for the DAgger run the curriculum and RNG
34
+ state, so training resumes exactly), a `model.safetensors` export of the EMA
35
+ weights for inference, the YAML config snapshot it was trained under, and a
36
+ `selection.json` recording how it was chosen.
 
37
 
38
+ Weights are PyTorch training states with a `safetensors` export of the EMA
39
+ weights alongside, and the paths above mirror the source repository so a
40
+ snapshot can be dropped straight into a working copy.
 
 
 
 
 
 
 
 
41
 
42
  `results/` holds the evaluation and ablation tables reported in the paper, as
43
  produced by `experiments/rl_finetuning`. Figures and raw logs stay in the code
 
48
  ```python
49
  from huggingface_hub import snapshot_download
50
 
51
+ # everything (~460 MB)
52
  snapshot_download(repo_id="mathisweil/remdm-minihack-checkpoints", local_dir=".")
53
 
54
+ # a single model
55
  snapshot_download(
56
  repo_id="mathisweil/remdm-minihack-checkpoints",
57
  local_dir=".",
58
+ allow_patterns="checkpoints/online/Minihack-*/**",
59
  )
60
  ```
61
 
 
69
  --config $DIR/config_iter600.yaml --checkpoint $DIR/iter600.pth
70
  ```
71
 
72
+ Programmatic loading uses `src.models.denoiser.make_model` with the checkpoint's
73
+ own config, then the safetensors export:
74
 
75
  ```python
76
  from safetensors.torch import load_file
 
83
  model.eval()
84
  ```
85
 
86
+ Architecture arguments should be read from the checkpoint's own config snapshot
87
  rather than from `configs/defaults.yaml`, which tracks the current code.
88
 
89
  ## Training
90
 
91
  The planners are bidirectional transformers that denoise a masked action plan
92
  conditioned on a cropped MiniHack glyph observation, trained either by offline
93
+ behaviour cloning on oracle rollouts or by online DAgger against the BFS oracle
94
+ under a dynamic environment curriculum. Model size and horizon differ per run
95
+ (see the table). Exact hyperparameters for every run, including the
96
+ in-distribution and out-of-distribution environment sets, the remasking
97
+ strategy, schedule and sampling settings, are in the per-checkpoint config
98
+ snapshots listed above, which are the authoritative record.
99
+
100
+ Both models are best-checkpoint selections rather than final-step dumps: each
101
+ trainer evaluates every periodic checkpoint on 50 episodes per environment
102
+ using EMA weights, and the highest-scoring one is published (the metric behind that selection is not recorded in this release).
103
+ Directory names encode the sample-equivalents the published model consumed
104
+ (gradient steps x batch size, rounded); file names carry each trainer's own
105
+ counter, DAgger iterations online and gradient steps offline. The offline run
106
+ was given the DAgger-matched budget of 60,000 gradient steps and its best
107
+ checkpoint fell at 40,000, so the two published models sit at different points
108
+ on a matched budget.
109
 
110
  ## Limitations
111
 
checkpoints/config_iter10.yaml ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ action_dim: 12
2
+ aux_loss_weight: 0.5
3
+ baselines_bc_batch_size: 256
4
+ baselines_bc_epochs: 50
5
+ baselines_bc_lr: 0.0003
6
+ baselines_bc_oracle_episodes_per_env: 5000
7
+ baselines_dqn_buffer_size: 100000
8
+ baselines_dt_batch_size: 256
9
+ baselines_dt_context_len: 64
10
+ baselines_dt_embed_dim: 256
11
+ baselines_dt_epochs: 50
12
+ baselines_dt_eval_max_steps: 200
13
+ baselines_dt_lr: 0.0003
14
+ baselines_dt_max_ep_len: 200
15
+ baselines_dt_n_heads: 4
16
+ baselines_dt_n_layers: 4
17
+ baselines_dt_oracle_episodes_per_env: 5000
18
+ baselines_eval_episodes_per_env: null
19
+ baselines_eval_freq_env_steps: 10000
20
+ baselines_n_envs_per_id: 2
21
+ baselines_output_dir: outputs/baselines
22
+ baselines_wandb_project: minihack-ReMDM-baselines
23
+ buffer_capacity: 50
24
+ checkpoint_dir: checkpoints
25
+ checkpoint_eval_episodes: 2
26
+ checkpoint_every_timesteps: 2500
27
+ collect_episodes_per_env: 5000
28
+ collect_num_workers: 8
29
+ collect_output: data/dataset.pt
30
+ crop_size: 9
31
+ curriculum_preseed: true
32
+ curriculum_queue_size: 100
33
+ dagger_batch_size: 256
34
+ dagger_grad_clip: 1.0
35
+ dagger_lr: 3.0e-05
36
+ device: cpu
37
+ diffusion_steps_collect: 5
38
+ diffusion_steps_eval: 10
39
+ dropout: 0.0
40
+ efficiency_multiplier: 1.5
41
+ ema_decay: 0.999
42
+ episodes_per_iteration: 2
43
+ eta: 0.15
44
+ eval_episodes_per_env: 2
45
+ global_gate_init: -3.0
46
+ grad_steps_per_iteration: 5
47
+ id_envs:
48
+ - MiniHack-Room-Random-5x5-v0
49
+ - MiniHack-Room-Random-15x15-v0
50
+ - MiniHack-Corridor-R2-v0
51
+ - MiniHack-MazeWalk-9x9-v0
52
+ id_eval_every_timesteps: 2500
53
+ label_smoothing: 0.0
54
+ loss_weight_clip: 1000.0
55
+ map_h: 21
56
+ map_w: 79
57
+ mask_token: 12
58
+ n_embd: 256
59
+ n_global_tokens: 8
60
+ n_head: 4
61
+ n_layer: 4
62
+ noise_schedule: linear
63
+ num_collection_workers: 0
64
+ num_diffusion_steps: 100
65
+ offline_batch_size: 256
66
+ offline_buffer_capacity: null
67
+ offline_checkpoint_every_grad_steps: null
68
+ offline_eval_every_grad_steps: null
69
+ offline_grad_clip: 1.0
70
+ offline_log_every: 10
71
+ offline_lr: 0.0003
72
+ offline_total_grad_steps: null
73
+ ood_envs:
74
+ - MiniHack-Room-Dark-15x15-v0
75
+ - MiniHack-Corridor-R5-v0
76
+ - MiniHack-MazeWalk-45x19-v0
77
+ ood_eval_every_timesteps: 2500
78
+ pad_token: 13
79
+ physics_aware_sampling: false
80
+ remask_strategy: conf
81
+ replan_every: 16
82
+ save_policy: true
83
+ seed: null
84
+ seq_len: 64
85
+ temperature: 0.5
86
+ top_p: 0.9
87
+ torch_compile: false
88
+ total_timesteps: 5000
89
+ use_amp: false
90
+ use_global_stream: true
91
+ use_wandb: false
92
+ weight_decay: 0.0001
checkpoints/config_iter11.yaml ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ action_dim: 12
2
+ aux_loss_weight: 0.5
3
+ baselines_bc_batch_size: 256
4
+ baselines_bc_epochs: 50
5
+ baselines_bc_lr: 0.0003
6
+ baselines_bc_oracle_episodes_per_env: 5000
7
+ baselines_dqn_buffer_size: 100000
8
+ baselines_dt_batch_size: 256
9
+ baselines_dt_context_len: 64
10
+ baselines_dt_embed_dim: 256
11
+ baselines_dt_epochs: 50
12
+ baselines_dt_eval_max_steps: 200
13
+ baselines_dt_lr: 0.0003
14
+ baselines_dt_max_ep_len: 200
15
+ baselines_dt_n_heads: 4
16
+ baselines_dt_n_layers: 4
17
+ baselines_dt_oracle_episodes_per_env: 5000
18
+ baselines_eval_episodes_per_env: null
19
+ baselines_eval_freq_env_steps: 10000
20
+ baselines_n_envs_per_id: 2
21
+ baselines_output_dir: outputs/baselines
22
+ baselines_wandb_project: minihack-ReMDM-baselines
23
+ buffer_capacity: 50
24
+ checkpoint_dir: checkpoints
25
+ checkpoint_eval_episodes: 2
26
+ checkpoint_every_timesteps: 2500
27
+ collect_episodes_per_env: 5000
28
+ collect_num_workers: 8
29
+ collect_output: data/dataset.pt
30
+ crop_size: 9
31
+ curriculum_preseed: true
32
+ curriculum_queue_size: 100
33
+ dagger_batch_size: 256
34
+ dagger_grad_clip: 1.0
35
+ dagger_lr: 3.0e-05
36
+ device: cpu
37
+ diffusion_steps_collect: 5
38
+ diffusion_steps_eval: 10
39
+ dropout: 0.0
40
+ efficiency_multiplier: 1.5
41
+ ema_decay: 0.999
42
+ episodes_per_iteration: 2
43
+ eta: 0.15
44
+ eval_episodes_per_env: 2
45
+ global_gate_init: -3.0
46
+ grad_steps_per_iteration: 5
47
+ id_envs:
48
+ - MiniHack-Room-Random-5x5-v0
49
+ - MiniHack-Room-Random-15x15-v0
50
+ - MiniHack-Corridor-R2-v0
51
+ - MiniHack-MazeWalk-9x9-v0
52
+ id_eval_every_timesteps: 2500
53
+ label_smoothing: 0.0
54
+ loss_weight_clip: 1000.0
55
+ map_h: 21
56
+ map_w: 79
57
+ mask_token: 12
58
+ n_embd: 256
59
+ n_global_tokens: 8
60
+ n_head: 4
61
+ n_layer: 4
62
+ noise_schedule: linear
63
+ num_collection_workers: 0
64
+ num_diffusion_steps: 100
65
+ offline_batch_size: 256
66
+ offline_buffer_capacity: null
67
+ offline_checkpoint_every_grad_steps: null
68
+ offline_eval_every_grad_steps: null
69
+ offline_grad_clip: 1.0
70
+ offline_log_every: 10
71
+ offline_lr: 0.0003
72
+ offline_total_grad_steps: null
73
+ ood_envs:
74
+ - MiniHack-Room-Dark-15x15-v0
75
+ - MiniHack-Corridor-R5-v0
76
+ - MiniHack-MazeWalk-45x19-v0
77
+ ood_eval_every_timesteps: 2500
78
+ pad_token: 13
79
+ physics_aware_sampling: false
80
+ remask_strategy: conf
81
+ replan_every: 16
82
+ save_policy: true
83
+ seed: null
84
+ seq_len: 64
85
+ temperature: 0.5
86
+ top_p: 0.9
87
+ torch_compile: false
88
+ total_timesteps: 5000
89
+ use_amp: false
90
+ use_global_stream: true
91
+ use_wandb: false
92
+ weight_decay: 0.0001
checkpoints/config_iter5.yaml ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ action_dim: 12
2
+ aux_loss_weight: 0.5
3
+ baselines_bc_batch_size: 256
4
+ baselines_bc_epochs: 50
5
+ baselines_bc_lr: 0.0003
6
+ baselines_bc_oracle_episodes_per_env: 5000
7
+ baselines_dqn_buffer_size: 100000
8
+ baselines_dt_batch_size: 256
9
+ baselines_dt_context_len: 64
10
+ baselines_dt_embed_dim: 256
11
+ baselines_dt_epochs: 50
12
+ baselines_dt_eval_max_steps: 200
13
+ baselines_dt_lr: 0.0003
14
+ baselines_dt_max_ep_len: 200
15
+ baselines_dt_n_heads: 4
16
+ baselines_dt_n_layers: 4
17
+ baselines_dt_oracle_episodes_per_env: 5000
18
+ baselines_eval_episodes_per_env: null
19
+ baselines_eval_freq_env_steps: 10000
20
+ baselines_n_envs_per_id: 2
21
+ baselines_output_dir: outputs/baselines
22
+ baselines_wandb_project: minihack-ReMDM-baselines
23
+ buffer_capacity: 50
24
+ checkpoint_dir: checkpoints
25
+ checkpoint_eval_episodes: 2
26
+ checkpoint_every_timesteps: 2500
27
+ collect_episodes_per_env: 5000
28
+ collect_num_workers: 8
29
+ collect_output: data/dataset.pt
30
+ crop_size: 9
31
+ curriculum_preseed: true
32
+ curriculum_queue_size: 100
33
+ dagger_batch_size: 256
34
+ dagger_grad_clip: 1.0
35
+ dagger_lr: 3.0e-05
36
+ device: cpu
37
+ diffusion_steps_collect: 5
38
+ diffusion_steps_eval: 10
39
+ dropout: 0.0
40
+ efficiency_multiplier: 1.5
41
+ ema_decay: 0.999
42
+ episodes_per_iteration: 2
43
+ eta: 0.15
44
+ eval_episodes_per_env: 2
45
+ global_gate_init: -3.0
46
+ grad_steps_per_iteration: 5
47
+ id_envs:
48
+ - MiniHack-Room-Random-5x5-v0
49
+ - MiniHack-Room-Random-15x15-v0
50
+ - MiniHack-Corridor-R2-v0
51
+ - MiniHack-MazeWalk-9x9-v0
52
+ id_eval_every_timesteps: 2500
53
+ label_smoothing: 0.0
54
+ loss_weight_clip: 1000.0
55
+ map_h: 21
56
+ map_w: 79
57
+ mask_token: 12
58
+ n_embd: 256
59
+ n_global_tokens: 8
60
+ n_head: 4
61
+ n_layer: 4
62
+ noise_schedule: linear
63
+ num_collection_workers: 0
64
+ num_diffusion_steps: 100
65
+ offline_batch_size: 256
66
+ offline_buffer_capacity: null
67
+ offline_checkpoint_every_grad_steps: null
68
+ offline_eval_every_grad_steps: null
69
+ offline_grad_clip: 1.0
70
+ offline_log_every: 10
71
+ offline_lr: 0.0003
72
+ offline_total_grad_steps: null
73
+ ood_envs:
74
+ - MiniHack-Room-Dark-15x15-v0
75
+ - MiniHack-Corridor-R5-v0
76
+ - MiniHack-MazeWalk-45x19-v0
77
+ ood_eval_every_timesteps: 2500
78
+ pad_token: 13
79
+ physics_aware_sampling: false
80
+ remask_strategy: conf
81
+ replan_every: 16
82
+ save_policy: true
83
+ seed: null
84
+ seq_len: 64
85
+ temperature: 0.5
86
+ top_p: 0.9
87
+ torch_compile: false
88
+ total_timesteps: 5000
89
+ use_amp: false
90
+ use_global_stream: true
91
+ use_wandb: false
92
+ weight_decay: 0.0001
checkpoints/iter10.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:684c6efd17adb8158e436b67f5cba5b66f58d81305658d92f13001cac943e61e
3
+ size 83984510
checkpoints/iter11.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:de57e58957564c62bc48e3aa9c31844b30b0098de069efab3d307a937002053e
3
+ size 83984510
checkpoints/iter5.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c933ca32ad857e3731bb9dddeddb1c013db732cf4a824e8452924a2c8b97785a
3
+ size 83972495
checkpoints/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e4a91c4aed49e5ab182816a8bcaa714387f89b26f170d67bd1902b9eb56425fa
3
+ size 20974876
checkpoints/online/Minihack-Online-Diffusion-DAgger-100M/model.safetensors CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:1a25616b8ebd7673982fea78ba33030a552cebd0356cbe9a6ff55c42380a3709
3
  size 20974876
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f023044d7a9d3b56396a0c71e2a4389a7fac941044e214a9fc05cc52af152b91
3
  size 20974876
checkpoints/selection.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "policy": "best-of-N over periodic checkpoints",
3
+ "selected": {
4
+ "dagger_iteration": 5
5
+ },
6
+ "selection_metric": null,
7
+ "candidates": {
8
+ "unit": "dagger_iterations",
9
+ "every": null,
10
+ "configured_max": null
11
+ },
12
+ "eval_protocol": {
13
+ "episodes_per_env": 2,
14
+ "weights": "ema",
15
+ "id_envs": [
16
+ "MiniHack-Room-Random-5x5-v0",
17
+ "MiniHack-Room-Random-15x15-v0",
18
+ "MiniHack-Corridor-R2-v0",
19
+ "MiniHack-MazeWalk-9x9-v0"
20
+ ],
21
+ "ood_envs": [
22
+ "MiniHack-Room-Dark-15x15-v0",
23
+ "MiniHack-Corridor-R5-v0",
24
+ "MiniHack-MazeWalk-45x19-v0"
25
+ ]
26
+ }
27
+ }