File size: 8,263 Bytes
82d31f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
---

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.