pointcal-c / README.md
grKnight's picture
Record H1 nuance, four-scalar count and erratum pointer in the card
82d31f0 verified
|
Raw
History Blame Contribute Delete
8.26 kB
---
license: cc-by-4.0
base_model: laion/CLIP-ViT-B-32-laion2B-s34B-b79K
pipeline_tag: zero-shot-classification
library_name: pointcal-c
tags:
- 3d
- point-cloud
- modelnet40-c
- clip
- calibration
- selective-prediction
- uncertainty
- zero-shot
---
# PointCal-C — selective zero-shot 3D recognition under corruption
A post-hoc **calibration and abstention head** on top of a frozen OpenCLIP
ViT-B/32, for zero-shot 3D point-cloud recognition under corruption, plus the
complete evaluation artifacts backing it.
Code: <https://github.com/crimsonKn1ght/pointcal-c>
## What the model is
The backbone is **never trained**. `laion/CLIP-ViT-B-32-laion2B-s34B-b79K` is
loaded frozen, in eval mode, with `requires_grad_(False)`.
The fitted model is **four scalars**, in `runs/full/results/calibration.json`,
fit on clean calibration objects only — corrupted labels, corruption identity
and severity never touch a fitted parameter:
| parameter | value | role |
|---|---|---|
| `temperature` | 1.2309 | divides logits before softmax |
| `bias` | -1.5723 | combined-score intercept |
| `weight_confidence` | +1.7071 | on `logit(p_calibrated)` |
| `weight_disagreement` | +4.9158 | on cross-view disagreement `d` |
Combined score: `sigmoid(bias + w_conf * logit(p_cal) + w_dis * d)`, where `d`
is `1 -` mean pairwise Jensen-Shannon divergence across the six views.
Converged, unclamped, not degenerate. Fit in 0.94 s on CPU.
## How inference works
```
point cloud (N,1024,3)
-> centroid-center, unit-radius normalize
-> 6 orthographic cameras [front right back left top bottom]
-> 64x64 splat raster + nearest-depth z-buffer -> upsample to 224x224
-> frozen OpenCLIP ViT-B/32 image encoder
-> per-view logits vs a fixed 8-template prompt ensemble <-- cached here
-> mean over views -> the prediction
-> four confidence scores over that one prediction
```
All four confidence methods (`msp`, `temperature`, `disagreement`, `combined`)
rank the **same** predictions. A confidence method that changed a prediction
would be a different classifier, and `assert_predictions_unchanged` raises if
one ever does.
## Results
All 75 corrupted conditions pooled against clean, 1975 evaluation objects,
95% bootstrap intervals resampled over base object IDs:
| | accuracy | ECE (MSP) | ECE (combined) | AURC (MSP) | AURC (combined) |
|---|---|---|---|---|---|
| clean | 0.2896 | 0.1160 | 0.0245 | 0.4339 | 0.4147 |
| corrupted | 0.2354 | 0.1416 | 0.0229 | 0.5217 | 0.5008 |
Accuracy degrades under corruption and MSP calibration degrades with it. The
clean-fit combined score holds ECE near **0.023** under shift and lowers AURC
by 0.021.
The ECE improvement is large and consistent. **The AURC gain is small** and
should be read against the intervals in `results.csv`, not as a headline. This
is a reliability audit and a bounded abstention baseline, not a
state-of-the-art claim.
Accuracy by severity: 0.2896 (clean), 0.2593, 0.2515, 0.2388, 0.2252, 0.2023 —
monotonically non-increasing.
### Pre-registered hypotheses
Of the four pre-registered hypotheses, three are mechanically checked. H2 and H3
resolve True. **H1 does not hold strictly:** accuracy, NLL, Brier and AURC all
worsen monotonically with severity, but ECE dips at severities 3→4 and again
from clean→1. A paired object-grouped bootstrap places both reversals within
noise of zero, so H1 is supported in direction but not as strict monotonicity.
H4 is read off the family-scope rows rather than reduced to a verdict.
## Repository contents
The expensive artifact is `runs/*/logits/` — per-view logits for every
condition under both prompt modes. Every metric, ablation, bootstrap interval
and figure here was computed on CPU from those caches, so **any re-analysis is
free**: a different aggregation, disagreement statistic, coverage level or
bootstrap depth costs no GPU time, because CLIP never runs again.
```
runs/<tier>/
logits/<condition>.npz per-view logits, both prompt modes (~1.4 MB each)
results/calibration.json the fitted scalars above
results/results.csv|.json metrics table with intervals
results/ablations.csv view-count, prompt-mode, disagreement ablations
results/predictions.npz per-sample confidences and correctness
results/results_summary.md auto-generated tables + hypothesis checks
figures/fig1..fig4 accuracy, ECE, risk-coverage, cost
provenance/ data manifest, run manifest, split audit
ledger_inference.json measured GPU-hours, dollars, throughput, memory
artifacts/split.json the frozen calibration/evaluation object split
env/requirements.lock.txt exact resolved environment (171 packages)
```
Tiers: `xs` (5 conditions, 100 objects), `s` (13 conditions), `full` (all 76 =
clean + 15 corruptions x 5 severities).
## Training / evaluation data
Evaluated on **ModelNet40-C** (2468 objects, 40 classes, 15 corruption types,
5 severities). The calibration scalars are fit on the clean split of 493
calibration objects; 1975 evaluation objects are held out.
The split is over **base object IDs**, not samples, and every corruption array
is verified row-aligned with the clean array, so holding an object out of
calibration holds it out under all 76 conditions. Audited: `overlap: 0`,
0 row-misaligned conditions, all 40 classes present on both sides.
## Compute
| tier | conditions | GPU-hours | USD | views/s | peak VRAM |
|---|---|---|---|---|---|
| xs | 5 | 0.001 | 0.0003 | 1091 | 2.5 GB |
| s | 13 | 0.015 | 0.004 | 2816 | 12.1 GB |
| full | 76 | 0.089 | 0.025 | 2808 | 12.1 GB |
**0.105 GPU-hours and about $0.03** of inference in total, on a single Runpod
RTX 4000 Ada at $0.28/hr (2026-08-16).
## Known defects
See **[ERRATUM.md](ERRATUM.md)** for the full list. In short: the `ledger` block
embedded in `runs/full/provenance/run_manifest.json` is wrong — it records a
cache-hit re-invocation, not the real run. **Trust `ledger_inference.json`,**
which every figure and the compute table above are derived from. `git_dirty` in
that manifest is not meaningful either, because the dirtiness check counts
expected untracked artifacts.
## Limitations
- `full` uses **200** bootstrap replicates, not the preregistered 1000. The CPU
bootstrap dominated runtime (~2 h at 1000 vs ~5 min of GPU work). Deeper
intervals recompute from the cached logits at no GPU cost.
- NLL and Brier require a distribution over all 40 classes, so they are reported
for `msp` and `temperature` only. For the two ranking scores they are `null`,
not a lookalike substitute.
- `delta_*_vs_clean` rows in `results.csv` carry `NaN` intervals: degradation is
reported as point estimates without paired bootstrap intervals. Method
differences should likewise not be read from the marginal intervals alone.
- Cross-view disagreement is prior art, and calibration degrading under 3D
corruption is a confirmation rather than a discovery.
- Absolute accuracy is low (~0.29 clean). This is zero-shot transfer of a 2D
model to depth renders, with no 3D training whatsoever.
- Severity is reported **1-indexed**, matching the on-disk release.
## Provenance
- Frozen spec hash: `ca487597c978ab17217bd640ab8bf95c8a21db0eaacd51ae5ba4b00618dcc820`
- Backbone checkpoint SHA-256:
`1bd3c7172de5b207ceac554f5ab5266166f3b9baccc9af5989bc801016d080ad`
- Split fingerprint: `cc5ed4b3ce7108154039f497d474f3ac6bdbfe7eb7dbfe4d0f90785e1829bb31`
## Licence and attribution
Cached logits and metrics are **derived from ModelNet40-C** and redistributed
under **CC BY 4.0**, as the source record declares.
- ModelNet40-C — Zenodo [6017834](https://zenodo.org/records/6017834),
DOI `10.5281/zenodo.6017834`, CC BY 4.0
- Generation code — <https://github.com/jiachens/ModelNet40-C>, BSD-3-Clause
- Underlying ModelNet40 carries its own original terms
- OpenCLIP — MIT · PointCal-C code — MIT
The multi-view depth-projection approach follows the PointCLIP paper (CVPR
2022); the projector is an independent reimplementation from the paper text,
with no PointCLIP repository code used.