Real-world captures recorded with the demo app will be added here.
Highlights
- Real time on a tablet. Model A produces a 480Ć640 metric point map in 152 ms end to end on an iPad Pro 11-inch (M5); Model B produces 240Ć320 in 129 ms.
- Fine structure. 25 % lower error on thin and nearby structures than PromptDAāL on 61 held-out rooms, with a third of its image tokens.
- Better than the sensor, everywhere. 15 % lower error than the calibrated LiDAR and 46 % lower than the raw sensor, in 61 of 61 rooms.
- Compression for free. The on-device Model A is within 0.4 % of the full-size model and identical for 3āD reconstruction.
Abstract
Every recent iPhone Pro and iPad Pro carries two depth sensors that are good at opposite things. The LiDAR measures real distances, but only on a 256Ć192 grid, with a bias of a few percent that changes with distance, and it simply does not see thin objects such as chair legs or cables. The camera sees all of that detail, and a monocular geometry model such as MoGeā3 can turn a single photo into remarkably crisp 3āD shape ā but it has to guess how large the scene is. On our ARKitScenes test frames MoGeā3's own scale estimate is off by 14.8 % on average, while the raw LiDAR is off by only 1.9 %.
PromptMoGe combines them. We feed the LiDAR depth and its confidence map into MoGeā3 as a prompt, so the network can use the sensor wherever it is trustworthy and fall back on what it sees in the image wherever it is not. Three design decisions make this work. The backbone stays frozen and the prompt enters through gates that start at zero, so training begins from exactly MoGeā3 and cannot easily destroy what it already knows. The network keeps predicting scale-free geometry, and we convert it to metres with a small closed-form fit to the sensor ā which we call the metric attachment and describe in detail below. And MoGeā3's sparse 3āD refiner is told, at every step, where its current estimate disagrees with the sensor.
Almost every one of these components exists because a simpler version failed in a way we could measure, and we report those failures alongside the results.
The second half of the work is making this run on the device itself. We derive two compressed models from the full-size one. Model A produces a 480Ć640 point map and is, on every benchmark we have, indistinguishable from the full model. Model B produces 240Ć320 and gives up about 3 % accuracy to save a further 23 ms. Both run end to end on an iPad, with the Neural Engine, the GPU and a set of custom int8 Metal kernels each doing the part they are fastest at, and their output agrees with the PyTorch reference to within 0.2 %.
How does it compare with PromptDAāL, the strongest published LiDAR-prompted depth model? We have tried to be careful here. As released, PromptDAāL is less accurate than PromptMoGe on our benchmarks. But much of that gap comes from how the output is tied to the sensor rather than from the network: once PromptDA's output is given the same metric attachment as ours, overall accuracy is a statistical tie. What remains are two large and opposite differences. PromptMoGe is about 25 % more accurate on thin and nearby structures; PromptDA is about 17 % more accurate on the rare pixels where the LiDAR is confidently wrong, such as glass and mirrors. PromptMoGe gets there with 1 200 image tokens instead of 3 888, which is what makes running it on a tablet possible.
Method
Starting point: MoGeā3
MoGeā3 [1] takes one image and predicts, for every pixel, a point in 3āD. It does not predict metric coordinates directly. Instead it predicts a viewing ray (x/z, y/z) and a logādepth log z that is only defined up to a global scale and a shift along the viewing direction; this is called an affine-invariant point map, and it is what lets one model train on datasets with wildly different scales. The architecture has three parts. A DINOv2 ViTāL/14 encoder turns a 420Ć560 image into a 30Ć40 grid of 1 200 tokens. A convolutional neck without normalisation layers decodes those tokens over five levels, doubling the resolution each time until it reaches 480Ć640, and separate heads read out points, surface normals and a validity mask.
The part that distinguishes MoGeā3 from its predecessors is its refiner. A 2āD decoder mixes features between pixels that are neighbours in the image, even when one lies on a chair leg and the other on the wall two metres behind it, and this is what blurs depth edges. MoGeā3 instead lifts every pixel into a voxel at (row, column, round(256Ā·log z)) and runs a sparse 3āD UāNet over the occupied voxels. Pixels that are far apart in depth land in different voxels and stop exchanging information, so the refiner can sharpen edges instead of smearing them. Each refinement step outputs a correction to logādepth and leaves the viewing rays untouched.
Could we skip the prompt entirely and just rescale MoGeā3's output to match the LiDAR? We tried: with the best possible robust scale and shift, stock MoGeā3 reaches 3.5 % error on the pixels where the sensor is confident, which is worse than the raw sensor's 1.9 %. A single scale and shift cannot fix the slow, scene-wide distortions in a monocular prediction. The sensor has to go into the network, where it can correct the geometry region by region.
The prompt
The LiDAR arrives as a 256Ć192 depth map in metres and a confidence map with three levels. We turn it into four channels. The first is logādepth with the frame's median subtracted, which removes the overall scale of the scene (the network predicts scale-free geometry anyway) while keeping the depth differences that describe its shape. The second marks which pixels have a reading at all, and the third is the sensor's confidence. The fourth is an uncertainty value that combines confidence with distance, rising between 3 and 5 m where phone LiDAR becomes unreliable; because it depends on absolute distance it also stops the prompt from being completely blind to scale. A pixel with no reading is encoded as āno depth, invalid, no confidence, fully uncertainā, so an empty prompt is a well-defined input that the network learns to treat as āuse the image onlyā.
This prompt map feeds two small convolutional encoders (Figure 1). A prompt stem reduces it to the 30Ć40 token grid, and its features are added to the image tokens before transformer blocks 0, 4 and 8. A prompt pyramid processes the prompt at full output resolution and adds one feature map to each of the five levels of the neck.
Zero-initialised gates, not zero-initialised projections
A new input path should not disturb a pretrained model at the start of training. The usual way to guarantee that, used by ControlNet [9] and by PromptDA [2], is to initialise the projection that adds the new features to zero. With a frozen ViT this did not work for us. Our first run diverged within 160 steps. Lowering the learning rate five-fold stopped the divergence but produced a slow drift instead: the projection weights grew 35āfold in 160 steps, and the scale of the predicted geometry slid steadily away from the sensor, all while the gradient norm looked perfectly healthy.
The explanation is a property of the Adam optimiser. Adam moves every weight by roughly the learning rate at every step, almost regardless of how informative its gradient is. A zero-initialised 256Ć1024 projection has 262 144 weights that all start moving at once, so what it injects into the transformer's residual stream is, early on, a growing random walk ā and the frozen backbone has no way to adapt to it. We therefore initialise the projection normally and multiply its output by a per-channel gate that starts at zero. The injection is now controlled by 1 024 numbers instead of a quarter of a million, it opens smoothly, and because a closed gate passes no gradient to the layers behind it, the gates get their own, higher learning rate. A unit test checks that the untrained model reproduces MoGeā3 bit for bit.
Which of the two injection paths matters? We trained three otherwise identical models from stock MoGeā3. Without the neck pyramid, error rises by 17.8 % and gets worse in all 61 test rooms. Without the token injection, overall error is unchanged (+0.5 %), but thin structures get 2.2 % worse. So the pyramid carries most of the benefit, and the early token injection buys fine detail (ablations).
The metric attachment
The network's output is geometry without units. The metric attachment is the step that converts it into metres using the LiDAR, and it turned out to matter as much as the network itself ā so much that any comparison between prompted depth models has to say how each one's output was attached. It has three stages: calibrate the sensor, fit a scale and shift, and optionally correct a smooth residual error across the frame.
Stage 1 ā calibrating the sensor. Compared with laser-scan ground truth, ARKit's LiDAR depth reads slightly short, and by an amount that depends on distance: 3.0 % short at 0.35 m, shrinking to 0.4 % at 4.5 m. That pattern is what a fixed range offset in a time-of-flight sensor looks like, and indeed the correction is almost exactly
We store it as a 12-point lookup table of correction factor against logādepth, fitted on training videos that share no rooms with any test data, and hold it constant outside 0.35ā4.5 m. The important detail is where it is applied: once, to the sensor input, before the prompt is built and before anything is fitted to the sensor. A scale-and-shift fit applied afterwards cannot do the same job, because the bias is neither a pure scale nor a pure shift ā calibrating the raw sensor with the best global scale and shift only brings its error from 1.93 % to 1.49 %, while the lookup table reaches 1.33 %. For a long time we mistook this for a limit of our architecture; it was a property of the sensor.
Stage 2 ā a robust scale and shift. Let z be the network's scale-free depth and d the calibrated LiDAR depth. We look for the two numbers s and t that make sĀ·z + t match d as closely as possible, which for a weighted least-squares criterion has a closed-form answer:
Three details make this reliable on real frames. First, the fit only uses pixels the sensor marks as high-confidence and the network's own mask marks as valid, and it is done at the sensor's resolution: the model's depth is averaged down to the 256Ć192 grid rather than the sparse sensor being interpolated up. Second, it is trimmed. The sensor is sometimes confidently wrong, and the model is sometimes wrong at depth edges, so after each solve we discard the 20 % of pixels with the largest relative error and solve again, four times in total. Third, if fewer than 32 usable pixels remain, the fit is skipped rather than trusted. The resulting (s, t) is applied to the full-resolution output. This is in the spirit of the alignment used to evaluate relative-depth models such as MiDaS [11], with the difference that we align to the sensor rather than to ground truth, so it is a legitimate part of inference.
Training through the fit. During training the same fit converts the network's output to metres before it is compared with ground truth. Our first implementation treated s and t as constants when back-propagating, and training collapsed: the loss rose from 0.030 to 0.073, the predicted logādepth drifted upwards by 4.6 (a factor of a hundred in depth), and the fitted scale fell from 0.83 to 0.01 to compensate. The network had discovered that it could reduce its loss a little by changing its overall scale; the fit then absorbed the change at the next step, the gradient pointed the same way again, and the two chased each other indefinitely. We call this the gauge treadmill.
The cure is to let gradients flow through the final least-squares solve, while still choosing which pixels to trim from detached values. With the weights held fixed, rescaling the network's output by any a and b simply changes the fitted values to s/a and t ā sĀ·b/a and leaves the metric result identical. The loss therefore becomes exactly insensitive to the network's global scale and shift, the gradient in that direction vanishes (we measured 10ā»ā·), and the network is left to learn shape. Since nothing then pins the absolute scale of its output, a weak extra term ties the mean logādepth to that of the frozen MoGeā3 teacher.
Stage 3 ā a per-frame quadratic gauge. Two numbers cannot remove an error that varies smoothly across the image, such as a slight tilt or bow. As an optional last step we therefore fit, on the confident pixels, a quadratic surface in image coordinates to the remaining logāratio between sensor and prediction,
using three rounds of robustly re-weighted least squares so that outliers do not steer it, and multiply the depth and the lateral coordinates by the result. Scaling all three coordinates together moves each point along its viewing ray, so the geometry stays consistent with the camera. On ARKit data this lowers confident-pixel error by a further 4.5 % and slightly improves fused reconstructions. We only use it at inference: supervising the network āup to a gaugeā during training made it 1 % worse. And it should be switched off for sparse sensors, where six free parameters start fitting the sensor's own distortion (error 3.50 % with it, 3.25 % without, on a simulated 112-beam sensor).
How much is the attachment worth? The table below separates the contribution of the attachment from that of the network, on our three-capture development set. Calibration alone takes the raw sensor most of the way to the prompted models. PromptDAāL improves from 1.37 % to 1.25 % when it is simply given our attachment. And if both networks are instead tied to the uncalibrated LiDAR with a plain scale and shift, they are indistinguishable. This is why every comparison below reports PromptDA both as released and āwith our attachmentā, meaning its output passed through exactly the three stages above.
| 1 094 frames Ā· error on sensor-confident pixels | how the output is made metric | AbsRel |
|---|---|---|
| raw ARKit LiDAR | as measured | 1.93 % |
| raw ARKit LiDAR | best global scale and shift | 1.49 % |
| raw ARKit LiDAR | depth lookup table (stage 1) | 1.33 % |
| stock MoGeā3, no prompt | its own scale prediction | 14.76 % |
| stock MoGeā3, no prompt | robust scale and shift to the LiDAR (stage 2) | 3.46 % |
| PromptDAāL | as released: metric output, uncalibrated prompt | 1.37 % |
| PromptDAāL | our attachment (stages 1ā3 applied to its output) | 1.25 % |
| PromptMoGe | our attachment (stages 1ā3) | 1.22 % |
| both networks re-attached identically, as a control | ||
| PromptDAāL / PromptMoGe | scale and shift to the uncalibrated LiDAR, no gauge | 1.90 % / 1.88 % |
| PromptDAāL / PromptMoGe | oracle scale and shift to ground truth | 1.05 % / 1.02 % |
gauge_poly=2), and the lookup table is optional (calibration_lut); the iOS demo uses the scale-and-shift fit alone, computed on the GPU.A refiner that sees the sensor
At our token budget the stock refiner does almost nothing for metric accuracy: error after three refinement steps equals error after none, to four decimal places. It has no way of knowing where the sensor disagrees with the current estimate. We give it that information as two extra input channels per voxel. Before every step the LiDAR is re-fitted to the current depth (the same robust fit as above, run in the network's scale-free frame), and the refiner receives the logādifference between sensor and estimate, together with a weight that is 1.0 for high-confidence readings, 0.58 for medium and 0.15 for low. The weight never reaches zero because ARKit's confidence is a heuristic and low-confidence readings are often correct. The projection that introduces these channels starts at zero, like every other new path.
With this change one refinement step lowers error where the sensor is weakest ā by about 5 % in holes, 4 % in low-confidence regions and 3 % at depth edges ā and also sharpens edges visibly. It has one consistent cost: thin structures get about 4 % worse, in 60 of our 61 test rooms. We ship one refinement step as the default and let the user choose none.
Training
What is trained
The DINOv2 backbone stays frozen in every model we release. We train the prompt stem, the prompt pyramid and their gates, MoGeā3's neck and heads and, in a separate stage, the refiner ā 24 million of the model's 374 million parameters. We did try to adapt the backbone as well, seven times in different ways: LoRA adapters, full fine-tuning at a small learning rate with a penalty for leaving the pretrained weights, and feature distillation. None improved accuracy on real data, and the more aggressive ones made the model forget more of what it knew about images without a prompt. With roughly 16 000 to 160 000 training frames there is simply not enough data to improve a backbone trained on hundreds of millions of images.
Data
Real training frames come from ARKitScenes [3], which pairs iPad video with the device's own LiDAR depth and confidence and with ground truth rendered from stationary Faro laser scans. Most of the development used about 16 000 frames from 800 videos; the final training stage uses a denser sampling of 157 000 frames from 1 570 videos. Rooms are split so that no test room, or any other video of it, is ever used for training.
One training sample in four is synthetic, from Hypersim [4], where depth and normals are exact. Synthetic frames have no LiDAR, so we simulate one ā and simple simulations turned out to be too clean to be useful. We measured the real sensor's errors against laser scans and found that they are structured: readings are biased by +3.8 % on the near side of depth edges, the noise is correlated over about 8 pixels, and holes come in large blobs rather than speckles. We therefore trained a small network on 14 000 real LiDAR/laser pairs to reproduce these statistics, including the confidence map, and use it to render a plausible LiDAR frame for every synthetic image. Even so, synthetic data mainly helps synthetic benchmarks; its lasting contribution to real accuracy is exact supervision for normals and edges, which real laser scans cannot provide.
Teaching the network not to copy the sensor
The easiest way for a prompted model to reduce its loss is to pass the prompt straight through, since the sensor is right most of the time. A model that does this is useless exactly where it is needed. We saw the symptoms early: a prompted model's surfaces were rougher than stock MoGeā3's (normal error 20.3° against 17.7°) because it was reproducing sensor noise, and it followed the sensor into its mistakes.
Several measures counter this. In a quarter of the samples the prompt is removed entirely and the network is trained to reproduce frozen MoGeā3, which both preserves its image-only ability and teaches it what an empty prompt means. In the remaining samples we punch rectangular holes into the LiDAR, mark regions as low-confidence, and add depth noise that grows with the sensor's stated uncertainty, so the network learns that the prompt can be missing or wrong and that the confidence channel means something. Errors on pixels without a confident reading count four times as much. And a loss on surface normals, computed from the predicted depth, penalises reproducing sensor fuzz directly; with it, normal error falls to 16.9°.
Depth edges need special care, because the ground truth is least reliable there: laser-scan edges sit a median of 4.9 pixels away from the corresponding edges in the image. Training on them teaches the network to blur. We mask the ground truth within 3 pixels of its own depth discontinuities, and supervise edges instead with the gradient of the frozen image-only teacher, whose edges are aligned with the image by construction. This single change is responsible for most of our advantage on thin structures.
Losses and optimisation
The main loss is a logādepth error against ground truth after the differentiable metric fit, truncated so that gross outliers in the ground truth do not dominate. A second term keeps the output, averaged over a neighbourhood of about 8 sensor pixels, within 0.3 % of the confident LiDAR: the network is free to add detail but not to drift away from measurements that are already good. Scale-invariant, multi-scale gradient and local-patch terms shape the relative geometry, and the frozen teacher supervises viewing rays, normals and the validity mask throughout.
We use AdamW with separate learning rates for the prompt path (5Ā·10ā»āµ), its gates (2Ā·10ā»ā“) and the decoder (2Ā·10ā»āµ), a short warm-up and cosine decay, MoGeā3's mixed-precision recipe, and a batch of four frames on a single 24ā48 GB GPU. The released full-size model is the last of several stages that each start from the previous one; its final stage runs for 12 000 steps and takes about two and a half hours on an RTX 4090.
| What went wrong | Evidence | What fixed it |
|---|---|---|
| Zero-init projections into a frozen ViT | diverged by step 160; at a lower rate, weight norm 0.005 ā 0.17 in 160 steps | per-channel zero gates with their own learning rate |
| Detached scale-and-shift fit | loss 0.030 ā 0.073, fitted scale 0.83 ā 0.01: a āgauge treadmillā | differentiate through the final least-squares solve |
| An apparent accuracy ceiling | a global affine fit of the raw sensor stalls at 1.49 %; a depth lookup table reaches 1.33 % | calibrate the sensor input once, before prompt, losses and fits |
| Copying the sensor | normals 20.3° vs 17.7° stock; follows the sensor where it is wrong | prompt dropout, simulated failures, geometric-normal loss |
| Blurred depth edges | laser ground truth is misregistered by ~5 px at edges | mask the edge band; supervise edges from the RGB-only teacher |
| Frozen int8 refiner still drifted | activation clips are buffers updated in forward: one grew 72.9 ā 519.2 | freeze quantisation observers whenever the refiner is not trained |
| Prompts with scattered holes | error Ć2ā4 with 50ā80 % of LiDAR pixels dropped | nearest-fill the prompt: error back within 3 % down to 5 % of pixels |
Running it on an iPad
When we first profiled the full model on an iPad Pro, module by module, it added up to 296 ms per frame, of which 82 ms went into merely building the voxel structure for one refinement step. Reaching 152 ms took two kinds of work: making the model smaller without changing what it computes, and building a runtime in which every part runs on the processor that is fastest at it.
Compression without an accuracy bill (Model A)
A cheaper prompt pyramid. In the original pyramid a single convolution, 256 channels in and out at the full 480Ć640 resolution, accounted for 84 % of the prompt path's 431 GFLOPs. It feeds the finest level of the neck, which is also where the prompt matters least: there the injected features amount to 0.25 % of the activations they are added to, against 71 % at the second-coarsest level. We redesigned the pyramid to be wide where the resolution is low and narrow where it is high, mirroring the neck. Because every tensor shape changes, no weights carry over; instead we train the new pyramid to reproduce the five feature maps of the old one, which takes two minutes. The result costs 29 GFLOPs and moves no metric by more than 0.5 %.
Exact rescaling for the Neural Engine. The Neural Engine computes in 16-bit floating point, and the neck and heads, having no normalisation layers, produce activations as large as 433 ā enough to overflow its accumulators, which on the device turned 99.9 % of the predicted normals into NaNs. Retraining with bounded activations was one option. But these layers use ReLU, and ReLU has a convenient property: scaling its input by a positive constant scales its output by the same constant. So dividing a block's input weights and all its biases by α, and multiplying its output weights by α, leaves the result mathematically unchanged while shrinking every intermediate value. We apply this throughout (the prompt gates must be divided too, since the pyramid adds into the same stream), bringing the peak activation down to 8, and verify for every layer that its worst-case accumulation stays far below the overflow limit.
A smaller, int8 refiner. The refiner's coarsest level used 27 % of its convolution time on 0.8 % of the voxels, so we halve its width. All 31 wide layers are then trained with quantisation in the loop, simulating precisely the arithmetic of our Metal kernels: int8 weights with one scale per output channel, int8 activations with one scale per tensor, and 32-bit integer accumulation. The student is trained to reproduce the uncompressed refiner's per-voxel corrections rather than the ground truth, because the refiner's job is edges and the ground truth is masked at edges. The refiner shrinks from 39.4 to 17.2 million parameters. One trap is worth recording: freezing a quantised layer's weights does not freeze its quantiser, whose activation ranges are statistics updated on every forward pass. A later training run that merely used the frozen refiner let one range drift from 72.9 to 519.2 and silently degraded it, until we froze those statistics explicitly.
Model B removes one doubling stage from the neck, the heads, the prompt pyramid and the refiner, so the same 1 200 tokens produce a 240Ć320 point map. The levels it shares with the full model are copied across, the final output layers are re-fitted by least squares, and the model is then fine-tuned and quantised like Model A.
Three processors, one frame
The Neural Engine is the most power-efficient processor in the device and handles convolutions and MLPs very well, but self-attention at 1 200 tokens is its weak point: the softmax over a 1 201Ć1 201 score matrix per head proceeds at a fixed, modest rate, and the ViT alone takes 264 ms there. The GPU's fused attention never materialises that matrix and is several times faster, but the rest of the network runs as fast or faster on the Neural Engine. Core ML will not split a model this way on its own, so we do it explicitly: each of the 24 transformer blocks is exported as two models, the attention half assigned to the GPU and the MLP half to the Neural Engine. Activations pass between them through IOSurface-backed buffers, so nothing is copied, and the prompt pyramid runs on the Neural Engine during the time it would otherwise sit idle waiting for the GPU. The neck and heads stay on the Neural Engine, where they are 1.9 times faster than on the GPU.
The refiner cannot be expressed in Core ML at all, so it runs on Metal kernels we wrote for it. A refinement step first needs the sparse structure: which voxels exist at each level, which voxels pool into which, and each voxel's 27 neighbours. Built with sorting and hashing on the CPU this took 60ā80 ms. The key observation is that the required voxel order ā sorted by row, column, then depth ā is just the image's pixel order with each pixel's voxels sorted by depth. Every level can therefore be stored column by column, pooling becomes a merge of four short lists, and a neighbour lookup is a short scan of nine columns. All of it runs in parallel on the GPU in about 2 ms. Each residual block then takes three GPU dispatches around a tiled int8 matrix multiply, with normalisation, activation, re-quantisation and the skip connection folded into the kernels so that no level of activations is read or written more than necessary. The robust metric fit runs on the GPU too, including its trimming step, which uses a two-level histogram instead of a sort.
One finding outside the model is worth passing on. In a camera app, leaving the capture session running while inference ran made Model A almost three times slower, because the image pipeline and preview compete with the ViT's attention for the GPU. The demo pauses the camera for the 150 ms it needs.
| stage Ā· ms, K = 1 | runs on | Model A Ā· 480Ć640 | Model B Ā· 240Ć320 |
|---|---|---|---|
| prompt build, nearest-fill | CPU | 0.8 | 0.8 |
| prompt stem | GPU | 1.9 | 1.9 |
| prompt pyramid | Neural Engine, overlapped with the ViT (time spent waiting for it) | 0.0 | 0.0 |
| ViT, 24 blocks | attention on GPU, MLPs on Neural Engine | 97.4 | 98.5 |
| encoder head | Neural Engine | 1.8 | 1.8 |
| neck + point and mask heads | Neural Engine | 20.3 | 13.2 |
| copy into Metal buffers | CPU | 0.5 | 0.5 |
| sparse refiner, one step | GPU, int8 Metal kernels | 27.3 | 10.4 |
| metric fit + depth | GPU | 0.8 | 1.1 |
| end to end, best / median of 10 | 152.5 / 153.6 | 128.8 / 129.8 | |
| each further refinement step | ā 23 | ā 11 | |
| depth error vs the PyTorch reference | 0.15 % | 0.17 % |
Results
A few conventions apply throughout. Our models use 1 200 tokens and one refinement step. The error measure is absolute relative error (AbsRel): the difference between predicted and true depth divided by the true depth, averaged over pixels, with no alignment to the ground truth of any kind. Besides all pixels, we report subsets that isolate particular difficulties: pixels where the sensor is confident, has low confidence or has no reading (holes); pixels near depth edges; thin structures, meaning the near side of a depth edge; and pixels where the sensor reports high confidence but is wrong by more than 15 %.
PromptMoGeāL is the full-size model; Model A and Model B are the on-device models. For PromptDAāL we ran the public checkpoint ourselves at its native 756Ć1008 resolution (3 888 tokens), once as released and once with our metric attachment applied to its output, which is the like-for-like comparison.
61 held-out rooms
Our main benchmark consists of 61 rooms, 3 340 frames, from the ARKitScenes validation pool. The pool was divided by physical room rather than by video, and the division was fixed before any of the data was downloaded, so that neither training nor design decisions could leak into it. No model in the table was trained on these rooms. The intervals we quote are 95 % bootstrap intervals obtained by resampling rooms, which is the honest unit: frames from one room are far from independent.
| AbsRel ā Ā· 61 rooms | tokens | all | confident | low-conf | holes | edges | thin | sensor wrong |
|---|---|---|---|---|---|---|---|---|
| raw ARKit LiDAR | ā | 0.0206 | 0.0189 | 0.0563 | 0.0635 | 0.1030 | 0.1123 | 0.2637 |
| LiDAR + depth calibration, no network | ā | 0.0131 | 0.0111 | 0.0556 | 0.0641 | 0.1014 | 0.1202 | 0.2629 |
| PromptDAāL as released | 3 888 | 0.0115 | 0.0102 | 0.0405 | 0.0451 | 0.0887 | 0.1265 | 0.1735 |
| PromptDAāL + our attachment | 3 888 | 0.0112 | 0.0099 | 0.0402 | 0.0451 | 0.0886 | 0.1256 | 0.1730 |
| PromptMoGeāL | 1 200 | 0.0112 | 0.0099 | 0.0402 | 0.0467 | 0.0865 | 0.0944 | 0.2023 |
| Model A (on-device) | 1 200 | 0.0112 | 0.0099 | 0.0405 | 0.0468 | 0.0867 | 0.0947 | 0.2025 |
| Model B (on-device, own 240Ć320 grid) | 1 200 | 0.0118 | 0.0103 | ā | ā | ā | ā | ā |
| PromptMoGeāL relative to ⦠| PromptDAāL + our attachment | PromptDAāL as released |
|---|---|---|
| all pixels | ā0.3 % [ā1.2, +0.7] | ā2.8 % [ā5.4, ā0.2] |
| sensor-confident pixels | ā0.5 % [ā1.3, +0.3] | ā3.3 % [ā6.3, ā0.4] |
| depth edges | ā2.3 % [ā4.4, ā0.1] | ā2.4 % [ā4.5, ā0.1] |
| thin / near structures | ā24.8 % [ā28.6, ā21.0] | ā25.3 % [ā29.1, ā21.6] |
| holes (no LiDAR return) | +3.5 % [ā1.7, +9.2] | +3.4 % [ā1.6, +9.0] |
| sensor confidently wrong | +17.0 % [+12.8, +21.7] | +16.6 % [+12.2, +21.7] |
| range 0ā1 m | ā2.2 % [ā3.0, ā1.2] | ā4.3 % [ā7.3, ā1.2] |
| range 2ā3 m | +3.8 % [+1.8, +6.3] | +4.0 % [+0.1, +8.2] |
| range 3ā4 m | +8.9 % [+3.6, +15.6] | +1.5 % [ā10.1, +14.9] |
Official ARKitScenes upsampling benchmark
ARKitScenes defines an official depth-upsampling benchmark, and PromptDA reports its headline result on it. We evaluated on the 60 % of its validation split that falls inside our development rooms (3 373 frames), following Apple's protocol at Ć4 upsampling, and kept the rest untouched as a future test set. On identical frames our models match or slightly beat our PromptDAāL run.
We want to be clear about what this does not show. The PromptDA paper reports 0.0132 m mean error on the full split; our run of its public checkpoint gives 0.0143 m on our part of it. We checked input resolution and image format and could not close that gap, although our sensor baseline matches the published one to within 1 %. We therefore make no claim against the published number, and label every PromptDA figure on this page as our own run.
| Ć4 Ā· 768Ć1024 | L1 (m) | RMSE (m) | AbsRel | paired vs PromptDAāL as released |
|---|---|---|---|---|
| raw ARKit depth | 0.0247 | 0.0432 | 0.0213 | |
| raw + depth calibration, no network | 0.0166 | 0.0390 | 0.0142 | |
| PromptDAāL, our run | 0.0143 | 0.0334 | 0.0125 | ā |
| PromptDAāL + our attachment | 0.0140 | 0.0332 | 0.0121 | |
| PromptMoGeāL | 0.0140 | 0.0334 | 0.0120 | AbsRel ā3.9 % [ā6.1, ā1.6] Ā· L1 ā2.2 % [ā4.3, +0.1] |
| Model A (on-device) | 0.0141 | 0.0334 | 0.0121 | AbsRel ā3.5 % [ā5.8, ā1.2] |
| Model B (on-device) | 0.0147 | 0.0340 | 0.0125 | |
| published, full split (not the same frames) | ||||
| PromptDAāL [2] | 0.0132 | 0.0315 | ā | |
| MSPF | 0.0149 | 0.0362 | ā | |
Zero-shot on seven other datasets
To test whether the model has learned to use a depth prompt in general, rather than ARKit's in particular, we ran it on seven datasets that neither it nor PromptDA was trained on, from tabletop scenes with transparent objects (HAMMER) to driving (KITTI). These datasets have no phone LiDAR, so the prompt is made from the ground truth: either downsampled 16 times, or downsampled 8 times with about 40 % of it removed in random rectangles. The second setting is the more informative. With a clean, dense Ć8 prompt, plain interpolation of the prompt beats every network, so that setting mostly measures how well a model passes its input through. All models receive the same prompt, with gaps filled from the nearest valid pixel, and none is given camera intrinsics. The sensor calibration table is switched off, since these are not ARKit sensors.
| dataset | prompt Ć16 | prompt Ć8, 40 % masked | |||||
|---|---|---|---|---|---|---|---|
| PromptDAāL | Model A | PromptMoGeāL | PromptDAāL | RGB-only + fit | Model A | PromptMoGeāL | |
| NYUv2 | 0.0256 | 0.0135 | 0.0136 | 0.0345 | 0.0348 | 0.0236 | 0.0235 |
| iBimsā1 | 0.0189 | 0.0145 | 0.0140 | 0.0287 | 0.0282 | 0.0241 | 0.0240 |
| DIODE indoor | 0.0078 | 0.0086 | 0.0071 | 0.0170 | 0.0427 | 0.0140 | 0.0129 |
| ETH3D | 0.0221 | 0.0205 | 0.0170 | 0.0398 | 0.0388 | 0.0331 | 0.0317 |
| HAMMER (transparent, reflective) | 0.0081 | 0.0058 | 0.0056 | 0.0199 | 0.0312 | 0.0145 | 0.0141 |
| KITTI (driving) | 0.0385 | 0.0364 | 0.0289 | 0.0986 | 0.0550 | 0.0778 | 0.0777 |
| DIODE outdoor | 0.0212 | 0.0417 | 0.0335 | 0.0377 | 0.0985 | 0.0498 | 0.0450 |
3āD reconstruction
Depth maps are rarely the end product; usually they are fused into a 3āD model of a room. We fused each model's depth into a volumetric (TSDF) reconstruction along ARKit's recorded camera trajectory, for 163 captures of the 61 rooms, and compared the result with a reconstruction made the same way from laser-scan depth. The Fāscore counts how much of the surface is reconstructed to within a threshold; accuracy and completeness are mean distances in the two directions.
Compared room by room, PromptMoGeāL beats PromptDAāL as released on F@2cm (+0.009, interval [+0.004, +0.015]) and beats the calibrated sensor on every measure in at least 59 of the 61 rooms. Against PromptDA with our attachment the two are close: we lead narrowly at the standard 4 cm voxel size and tie at 2 cm, while our surface normals are consistently 0.4ā0.65° better. The most useful result for deployment is that Model A is indistinguishable from the full model, within 0.0003 Fāscore across all 163 captures.
On three longer captures we also refined the camera poses using each model's own depth, without any ground truth. This improves on ARKit's trajectory (mean position error 1.55 ā 1.34 cm) and raises F@2cm to 0.856 for both of our models, against 0.846 for PromptDA with our attachment. PromptDA's surfaces are, however, placed slightly more accurately on average (2.69 against 2.83 cm), consistent with its strength on pixels where the sensor is wrong.
| 163 captures Ā· 4 cm voxels | F@2cm ā | F@5cm ā | accuracy cm ā | completeness cm ā | normals ° ā |
|---|---|---|---|---|---|
| raw LiDAR + calibration | 0.764 | 0.893 | 3.75 | 1.16 | 16.2 |
| PromptDAāL as released | 0.779 | 0.895 | 3.67 | 1.07 | 14.1 |
| PromptDAāL + our attachment | 0.785 | 0.896 | 3.64 | 1.05 | 14.1 |
| PromptMoGeāL | 0.788 | 0.898 | 3.63 | 1.06 | 13.5 |
| Model A (on-device) | 0.788 | 0.898 | 3.62 | 1.06 | 13.5 |
Robustness to a degraded prompt
Real sensors misbehave, so we degraded the ARKit prompt in controlled ways and gave every model the same degraded input. Depth noise barely affects our models: with 10 % multiplicative noise their error moves from 1.38 % to 1.40 %, while PromptDA's triples and the sensor's own rises five-fold. The robust fit averages noise out, and the network has been trained not to copy individual readings. A misaligned prompt, as produced by a timestamp or calibration error between camera and LiDAR, hurts all methods about equally. Cutting the prompt off beyond 2 m is handled best by the full-size model and worst by Model A, a case where compression does cost robustness.
Randomly deleting prompt pixels initially looked like a serious weakness: with half of them missing our error almost doubled. It turned out not to be a loss of information ā the models were actually more accurate with 5 % of the pixels than with 20 % ā but an unfamiliar input pattern, since training only ever removed rectangular blocks. Filling each gap with the nearest valid reading and marking it as lower-confidence restores accuracy to within 3 % of the clean result even when only one pixel in twenty survives. The released code and the demo app do this by default. It matters on a real device, where the raw LiDAR stream has far more gaps than the processed depth in ARKitScenes.
| AbsRel, all pixels Ā· 275 frames | clean | noise Ļ 5 % | noise Ļ 10 % | shift 4 px | range cut at 2 m | 20 % of pixels kept | 5 % kept |
|---|---|---|---|---|---|---|---|
| raw LiDAR + calibration | 0.0154 | 0.0450 | 0.0833 | 0.0239 | 0.0261 | 0.0165 | 0.0191 |
| PromptDAāL as released | 0.0157 | 0.0279 | 0.0461 | 0.0209 | 0.0277 | 0.0159 | 0.0163 |
| PromptDAāL + our attachment | 0.0142 | 0.0181 | 0.0263 | 0.0194 | 0.0249 | 0.0143 | 0.0145 |
| PromptMoGeāL | 0.0138 | 0.0139 | 0.0140 | 0.0188 | 0.0227 | 0.0140 | 0.0142 |
| Model A (on-device) | 0.0138 | 0.0139 | 0.0141 | 0.0189 | 0.0290 | 0.0140 | 0.0141 |
Ablations
The table below collects the controlled comparisons behind claims made earlier on this page. All are paired over the same 61 rooms.
| 61 rooms Ā· relative change in AbsRel | all | confident | holes | edges | thin | sensor wrong | rooms worse |
|---|---|---|---|---|---|---|---|
| Injection site ā trained from stock MoGeā3, 4 000 steps, vs. tokens + neck | |||||||
| tokens only (no neck pyramid) | +17.8 % | +18.7 % | +11.2 % | +1.7 % | +1.2 % | ā5.1 % | 61 / 61 |
| neck pyramid only (no tokens) | +0.5 % | +0.4 % | +1.2 % | ā0.3 % | +2.2 % | ā0.5 % | 22 / 61 |
| Refinement ā K = 1 vs K = 0 | |||||||
| one refinement step | ā1.9 % | ā1.0 % | ā5.3 % | ā2.8 % | +4.3 % | ā | thin worse in 60 / 61 |
| Final training stage (dense frames, teacher-edge loss) vs. the previous checkpoint | |||||||
| seed 0 (released) | ā0.64 % | ā0.65 % | ā2.8 % | ā0.2 % | ā6.4 % | ā2.5 % | 18 / 61 |
| seed 1 | ā0.80 % | ā0.84 % | ā2.1 % | ā1.0 % | ā9.2 % | ā2.0 % | 10 / 61 |
| Compression vs. the teacher | |||||||
| Model A | +0.4 % | +0.4 % | +0.3 % | 0.0 % | ā0.2 % | 0.0 % | |
| Model B (own 240Ć320 grid, vs A) | +2.7 % | +2.4 % | ā | +4.1 % | +7.3 % | ā | |
Sparse sensors and confidence
Two further lines of work are not part of this release but shaped it. ARKit's depth map is the product of several frames of temporal integration. A device that exposes only a single pulse of its laser pattern ā we simulated 112 beams ā provides a far sparser prompt, and a model trained only on ARKit's dense maps handles it badly: error on confident pixels rises from 1.2 % to 3.2 %, and the model copies the prompt's smeared object boundaries so faithfully that its edges become worse than if it had ignored the prompt. Re-drawing a quarter of the training prompts through a learned simulator of that sensor recovers 13 % of the lost accuracy and most of the edge quality, at a cost of 4 % on ARKit data.
We also trained two small heads that predict, per pixel, the error of the sensor and the error of the model's own output. They are trained after the fact on frozen features, so adding them changes no depth value, which we verified bit for bit. They are good at ranking pixels by error, recovering 50ā70 % of the gap between a random and a perfect ordering, but they under-estimate its magnitude; a single scale factor per head, fitted on held-out videos, fixes that for the model-error head, whose 90 % intervals then cover 91ā92 % of pixels.
Limitations
It is not better than PromptDAāL everywhere. With identical metric attachment, overall accuracy is a tie. PromptDA is 17 % more accurate where the sensor is confidently wrong and 4ā9 % more accurate between 2 and 4 m. We believe the first is a side effect of our fidelity loss, which pulls the output towards every confident sensor reading, including the wrong ones; restricting it to readings that agree with ground truth is an obvious next experiment.
It is an indoor, short-range model. Training data covers rooms up to about 5 m. On outdoor scenes (DIODE outdoor) PromptDAāL is roughly twice as accurate.
Image-only geometry has eroded. If the prompt path is bypassed entirely, the model's scale-free geometry is 2ā22 % worse than stock MoGeā3 on MoGe's own evaluation suite, worst on KITTI. The gates guarantee an exact start, but the decoder is fine-tuned afterwards and drifts. Predicted scale and field of view are unaffected, and on a device the prompt is always present, but this is a genuine regression that a future training recipe should address, for instance by replaying generic images.
The measurements have a floor. On sensor-confident pixels the laser ground truth disagrees with a fusion of itself by 0.66 %, so differences much below 1 % on that subset mean little. The sparse-sensor results rely on a simulator rather than hardware, and we could not reproduce PromptDA's published ARKitScenes figure.
Refinement trades thin structures for everything else, by about 4 %. A refiner that knows which structures are thin is future work.
Related work
Prompted depth foundation models. PromptDA [2] is the closest system to ours and the one we compare with throughout. It fine-tunes Depth Anything V2, including its backbone, and adds the LiDAR map at four scales of the decoder through zero-initialised convolutions. Its prompt is a single depth channel normalised to the range of each frame, without confidence or validity, and it is trained on ARKitScenes and ScanNet++. Prior Depth Anything [5] first densifies an arbitrary depth prior and then refines it with a conditioned network; LDCM [6] combines a Poisson-based pre-fill with a point-map output; SLIM [7] fuses sparse LiDAR into the neck of MoGeā2 for long-range driving. To our knowledge none of these reports latency on a phone or tablet; their timings are for datacenter GPUs.
Depth completion. Dedicated completion networks, from propagation-based designs to OMNIāDC [8], are strong on the sensor pattern they were trained for and tend to break when it changes. Conditioning a frozen foundation model is our way of inheriting robustness that such networks have to learn from scratch.
Conditioning frozen models. Our gates belong to the family of zero-initialised conditioning mechanisms that includes ControlNet [9], and are closest in spirit to the tanh gates with which Flamingo [10] connects new layers to a frozen language model. The metric attachment borrows the closed-form alignment and the residual trimming of MiDaS [11], applies them to sensor readings instead of ground truth, and makes them part of the training graph.
References
- L. Kong, R. Li, R. Wang, S. Xu, C. Yao, J. Xiang, J. Yang. MoGeā3: Fine-Detail Monocular Geometry Estimation with Self-Guided Sparse Volumetric Refinement. 2026.
- H. Lin, S. Peng, J. Chen, S. Peng, J. Sun, M. Liu, H. Bao, J. Feng, X. Zhou, B. Kang. Prompting Depth Anything for 4K Resolution Accurate Metric Depth Estimation. CVPR 2025.
- G. Baruch et al. ARKitScenes. NeurIPS Datasets and Benchmarks 2021.
- M. Roberts et al. Hypersim. ICCV 2021.
- Z. Wang et al. Depth Anything with Any Prior. ICLR 2026.
- Z. Yu et al. Large Depth Completion Model from Sparse Observations. ICLR 2026.
- K. Zheng et al. Sparse-LiDAR Prompting of Monocular Geometry Foundations. 2026.
- Y. Zuo, W. Yang, Z. Ma, J. Deng. OMNIāDC. ICCV 2025.
- L. Zhang, A. Rao, M. Agrawala. Adding Conditional Control to Text-to-Image Diffusion Models. ICCV 2023.
- J.-B. Alayrac et al. Flamingo. NeurIPS 2022.
- R. Ranftl et al. Towards Robust Monocular Depth Estimation. TPAMI 2020.
- R. Wang et al. MoGeā2. NeurIPS 2025. Ā· M. Oquab et al. DINOv2. TMLR 2024. Ā· L. Yang et al. Depth Anything V2. NeurIPS 2024.
BibTeX
@misc{promptmoge2026,
title = {PromptMoGe: LiDAR-Prompted Monocular Geometry on the Device},
author = {Sergii Penner},
year = {2026},
url = {https://github.com/sergmister/PromptMoGe}
}