Skip to content

Commit 0afced2

Browse files
authored
Merge pull request #753 from PolicyEngine/fix-us-h5-report-card
National calibration fixes and chunked matrix builder
2 parents 2ab5f59 + 698d207 commit 0afced2

27 files changed

Lines changed: 3208 additions & 244 deletions

.github/workflows/pipeline.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ on:
1515
type: string
1616
national_epochs:
1717
description: "Epochs for national calibration"
18-
default: "4000"
18+
default: "1000"
1919
type: string
2020
num_workers:
2121
description: "Number of parallel H5 workers"
@@ -63,7 +63,7 @@ jobs:
6363
6464
GPU="${{ inputs.gpu || 'T4' }}"
6565
EPOCHS="${{ inputs.epochs || '1000' }}"
66-
NATIONAL_EPOCHS="${{ inputs.national_epochs || '4000' }}"
66+
NATIONAL_EPOCHS="${{ inputs.national_epochs || '1000' }}"
6767
NUM_WORKERS="${{ inputs.num_workers || '50' }}"
6868
SKIP_NATIONAL="${{ inputs.skip_national || 'false' }}"
6969
RESUME_RUN_ID="${{ inputs.resume_run_id || '' }}"

Makefile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ YEAR ?= 2024
88
GPU ?= T4
99
EPOCHS ?= 1000
1010
NATIONAL_GPU ?= T4
11-
NATIONAL_EPOCHS ?= 4000
11+
NATIONAL_EPOCHS ?= 1000
1212
BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
1313
NUM_WORKERS ?= 8
1414
N_CLONES ?= 430
@@ -116,7 +116,8 @@ data-legacy: data
116116

117117
calibrate: data
118118
python -m policyengine_us_data.calibration.unified_calibration \
119-
--target-config policyengine_us_data/calibration/target_config.yaml
119+
--target-config policyengine_us_data/calibration/target_config.yaml \
120+
--log-freq 100
120121

121122
calibrate-build: data
122123
python -m policyengine_us_data.calibration.unified_calibration \
@@ -187,15 +188,15 @@ build-matrices:
187188
calibrate-modal:
188189
modal run --detach modal_app/remote_calibration_runner.py::main \
189190
--branch $(BRANCH) --gpu $(GPU) --epochs $(EPOCHS) \
190-
--beta 0.65 --lambda-l0 1e-7 --lambda-l2 1e-8 --log-freq 500 \
191+
--beta 0.65 --lambda-l0 1e-7 --lambda-l2 1e-8 --log-freq 100 \
191192
--target-config policyengine_us_data/calibration/target_config.yaml \
192193
--push-results
193194

194195
calibrate-modal-national:
195196
modal run --detach modal_app/remote_calibration_runner.py::main \
196197
--branch $(BRANCH) --gpu $(NATIONAL_GPU) \
197198
--epochs $(NATIONAL_EPOCHS) \
198-
--beta 0.65 --lambda-l0 1e-4 --lambda-l2 1e-12 --log-freq 500 \
199+
--beta 0.65 --lambda-l0 2e-2 --lambda-l2 1e-12 --log-freq 100 \
199200
--target-config policyengine_us_data/calibration/target_config.yaml \
200201
--push-results --national
201202

@@ -258,7 +259,7 @@ pipeline:
258259
clean:
259260
rm -f policyengine_us_data/storage/*.h5
260261
rm -f policyengine_us_data/storage/*.db
261-
git clean -fX -- '*.csv'
262+
git ls-files --others --ignored --exclude-standard -- '*.csv' | grep -Ev '(^|/)(\.venv|venv|env|\.tox|\.nox|node_modules)/' | xargs -r rm -f
262263
rm -rf policyengine_us_data/docs/_build
263264

264265
build:

changelog.d/753.changed.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Add a chunked mixed-geography matrix builder for memory-bounded national
2+
calibration (`--chunked-matrix`) that streams matrix columns in clone-household
3+
chunks with resumable per-chunk COO shards, progress logging (running average,
4+
elapsed, ETA), and a shared `entity_clone` module for household-subset
5+
materialization.
6+
7+
Fix three target-input integrity bugs surfaced by a new
8+
`analyze_target_consistency` diagnostic that flags cross-level and
9+
AGI-bucket-coverage inconsistencies:
10+
11+
- Drop the IRS workbook override for `total_self_employment_income`,
12+
`tax_unit_partnership_s_corp_income`, and `net_capital_gains`. The workbook
13+
columns `business_net_profits` / `partnership_and_s_corp_income` /
14+
`capital_gains_gross` are gross-only, while the geography-file line codes
15+
00900 / 26270 / 01000 already report net-of-loss. The override inflated
16+
these national targets by +40.7% / +26.1% / +3.1% at 2023 values. After
17+
the fix, all three reconcile to the penny across national, state, and
18+
district levels.
19+
- Remove the self-employment QRF winsor in `puf_impute.py`. QRF predictions
20+
are already bounded by training support; the 0.5/99.5 percentile clip
21+
was discarding the top 0.5% of legitimate signal and truncating imputed
22+
self-employment income at ~$1.1M vs the PUF training max of $74.6M.
23+
- Replace percentile-based top selection in `create_stratified_cps` with
24+
per-bracket caps (400/400/400/300/300 for the $500k-$1M through $10M+
25+
bands). Stops PUF templates from piling up above $10M and starving the
26+
middle-high $1M-$10M range.
27+
28+
Split calibration checkpoint signature validation into fatal structural
29+
mismatches and soft hyperparameter mismatches, letting callers tune
30+
`lambda_l0`, `beta`, `lambda_l2`, and `learning_rate` across resume phases.
31+
32+
Add `income_tax` national and state SOI targets, drop the unachievable
33+
JCT `deductible_mortgage_interest` target, and preserve positive mortgage
34+
interest inputs through structural conversion.
35+
36+
Retune the national Modal calibration to `lambda_l0=2e-2` at 1000 epochs
37+
and align `modal_app/pipeline.py` `log_freq` to 100.
38+
39+
Harden `make clean` so its ignored-CSV cleanup skips local environment and
40+
dependency directories such as `.venv/`, `venv/`, `env/`, `.tox/`, `.nox/`,
41+
and `node_modules/`, avoiding accidental deletion of package data inside local
42+
virtual environments.

docs/appendix.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,10 @@ for iteration in range(5000):
122122
- farm_operations_income_would_be_qualified
123123
- farm_rent_income_would_be_qualified
124124

125-
The current PUF/calibration pipeline uses the legacy `business_is_sstb` flag to
126-
split these SSTB variables on an all-or-nothing basis. It does not yet infer
127-
mixed SSTB and non-SSTB allocations within the same record.
125+
The current PUF/calibration pipeline uses the legacy `business_is_sstb` flag to split these SSTB
126+
variables on an all-or-nothing basis. It does not yet infer mixed SSTB and non-SSTB allocations
127+
within the same record.
128+
128129
- partnership_s_corp_income_would_be_qualified
129130
- rental_income_would_be_qualified
130131
- self_employment_income_would_be_qualified

docs/calibration.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,9 @@ You can re-run Step 2 as many times as you want with different hyperparameters.
9595
build only happens once.
9696

9797
Every fit now also writes a checkpoint next to the weights output
98-
(`calibration_weights.checkpoint.pt` by default). To continue the same fit,
99-
pass `--resume-from` with the weights file or checkpoint path. If a sibling
100-
checkpoint exists next to the weights file, it is used automatically so the
101-
L0 gate state is restored as well.
98+
(`calibration_weights.checkpoint.pt` by default). To continue the same fit, pass `--resume-from`
99+
with the weights file or checkpoint path. If a sibling checkpoint exists next to the weights file,
100+
it is used automatically so the L0 gate state is restored as well.
102101

103102
```bash
104103
python -m policyengine_us_data.calibration.unified_calibration \
@@ -114,9 +113,9 @@ python -m policyengine_us_data.calibration.unified_calibration \
114113
--resume-from policyengine_us_data/storage/calibration/national/weights.npy
115114
```
116115

117-
When `--resume-from` points to a checkpoint, `--epochs` means additional epochs
118-
to run beyond the saved checkpoint epoch count. If only a `.npy` weights file
119-
exists, the run warm-starts from those weights.
116+
When `--resume-from` points to a checkpoint, `--epochs` means additional epochs to run beyond the
117+
saved checkpoint epoch count. If only a `.npy` weights file exists, the run warm-starts from those
118+
weights.
120119

121120
### 2. Full pipeline with PUF
122121

modal_app/pipeline.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ def run_pipeline(
605605
gpu: str = "T4",
606606
epochs: int = 1000,
607607
national_gpu: str = "T4",
608-
national_epochs: int = 4000,
608+
national_epochs: int = 1000,
609609
num_workers: int = 50,
610610
n_clones: int = 430,
611611
skip_national: bool = False,
@@ -795,7 +795,7 @@ def run_pipeline(
795795
beta=0.65,
796796
lambda_l0=1e-7,
797797
lambda_l2=1e-8,
798-
log_freq=500,
798+
log_freq=100,
799799
)
800800
print(f" → regional fit fc: {regional_handle.object_id}")
801801

@@ -814,9 +814,9 @@ def run_pipeline(
814814
volume_package_path=vol_path,
815815
target_config=target_cfg,
816816
beta=0.65,
817-
lambda_l0=1e-4,
817+
lambda_l0=2e-2,
818818
lambda_l2=1e-12,
819-
log_freq=500,
819+
log_freq=100,
820820
)
821821
print(f" → national fit fc: {national_handle.object_id}")
822822

@@ -1283,7 +1283,7 @@ def main(
12831283
gpu: str = "T4",
12841284
epochs: int = 1000,
12851285
national_gpu: str = "T4",
1286-
national_epochs: int = 4000,
1286+
national_epochs: int = 1000,
12871287
num_workers: int = 50,
12881288
n_clones: int = 430,
12891289
skip_national: bool = False,

0 commit comments

Comments
 (0)