shu223 commited on
Commit
a50a985
Β·
verified Β·
1 Parent(s): f606d45

Rewrite the model card

Browse files
Files changed (1) hide show
  1. README.md +129 -76
README.md CHANGED
@@ -1,90 +1,136 @@
1
  ---
2
  license: apache-2.0
3
- base_model: depth-anything/DA3-SMALL
4
  library_name: coreml
5
  pipeline_tag: depth-estimation
 
 
6
  tags:
7
  - coreml
8
  - core-ml
9
- - depth-estimation
10
  - depth-anything-3
11
- - DA3
 
 
 
12
  - multi-view
 
13
  - multi-view-geometry
14
  - pose-conditioned
 
 
 
 
15
  - arkit
16
  - ios
17
  - iphone
 
 
 
18
  - apple-neural-engine
 
19
  - on-device
 
20
  ---
21
 
22
- # Depth Anything 3 (DA3) Small β€” Multi-View, Pose-Conditioned Core ML for iPhone
23
 
24
- Core ML packages of [Depth Anything 3 Small](https://huggingface.co/depth-anything/DA3-SMALL) (`DA3-SMALL`,
25
- revision `e08cab65ca0ec38e7826075418411ab90cab4da3`) that run the **multi-view, pose-conditioned** path of the
26
- network on iPhone. Each model takes 2 or 3 images together with their camera poses (extrinsics and intrinsics, for
27
- example from ARKit) and returns, for every image, a depth map, a confidence map and the camera pose the network
28
- estimates. The variants are rewritten to run faster and use less memory on the iPhone Neural Engine than a plain
29
- conversion.
30
 
31
- Existing Core ML conversions of DA3 Small take a single image. These packages keep the camera encoder and decoder,
32
- so depth from several views is consistent across the views and can be brought to metres with the input poses.
 
 
 
33
 
34
- ## Variants
 
35
 
36
- | Package | Views | Input | What is changed | Minimum iOS | Size |
 
 
37
  |---|---|---|---|---|---|
38
- | `models/DA3-Small-3views-392-fast.mlpackage` (recommended) | 3 | 392 Γ— 392 | 392 input, global attention in 8 slices, depth head rewritten | 18.0 | 72.0 MB |
39
- | `models/DA3-Small-2views-392-fast.mlpackage` | 2 | 392 Γ— 392 | 392 input, global attention in 16 slices, depth head rewritten | 18.0 | 71.8 MB |
40
- | `models/DA3-Small-3views-504-sliced.mlpackage` | 3 | 504 Γ— 504 | global attention in 16 slices | 18.0 | 86.8 MB |
41
- | `models/DA3-Small-3views-504.mlpackage` | 3 | 504 Γ— 504 | none (plain conversion of the pose-conditioned path) | 17.0 | 86.7 MB |
42
-
43
- All packages are FP16.
44
-
45
- - **Sliced global attention** (`sliced`, `sliced8`): the attention across all views is computed in slices of the
46
- query, so the intermediate attention matrices stay small. It only changes the order of the operations: the
47
- weights are identical (`DA3-Small-3views-504` and `DA3-Small-3views-504-sliced` have the same `weight.bin`), and the output matches the
48
- original PyTorch model (mean depth difference 0.03–0.05% on a Mac).
49
- - **Head rewrite** (`headcombo`): the DPT depth head uses transposed-convolution upsampling and upsamples later in
50
- the head. Depth and confidence change slightly, mostly at object edges. The pose output does not change (the
51
- camera decoder reads the backbone, not the head).
52
- - **392 input**: fewer tokens per image. With the poses from ARKit, the metric scale estimated from the 392
53
- variants differs from the 504 sliced variant by a median of 2.6% (3 views) and 4.5% (2 views).
54
-
55
- ## Measured on iPhone
56
-
57
- Two devices only: iPhone 12 Pro (A14, iOS 27.0.1) and iPhone 17 Pro (A19 Pro, iOS 27.0.1), default compute units
58
- (`.all`). Times are the median inference time of one forward pass (all views). The conditions differ between rows,
59
- so compare numbers within a row.
60
-
61
- | Comparison | Device | Condition | Result |
62
  |---|---|---|---|
63
- | `DA3-Small-3views-504` β†’ `DA3-Small-3views-504-sliced` | 17 Pro | Release, ARKit poses, handheld, 120 s each from nominal thermal state | 464.3 β†’ 310.5 ms, app memory 1,121 β†’ 762 MB |
64
- | `DA3-Small-3views-504` β†’ `DA3-Small-3views-504-sliced` | 12 Pro | Release, ARKit poses, handheld, 1 min each, not cooled in between | 774 β†’ 566 ms, Neural Engine memory 760 β†’ 367 MB |
65
- | `DA3-Small-3views-504-sliced` β†’ `DA3-Small-3views-392-fast` | 17 Pro | Debug build test, fixed images | 224 β†’ 91 ms |
66
- | `DA3-Small-3views-504-sliced` β†’ `DA3-Small-3views-392-fast` | 12 Pro | Debug build test, fixed images | 579.5 β†’ 183.4 ms |
67
- | `DA3-Small-2views-392-fast` | 17 Pro | Debug build test, fixed images | 53.6–54.6 ms |
68
-
69
- Notes from these devices:
70
-
71
- - On the iPhone 17 Pro Neural Engine, the 2-view 504 sliced package does not return (the first inference stalls
72
- and is cancelled). The 2-view 392 package above returns.
73
- - A 3-view 392 package with 16 slices also does not return on the iPhone 17 Pro, which is why the recommended
74
- 3-view variant uses 8 slices.
75
  - The first load compiles the model for the Neural Engine and can take one to several minutes on an iPhone 12 Pro.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
  ## Inputs
78
 
79
  | Name | Type | Shape | Content |
80
  |---|---|---|---|
81
  | `image_0` … `image_{S-1}` | Image (RGB, 8-bit) | 392 Γ— 392 or 504 Γ— 504 | The views. View 0 is the reference view. ImageNet normalisation is inside the model. |
82
- | `extrinsics` | MultiArray Float32 | (1, S, 4, 4) | World-to-camera matrices in the OpenCV camera convention (x right, y down, z forward), **already normalised** (see below). |
83
- | `intrinsics` | MultiArray Float32 | (1, S, 3, 3) | Pinhole intrinsics of each model input image in pixels (after cropping and resizing to the input size). Only `fx` and `fy` reach the network. |
84
 
85
- The normalisation of the extrinsics is the one the official `DepthAnything3._normalize_extrinsics` (`api.py`) does
86
- before the forward pass. It is left to the caller so that it runs in Float32 / Float64 instead of the FP16 of the
87
- model:
88
 
89
  ```python
90
  import numpy as np
@@ -100,41 +146,48 @@ def normalize_extrinsics(w2c): # w2c: (S, 4, 4) world-to-camera, Open
100
 
101
  With 2 views the median is the distance of view 0 to itself, so the divisor is always 0.1.
102
 
103
- ARKit's camera axes (`ARCamera.transform`) are x right, y up and z toward the viewer in the sensor's landscape
104
- orientation, so the camera-to-world from ARKit has to be rotated into the OpenCV axes of the image you pass before it
105
- is inverted to world-to-camera. For an image rotated 90 degrees clockwise to portrait (the usual way to show it
106
- upright when the phone is held in portrait), the model's x is ARKit's +y, the model's y is ARKit's +x and the
107
- model's z is ARKit's βˆ’z: `c2w_model = c2w_arkit @ R`, with the columns of `R` being (0, 1, 0), (1, 0, 0) and
108
- (0, 0, βˆ’1). The intrinsics have to follow the same rotation, centre crop and resize.
109
 
110
  ## Outputs
111
 
112
  | Name | Type | Shape | Content |
113
  |---|---|---|---|
114
- | `depth` | MultiArray Float16 | (1, S, H, W) | Depth of every view in the normalised frame of the input poses. |
115
- | `confidence` | MultiArray Float16 | (1, S, H, W) | Confidence of every depth value. |
116
- | `pose_encoding` | MultiArray Float16 | (1, S, 9) | The pose the network estimates for every view: translation (3), quaternion xyzw (4), horizontal and vertical field of view. The translation is the camera position (camera-to-world) in the normalised frame. |
117
 
118
- To bring the depth to metres, do what the official `api.py` does: align the estimated camera positions from
119
- `pose_encoding` to the input camera positions with Umeyama's method (similarity transform) and divide the depth by
120
- the resulting scale.
121
 
122
- ## Model list
123
 
124
- `models.json` lists every package with the size and SHA-256 of each file inside it, the input size, the number of
125
- views and the minimum iOS version. Apps can read it to download the files of a package one by one from
126
- `https://huggingface.co/shu223/Depth-Anything-3-Small-MultiView-CoreML/resolve/main/<path>`, check them and compile
127
- the package on the device with `MLModel.compileModel(at:)`.
 
128
 
129
- ## Conversion
130
 
131
  Converted with coremltools from the original PyTorch implementation
132
- ([ByteDance-Seed/Depth-Anything-3](https://github.com/ByteDance-Seed/Depth-Anything-3)), with the changes listed in
133
- `NOTICE`. Ray decoding, sky handling and the Gaussian branch of the original model are not included.
 
 
 
 
 
 
 
 
134
 
135
  ## License
136
 
137
- Apache License 2.0, the same as the original weights. See `LICENSE` and `NOTICE`.
138
 
139
  ## Citation
140
 
 
1
  ---
2
  license: apache-2.0
 
3
  library_name: coreml
4
  pipeline_tag: depth-estimation
5
+ base_model: depth-anything/DA3-SMALL
6
+ base_model_relation: quantized
7
  tags:
8
  - coreml
9
  - core-ml
10
+ - depth-anything
11
  - depth-anything-3
12
+ - depth-anything-3-small
13
+ - da3
14
+ - da3-small
15
+ - depth-estimation
16
  - multi-view
17
+ - multi-view-depth
18
  - multi-view-geometry
19
  - pose-conditioned
20
+ - camera-pose
21
+ - pose-estimation
22
+ - 3d-reconstruction
23
+ - 3d-scanning
24
  - arkit
25
  - ios
26
  - iphone
27
+ - iphone-12-pro
28
+ - iphone-17-pro
29
+ - apple-silicon
30
  - apple-neural-engine
31
+ - ane
32
  - on-device
33
+ - swift
34
  ---
35
 
36
+ # Depth Anything 3 Small β€” Multi-View Core ML for iPhone
37
 
38
+ **Multi-view depth with camera poses, running on the iPhone Neural Engine. `DA3-Small-3views-392-fast` is
39
+ recommended: 2.5x (iPhone 17 Pro) to 3.2x (iPhone 12 Pro) faster than the full-size 504 file.**
 
 
 
 
40
 
41
+ [Depth Anything 3](https://huggingface.co/depth-anything/DA3-SMALL) (DA3) Small, converted to Core ML with the
42
+ multi-view, pose-conditioned path of the network kept. Give it 2 or 3 photos and their camera poses (for example from
43
+ ARKit), and it returns a depth map and a confidence map for every photo, plus the camera pose it estimates. The depth
44
+ of all views comes out in one consistent frame, so you can fuse it into a mesh or a point cloud and bring it to metres
45
+ with the poses you passed. Other Core ML conversions of DA3 Small take one image at a time.
46
 
47
+ The graph is rewritten for the iPhone: the attention across views is computed in slices, and the depth head and the
48
+ input size are changed for speed. The weights are the original ones in FP16.
49
 
50
+ ## Which file should I choose?
51
+
52
+ | File | Views | Input | What is changed | Min iOS | Size |
53
  |---|---|---|---|---|---|
54
+ | [`DA3-Small-3views-392-fast`](https://huggingface.co/shu223/Depth-Anything-3-Small-MultiView-CoreML/tree/main/models/DA3-Small-3views-392-fast.mlpackage) | 3 | 392 Γ— 392 | 392 input, attention in 8 slices, depth head rewritten. **Recommended.** | 18 | 72 MB |
55
+ | [`DA3-Small-2views-392-fast`](https://huggingface.co/shu223/Depth-Anything-3-Small-MultiView-CoreML/tree/main/models/DA3-Small-2views-392-fast.mlpackage) | 2 | 392 Γ— 392 | The same speed-ups with 2 views. Fastest. | 18 | 72 MB |
56
+ | [`DA3-Small-3views-504-sliced`](https://huggingface.co/shu223/Depth-Anything-3-Small-MultiView-CoreML/tree/main/models/DA3-Small-3views-504-sliced.mlpackage) | 3 | 504 Γ— 504 | Attention in 16 slices only. Same output as the original model. | 18 | 87 MB |
57
+ | [`DA3-Small-3views-504`](https://huggingface.co/shu223/Depth-Anything-3-Small-MultiView-CoreML/tree/main/models/DA3-Small-3views-504.mlpackage) | 3 | 504 Γ— 504 | Nothing. The plain conversion, for comparison and for iOS 17. | 17 | 87 MB |
58
+
59
+ - Start with **`DA3-Small-3views-392-fast`**. It is the one to use for scanning with ARKit.
60
+ - Use **`DA3-Small-2views-392-fast`** if you only have two photos or need the shortest time per inference.
61
+ - Use **`DA3-Small-3views-504-sliced`** if you want the output of the original model at its native 504 input: the
62
+ slicing only changes the order of the operations (it has the same `weight.bin` as `DA3-Small-3views-504`), and the
63
+ mean depth difference from the original PyTorch model is 0.03–0.05% on a Mac.
64
+ - The `fast` files trade a little accuracy for speed. The rewritten head changes depth and confidence slightly, mostly
65
+ at object edges (the pose output does not change). With ARKit poses, the metric scale from the 392 files differs
66
+ from the 504 sliced file by a median of 2.6% (3 views) and 4.5% (2 views).
67
+
68
+ ## Speed on iPhone
69
+
70
+ Median time of one inference (all views at once), default compute units (`.all`), iOS 27.0.1. Measured on two
71
+ devices only. The conditions differ between rows, so compare the numbers within a row.
72
+
73
+ | Device | Comparison | Condition | Result |
 
 
 
 
74
  |---|---|---|---|
75
+ | iPhone 17 Pro (A19 Pro) | `3views-504-sliced` β†’ `3views-392-fast` | Fixed images, Debug build | 224 β†’ **91 ms** |
76
+ | iPhone 12 Pro (A14) | `3views-504-sliced` β†’ `3views-392-fast` | Fixed images, Debug build | 579.5 β†’ **183.4 ms** |
77
+ | iPhone 17 Pro (A19 Pro) | `2views-392-fast` | Fixed images, Debug build | **53.6–54.6 ms** |
78
+ | iPhone 17 Pro (A19 Pro) | `3views-504` β†’ `3views-504-sliced` | Release, ARKit, handheld, 120 s each from the nominal thermal state | 464.3 β†’ **310.5 ms**, app memory 1,121 β†’ 762 MB |
79
+ | iPhone 12 Pro (A14) | `3views-504` β†’ `3views-504-sliced` | Release, ARKit, handheld, 1 min each | 774 β†’ **566 ms**, Neural Engine memory 760 β†’ 367 MB |
80
+
81
+ Things to know on these devices:
82
+
 
 
 
 
83
  - The first load compiles the model for the Neural Engine and can take one to several minutes on an iPhone 12 Pro.
84
+ Later loads are quick.
85
+ - A 2-view 504 file sliced in 16 does not return on the iPhone 17 Pro Neural Engine (the first inference stalls and is
86
+ cancelled), and neither does a 3-view 392 file sliced in 16. That is why the files here are 2 views at 392, and 3
87
+ views at 392 sliced in 8.
88
+
89
+ ## Use it
90
+
91
+ Download one file (a Core ML package is a folder):
92
+
93
+ ```bash
94
+ hf download shu223/Depth-Anything-3-Small-MultiView-CoreML \
95
+ --include "models/DA3-Small-3views-392-fast.mlpackage/*" --local-dir .
96
+ ```
97
+
98
+ Then add the `.mlpackage` to your Xcode project, or download it at run time and compile it on the device with
99
+ `MLModel.compileModel(at:)`. A minimal prediction in Swift:
100
+
101
+ ```swift
102
+ import CoreML
103
+
104
+ let compiledURL = try await MLModel.compileModel(at: packageURL) // once; keep the .mlmodelc
105
+ let model = try MLModel(contentsOf: compiledURL)
106
+
107
+ // 3 views, row-major: element (0, view, row, column)
108
+ let extrinsics = try MLMultiArray(shape: [1, 3, 4, 4], dataType: .float32) // normalised world-to-camera
109
+ let intrinsics = try MLMultiArray(shape: [1, 3, 3, 3], dataType: .float32) // of the 392 x 392 images
110
+ // ... fill both (see Inputs below)
111
+
112
+ let input = try MLDictionaryFeatureProvider(dictionary: [
113
+ "image_0": MLFeatureValue(pixelBuffer: image0), // 392 x 392 BGRA CVPixelBuffer
114
+ "image_1": MLFeatureValue(pixelBuffer: image1),
115
+ "image_2": MLFeatureValue(pixelBuffer: image2),
116
+ "extrinsics": MLFeatureValue(multiArray: extrinsics),
117
+ "intrinsics": MLFeatureValue(multiArray: intrinsics),
118
+ ])
119
+ let output = try model.prediction(from: input)
120
+ let depth = output.featureValue(for: "depth")!.multiArrayValue! // [1, 3, 392, 392]
121
+ let poseEncoding = output.featureValue(for: "pose_encoding")!.multiArrayValue! // [1, 3, 9]
122
+ ```
123
 
124
  ## Inputs
125
 
126
  | Name | Type | Shape | Content |
127
  |---|---|---|---|
128
  | `image_0` … `image_{S-1}` | Image (RGB, 8-bit) | 392 Γ— 392 or 504 Γ— 504 | The views. View 0 is the reference view. ImageNet normalisation is inside the model. |
129
+ | `extrinsics` | Float32 | (1, S, 4, 4) | World-to-camera matrices in the OpenCV camera axes (x right, y down, z forward), **already normalised** as below. |
130
+ | `intrinsics` | Float32 | (1, S, 3, 3) | Pinhole intrinsics of each input image in pixels, after your crop and resize. Only `fx` and `fy` reach the network. |
131
 
132
+ Normalise the extrinsics the way the official `DepthAnything3._normalize_extrinsics` (`api.py`) does before the
133
+ forward pass. It is left out of the model so that it runs in Float32 / Float64 instead of the model's FP16:
 
134
 
135
  ```python
136
  import numpy as np
 
146
 
147
  With 2 views the median is the distance of view 0 to itself, so the divisor is always 0.1.
148
 
149
+ From ARKit: `ARCamera.transform` is camera-to-world with x right, y up and z toward the viewer in the sensor's
150
+ landscape orientation. For an image rotated 90 degrees clockwise to portrait, the model's x is ARKit's +y, the model's
151
+ y is ARKit's +x and the model's z is ARKit's βˆ’z: `c2w_model = c2w_arkit @ R`, where the columns of `R` are
152
+ (0, 1, 0), (1, 0, 0) and (0, 0, βˆ’1). Invert it to get world-to-camera. The intrinsics follow the same rotation, crop
153
+ and resize.
 
154
 
155
  ## Outputs
156
 
157
  | Name | Type | Shape | Content |
158
  |---|---|---|---|
159
+ | `depth` | Float16 | (1, S, H, W) | Depth of every view, in the normalised frame of the input poses. |
160
+ | `confidence` | Float16 | (1, S, H, W) | Confidence of every depth value. |
161
+ | `pose_encoding` | Float16 | (1, S, 9) | The camera pose the network estimates for every view: translation (3), quaternion xyzw (4), horizontal and vertical field of view. The translation is the camera position (camera-to-world) in the normalised frame. |
162
 
163
+ To get metres, do what the official `api.py` does: align the camera positions in `pose_encoding` to the camera
164
+ positions you passed with Umeyama's method (a similarity transform), and divide the depth by its scale.
 
165
 
166
+ ## Downloading from an app
167
 
168
+ `models.json` at the top of this repository lists every file with the size and SHA-256 of each file inside its
169
+ package, the input size, the number of views and the minimum iOS version. An app can read it, download the files of
170
+ one package from `https://huggingface.co/shu223/Depth-Anything-3-Small-MultiView-CoreML/resolve/main/<path>`, check
171
+ them and compile the package on the device. Compiling the `.mlpackage` on the device works on iOS 27 (checked on an
172
+ iPhone 12 Pro and the simulator).
173
 
174
+ ## How it is built
175
 
176
  Converted with coremltools from the original PyTorch implementation
177
+ ([ByteDance-Seed/Depth-Anything-3](https://github.com/ByteDance-Seed/Depth-Anything-3)), `DA3-SMALL` revision
178
+ `e08cab65ca0ec38e7826075418411ab90cab4da3`:
179
+
180
+ - The pose-conditioned path is kept: the camera encoder turns the extrinsics and intrinsics into the camera tokens,
181
+ and the camera decoder returns the estimated poses. Ray decoding, sky handling and the Gaussian branch are not
182
+ included.
183
+ - The number of views and the input size are fixed per file (Core ML needs fixed shapes).
184
+ - **Sliced attention**: the global attention across all views is computed in slices of the query, so the attention
185
+ matrices stay small on the Neural Engine.
186
+ - **Rewritten depth head** (`fast`): the DPT head upsamples with transposed convolutions, later in the head.
187
 
188
  ## License
189
 
190
+ Apache License 2.0, the same as the original `DA3-SMALL` weights. See `LICENSE` and `NOTICE`.
191
 
192
  ## Citation
193