YeMoKoo commited on
Commit
a90a801
·
verified ·
1 Parent(s): 6cc8fb3

Add pre_error GRPO LoRA adapters (scalar / discrete), 2026-08-18

Browse files
README.md CHANGED
@@ -10,13 +10,21 @@ tags: [lora, grpo, rlhf, gui-agent, android, androidflux]
10
  GRPO-trained LoRA adapters for **Qwen3-VL-2B-Instruct** on Android GUI error
11
  recovery. Each adapter lives in its own subfolder.
12
 
13
- | subfolder | reward model | final reward |
14
- |---|---|---|
15
- | `scalar-firsterror-20260817` | Bradley-Terry scalar head | +4.608 |
16
- | `discrete-firsterror-20260817` | judge-token `<\|+\|>` / `<\|-\|>` margin | −2.273 |
17
-
18
- Reward scales are **not comparable across the two** they come from different
19
- reward models. Compare policies by downstream task performance, not by these numbers.
 
 
 
 
 
 
 
 
20
 
21
  ```python
22
  import torch
@@ -28,7 +36,7 @@ base = AutoModelForImageTextToText.from_pretrained(
28
  revision="89644892e4d85e24eaac8bacfd4f463576704203",
29
  dtype=torch.bfloat16, device_map="cuda")
30
  model = PeftModel.from_pretrained(
31
- base, "YeMoKoo/AF_RL", subfolder="scalar-firsterror-20260817")
32
  ```
33
 
34
  Qwen3-VL is a vision-language model, so `AutoModelForCausalLM` /
@@ -36,10 +44,10 @@ Qwen3-VL is a vision-language model, so `AutoModelForCausalLM` /
36
  After loading, assert
37
  `sum("lora" in n.lower() for n, _ in model.named_parameters()) == 392`.
38
 
39
- Both were trained on the `first_error` split (2,662 samples) of
40
- `Gyubeum/AndroidFlux_RL_Train_Test` @ `4545695c26951a4884e8f18e6468d69cbdf9d174`,
41
- for 1 epoch with identical hyperparameters — the reward model is the only
42
- difference. See each subfolder's `README.md` for full details.
43
 
44
  Intended comparison (run elsewhere, on held-out data):
45
  base `Qwen/Qwen3-VL-2B-Instruct` vs. scalar-GRPO vs. discrete-GRPO.
 
10
  GRPO-trained LoRA adapters for **Qwen3-VL-2B-Instruct** on Android GUI error
11
  recovery. Each adapter lives in its own subfolder.
12
 
13
+ | subfolder | data split | reward model | final reward |
14
+ |---|---|---|---|
15
+ | `scalar-firsterror-20260817` | first_error (2,662) | Bradley-Terry scalar head | +4.608 |
16
+ | `discrete-firsterror-20260817` | first_error (2,662) | judge-token margin | −2.273 |
17
+ | `scalar-preerror-20260818` | pre_error (2,669) | Bradley-Terry scalar head | +4.982 |
18
+ | `discrete-preerror-20260818` | pre_error (2,669) | judge-token margin | −5.053 |
19
+
20
+ **Reward numbers are not comparable across rows.** The two reward models emit
21
+ different scales, and the two splits are different states. Compare policies by
22
+ downstream task performance, not by these values.
23
+
24
+ - **first_error** — the screen *immediately after* the first erroneous action;
25
+ the policy must recover.
26
+ - **pre_error** — the screen *before* the erroneous action; the policy must avoid
27
+ the mistake.
28
 
29
  ```python
30
  import torch
 
36
  revision="89644892e4d85e24eaac8bacfd4f463576704203",
37
  dtype=torch.bfloat16, device_map="cuda")
38
  model = PeftModel.from_pretrained(
39
+ base, "YeMoKoo/AF_RL", subfolder="scalar-preerror-20260818")
40
  ```
41
 
42
  Qwen3-VL is a vision-language model, so `AutoModelForCausalLM` /
 
44
  After loading, assert
45
  `sum("lora" in n.lower() for n, _ in model.named_parameters()) == 392`.
46
 
47
+ All four were trained from
48
+ `Gyubeum/AndroidFlux_RL_Train_Test` @ `4545695c26951a4884e8f18e6468d69cbdf9d174`
49
+ for 1 epoch with identical hyperparameters — only the reward model and the data
50
+ split differ. See each subfolder's `README.md` for full details.
51
 
52
  Intended comparison (run elsewhere, on held-out data):
53
  base `Qwen/Qwen3-VL-2B-Instruct` vs. scalar-GRPO vs. discrete-GRPO.
discrete-preerror-20260818/README.md ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # discrete-preerror-20260818
2
+
3
+ GRPO-trained LoRA adapter for **Qwen3-VL-2B-Instruct** on Android GUI recovery.
4
+ The policy sees a screen from the `pre_error` split - the state *before* the
5
+ erroneous action of a trajectory - and must produce the next action.
6
+
7
+ Reward model: **discrete** - judge-token `<|+|>` / `<|-|>` log-probability margin.
8
+
9
+ Companion of `discrete-firsterror-20260817`, which is the same recipe on the
10
+ `first_error` split (the screen *after* the first erroneous action).
11
+
12
+ ## Load
13
+
14
+ ```python
15
+ import torch
16
+ from transformers import AutoModelForImageTextToText, AutoProcessor
17
+ from peft import PeftModel
18
+
19
+ BASE, REV = "Qwen/Qwen3-VL-2B-Instruct", "89644892e4d85e24eaac8bacfd4f463576704203"
20
+
21
+ base = AutoModelForImageTextToText.from_pretrained(
22
+ BASE, revision=REV, dtype=torch.bfloat16, device_map="cuda")
23
+ model = PeftModel.from_pretrained(base, "YeMoKoo/AF_RL", subfolder="discrete-preerror-20260818")
24
+ processor = AutoProcessor.from_pretrained(BASE, revision=REV)
25
+
26
+ # sanity check: must be 392, not 0
27
+ assert sum("lora" in n.lower() for n, _ in model.named_parameters()) == 392
28
+ ```
29
+
30
+ Qwen3-VL is a vision-language model (`Qwen3VLForConditionalGeneration`) and is
31
+ **not** registered in `MODEL_FOR_CAUSAL_LM_MAPPING`, so `AutoModelForCausalLM` and
32
+ `AutoPeftModelForCausalLM` do not work here - use `AutoModelForImageTextToText`.
33
+
34
+ The base checkpoint is also pinned in `adapter_config.json`.
35
+
36
+ > `target_modules` is a **regex** over `model.language_model.*`. A different
37
+ > `transformers` version can rename modules so the regex matches **zero** of them;
38
+ > the adapter then loads without any error and the model behaves exactly like the
39
+ > base. Always assert the 392 LoRA parameter count above.
40
+ > Trained with `transformers==4.57.6`, `peft==0.19.1`, `torch==2.8.0`.
41
+
42
+ ## Training data
43
+
44
+ `Gyubeum/AndroidFlux_RL_Train_Test` @ `4545695c26951a4884e8f18e6468d69cbdf9d174`,
45
+ directory `data_rl_v0_from_error_only`, filtered to `sampling_category == "pre_error"`.
46
+
47
+ | | |
48
+ |---|---|
49
+ | samples | 2,669 (unique 2,669) |
50
+ | images | 10,916 |
51
+ | policy / reward history window | 10 / 5 |
52
+ | hidden labels exported | false |
53
+ | dataset SHA-256 | `b9d33be41f9d9e1549221886917b653250d786e7c0d8cdfafba9675ed1a76503` |
54
+
55
+ Prompts are label-free: no sampling category, error location, or recorded next
56
+ action is present at runtime.
57
+
58
+ ## Training
59
+
60
+ LoRA r=8, alpha=32, dropout=0.05, `target_modules=all-linear` (ViT and aligner
61
+ frozen, LLM trainable). GRPO with `num_generations=8`, `generation_batch_size=8`,
62
+ temperature 0.9, top_p 0.95, lr 1e-6, 1 epoch, warmup_ratio 0.03, weight_decay 0,
63
+ beta 0.001, `scale_rewards=group`, max_length 8192, max_completion_length 256,
64
+ seed 42, bf16. vLLM colocate rollout. Single H100 for the policy
65
+ (`per_device_train_batch_size=1`, `gradient_accumulation_steps=8`) plus one H100
66
+ for the reward model. 2,669 optimizer steps, one prompt per step.
67
+
68
+ Reward model: `Gyubeum/Qwen3-VL-8B-Instruct-UI-Genie` @ `05bf461bed27a18ee18cf9eacc6706f424a53d5e`, invalid-action penalty -5.0.
69
+
70
+ ms-swift `23e06ccd93ea00533c0e14d579095f45ac7976bc` (4.5.0.dev0), Python 3.11.15.
71
+
72
+ ## Final metrics
73
+
74
+ | metric | value |
75
+ |---|---|
76
+ | reward (final) | -5.0528 |
77
+ | reward, first 10 logs -> last 10 logs | -3.9981 -> -4.0804 |
78
+ | reward_std (final) | 1.3360 |
79
+ | frac_reward_zero_std (final) | 0.0000 |
80
+ | train_loss | 0.00084 |
81
+ | completion length min/mean/max | 107.0 / 132.8 / 166.5 |
82
+ | clipped_ratio | 0.000 |
83
+ | train_runtime | 44590 s (12.39 h) |
84
+
85
+ Trained 2026-08-18. Checkpoint `checkpoint-2669` (final, 1 full epoch).
discrete-preerror-20260818/adapter_config.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "alora_invocation_tokens": null,
3
+ "alpha_pattern": {},
4
+ "arrow_config": null,
5
+ "auto_mapping": null,
6
+ "base_model_name_or_path": "Qwen/Qwen3-VL-2B-Instruct",
7
+ "bias": "none",
8
+ "corda_config": null,
9
+ "ensure_weight_tying": false,
10
+ "eva_config": null,
11
+ "exclude_modules": null,
12
+ "fan_in_fan_out": false,
13
+ "inference_mode": true,
14
+ "init_lora_weights": true,
15
+ "layer_replication": null,
16
+ "layers_pattern": null,
17
+ "layers_to_transform": null,
18
+ "loftq_config": {},
19
+ "lora_alpha": 32,
20
+ "lora_bias": false,
21
+ "lora_dropout": 0.05,
22
+ "lora_ga_config": null,
23
+ "megatron_config": null,
24
+ "megatron_core": "megatron.core",
25
+ "modules_to_save": [],
26
+ "peft_type": "LORA",
27
+ "peft_version": "0.19.1",
28
+ "qalora_group_size": 16,
29
+ "r": 8,
30
+ "rank_pattern": {},
31
+ "revision": "89644892e4d85e24eaac8bacfd4f463576704203",
32
+ "target_modules": "^(model\\.language_model(?=\\.).*\\.(v_proj|down_proj|up_proj|k_proj|q_proj|o_proj|gate_proj))$",
33
+ "target_parameters": null,
34
+ "task_type": "CAUSAL_LM",
35
+ "trainable_token_indices": null,
36
+ "use_bdlora": null,
37
+ "use_dora": false,
38
+ "use_qalora": false,
39
+ "use_rslora": false
40
+ }
discrete-preerror-20260818/adapter_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:284e4c99969e61d9c026996f5a016fa5d5af7181f096971d22a5657b89978d9a
3
+ size 17490168
scalar-preerror-20260818/README.md ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # scalar-preerror-20260818
2
+
3
+ GRPO-trained LoRA adapter for **Qwen3-VL-2B-Instruct** on Android GUI recovery.
4
+ The policy sees a screen from the `pre_error` split - the state *before* the
5
+ erroneous action of a trajectory - and must produce the next action.
6
+
7
+ Reward model: **scalar** - Bradley-Terry scalar head; raw scalar reward.
8
+
9
+ Companion of `scalar-firsterror-20260817`, which is the same recipe on the
10
+ `first_error` split (the screen *after* the first erroneous action).
11
+
12
+ ## Load
13
+
14
+ ```python
15
+ import torch
16
+ from transformers import AutoModelForImageTextToText, AutoProcessor
17
+ from peft import PeftModel
18
+
19
+ BASE, REV = "Qwen/Qwen3-VL-2B-Instruct", "89644892e4d85e24eaac8bacfd4f463576704203"
20
+
21
+ base = AutoModelForImageTextToText.from_pretrained(
22
+ BASE, revision=REV, dtype=torch.bfloat16, device_map="cuda")
23
+ model = PeftModel.from_pretrained(base, "YeMoKoo/AF_RL", subfolder="scalar-preerror-20260818")
24
+ processor = AutoProcessor.from_pretrained(BASE, revision=REV)
25
+
26
+ # sanity check: must be 392, not 0
27
+ assert sum("lora" in n.lower() for n, _ in model.named_parameters()) == 392
28
+ ```
29
+
30
+ Qwen3-VL is a vision-language model (`Qwen3VLForConditionalGeneration`) and is
31
+ **not** registered in `MODEL_FOR_CAUSAL_LM_MAPPING`, so `AutoModelForCausalLM` and
32
+ `AutoPeftModelForCausalLM` do not work here - use `AutoModelForImageTextToText`.
33
+
34
+ The base checkpoint is also pinned in `adapter_config.json`.
35
+
36
+ > `target_modules` is a **regex** over `model.language_model.*`. A different
37
+ > `transformers` version can rename modules so the regex matches **zero** of them;
38
+ > the adapter then loads without any error and the model behaves exactly like the
39
+ > base. Always assert the 392 LoRA parameter count above.
40
+ > Trained with `transformers==4.57.6`, `peft==0.19.1`, `torch==2.8.0`.
41
+
42
+ ## Training data
43
+
44
+ `Gyubeum/AndroidFlux_RL_Train_Test` @ `4545695c26951a4884e8f18e6468d69cbdf9d174`,
45
+ directory `data_rl_v0_from_error_only`, filtered to `sampling_category == "pre_error"`.
46
+
47
+ | | |
48
+ |---|---|
49
+ | samples | 2,669 (unique 2,669) |
50
+ | images | 10,916 |
51
+ | policy / reward history window | 10 / 5 |
52
+ | hidden labels exported | false |
53
+ | dataset SHA-256 | `b9d33be41f9d9e1549221886917b653250d786e7c0d8cdfafba9675ed1a76503` |
54
+
55
+ Prompts are label-free: no sampling category, error location, or recorded next
56
+ action is present at runtime.
57
+
58
+ ## Training
59
+
60
+ LoRA r=8, alpha=32, dropout=0.05, `target_modules=all-linear` (ViT and aligner
61
+ frozen, LLM trainable). GRPO with `num_generations=8`, `generation_batch_size=8`,
62
+ temperature 0.9, top_p 0.95, lr 1e-6, 1 epoch, warmup_ratio 0.03, weight_decay 0,
63
+ beta 0.001, `scale_rewards=group`, max_length 8192, max_completion_length 256,
64
+ seed 42, bf16. vLLM colocate rollout. Single H100 for the policy
65
+ (`per_device_train_batch_size=1`, `gradient_accumulation_steps=8`) plus one H100
66
+ for the reward model. 2,669 optimizer steps, one prompt per step.
67
+
68
+ Reward model: `Gyubeum/Qwen3-VL-8B-Instruct-UI-Genie-scoring` @ `b7d953e59c49a3108416f860d430712d8b81094f`, invalid-action penalty -5.0.
69
+
70
+ ms-swift `23e06ccd93ea00533c0e14d579095f45ac7976bc` (4.5.0.dev0), Python 3.11.15.
71
+
72
+ ## Final metrics
73
+
74
+ | metric | value |
75
+ |---|---|
76
+ | reward (final) | +4.9824 |
77
+ | reward, first 10 logs -> last 10 logs | +4.7519 -> +3.6207 |
78
+ | reward_std (final) | 0.4867 |
79
+ | frac_reward_zero_std (final) | 0.0000 |
80
+ | train_loss | 0.00083 |
81
+ | completion length min/mean/max | 92.5 / 114.3 / 144.2 |
82
+ | clipped_ratio | 0.000 |
83
+ | train_runtime | 43774 s (12.16 h) |
84
+
85
+ Trained 2026-08-18. Checkpoint `checkpoint-2669` (final, 1 full epoch).
scalar-preerror-20260818/adapter_config.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "alora_invocation_tokens": null,
3
+ "alpha_pattern": {},
4
+ "arrow_config": null,
5
+ "auto_mapping": null,
6
+ "base_model_name_or_path": "Qwen/Qwen3-VL-2B-Instruct",
7
+ "bias": "none",
8
+ "corda_config": null,
9
+ "ensure_weight_tying": false,
10
+ "eva_config": null,
11
+ "exclude_modules": null,
12
+ "fan_in_fan_out": false,
13
+ "inference_mode": true,
14
+ "init_lora_weights": true,
15
+ "layer_replication": null,
16
+ "layers_pattern": null,
17
+ "layers_to_transform": null,
18
+ "loftq_config": {},
19
+ "lora_alpha": 32,
20
+ "lora_bias": false,
21
+ "lora_dropout": 0.05,
22
+ "lora_ga_config": null,
23
+ "megatron_config": null,
24
+ "megatron_core": "megatron.core",
25
+ "modules_to_save": [],
26
+ "peft_type": "LORA",
27
+ "peft_version": "0.19.1",
28
+ "qalora_group_size": 16,
29
+ "r": 8,
30
+ "rank_pattern": {},
31
+ "revision": "89644892e4d85e24eaac8bacfd4f463576704203",
32
+ "target_modules": "^(model\\.language_model(?=\\.).*\\.(down_proj|v_proj|up_proj|k_proj|q_proj|o_proj|gate_proj))$",
33
+ "target_parameters": null,
34
+ "task_type": "CAUSAL_LM",
35
+ "trainable_token_indices": null,
36
+ "use_bdlora": null,
37
+ "use_dora": false,
38
+ "use_qalora": false,
39
+ "use_rslora": false
40
+ }
scalar-preerror-20260818/adapter_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a349950261e8ba93fbd794ceb8e39fac5a80c87c7f1fb0d8a3977f86b6508007
3
+ size 17490168