File size: 5,305 Bytes
be00c30
217a563
 
 
 
 
 
 
 
 
be00c30
b8f29b6
217a563
b8f29b6
217a563
 
 
 
 
307bdde
217a563
b8f29b6
217a563
b8f29b6
217a563
 
 
 
 
 
 
b8f29b6
217a563
b8f29b6
217a563
 
 
 
 
b8f29b6
217a563
b8f29b6
217a563
b8f29b6
307bdde
 
217a563
307bdde
 
edb57fe
40c9099
 
edb57fe
307bdde
f8b6318
b8f29b6
217a563
 
 
 
 
 
b8f29b6
217a563
f8b6318
217a563
 
edb57fe
217a563
 
 
f8b6318
217a563
307bdde
f8b6318
217a563
 
 
 
 
f8b6318
 
217a563
f8b6318
217a563
e04302c
217a563
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e04302c
217a563
 
 
 
 
 
907a236
b8f29b6
217a563
b8f29b6
f8b6318
 
217a563
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
---
license: agpl-3.0
library_name: stable-baselines3
tags:
  - deep-reinforcement-learning
  - agricultural-ai
  - weather-modelling
  - curriculum-learning
  - edge-ai
pipeline_tag: reinforcement-learning
---

# Agricultural Weather-Risk RL β€” MaskablePPO + Zone-Equivariant GRU

Budget-constrained multi-zone weather-risk inspection for Indonesian rice
zones. A Gymnasium environment tracks per-zone beliefs under a scarce
inspection budget. A zone-equivariant GRU policy supports curriculum phases
with changing `n_zones`. Deterministic crop-risk scoring grounds rewards
and product alerts. An ONNX β†’ MNN path is provided for edge inference.

Research codebase, not a production alerting service.

## What is included

- `weather_forecast_env.py` β€” Gymnasium env (belief map, action masks, triage/scarce/full budget modes, zone-order shuffle, real EpisodeContext injection)
- `gru_weather_policy.py` β€” Zone-equivariant GRU extractor (`ZoneEquivariantMaskablePolicy`; shared per-zone weights; precip input scaling, `precip_scale=40.0`)
- `train_curriculum.py` / `train_kaggle.py` β€” Curriculum and standalone training (`--budget-mode triage|scarce|full`, `--precip-scale`)
- `crop_risk_scorer.py` β€” Deterministic, economics-calibrated risk scoring
- `climatology.py` + `indonesia_zones.py` β€” Per-zone climatology and Indonesian agricultural zones
- `evaluate_checkpoint_real.py` β€” Real-trajectory eval (L1 labels, belief Ξ”, zero_inspect control)
- `mnn_export.py` + `edge_wrapper.cpp` β€” ONNX/MNN export and C++ edge runtime with external GRU hidden state

## Architecture note

Inspect logits are scored **per zone before pooling** (`ZoneEquivariantMaskablePolicy`).
The value path stays permutation-invariant so most weights transfer across
`n_zones`. Full-tour episode length is not zone-selection skill; allocation
under triage is evaluated with `max_steps < n_zones` and per-episode zone-order
shuffle.

## How to use

### Train (triage, recommended recipe)

```bash
python train_kaggle.py \
  --out ./run_nz2_triage \
  --n-zones 2 \
  --budget-mode triage \
  --steps 2400000 \
  --clean-episode-ratio 0.80 \
  --event-spatial-correlation 0.50 \
  --precip-scale 40.0 \
  --device auto
```

Requires `ZoneEquivariantMaskablePolicy` from `gru_weather_policy.py` (not
the string `"MultiInputPolicy"`). `--precip-scale` is a real CLI flag
(default `40.0`, matching the validated recipe). **Step count matters**:
150k steps is enough for drought/flood selection but not fungi; fungi
selection was confirmed solved by 2.4M steps on the same recipe β€” see
Validation status.

### Load

```python
from sb3_contrib import MaskablePPO

model = MaskablePPO.load("run_nz2_triage/final_model.zip")
action, _ = model.predict(obs, action_masks=masks, deterministic=True)
```

### Edge export

```bash
python mnn_export.py \
  --checkpoint run_nz2_triage/final_model.zip \
  --output weather_rl_model.mnn \
  --quantize int8 \
  --n-zones 2
```

## Validation status

| Claim | Status |
|-------|--------|
| Weight transfer across `n_zones` changes | Supported by design |
| Zone-order shuffle avoids fixed-slot lock-in | Observed, confirmed at 250k and 2.4M steps (raw per-slot action counts stay ~50/50) |
| Risk-conditioned zone choice β€” drought (synthetic, single-dirty) | **Confirmed 100%** at 2.4M steps (n=76 combined, two seed blocks + ρ=0.85 transfer) |
| Risk-conditioned zone choice β€” flood (synthetic, single-dirty) | **Confirmed 100%** at 2.4M steps (n=97 combined, two seed blocks + ρ=0.85 transfer) |
| Risk-conditioned zone choice β€” fungi/disease pressure (synthetic, single-dirty) | **Confirmed 100%** at 2.4M steps (n=95 combined, two seed blocks + ρ=0.85 transfer) β€” lagged at ~57–67% through 250k on the same run; needed more steps, not a different mechanism |
| Triage agent evaluated against real L1 trajectories | Open β€” all accuracy figures above are synthetic; `evaluate_checkpoint_real.py` has not yet been run on a triage-trained checkpoint |
| Product skill vs curated L1 labels | Scorer/product path available; L1 density limits apply |
| Multi-seed replication of the triage recipe | Open β€” the 2.4M result is one training run (`--seed 7`, confirmed via the training command; this pins the environment's episode generation but not PyTorch's weight-init RNG, which `train_kaggle.py` doesn't currently seed separately). A second seed reaching the same result has not been tried. |
| Held-out real product / emit metrics | Open |

## Limitations

- Research stack only: no on-call, feed SLA, or regulatory certification.
- Training is largely synthetic for the moment.
- Full-tour belief or episode-length metrics are not zone-selection skill.
- All zone-selection accuracy figures to date are from synthetic episodes;
  the triage-trained policy has not been evaluated against real L1
  trajectories (see Validation status).
- The 2.4M-step selection-accuracy result comes from a single training run;
  not yet replicated on a second seed.
- MNN/C++ path is export-oriented, not a validated production edge deployment.

## Dependencies

```
torch>=2.0
gymnasium>=0.29
stable-baselines3>=2.0
sb3-contrib>=2.0
numpy>=1.24
```

While GPU is recommended for training, CPUs can be used successfully.

## License

AGPL-3.0. See repository for full terms.