Instructions to use mlx-community/sam-3d-objects-bf16 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use mlx-community/sam-3d-objects-bf16 with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download mlx-community/sam-3d-objects-bf16 --local-dir sam-3d-objects-bf16
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Keep weights only: runtime lives in mlx-vlm; refresh card and validation
Browse files- README.md +36 -50
- pyproject.toml +0 -20
- sam3d_objects_mlx/LICENSE +0 -52
- sam3d_objects_mlx/LICENSE-APACHE +0 -224
- sam3d_objects_mlx/README.md +0 -174
- sam3d_objects_mlx/__init__.py +0 -6
- sam3d_objects_mlx/bundle.py +0 -171
- sam3d_objects_mlx/checkpoint.py +0 -136
- sam3d_objects_mlx/config.py +0 -75
- sam3d_objects_mlx/convert.py +0 -184
- sam3d_objects_mlx/decoders.py +0 -182
- sam3d_objects_mlx/depth.py +0 -210
- sam3d_objects_mlx/flow.py +0 -132
- sam3d_objects_mlx/generate.py +0 -122
- sam3d_objects_mlx/io.py +0 -154
- sam3d_objects_mlx/layers.py +0 -194
- sam3d_objects_mlx/mesh.py +0 -223
- sam3d_objects_mlx/mesh_tables.py +0 -2327
- sam3d_objects_mlx/pipeline.py +0 -311
- sam3d_objects_mlx/processing.py +0 -213
- sam3d_objects_mlx/resize.py +0 -70
- sam3d_objects_mlx/sam3d_objects.py +0 -72
- sam3d_objects_mlx/sparse.py +0 -172
- sam3d_objects_mlx/vision.py +0 -215
- validation.json +13 -13
README.md
CHANGED
|
@@ -18,65 +18,50 @@ tags:
|
|
| 18 |
|
| 19 |
# SAM 3D Objects — MLX BF16
|
| 20 |
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
The
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
| 30 |
|
| 31 |
-
##
|
| 32 |
|
| 33 |
-
|
|
|
|
| 34 |
|
| 35 |
```sh
|
|
|
|
| 36 |
hf download mlx-community/sam-3d-objects-bf16 --local-dir sam-3d-objects-bf16
|
| 37 |
-
python -m
|
| 38 |
-
|
| 39 |
-
--
|
| 40 |
-
--formats gaussian mesh
|
| 41 |
```
|
| 42 |
|
| 43 |
-
`hf` is an optional download tool; it is not a runtime dependency. The package
|
| 44 |
-
can also be imported directly from the downloaded directory. The same model
|
| 45 |
-
implementation lives under `mlx_vlm/models/sam3d_objects` in the port checkout.
|
| 46 |
-
|
| 47 |
```python
|
| 48 |
-
from
|
| 49 |
-
from
|
| 50 |
|
| 51 |
pipeline = Pipeline.from_pretrained("sam-3d-objects-bf16")
|
| 52 |
image, mask = read_png("image.png")[..., :3], read_mask("mask.png")
|
| 53 |
result = pipeline.generate(image, mask, seed=42)
|
| 54 |
-
|
| 55 |
-
async def reconstruct(requests):
|
| 56 |
-
async for event in pipeline.astream(requests):
|
| 57 |
-
if event.stage == "complete":
|
| 58 |
-
consume(event.data)
|
| 59 |
```
|
| 60 |
|
| 61 |
-
`requests`
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
evaluating on the GPU when yielded; use `mx.eval` before host consumption.
|
| 67 |
-
|
| 68 |
-
Inputs are HWC RGB/RGBA MLX arrays and HW masks. The included file reader
|
| 69 |
-
supports non-interlaced 8-bit PNG, including RGBA alpha masks. Callers can use
|
| 70 |
-
other decoders and pass arrays directly. Automatic MoGe depth is included;
|
| 71 |
-
external HWC point maps use +X left, +Y up, +Z forward, with NaN invalid values.
|
| 72 |
-
Set `estimate_depth=False` to use the trained point-map dropout instead.
|
| 73 |
-
|
| 74 |
Results include local-space Gaussians, mesh vertices/faces/colors, latent
|
| 75 |
features, occupied voxels, and a separate pose (rotation, translation, scale).
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
Training, latent training encoders, rendering, texture baking, mesh
|
| 79 |
-
simplification, and iterative layout optimization are not included.
|
| 80 |
|
| 81 |
## Conversion and validation
|
| 82 |
|
|
@@ -94,20 +79,21 @@ FlexiCubes. Maximum absolute error was below 0.000002 on these fixtures;
|
|
| 94 |
mesh face indices matched exactly. This is not a claim of bitwise BF16
|
| 95 |
end-to-end parity or a reconstruction-quality evaluation.
|
| 96 |
|
| 97 |
-
See `validation.json`
|
| 98 |
-
|
| 99 |
-
|
| 100 |
|
| 101 |
### Local performance
|
| 102 |
|
| 103 |
-
Hardware: Apple M5 Max, 128 GiB unified memory. Input: 448×672 RGB plus object mask; automatic
|
| 104 |
-
depth, 25 structure steps and 25 latent steps, both Gaussian heads
|
| 105 |
-
One warmup was excluded; the same seed produced identical latent
|
|
|
|
| 106 |
|
| 107 |
| Metric | Result |
|
| 108 |
| --- | ---: |
|
| 109 |
-
| Median latency (3 runs) |
|
| 110 |
-
| Maximum peak memory | 10.
|
| 111 |
|
| 112 |
Two additional async requests matched the synchronous latent output while
|
| 113 |
the event-loop heartbeat continued. These measurements describe one input.
|
|
|
|
| 18 |
|
| 19 |
# SAM 3D Objects — MLX BF16
|
| 20 |
|
| 21 |
+
BF16 weights of Meta SAM 3D Objects, including the upstream MoGe-v1 depth
|
| 22 |
+
estimator, converted for the MLX runtime in
|
| 23 |
+
[mlx-vlm](https://github.com/Blaizzy/mlx-vlm) (`mlx_vlm/models/sam3d_objects`).
|
| 24 |
+
This repository holds weights and metadata only; the inference code lives in
|
| 25 |
+
mlx-vlm. This is an unofficial derivative. SAM components retain the SAM
|
| 26 |
+
License; MoGe retains MIT; FlexiCubes retains Apache-2.0.
|
| 27 |
|
| 28 |
+
The 3,709 BF16 tensors across seven safetensors files cover the structure and
|
| 29 |
+
pose flow model, the sparse-latent flow model, image and point-map
|
| 30 |
+
conditioners, the occupancy decoder, both Gaussian decoders (32 or 4 Gaussians
|
| 31 |
+
per voxel), the mesh decoder, and MoGe-v1. The model generates geometry and
|
| 32 |
+
pose; it has no text or tool-calling interface.
|
| 33 |
|
| 34 |
+
## Usage
|
| 35 |
|
| 36 |
+
Install an mlx-vlm version that includes `sam3d_objects`, download this
|
| 37 |
+
repository, and run the CLI or the Python API:
|
| 38 |
|
| 39 |
```sh
|
| 40 |
+
pip install mlx-vlm
|
| 41 |
hf download mlx-community/sam-3d-objects-bf16 --local-dir sam-3d-objects-bf16
|
| 42 |
+
python -m mlx_vlm.models.sam3d_objects.generate \
|
| 43 |
+
--model sam-3d-objects-bf16 --image image.png --mask mask.png \
|
| 44 |
+
--output output --formats gaussian mesh
|
|
|
|
| 45 |
```
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
```python
|
| 48 |
+
from mlx_vlm.models.sam3d_objects.io import read_mask, read_png
|
| 49 |
+
from mlx_vlm.models.sam3d_objects.pipeline import Pipeline
|
| 50 |
|
| 51 |
pipeline = Pipeline.from_pretrained("sam-3d-objects-bf16")
|
| 52 |
image, mask = read_png("image.png")[..., :3], read_mask("mask.png")
|
| 53 |
result = pipeline.generate(image, mask, seed=42)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
```
|
| 55 |
|
| 56 |
+
`pipeline.astream(requests)` streams ordered events for an iterable or async
|
| 57 |
+
iterable of `Request` values, one request at a time with backpressure; the
|
| 58 |
+
same weights also load through `mlx_vlm.utils.load_model`. Inputs are HWC
|
| 59 |
+
RGB/RGBA MLX arrays and HW masks. Automatic MoGe depth is included; external
|
| 60 |
+
HWC point maps use +X left, +Y up, +Z forward with NaN for invalid points.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
Results include local-space Gaussians, mesh vertices/faces/colors, latent
|
| 62 |
features, occupied voxels, and a separate pose (rotation, translation, scale).
|
| 63 |
+
The mlx-vlm model README documents the full API, CLI, JSONL streaming, and
|
| 64 |
+
the inference optimizations.
|
|
|
|
|
|
|
| 65 |
|
| 66 |
## Conversion and validation
|
| 67 |
|
|
|
|
| 79 |
mesh face indices matched exactly. This is not a claim of bitwise BF16
|
| 80 |
end-to-end parity or a reconstruction-quality evaluation.
|
| 81 |
|
| 82 |
+
See `validation.json` and `conversion.json` for details. The original sources
|
| 83 |
+
are [SAM 3D Objects](https://github.com/facebookresearch/sam-3d-objects) and
|
| 84 |
+
[MoGe](https://github.com/microsoft/MoGe).
|
| 85 |
|
| 86 |
### Local performance
|
| 87 |
|
| 88 |
+
Hardware: Apple M5 Max, 128 GiB unified memory. Input: 448×672 RGB plus object mask; automatic
|
| 89 |
+
MoGe depth, 25 structure steps and 25 latent steps, both Gaussian heads
|
| 90 |
+
and mesh. One warmup was excluded; the same seed produced identical latent
|
| 91 |
+
outputs.
|
| 92 |
|
| 93 |
| Metric | Result |
|
| 94 |
| --- | ---: |
|
| 95 |
+
| Median latency (3 runs) | 15.68 s |
|
| 96 |
+
| Maximum peak memory | 10.98 GB |
|
| 97 |
|
| 98 |
Two additional async requests matched the synchronous latent output while
|
| 99 |
the event-loop heartbeat continued. These measurements describe one input.
|
pyproject.toml
DELETED
|
@@ -1,20 +0,0 @@
|
|
| 1 |
-
[build-system]
|
| 2 |
-
requires = ["setuptools>=61"]
|
| 3 |
-
build-backend = "setuptools.build_meta"
|
| 4 |
-
|
| 5 |
-
[project]
|
| 6 |
-
name = "sam3d-objects-mlx-inference"
|
| 7 |
-
version = "0.1.0"
|
| 8 |
-
description = "Frozen SAM 3D Objects inference using MLX and the Python standard library"
|
| 9 |
-
requires-python = ">=3.10"
|
| 10 |
-
dependencies = ["mlx>=0.32.2"]
|
| 11 |
-
license = {text = "SAM License; Apache-2.0 for MoGe/FlexiCubes"}
|
| 12 |
-
|
| 13 |
-
[project.scripts]
|
| 14 |
-
sam3d-mlx = "sam3d_objects_mlx.generate:main"
|
| 15 |
-
|
| 16 |
-
[tool.setuptools.packages.find]
|
| 17 |
-
include = ["sam3d_objects_mlx*"]
|
| 18 |
-
|
| 19 |
-
[tool.setuptools.package-data]
|
| 20 |
-
sam3d_objects_mlx = ["LICENSE", "LICENSE-APACHE", "README.md"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/LICENSE
DELETED
|
@@ -1,52 +0,0 @@
|
|
| 1 |
-
SAM License
|
| 2 |
-
Last Updated: November 19, 2025
|
| 3 |
-
|
| 4 |
-
“Agreement” means the terms and conditions for use, reproduction, distribution and modification of the SAM Materials set forth herein.
|
| 5 |
-
|
| 6 |
-
“SAM Materials” means, collectively, Documentation and the models, software and algorithms, including machine-learning model code, trained model weights, inference-enabling code, training-enabling code, fine-tuning enabling code, and other elements of the foregoing distributed by Meta and made available under this Agreement.
|
| 7 |
-
|
| 8 |
-
“Documentation” means the specifications, manuals and documentation accompanying
|
| 9 |
-
SAM Materials distributed by Meta.
|
| 10 |
-
|
| 11 |
-
“Licensee” or “you” means you, or your employer or any other person or entity (if you are entering into this Agreement on such person or entity’s behalf), of the age required under applicable laws, rules or regulations to provide legal consent and that has legal authority to bind your employer or such other person or entity if you are entering in this Agreement on their behalf.
|
| 12 |
-
|
| 13 |
-
“Meta” or “we” means Meta Platforms Ireland Limited (if you are located in or, if you are an entity, your principal place of business is in the EEA or Switzerland) or Meta Platforms, Inc. (if you are located outside of the EEA or Switzerland).
|
| 14 |
-
|
| 15 |
-
“Sanctions” means any economic or trade sanctions or restrictions administered or enforced by the United States (including the Office of Foreign Assets Control of the U.S. Department of the Treasury (“OFAC”), the U.S. Department of State and the U.S. Department of Commerce), the United Nations, the European Union, or the United Kingdom.
|
| 16 |
-
|
| 17 |
-
“Trade Controls” means any of the following: Sanctions and applicable export and import controls.
|
| 18 |
-
|
| 19 |
-
By using or distributing any portion or element of the SAM Materials, you agree to be bound by this Agreement.
|
| 20 |
-
|
| 21 |
-
1. License Rights and Redistribution.
|
| 22 |
-
|
| 23 |
-
a. Grant of Rights. You are granted a non-exclusive, worldwide, non-transferable and royalty-free limited license under Meta’s intellectual property or other rights owned by Meta embodied in the SAM Materials to use, reproduce, distribute, copy, create derivative works of, and make modifications to the SAM Materials.
|
| 24 |
-
|
| 25 |
-
i. Grant of Patent License. Subject to the terms and conditions of this License, you are granted a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by Meta that are necessarily infringed alone or by combination of their contribution(s) with the SAM 3 Materials. If you institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the SAM 3 Materials incorporated within the work constitutes direct or contributory patent infringement, then any patent licenses granted to you under this License for that work shall terminate as of the date such litigation is filed.
|
| 26 |
-
|
| 27 |
-
b. Redistribution and Use.
|
| 28 |
-
|
| 29 |
-
i. Distribution of SAM Materials, and any derivative works thereof, are subject to the terms of this Agreement. If you distribute or make the SAM Materials, or any derivative works thereof, available to a third party, you may only do so under the terms of this Agreement and you shall provide a copy of this Agreement with any such SAM Materials.
|
| 30 |
-
|
| 31 |
-
ii. If you submit for publication the results of research you perform on, using, or otherwise in connection with SAM Materials, you must acknowledge the use of SAM Materials in your publication.
|
| 32 |
-
|
| 33 |
-
iii. Your use of the SAM Materials must comply with applicable laws and regulations, including Trade Control Laws and applicable privacy and data protection laws.
|
| 34 |
-
iv. Your use of the SAM Materials will not involve or encourage others to reverse engineer, decompile or discover the underlying components of the SAM Materials.
|
| 35 |
-
v. You are not the target of Trade Controls and your use of SAM Materials must comply with Trade Controls. You agree not to use, or permit others to use, SAM Materials for any activities subject to the International Traffic in Arms Regulations (ITAR) or end uses prohibited by Trade Controls, including those related to military or warfare purposes, nuclear industries or applications, espionage, or the development or use of guns or illegal weapons.
|
| 36 |
-
2. User Support. Your use of the SAM Materials is done at your own discretion; Meta does not process any information nor provide any service in relation to such use. Meta is under no obligation to provide any support services for the SAM Materials. Any support provided is “as is”, “with all faults”, and without warranty of any kind.
|
| 37 |
-
|
| 38 |
-
3. Disclaimer of Warranty. UNLESS REQUIRED BY APPLICABLE LAW, THE SAM MATERIALS AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OF ANY KIND, AND META DISCLAIMS ALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE SAM MATERIALS AND ASSUME ANY RISKS ASSOCIATED WITH YOUR USE OF THE SAM MATERIALS AND ANY OUTPUT AND RESULTS.
|
| 39 |
-
|
| 40 |
-
4. Limitation of Liability. IN NO EVENT WILL META OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT, FOR ANY LOST PROFITS OR ANY DIRECT OR INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL, EXEMPLARY OR PUNITIVE DAMAGES, EVEN IF META OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
|
| 41 |
-
|
| 42 |
-
5. Intellectual Property.
|
| 43 |
-
|
| 44 |
-
a. Subject to Meta’s ownership of SAM Materials and derivatives made by or for Meta, with respect to any derivative works and modifications of the SAM Materials that are made by you, as between you and Meta, you are and will be the owner of such derivative works and modifications.
|
| 45 |
-
|
| 46 |
-
b. If you institute litigation or other proceedings against Meta or any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the SAM Materials, outputs or results, or any portion of any of the foregoing, constitutes infringement of intellectual property or other rights owned or licensable by you, then any licenses granted to you under this Agreement shall terminate as of the date such litigation or claim is filed or instituted. You will indemnify and hold harmless Meta from and against any claim by any third party arising out of or related to your use or distribution of the SAM Materials.
|
| 47 |
-
|
| 48 |
-
6. Term and Termination. The term of this Agreement will commence upon your acceptance of this Agreement or access to the SAM Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein. Meta may terminate this Agreement if you are in breach of any term or condition of this Agreement. Upon termination of this Agreement, you shall delete and cease use of the SAM Materials. Sections 3, 4 and 7 shall survive the termination of this Agreement.
|
| 49 |
-
|
| 50 |
-
7. Governing Law and Jurisdiction. This Agreement will be governed and construed under the laws of the State of California without regard to choice of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement. The courts of California shall have exclusive jurisdiction of any dispute arising out of this Agreement.
|
| 51 |
-
|
| 52 |
-
8. Modifications and Amendments. Meta may modify this Agreement from time to time; provided that they are similar in spirit to the current version of the Agreement, but may differ in detail to address new problems or concerns. All such changes will be effective immediately. Your continued use of the SAM Materials after any modification to this Agreement constitutes your agreement to such modification. Except as provided in this Agreement, no modification or addition to any provision of this Agreement will be binding unless it is in writing and signed by an authorized representative of both you and Meta.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/LICENSE-APACHE
DELETED
|
@@ -1,224 +0,0 @@
|
|
| 1 |
-
MIT License
|
| 2 |
-
|
| 3 |
-
Copyright (c) Microsoft Corporation.
|
| 4 |
-
|
| 5 |
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
-
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
-
in the Software without restriction, including without limitation the rights
|
| 8 |
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
-
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
-
furnished to do so, subject to the following conditions:
|
| 11 |
-
|
| 12 |
-
The above copyright notice and this permission notice shall be included in all
|
| 13 |
-
copies or substantial portions of the Software.
|
| 14 |
-
|
| 15 |
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
-
SOFTWARE
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
Apache License
|
| 25 |
-
Version 2.0, January 2004
|
| 26 |
-
http://www.apache.org/licenses/
|
| 27 |
-
|
| 28 |
-
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 29 |
-
|
| 30 |
-
1. Definitions.
|
| 31 |
-
|
| 32 |
-
"License" shall mean the terms and conditions for use, reproduction,
|
| 33 |
-
and distribution as defined by Sections 1 through 9 of this document.
|
| 34 |
-
|
| 35 |
-
"Licensor" shall mean the copyright owner or entity authorized by
|
| 36 |
-
the copyright owner that is granting the License.
|
| 37 |
-
|
| 38 |
-
"Legal Entity" shall mean the union of the acting entity and all
|
| 39 |
-
other entities that control, are controlled by, or are under common
|
| 40 |
-
control with that entity. For the purposes of this definition,
|
| 41 |
-
"control" means (i) the power, direct or indirect, to cause the
|
| 42 |
-
direction or management of such entity, whether by contract or
|
| 43 |
-
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 44 |
-
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 45 |
-
|
| 46 |
-
"You" (or "Your") shall mean an individual or Legal Entity
|
| 47 |
-
exercising permissions granted by this License.
|
| 48 |
-
|
| 49 |
-
"Source" form shall mean the preferred form for making modifications,
|
| 50 |
-
including but not limited to software source code, documentation
|
| 51 |
-
source, and configuration files.
|
| 52 |
-
|
| 53 |
-
"Object" form shall mean any form resulting from mechanical
|
| 54 |
-
transformation or translation of a Source form, including but
|
| 55 |
-
not limited to compiled object code, generated documentation,
|
| 56 |
-
and conversions to other media types.
|
| 57 |
-
|
| 58 |
-
"Work" shall mean the work of authorship, whether in Source or
|
| 59 |
-
Object form, made available under the License, as indicated by a
|
| 60 |
-
copyright notice that is included in or attached to the work
|
| 61 |
-
(an example is provided in the Appendix below).
|
| 62 |
-
|
| 63 |
-
"Derivative Works" shall mean any work, whether in Source or Object
|
| 64 |
-
form, that is based on (or derived from) the Work and for which the
|
| 65 |
-
editorial revisions, annotations, elaborations, or other modifications
|
| 66 |
-
represent, as a whole, an original work of authorship. For the purposes
|
| 67 |
-
of this License, Derivative Works shall not include works that remain
|
| 68 |
-
separable from, or merely link (or bind by name) to the interfaces of,
|
| 69 |
-
the Work and Derivative Works thereof.
|
| 70 |
-
|
| 71 |
-
"Contribution" shall mean any work of authorship, including
|
| 72 |
-
the original version of the Work and any modifications or additions
|
| 73 |
-
to that Work or Derivative Works thereof, that is intentionally
|
| 74 |
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 75 |
-
or by an individual or Legal Entity authorized to submit on behalf of
|
| 76 |
-
the copyright owner. For the purposes of this definition, "submitted"
|
| 77 |
-
means any form of electronic, verbal, or written communication sent
|
| 78 |
-
to the Licensor or its representatives, including but not limited to
|
| 79 |
-
communication on electronic mailing lists, source code control systems,
|
| 80 |
-
and issue tracking systems that are managed by, or on behalf of, the
|
| 81 |
-
Licensor for the purpose of discussing and improving the Work, but
|
| 82 |
-
excluding communication that is conspicuously marked or otherwise
|
| 83 |
-
designated in writing by the copyright owner as "Not a Contribution."
|
| 84 |
-
|
| 85 |
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 86 |
-
on behalf of whom a Contribution has been received by Licensor and
|
| 87 |
-
subsequently incorporated within the Work.
|
| 88 |
-
|
| 89 |
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 90 |
-
this License, each Contributor hereby grants to You a perpetual,
|
| 91 |
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 92 |
-
copyright license to reproduce, prepare Derivative Works of,
|
| 93 |
-
publicly display, publicly perform, sublicense, and distribute the
|
| 94 |
-
Work and such Derivative Works in Source or Object form.
|
| 95 |
-
|
| 96 |
-
3. Grant of Patent License. Subject to the terms and conditions of
|
| 97 |
-
this License, each Contributor hereby grants to You a perpetual,
|
| 98 |
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 99 |
-
(except as stated in this section) patent license to make, have made,
|
| 100 |
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 101 |
-
where such license applies only to those patent claims licensable
|
| 102 |
-
by such Contributor that are necessarily infringed by their
|
| 103 |
-
Contribution(s) alone or by combination of their Contribution(s)
|
| 104 |
-
with the Work to which such Contribution(s) was submitted. If You
|
| 105 |
-
institute patent litigation against any entity (including a
|
| 106 |
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 107 |
-
or a Contribution incorporated within the Work constitutes direct
|
| 108 |
-
or contributory patent infringement, then any patent licenses
|
| 109 |
-
granted to You under this License for that Work shall terminate
|
| 110 |
-
as of the date such litigation is filed.
|
| 111 |
-
|
| 112 |
-
4. Redistribution. You may reproduce and distribute copies of the
|
| 113 |
-
Work or Derivative Works thereof in any medium, with or without
|
| 114 |
-
modifications, and in Source or Object form, provided that You
|
| 115 |
-
meet the following conditions:
|
| 116 |
-
|
| 117 |
-
(a) You must give any other recipients of the Work or
|
| 118 |
-
Derivative Works a copy of this License; and
|
| 119 |
-
|
| 120 |
-
(b) You must cause any modified files to carry prominent notices
|
| 121 |
-
stating that You changed the files; and
|
| 122 |
-
|
| 123 |
-
(c) You must retain, in the Source form of any Derivative Works
|
| 124 |
-
that You distribute, all copyright, patent, trademark, and
|
| 125 |
-
attribution notices from the Source form of the Work,
|
| 126 |
-
excluding those notices that do not pertain to any part of
|
| 127 |
-
the Derivative Works; and
|
| 128 |
-
|
| 129 |
-
(d) If the Work includes a "NOTICE" text file as part of its
|
| 130 |
-
distribution, then any Derivative Works that You distribute must
|
| 131 |
-
include a readable copy of the attribution notices contained
|
| 132 |
-
within such NOTICE file, excluding those notices that do not
|
| 133 |
-
pertain to any part of the Derivative Works, in at least one
|
| 134 |
-
of the following places: within a NOTICE text file distributed
|
| 135 |
-
as part of the Derivative Works; within the Source form or
|
| 136 |
-
documentation, if provided along with the Derivative Works; or,
|
| 137 |
-
within a display generated by the Derivative Works, if and
|
| 138 |
-
wherever such third-party notices normally appear. The contents
|
| 139 |
-
of the NOTICE file are for informational purposes only and
|
| 140 |
-
do not modify the License. You may add Your own attribution
|
| 141 |
-
notices within Derivative Works that You distribute, alongside
|
| 142 |
-
or as an addendum to the NOTICE text from the Work, provided
|
| 143 |
-
that such additional attribution notices cannot be construed
|
| 144 |
-
as modifying the License.
|
| 145 |
-
|
| 146 |
-
You may add Your own copyright statement to Your modifications and
|
| 147 |
-
may provide additional or different license terms and conditions
|
| 148 |
-
for use, reproduction, or distribution of Your modifications, or
|
| 149 |
-
for any such Derivative Works as a whole, provided Your use,
|
| 150 |
-
reproduction, and distribution of the Work otherwise complies with
|
| 151 |
-
the conditions stated in this License.
|
| 152 |
-
|
| 153 |
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 154 |
-
any Contribution intentionally submitted for inclusion in the Work
|
| 155 |
-
by You to the Licensor shall be under the terms and conditions of
|
| 156 |
-
this License, without any additional terms or conditions.
|
| 157 |
-
Notwithstanding the above, nothing herein shall supersede or modify
|
| 158 |
-
the terms of any separate license agreement you may have executed
|
| 159 |
-
with Licensor regarding such Contributions.
|
| 160 |
-
|
| 161 |
-
6. Trademarks. This License does not grant permission to use the trade
|
| 162 |
-
names, trademarks, service marks, or product names of the Licensor,
|
| 163 |
-
except as required for reasonable and customary use in describing the
|
| 164 |
-
origin of the Work and reproducing the content of the NOTICE file.
|
| 165 |
-
|
| 166 |
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 167 |
-
agreed to in writing, Licensor provides the Work (and each
|
| 168 |
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 169 |
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 170 |
-
implied, including, without limitation, any warranties or conditions
|
| 171 |
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 172 |
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 173 |
-
appropriateness of using or redistributing the Work and assume any
|
| 174 |
-
risks associated with Your exercise of permissions under this License.
|
| 175 |
-
|
| 176 |
-
8. Limitation of Liability. In no event and under no legal theory,
|
| 177 |
-
whether in tort (including negligence), contract, or otherwise,
|
| 178 |
-
unless required by applicable law (such as deliberate and grossly
|
| 179 |
-
negligent acts) or agreed to in writing, shall any Contributor be
|
| 180 |
-
liable to You for damages, including any direct, indirect, special,
|
| 181 |
-
incidental, or consequential damages of any character arising as a
|
| 182 |
-
result of this License or out of the use or inability to use the
|
| 183 |
-
Work (including but not limited to damages for loss of goodwill,
|
| 184 |
-
work stoppage, computer failure or malfunction, or any and all
|
| 185 |
-
other commercial damages or losses), even if such Contributor
|
| 186 |
-
has been advised of the possibility of such damages.
|
| 187 |
-
|
| 188 |
-
9. Accepting Warranty or Additional Liability. While redistributing
|
| 189 |
-
the Work or Derivative Works thereof, You may choose to offer,
|
| 190 |
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 191 |
-
or other liability obligations and/or rights consistent with this
|
| 192 |
-
License. However, in accepting such obligations, You may act only
|
| 193 |
-
on Your own behalf and on Your sole responsibility, not on behalf
|
| 194 |
-
of any other Contributor, and only if You agree to indemnify,
|
| 195 |
-
defend, and hold each Contributor harmless for any liability
|
| 196 |
-
incurred by, or claims asserted against, such Contributor by reason
|
| 197 |
-
of your accepting any such warranty or additional liability.
|
| 198 |
-
|
| 199 |
-
END OF TERMS AND CONDITIONS
|
| 200 |
-
|
| 201 |
-
APPENDIX: How to apply the Apache License to your work.
|
| 202 |
-
|
| 203 |
-
To apply the Apache License to your work, attach the following
|
| 204 |
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 205 |
-
replaced with your own identifying information. (Don't include
|
| 206 |
-
the brackets!) The text should be enclosed in the appropriate
|
| 207 |
-
comment syntax for the file format. We also recommend that a
|
| 208 |
-
file or class name and description of purpose be included on the
|
| 209 |
-
same "printed page" as the copyright notice for easier
|
| 210 |
-
identification within third-party archives.
|
| 211 |
-
|
| 212 |
-
Copyright [yyyy] [name of copyright owner]
|
| 213 |
-
|
| 214 |
-
Licensed under the Apache License, Version 2.0 (the "License");
|
| 215 |
-
you may not use this file except in compliance with the License.
|
| 216 |
-
You may obtain a copy of the License at
|
| 217 |
-
|
| 218 |
-
http://www.apache.org/licenses/LICENSE-2.0
|
| 219 |
-
|
| 220 |
-
Unless required by applicable law or agreed to in writing, software
|
| 221 |
-
distributed under the License is distributed on an "AS IS" BASIS,
|
| 222 |
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 223 |
-
See the License for the specific language governing permissions and
|
| 224 |
-
limitations under the License.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/README.md
DELETED
|
@@ -1,174 +0,0 @@
|
|
| 1 |
-
# SAM 3D Objects for MLX
|
| 2 |
-
|
| 3 |
-
Inference-only port of [Meta SAM 3D Objects](https://github.com/facebookresearch/sam-3d-objects).
|
| 4 |
-
The runtime and checkpoint converter use **MLX and Python's standard library**.
|
| 5 |
-
All parameters are frozen and every model runs in evaluation mode.
|
| 6 |
-
|
| 7 |
-
The BF16 bundle is published as
|
| 8 |
-
[`mlx-community/sam-3d-objects-bf16`](https://huggingface.co/mlx-community/sam-3d-objects-bf16).
|
| 9 |
-
It includes the structure/pose flow model, sparse-latent flow model, image and
|
| 10 |
-
point-map conditioners, occupancy decoder, both Gaussian decoders (32 or 4
|
| 11 |
-
Gaussians per voxel), mesh decoder, and the MoGe-v1 depth estimator used by
|
| 12 |
-
the upstream pipeline. The learned model outputs are decoded with MLX
|
| 13 |
-
FlexiCubes into colored triangle meshes.
|
| 14 |
-
|
| 15 |
-
Training, latent encoders used for training, differentiable renderers,
|
| 16 |
-
texture baking, mesh simplification, and iterative layout optimization are
|
| 17 |
-
outside this inference port. This model has no text or tool-calling protocol.
|
| 18 |
-
|
| 19 |
-
## Load and generate
|
| 20 |
-
|
| 21 |
-
Download the bundle with your preferred Hugging Face client. Hub transfer is
|
| 22 |
-
separate from the inference runtime; the example below uses the optional `hf`
|
| 23 |
-
command-line tool:
|
| 24 |
-
|
| 25 |
-
```sh
|
| 26 |
-
hf download mlx-community/sam-3d-objects-bf16 --local-dir models/sam-3d-objects-bf16
|
| 27 |
-
```
|
| 28 |
-
|
| 29 |
-
Use a checkout containing this port. Installing the entire mlx-vlm project
|
| 30 |
-
also installs its other model dependencies; this model itself only needs MLX:
|
| 31 |
-
|
| 32 |
-
```sh
|
| 33 |
-
python -m pip install mlx
|
| 34 |
-
```
|
| 35 |
-
|
| 36 |
-
From the repository root:
|
| 37 |
-
|
| 38 |
-
```python
|
| 39 |
-
from mlx_vlm.models.sam3d_objects.io import read_mask, read_png, write_gaussians, write_obj
|
| 40 |
-
from mlx_vlm.models.sam3d_objects.pipeline import Pipeline
|
| 41 |
-
|
| 42 |
-
pipeline = Pipeline.from_pretrained("models/sam-3d-objects-bf16")
|
| 43 |
-
image = read_png("image.png")[..., :3]
|
| 44 |
-
mask = read_mask("mask.png")
|
| 45 |
-
result = pipeline.generate(image, mask, seed=42)
|
| 46 |
-
write_gaussians("object.ply", result["gaussian"])
|
| 47 |
-
write_obj("object.obj", result["mesh"])
|
| 48 |
-
```
|
| 49 |
-
|
| 50 |
-
Inputs are HWC RGB/RGBA MLX arrays and an HW object mask. Images may be
|
| 51 |
-
`uint8` or floating values in `[0, 1]`; masks may be boolean, 0/1, or 0/255.
|
| 52 |
-
The small stdlib image reader supports non-interlaced, 8-bit PNG images.
|
| 53 |
-
Other codecs can be decoded by the caller and passed as MLX arrays.
|
| 54 |
-
|
| 55 |
-
Automatic point maps come from the bundled MoGe model. To use a camera or
|
| 56 |
-
an existing depth pipeline, supply an HWC `pointmap` in the upstream camera
|
| 57 |
-
convention: +X left, +Y up, +Z forward. Invalid points use NaN. Setting
|
| 58 |
-
`estimate_depth=False` without a point map uses the trained point-map dropout;
|
| 59 |
-
that path cannot establish scene-relative layout from observed depth.
|
| 60 |
-
|
| 61 |
-
Outputs include `pose` (quaternion WXYZ, rotation matrix, translation, scale),
|
| 62 |
-
voxel `coords`, denormalized `latents`, `gaussian`, and `mesh`. Geometry is in
|
| 63 |
-
object-local coordinates; pose is returned separately. Gaussian fields are
|
| 64 |
-
`positions`, `sh_dc`, `scales`, `rotations`, and `opacities`. Mesh fields are
|
| 65 |
-
`vertices`, `faces`, and six-channel `vertex_colors` (RGB plus learned attributes).
|
| 66 |
-
PLY uses standard Gaussian-splat fields; OBJ includes RGB vertex colors.
|
| 67 |
-
|
| 68 |
-
## Streaming
|
| 69 |
-
|
| 70 |
-
```python
|
| 71 |
-
from mlx_vlm.models.sam3d_objects.pipeline import Request
|
| 72 |
-
|
| 73 |
-
async def requests(camera):
|
| 74 |
-
async for frame, mask in camera:
|
| 75 |
-
yield Request(frame, mask, request_id="object-1", seed=42)
|
| 76 |
-
|
| 77 |
-
async def reconstruct(camera):
|
| 78 |
-
async for event in pipeline.astream(requests(camera)):
|
| 79 |
-
print(event.request_id, event.stage, event.step, event.total_steps)
|
| 80 |
-
if event.stage == "complete":
|
| 81 |
-
consume(event.data)
|
| 82 |
-
```
|
| 83 |
-
|
| 84 |
-
`astream` accepts synchronous or asynchronous input iterables. It consumes
|
| 85 |
-
one request at a time, preserves request order, and applies backpressure at
|
| 86 |
-
each yield. One worker submits MLX operations so preprocessing and sparse
|
| 87 |
-
topology work do not block the caller's event loop. Close the async generator
|
| 88 |
-
with `aclose()` when stopping early, or use `contextlib.aclosing`.
|
| 89 |
-
|
| 90 |
-
Events cover depth, conditioning, every structure/pose and sparse-latent
|
| 91 |
-
flow step, occupancy, each selected decoder, and the final result. Arrays are
|
| 92 |
-
scheduled with `mx.async_eval`; GPU work may still be in flight when yielded.
|
| 93 |
-
Use `mx.eval(event.data)` if host-side code needs completed values. The
|
| 94 |
-
blocking `generate` convenience method evaluates its final result.
|
| 95 |
-
Sparse topology needs scalar synchronization to determine variable output
|
| 96 |
-
sizes. Cancellation stops further submissions and drains already submitted
|
| 97 |
-
work before releasing the worker stream. Each pipeline permits one active
|
| 98 |
-
stream; use separate instances for independent streams.
|
| 99 |
-
|
| 100 |
-
## CLI
|
| 101 |
-
|
| 102 |
-
```sh
|
| 103 |
-
python -m mlx_vlm.models.sam3d_objects.generate \
|
| 104 |
-
--model models/sam-3d-objects-bf16 \
|
| 105 |
-
--image image.png --mask mask.png --output outputs/object \
|
| 106 |
-
--formats gaussian mesh --ss-steps 25 --slat-steps 25
|
| 107 |
-
```
|
| 108 |
-
|
| 109 |
-
After installing mlx-vlm, the same command is available as `mlx_vlm.sam3d`.
|
| 110 |
-
For JSONL streaming, pass `--jsonl` and provide one request per stdin line:
|
| 111 |
-
|
| 112 |
-
```json
|
| 113 |
-
{"id":"frame-1","image":"frame-1.png","mask":"mask-1.png","seed":42}
|
| 114 |
-
{"id":"frame-2","image":"frame-2.png","mask":"mask-2.png","seed":42}
|
| 115 |
-
```
|
| 116 |
-
|
| 117 |
-
Progress is emitted as JSONL. Results go into numbered subdirectories under
|
| 118 |
-
`--output`, each containing `result.safetensors` and the requested PLY/OBJ
|
| 119 |
-
files. Input IDs are preserved as labels and never used as filesystem paths.
|
| 120 |
-
For externally computed points, `--pointmap` accepts a safetensors file
|
| 121 |
-
containing a `points` tensor.
|
| 122 |
-
|
| 123 |
-
## Conversion
|
| 124 |
-
|
| 125 |
-
Obtain the original checkpoints from `facebook/sam-3d-objects` and
|
| 126 |
-
`Ruicheng/moge-vitl`, then run:
|
| 127 |
-
|
| 128 |
-
```sh
|
| 129 |
-
python -m mlx_vlm.models.sam3d_objects.convert \
|
| 130 |
-
--source /path/to/sam-3d-objects/checkpoints \
|
| 131 |
-
--moge-checkpoint /path/to/moge-vitl/model.pt \
|
| 132 |
-
--output models/sam-3d-objects-bf16
|
| 133 |
-
```
|
| 134 |
-
|
| 135 |
-
The converter reads tensor-only PyTorch ZIP archives through a restricted
|
| 136 |
-
stdlib unpickler, streams their original storage bytes to safetensors, maps
|
| 137 |
-
the inference weights to MLX layouts, and casts floating tensors to BF16.
|
| 138 |
-
It does not import PyTorch, NumPy, or the safetensors Python library.
|
| 139 |
-
Unknown pickle globals and unsupported storage layouts are rejected.
|
| 140 |
-
The duplicate occupancy decoder embedded in the structure checkpoint is
|
| 141 |
-
omitted in favor of its dedicated released checkpoint. Loading is strict:
|
| 142 |
-
missing, extra, and incorrectly shaped model parameters are errors.
|
| 143 |
-
|
| 144 |
-
The full bundle contains 3,709 tensors across seven safetensors files.
|
| 145 |
-
There are no tokenizer or chat-template files because this is a geometry model.
|
| 146 |
-
|
| 147 |
-
## Validation
|
| 148 |
-
|
| 149 |
-
```sh
|
| 150 |
-
python -m unittest mlx_vlm.tests.test_models.TestSAM3DObjects -v
|
| 151 |
-
```
|
| 152 |
-
|
| 153 |
-
Tests cover frozen BF16 checkpoint round trips, sparse convolution versus
|
| 154 |
-
dense convolution, reference pooling semantics, window attention versus
|
| 155 |
-
masked full attention, Euler/CFG scheduling, closed mesh topology, async
|
| 156 |
-
backpressure/early close/reuse, and restricted checkpoint deserialization.
|
| 157 |
-
|
| 158 |
-
Additional local comparisons against the original PyTorch source used FP32
|
| 159 |
-
MLX CPU to isolate equation parity from accelerated Metal precision. Attention,
|
| 160 |
-
both flow networks, occupancy decoding, interpolation, pretrained MoGe, and
|
| 161 |
-
FlexiCubes matched within 0.000002 maximum absolute error on those fixtures;
|
| 162 |
-
mesh face indices matched exactly. These are component checks, not a claim of
|
| 163 |
-
bitwise BF16 end-to-end parity or a reconstruction quality benchmark.
|
| 164 |
-
|
| 165 |
-
The actual BF16 Metal pipeline was also exercised on an upstream example
|
| 166 |
-
image with automatic depth and both 25-step sampling stages. See the Hub
|
| 167 |
-
model card's validation report for measured timings and memory.
|
| 168 |
-
|
| 169 |
-
## Licenses
|
| 170 |
-
|
| 171 |
-
SAM-derived code and weights retain the [SAM License](LICENSE).
|
| 172 |
-
MoGe and FlexiCubes components retain Apache-2.0; see
|
| 173 |
-
[LICENSE-APACHE](LICENSE-APACHE) and source copyright notices.
|
| 174 |
-
This is an unofficial MLX port.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/__init__.py
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
"""SAM 3D Objects inference on Apple Silicon, using MLX and the stdlib."""
|
| 2 |
-
|
| 3 |
-
from .config import ModelConfig
|
| 4 |
-
from .sam3d_objects import Model
|
| 5 |
-
|
| 6 |
-
__all__ = ["Model", "ModelConfig"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/bundle.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
| 1 |
-
"""Package the inference code beside the converted Hub weights."""
|
| 2 |
-
|
| 3 |
-
import argparse
|
| 4 |
-
import json
|
| 5 |
-
import shutil
|
| 6 |
-
from pathlib import Path
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
def package(destination):
|
| 10 |
-
root = Path(destination)
|
| 11 |
-
source = Path(__file__).parent
|
| 12 |
-
package_root = root / "sam3d_objects_mlx"
|
| 13 |
-
package_root.mkdir(parents=True, exist_ok=True)
|
| 14 |
-
for path in source.glob("*.py"):
|
| 15 |
-
shutil.copyfile(path, package_root / path.name)
|
| 16 |
-
for name in ("LICENSE", "LICENSE-APACHE", "README.md"):
|
| 17 |
-
shutil.copyfile(source / name, package_root / name)
|
| 18 |
-
(root / "LICENSE").write_text((source / "LICENSE").read_text())
|
| 19 |
-
(root / "LICENSE-APACHE").write_text((source / "LICENSE-APACHE").read_text())
|
| 20 |
-
(root / "pyproject.toml").write_text("""[build-system]
|
| 21 |
-
requires = ["setuptools>=61"]
|
| 22 |
-
build-backend = "setuptools.build_meta"
|
| 23 |
-
|
| 24 |
-
[project]
|
| 25 |
-
name = "sam3d-objects-mlx-inference"
|
| 26 |
-
version = "0.1.0"
|
| 27 |
-
description = "Frozen SAM 3D Objects inference using MLX and the Python standard library"
|
| 28 |
-
requires-python = ">=3.10"
|
| 29 |
-
dependencies = ["mlx>=0.32.2"]
|
| 30 |
-
license = {text = "SAM License; Apache-2.0 for MoGe/FlexiCubes"}
|
| 31 |
-
|
| 32 |
-
[project.scripts]
|
| 33 |
-
sam3d-mlx = "sam3d_objects_mlx.generate:main"
|
| 34 |
-
|
| 35 |
-
[tool.setuptools.packages.find]
|
| 36 |
-
include = ["sam3d_objects_mlx*"]
|
| 37 |
-
|
| 38 |
-
[tool.setuptools.package-data]
|
| 39 |
-
sam3d_objects_mlx = ["LICENSE", "LICENSE-APACHE", "README.md"]
|
| 40 |
-
""")
|
| 41 |
-
card = """---
|
| 42 |
-
library_name: mlx
|
| 43 |
-
pipeline_tag: image-to-3d
|
| 44 |
-
license: other
|
| 45 |
-
license_name: sam-license
|
| 46 |
-
license_link: LICENSE
|
| 47 |
-
base_model:
|
| 48 |
-
- facebook/sam-3d-objects
|
| 49 |
-
- Ruicheng/moge-vitl
|
| 50 |
-
tags:
|
| 51 |
-
- mlx
|
| 52 |
-
- apple-silicon
|
| 53 |
-
- bfloat16
|
| 54 |
-
- image-to-3d
|
| 55 |
-
- gaussian-splatting
|
| 56 |
-
- inference
|
| 57 |
-
---
|
| 58 |
-
|
| 59 |
-
# SAM 3D Objects — MLX BF16
|
| 60 |
-
|
| 61 |
-
Frozen inference port of Meta SAM 3D Objects, including the upstream MoGe-v1
|
| 62 |
-
depth estimator. Runtime and conversion require **MLX and Python's standard
|
| 63 |
-
library only**. This is an unofficial derivative. SAM components retain the
|
| 64 |
-
SAM License; MoGe and FlexiCubes retain Apache-2.0.
|
| 65 |
-
|
| 66 |
-
The bundle includes 3,709 BF16 tensors, strict loading, MLX sparse convolutions,
|
| 67 |
-
windowed attention, Gaussian and colored-mesh decoding, `mx.async_eval`, and
|
| 68 |
-
synchronous/asynchronous streaming APIs. Both Gaussian heads are included.
|
| 69 |
-
It generates geometry and pose; it has no text or tool-calling interface.
|
| 70 |
-
|
| 71 |
-
## Install the included runtime
|
| 72 |
-
|
| 73 |
-
Download this repository, then install its small runtime package:
|
| 74 |
-
|
| 75 |
-
```sh
|
| 76 |
-
hf download mlx-community/sam-3d-objects-bf16 --local-dir sam-3d-objects-bf16
|
| 77 |
-
python -m pip install ./sam-3d-objects-bf16
|
| 78 |
-
sam3d-mlx --model ./sam-3d-objects-bf16 \\
|
| 79 |
-
--image image.png --mask mask.png --output ./output \\
|
| 80 |
-
--formats gaussian mesh
|
| 81 |
-
```
|
| 82 |
-
|
| 83 |
-
`hf` is an optional download tool; it is not a runtime dependency. The package
|
| 84 |
-
can also be imported directly from the downloaded directory. The same model
|
| 85 |
-
implementation lives under `mlx_vlm/models/sam3d_objects` in the port checkout.
|
| 86 |
-
|
| 87 |
-
```python
|
| 88 |
-
from sam3d_objects_mlx.io import read_png, read_mask
|
| 89 |
-
from sam3d_objects_mlx.pipeline import Pipeline, Request
|
| 90 |
-
|
| 91 |
-
pipeline = Pipeline.from_pretrained("sam-3d-objects-bf16")
|
| 92 |
-
image, mask = read_png("image.png")[..., :3], read_mask("mask.png")
|
| 93 |
-
result = pipeline.generate(image, mask, seed=42)
|
| 94 |
-
|
| 95 |
-
async def reconstruct(requests):
|
| 96 |
-
async for event in pipeline.astream(requests):
|
| 97 |
-
if event.stage == "complete":
|
| 98 |
-
consume(event.data)
|
| 99 |
-
```
|
| 100 |
-
|
| 101 |
-
`requests` is an iterable or async iterable of `Request` values. Input is
|
| 102 |
-
consumed one request at a time with backpressure. Events preserve IDs and
|
| 103 |
-
order and include every sampling step plus decoded outputs. The event loop
|
| 104 |
-
remains responsive while one worker submits MLX work. Early `aclose()` or
|
| 105 |
-
cancellation stops submissions and drains the worker. Arrays may still be
|
| 106 |
-
evaluating on the GPU when yielded; use `mx.eval` before host consumption.
|
| 107 |
-
|
| 108 |
-
Inputs are HWC RGB/RGBA MLX arrays and HW masks. The included file reader
|
| 109 |
-
supports non-interlaced 8-bit PNG, including RGBA alpha masks. Callers can use
|
| 110 |
-
other decoders and pass arrays directly. Automatic MoGe depth is included;
|
| 111 |
-
external HWC point maps use +X left, +Y up, +Z forward, with NaN invalid values.
|
| 112 |
-
Set `estimate_depth=False` to use the trained point-map dropout instead.
|
| 113 |
-
|
| 114 |
-
Results include local-space Gaussians, mesh vertices/faces/colors, latent
|
| 115 |
-
features, occupied voxels, and a separate pose (rotation, translation, scale).
|
| 116 |
-
CLI outputs standard Gaussian PLY, colored OBJ, and raw safetensors.
|
| 117 |
-
`--jsonl` consumes stdin request lines and emits ordered progress records.
|
| 118 |
-
Training, latent training encoders, rendering, texture baking, mesh
|
| 119 |
-
simplification, and iterative layout optimization are not included.
|
| 120 |
-
|
| 121 |
-
## Conversion and validation
|
| 122 |
-
|
| 123 |
-
SAM weights were converted directly from the official tensor-only PyTorch
|
| 124 |
-
ZIP checkpoints through a restricted stdlib reader. Tensor bytes are first
|
| 125 |
-
preserved in safetensors, then mapped to MLX layouts and cast to BF16. The
|
| 126 |
-
duplicate occupancy decoder is removed. MoGe uses its original safetensors
|
| 127 |
-
export. No PyTorch or NumPy is imported by conversion or inference.
|
| 128 |
-
|
| 129 |
-
All parameter names/shapes were checked with strict loading, every floating
|
| 130 |
-
tensor is BF16, and the loaded model has zero trainable parameters. Component
|
| 131 |
-
checks against the original reference in FP32 MLX CPU cover attention, both
|
| 132 |
-
flow models, occupancy decoding, interpolation, pretrained MoGe, and
|
| 133 |
-
FlexiCubes. Maximum absolute error was below 0.000002 on these fixtures;
|
| 134 |
-
mesh face indices matched exactly. This is not a claim of bitwise BF16
|
| 135 |
-
end-to-end parity or a reconstruction-quality evaluation.
|
| 136 |
-
|
| 137 |
-
See `validation.json`, `conversion.json`, and the included source for details.
|
| 138 |
-
The original sources are [SAM 3D Objects](https://github.com/facebookresearch/sam-3d-objects)
|
| 139 |
-
and [MoGe](https://github.com/microsoft/MoGe).
|
| 140 |
-
"""
|
| 141 |
-
validation = root / "validation.json"
|
| 142 |
-
if validation.exists():
|
| 143 |
-
report = json.loads(validation.read_text())
|
| 144 |
-
if "benchmark" in report:
|
| 145 |
-
b = report["benchmark"]
|
| 146 |
-
card += f"""
|
| 147 |
-
### Local performance
|
| 148 |
-
|
| 149 |
-
Hardware: {b["hardware"]}. Input: 448×672 RGB plus object mask; automatic MoGe
|
| 150 |
-
depth, 25 structure steps and 25 latent steps, both Gaussian heads and mesh.
|
| 151 |
-
One warmup was excluded; the same seed produced identical latent outputs.
|
| 152 |
-
|
| 153 |
-
| Metric | Result |
|
| 154 |
-
| --- | ---: |
|
| 155 |
-
| Median latency ({len(b["samples"])} runs) | {b["median_seconds"]:.2f} s |
|
| 156 |
-
| Maximum peak memory | {b["peak_memory_gb"]:.2f} GB |
|
| 157 |
-
|
| 158 |
-
Two additional async requests matched the synchronous latent output while
|
| 159 |
-
the event-loop heartbeat continued. These measurements describe one input.
|
| 160 |
-
"""
|
| 161 |
-
(root / "README.md").write_text(card)
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
def main():
|
| 165 |
-
parser = argparse.ArgumentParser(description=__doc__)
|
| 166 |
-
parser.add_argument("destination")
|
| 167 |
-
package(parser.parse_args().destination)
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
if __name__ == "__main__":
|
| 171 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/checkpoint.py
DELETED
|
@@ -1,136 +0,0 @@
|
|
| 1 |
-
"""Read tensor-only torch ZIP checkpoints without importing torch or NumPy.
|
| 2 |
-
|
| 3 |
-
The restricted unpickler creates metadata, never source classes. Only dense,
|
| 4 |
-
contiguous tensor storages and OrderedDict are accepted. The intermediate
|
| 5 |
-
safetensors file preserves source bytes; MLX handles BF16 conversion later.
|
| 6 |
-
"""
|
| 7 |
-
|
| 8 |
-
import collections
|
| 9 |
-
import io
|
| 10 |
-
import json
|
| 11 |
-
import math
|
| 12 |
-
import pickle
|
| 13 |
-
import struct
|
| 14 |
-
import zipfile
|
| 15 |
-
from dataclasses import dataclass
|
| 16 |
-
|
| 17 |
-
DTYPES = {
|
| 18 |
-
"FloatStorage": ("F32", 4),
|
| 19 |
-
"HalfStorage": ("F16", 2),
|
| 20 |
-
"BFloat16Storage": ("BF16", 2),
|
| 21 |
-
"DoubleStorage": ("F64", 8),
|
| 22 |
-
"LongStorage": ("I64", 8),
|
| 23 |
-
"IntStorage": ("I32", 4),
|
| 24 |
-
"BoolStorage": ("BOOL", 1),
|
| 25 |
-
"ByteStorage": ("U8", 1),
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
@dataclass
|
| 30 |
-
class Storage:
|
| 31 |
-
kind: str
|
| 32 |
-
key: str
|
| 33 |
-
size: int
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
@dataclass
|
| 37 |
-
class Tensor:
|
| 38 |
-
storage: Storage
|
| 39 |
-
offset: int
|
| 40 |
-
shape: tuple
|
| 41 |
-
stride: tuple
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def _tensor(storage, offset, shape, stride, *unused):
|
| 45 |
-
return Tensor(storage, offset, shape, stride)
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
class TensorUnpickler(pickle.Unpickler):
|
| 49 |
-
def find_class(self, module, name):
|
| 50 |
-
if module == "collections" and name == "OrderedDict":
|
| 51 |
-
return collections.OrderedDict
|
| 52 |
-
if module == "torch" and name in DTYPES:
|
| 53 |
-
return name
|
| 54 |
-
if module == "torch._utils" and name in (
|
| 55 |
-
"_rebuild_tensor_v2",
|
| 56 |
-
"_rebuild_tensor",
|
| 57 |
-
):
|
| 58 |
-
return _tensor
|
| 59 |
-
if module == "torch._utils" and name == "_rebuild_parameter":
|
| 60 |
-
return lambda tensor, *args: tensor
|
| 61 |
-
raise pickle.UnpicklingError(f"Unsupported checkpoint global: {module}.{name}")
|
| 62 |
-
|
| 63 |
-
def persistent_load(self, value):
|
| 64 |
-
if (
|
| 65 |
-
not isinstance(value, tuple)
|
| 66 |
-
or len(value) != 5
|
| 67 |
-
or value[0] != "storage"
|
| 68 |
-
or value[1] not in DTYPES
|
| 69 |
-
):
|
| 70 |
-
raise pickle.UnpicklingError("Unsupported checkpoint storage")
|
| 71 |
-
return Storage(value[1], str(value[2]), value[4])
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
def read_metadata(archive):
|
| 75 |
-
names = archive.namelist()
|
| 76 |
-
candidates = [n for n in names if n.endswith("/data.pkl")]
|
| 77 |
-
if len(candidates) != 1:
|
| 78 |
-
raise ValueError("Expected a tensor ZIP checkpoint with one data.pkl")
|
| 79 |
-
prefix = candidates[0].removesuffix("data.pkl")
|
| 80 |
-
if (
|
| 81 |
-
prefix + "byteorder" in names
|
| 82 |
-
and archive.read(prefix + "byteorder") != b"little"
|
| 83 |
-
):
|
| 84 |
-
raise ValueError("Only little-endian checkpoints are supported")
|
| 85 |
-
data = TensorUnpickler(io.BytesIO(archive.read(candidates[0]))).load()
|
| 86 |
-
if "state_dict" in data:
|
| 87 |
-
data = data["state_dict"]
|
| 88 |
-
elif "model" in data and "model_config" in data:
|
| 89 |
-
data = data["model"]
|
| 90 |
-
# The released structure generator contains non-tensor training metadata.
|
| 91 |
-
data.pop("__mixhavior__", None)
|
| 92 |
-
if not isinstance(data, dict) or not all(
|
| 93 |
-
isinstance(v, Tensor) for v in data.values()
|
| 94 |
-
):
|
| 95 |
-
raise ValueError("Checkpoint must contain only named dense tensors")
|
| 96 |
-
return prefix, data
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
def to_safetensors(source, destination):
|
| 100 |
-
"""Stream a tensor-only checkpoint to a byte-exact safetensors file."""
|
| 101 |
-
with zipfile.ZipFile(source) as archive:
|
| 102 |
-
prefix, tensors = read_metadata(archive)
|
| 103 |
-
header, offset = {}, 0
|
| 104 |
-
for name, t in tensors.items():
|
| 105 |
-
stride = 1
|
| 106 |
-
for size, actual in zip(reversed(t.shape), reversed(t.stride)):
|
| 107 |
-
if size > 1 and actual != stride:
|
| 108 |
-
raise ValueError(f"Non-contiguous tensor: {name}")
|
| 109 |
-
stride *= size
|
| 110 |
-
dtype, width = DTYPES[t.storage.kind]
|
| 111 |
-
length = math.prod(t.shape) * width
|
| 112 |
-
if t.offset < 0 or t.offset + math.prod(t.shape) > t.storage.size:
|
| 113 |
-
raise ValueError(f"Tensor outside storage: {name}")
|
| 114 |
-
header[name] = {
|
| 115 |
-
"dtype": dtype,
|
| 116 |
-
"shape": list(t.shape),
|
| 117 |
-
"data_offsets": [offset, offset + length],
|
| 118 |
-
}
|
| 119 |
-
offset += length
|
| 120 |
-
encoded = json.dumps(header, separators=(",", ":")).encode()
|
| 121 |
-
encoded += b" " * (-len(encoded) % 8)
|
| 122 |
-
with open(destination, "wb") as out:
|
| 123 |
-
out.write(struct.pack("<Q", len(encoded)))
|
| 124 |
-
out.write(encoded)
|
| 125 |
-
for name, t in tensors.items():
|
| 126 |
-
width = DTYPES[t.storage.kind][1]
|
| 127 |
-
remaining = math.prod(t.shape) * width
|
| 128 |
-
with archive.open(prefix + "data/" + t.storage.key) as raw:
|
| 129 |
-
raw.seek(t.offset * width)
|
| 130 |
-
while remaining:
|
| 131 |
-
chunk = raw.read(min(remaining, 8 << 20))
|
| 132 |
-
if not chunk:
|
| 133 |
-
raise ValueError(f"Truncated storage: {name}")
|
| 134 |
-
out.write(chunk)
|
| 135 |
-
remaining -= len(chunk)
|
| 136 |
-
return len(tensors)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/config.py
DELETED
|
@@ -1,75 +0,0 @@
|
|
| 1 |
-
"""Inference configuration for Meta SAM 3D Objects."""
|
| 2 |
-
|
| 3 |
-
from dataclasses import asdict, dataclass, field
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
@dataclass
|
| 7 |
-
class ModelConfig:
|
| 8 |
-
model_type: str = "sam3d_objects"
|
| 9 |
-
dtype: str = "bfloat16"
|
| 10 |
-
hidden_size: int = 1024
|
| 11 |
-
num_heads: int = 16
|
| 12 |
-
num_blocks: int = 24
|
| 13 |
-
cond_channels: int = 1024
|
| 14 |
-
latent_channels: int = 8
|
| 15 |
-
latent_resolution: int = 16
|
| 16 |
-
resolution: int = 64
|
| 17 |
-
io_channels: int = 128
|
| 18 |
-
decoder_channels: int = 768
|
| 19 |
-
decoder_heads: int = 12
|
| 20 |
-
decoder_blocks: int = 12
|
| 21 |
-
window_size: int = 8
|
| 22 |
-
structure_channels: list = field(default_factory=lambda: [512, 128, 32])
|
| 23 |
-
structure_res_blocks: int = 2
|
| 24 |
-
dino_hidden_size: int = 1024
|
| 25 |
-
dino_heads: int = 16
|
| 26 |
-
dino_layers: int = 24
|
| 27 |
-
dino_image_size: int = 518
|
| 28 |
-
image_size: int = 518
|
| 29 |
-
point_size: int = 256
|
| 30 |
-
point_patch_size: int = 8
|
| 31 |
-
point_channels: int = 512
|
| 32 |
-
point_heads: int = 16
|
| 33 |
-
# Enable the bundled MoGe-v1 inference model when its weights are present.
|
| 34 |
-
depth_model: bool = False
|
| 35 |
-
depth_num_tokens: int = 2551
|
| 36 |
-
ss_steps: int = 25
|
| 37 |
-
slat_steps: int = 25
|
| 38 |
-
ss_guidance: float = 7.0
|
| 39 |
-
slat_guidance: float = 1.0
|
| 40 |
-
ss_rescale_t: float = 3.0
|
| 41 |
-
slat_rescale_t: float = 1.0
|
| 42 |
-
# Match the released inference pipeline's occupancy pruning.
|
| 43 |
-
downsample_ss_dist: int = 1
|
| 44 |
-
slat_mean: list = field(
|
| 45 |
-
default_factory=lambda: [
|
| 46 |
-
0.12211431,
|
| 47 |
-
0.37204156,
|
| 48 |
-
-1.26521907,
|
| 49 |
-
-2.05276058,
|
| 50 |
-
-3.10432536,
|
| 51 |
-
-0.11294304,
|
| 52 |
-
-0.85146744,
|
| 53 |
-
0.45506954,
|
| 54 |
-
]
|
| 55 |
-
)
|
| 56 |
-
slat_std: list = field(
|
| 57 |
-
default_factory=lambda: [
|
| 58 |
-
2.37326008,
|
| 59 |
-
2.13174402,
|
| 60 |
-
2.2413953,
|
| 61 |
-
2.30589401,
|
| 62 |
-
2.1191894,
|
| 63 |
-
1.8969511,
|
| 64 |
-
2.41684989,
|
| 65 |
-
2.08374642,
|
| 66 |
-
]
|
| 67 |
-
)
|
| 68 |
-
|
| 69 |
-
@classmethod
|
| 70 |
-
def from_dict(cls, values):
|
| 71 |
-
names = cls.__dataclass_fields__
|
| 72 |
-
return cls(**{k: v for k, v in values.items() if k in names})
|
| 73 |
-
|
| 74 |
-
def to_dict(self):
|
| 75 |
-
return asdict(self)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/convert.py
DELETED
|
@@ -1,184 +0,0 @@
|
|
| 1 |
-
"""Convert released inference checkpoints with MLX and the standard library."""
|
| 2 |
-
|
| 3 |
-
import argparse
|
| 4 |
-
import json
|
| 5 |
-
import tempfile
|
| 6 |
-
from pathlib import Path
|
| 7 |
-
|
| 8 |
-
import mlx.core as mx
|
| 9 |
-
|
| 10 |
-
from .checkpoint import to_safetensors
|
| 11 |
-
from .config import ModelConfig
|
| 12 |
-
|
| 13 |
-
COMPONENTS = (
|
| 14 |
-
"ss_generator",
|
| 15 |
-
"slat_generator",
|
| 16 |
-
"ss_decoder",
|
| 17 |
-
"slat_decoder_gs",
|
| 18 |
-
"slat_decoder_gs_4",
|
| 19 |
-
"slat_decoder_mesh",
|
| 20 |
-
)
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
def map_tensor(component, name, tensor):
|
| 24 |
-
if component.endswith("generator"):
|
| 25 |
-
if name.startswith("_base_models.generator.reverse_fn.backbone."):
|
| 26 |
-
name = (
|
| 27 |
-
component
|
| 28 |
-
+ "."
|
| 29 |
-
+ name.removeprefix("_base_models.generator.reverse_fn.backbone.")
|
| 30 |
-
)
|
| 31 |
-
elif name.startswith("_base_models.condition_embedder."):
|
| 32 |
-
name = (
|
| 33 |
-
component.replace("generator", "condition_embedder")
|
| 34 |
-
+ "."
|
| 35 |
-
+ name.removeprefix("_base_models.condition_embedder.")
|
| 36 |
-
)
|
| 37 |
-
elif name.startswith("_base_models.decoder."):
|
| 38 |
-
# Duplicate occupancy decoder bundled with the structure generator.
|
| 39 |
-
return None
|
| 40 |
-
else:
|
| 41 |
-
raise ValueError(f"Unmapped inference tensor: {name}")
|
| 42 |
-
else:
|
| 43 |
-
name = component + "." + name
|
| 44 |
-
if name.startswith("ss_decoder.") and tensor.ndim == 5:
|
| 45 |
-
tensor = tensor.transpose(0, 2, 3, 4, 1)
|
| 46 |
-
elif name.endswith("patch_embed.proj.weight"):
|
| 47 |
-
tensor = tensor.transpose(0, 2, 3, 1)
|
| 48 |
-
if mx.issubdtype(tensor.dtype, mx.floating):
|
| 49 |
-
tensor = tensor.astype(mx.bfloat16)
|
| 50 |
-
return name, tensor
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
def convert(source, destination):
|
| 54 |
-
source, destination = Path(source), Path(destination)
|
| 55 |
-
if (source / "checkpoints").is_dir():
|
| 56 |
-
source = source / "checkpoints"
|
| 57 |
-
destination.mkdir(parents=True, exist_ok=True)
|
| 58 |
-
index, total_size, report = {}, 0, {}
|
| 59 |
-
for i, component in enumerate(COMPONENTS, 1):
|
| 60 |
-
checkpoint = source / f"{component}.ckpt"
|
| 61 |
-
safe = source / f"{component}.safetensors"
|
| 62 |
-
with tempfile.TemporaryDirectory(prefix="sam3d-convert-") as scratch:
|
| 63 |
-
if checkpoint.exists():
|
| 64 |
-
safe = Path(scratch) / "source.safetensors"
|
| 65 |
-
count = to_safetensors(checkpoint, safe)
|
| 66 |
-
elif safe.exists():
|
| 67 |
-
count = None
|
| 68 |
-
else:
|
| 69 |
-
raise FileNotFoundError(checkpoint)
|
| 70 |
-
weights = {}
|
| 71 |
-
for name, tensor in mx.load(str(safe)).items():
|
| 72 |
-
mapped = map_tensor(component, name, tensor)
|
| 73 |
-
if mapped is not None:
|
| 74 |
-
key, value = mapped
|
| 75 |
-
weights[key] = value
|
| 76 |
-
mx.async_eval(weights)
|
| 77 |
-
shard = f"model-{i:05d}-of-{len(COMPONENTS):05d}.safetensors"
|
| 78 |
-
mx.save_safetensors(
|
| 79 |
-
str(destination / shard),
|
| 80 |
-
weights,
|
| 81 |
-
metadata={"format": "mlx", "dtype": "bfloat16"},
|
| 82 |
-
)
|
| 83 |
-
index.update({k: shard for k in weights})
|
| 84 |
-
total_size += sum(v.nbytes for v in weights.values())
|
| 85 |
-
report[component] = {
|
| 86 |
-
"source_tensors": count,
|
| 87 |
-
"converted_tensors": len(weights),
|
| 88 |
-
"shard": shard,
|
| 89 |
-
}
|
| 90 |
-
print(f"{component}: {len(weights)} tensors -> {shard}", flush=True)
|
| 91 |
-
del weights
|
| 92 |
-
mx.clear_cache()
|
| 93 |
-
(destination / "config.json").write_text(
|
| 94 |
-
json.dumps(ModelConfig().to_dict(), indent=2) + "\n"
|
| 95 |
-
)
|
| 96 |
-
(destination / "model.safetensors.index.json").write_text(
|
| 97 |
-
json.dumps(
|
| 98 |
-
{"metadata": {"total_size": total_size}, "weight_map": index}, indent=2
|
| 99 |
-
)
|
| 100 |
-
+ "\n"
|
| 101 |
-
)
|
| 102 |
-
(destination / "conversion.json").write_text(
|
| 103 |
-
json.dumps(
|
| 104 |
-
{
|
| 105 |
-
"source": "facebook/sam-3d-objects",
|
| 106 |
-
"dtype": "bfloat16",
|
| 107 |
-
"components": report,
|
| 108 |
-
},
|
| 109 |
-
indent=2,
|
| 110 |
-
)
|
| 111 |
-
+ "\n"
|
| 112 |
-
)
|
| 113 |
-
(destination / "LICENSE").write_text(
|
| 114 |
-
(Path(__file__).parent / "LICENSE").read_text()
|
| 115 |
-
)
|
| 116 |
-
return destination
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
def add_depth(source, destination):
|
| 120 |
-
"""Add the released Ruicheng/moge-vitl inference checkpoint to a bundle."""
|
| 121 |
-
from .depth import DepthModel
|
| 122 |
-
|
| 123 |
-
source, destination = Path(source), Path(destination)
|
| 124 |
-
with tempfile.TemporaryDirectory(prefix="moge-convert-") as scratch:
|
| 125 |
-
if source.suffix != ".safetensors":
|
| 126 |
-
raw = Path(scratch) / "moge.safetensors"
|
| 127 |
-
to_safetensors(source, raw)
|
| 128 |
-
else:
|
| 129 |
-
raw = source
|
| 130 |
-
weights = {}
|
| 131 |
-
for name, value in mx.load(str(raw)).items():
|
| 132 |
-
if value.ndim == 4 and name.endswith("weight"):
|
| 133 |
-
if name.startswith("head.upsample_blocks.") and ".0.0.weight" in name:
|
| 134 |
-
value = value.transpose(1, 2, 3, 0)
|
| 135 |
-
else:
|
| 136 |
-
value = value.transpose(0, 2, 3, 1)
|
| 137 |
-
weights[name] = (
|
| 138 |
-
value.astype(mx.bfloat16)
|
| 139 |
-
if mx.issubdtype(value.dtype, mx.floating)
|
| 140 |
-
else value
|
| 141 |
-
)
|
| 142 |
-
model = DepthModel()
|
| 143 |
-
model.load_weights(list(weights.items()), strict=True)
|
| 144 |
-
weights = {"depth_model." + k: v for k, v in weights.items()}
|
| 145 |
-
mx.save_safetensors(str(destination / "moge.safetensors"), weights)
|
| 146 |
-
index_path = destination / "model.safetensors.index.json"
|
| 147 |
-
index = json.loads(index_path.read_text())
|
| 148 |
-
index["weight_map"].update({k: "moge.safetensors" for k in weights})
|
| 149 |
-
index["metadata"]["total_size"] = sum(
|
| 150 |
-
p.stat().st_size for p in destination.glob("*.safetensors")
|
| 151 |
-
)
|
| 152 |
-
index_path.write_text(json.dumps(index, indent=2) + "\n")
|
| 153 |
-
path = destination / "config.json"
|
| 154 |
-
config = json.loads(path.read_text())
|
| 155 |
-
config["depth_model"] = True
|
| 156 |
-
path.write_text(json.dumps(config, indent=2) + "\n")
|
| 157 |
-
(destination / "LICENSE-APACHE").write_text(
|
| 158 |
-
(Path(__file__).parent / "LICENSE-APACHE").read_text()
|
| 159 |
-
)
|
| 160 |
-
print(f"MoGe: {len(weights)} BF16 tensors added", flush=True)
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
def main():
|
| 164 |
-
parser = argparse.ArgumentParser(description=__doc__)
|
| 165 |
-
parser.add_argument("--source")
|
| 166 |
-
parser.add_argument("--output", required=True)
|
| 167 |
-
parser.add_argument(
|
| 168 |
-
"--moge-checkpoint",
|
| 169 |
-
help="Optional Ruicheng/moge-vitl model.pt or source safetensors",
|
| 170 |
-
)
|
| 171 |
-
args = parser.parse_args()
|
| 172 |
-
if args.source:
|
| 173 |
-
convert(args.source, args.output)
|
| 174 |
-
if args.moge_checkpoint:
|
| 175 |
-
add_depth(args.moge_checkpoint, args.output)
|
| 176 |
-
if not args.source and not args.moge_checkpoint:
|
| 177 |
-
parser.error("Provide --source and/or --moge-checkpoint")
|
| 178 |
-
from .bundle import package
|
| 179 |
-
|
| 180 |
-
package(args.output)
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
if __name__ == "__main__":
|
| 184 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/decoders.py
DELETED
|
@@ -1,182 +0,0 @@
|
|
| 1 |
-
# Adapted from Meta SAM 3D Objects. See LICENSE in this directory.
|
| 2 |
-
"""Occupancy, Gaussian, and mesh-feature inference decoders."""
|
| 3 |
-
|
| 4 |
-
import math
|
| 5 |
-
|
| 6 |
-
import mlx.core as mx
|
| 7 |
-
import mlx.nn as nn
|
| 8 |
-
|
| 9 |
-
from .layers import (
|
| 10 |
-
Attention,
|
| 11 |
-
FeedForward,
|
| 12 |
-
LayerNorm,
|
| 13 |
-
Sequential,
|
| 14 |
-
layer_norm,
|
| 15 |
-
position_embedding,
|
| 16 |
-
)
|
| 17 |
-
from .sparse import SparseConv, SparseGroupNorm, window_attention
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
class DenseResBlock(nn.Module):
|
| 21 |
-
def __init__(self, channels):
|
| 22 |
-
super().__init__()
|
| 23 |
-
self.norm1 = LayerNorm(channels)
|
| 24 |
-
self.norm2 = LayerNorm(channels)
|
| 25 |
-
self.conv1 = nn.Conv3d(channels, channels, 3, padding=1)
|
| 26 |
-
self.conv2 = nn.Conv3d(channels, channels, 3, padding=1)
|
| 27 |
-
|
| 28 |
-
def __call__(self, x):
|
| 29 |
-
return x + self.conv2(nn.silu(self.norm2(self.conv1(nn.silu(self.norm1(x))))))
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
class DenseUpsample(nn.Module):
|
| 33 |
-
def __init__(self, inputs, outputs):
|
| 34 |
-
super().__init__()
|
| 35 |
-
self.conv = nn.Conv3d(inputs, outputs * 8, 3, padding=1)
|
| 36 |
-
|
| 37 |
-
def __call__(self, x):
|
| 38 |
-
x = self.conv(x)
|
| 39 |
-
b, d, h, w, c = x.shape
|
| 40 |
-
x = x.reshape(b, d, h, w, c // 8, 2, 2, 2)
|
| 41 |
-
return x.transpose(0, 1, 5, 2, 6, 3, 7, 4).reshape(
|
| 42 |
-
b, d * 2, h * 2, w * 2, c // 8
|
| 43 |
-
)
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
class StructureDecoder(nn.Module):
|
| 47 |
-
def __init__(self, config):
|
| 48 |
-
super().__init__()
|
| 49 |
-
channels = config.structure_channels
|
| 50 |
-
self.input_layer = nn.Conv3d(config.latent_channels, channels[0], 3, padding=1)
|
| 51 |
-
self.middle_block = Sequential(
|
| 52 |
-
*(DenseResBlock(channels[0]) for _ in range(config.structure_res_blocks))
|
| 53 |
-
)
|
| 54 |
-
self.blocks = []
|
| 55 |
-
for i, c in enumerate(channels):
|
| 56 |
-
self.blocks.extend(
|
| 57 |
-
DenseResBlock(c) for _ in range(config.structure_res_blocks)
|
| 58 |
-
)
|
| 59 |
-
if i + 1 < len(channels):
|
| 60 |
-
self.blocks.append(DenseUpsample(c, channels[i + 1]))
|
| 61 |
-
self.out_layer = Sequential(
|
| 62 |
-
LayerNorm(channels[-1]), nn.SiLU(), nn.Conv3d(channels[-1], 1, 3, padding=1)
|
| 63 |
-
)
|
| 64 |
-
|
| 65 |
-
def __call__(self, x):
|
| 66 |
-
side = round(x.shape[1] ** (1 / 3))
|
| 67 |
-
x = x.reshape(x.shape[0], side, side, side, x.shape[-1])
|
| 68 |
-
x = self.middle_block(self.input_layer(x.astype(self.input_layer.weight.dtype)))
|
| 69 |
-
for block in self.blocks:
|
| 70 |
-
x = block(x)
|
| 71 |
-
return self.out_layer(x)
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
class WindowBlock(nn.Module):
|
| 75 |
-
def __init__(self, channels, heads, window, shift):
|
| 76 |
-
super().__init__()
|
| 77 |
-
self.attn = Attention(channels, heads)
|
| 78 |
-
self.mlp = FeedForward(channels)
|
| 79 |
-
self._window, self._shift, self._heads = window, shift, heads
|
| 80 |
-
|
| 81 |
-
def __call__(self, x, grid):
|
| 82 |
-
h = self.attn.to_qkv(layer_norm(x, 1e-6)).reshape(
|
| 83 |
-
x.shape[0], 3, self._heads, -1
|
| 84 |
-
)
|
| 85 |
-
h = window_attention(h, grid, self._window, self._shift)
|
| 86 |
-
x = x + self.attn.to_out(h)
|
| 87 |
-
return x + self.mlp(layer_norm(x, 1e-6))
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
class DecoderBase(nn.Module):
|
| 91 |
-
def __init__(self, config):
|
| 92 |
-
super().__init__()
|
| 93 |
-
c = config.decoder_channels
|
| 94 |
-
self.input_layer = nn.Linear(config.latent_channels, c)
|
| 95 |
-
self.blocks = [
|
| 96 |
-
WindowBlock(
|
| 97 |
-
c,
|
| 98 |
-
config.decoder_heads,
|
| 99 |
-
config.window_size,
|
| 100 |
-
config.window_size // 2 * (i % 2),
|
| 101 |
-
)
|
| 102 |
-
for i in range(config.decoder_blocks)
|
| 103 |
-
]
|
| 104 |
-
|
| 105 |
-
def encode(self, x, grid):
|
| 106 |
-
x = self.input_layer(x.astype(self.input_layer.weight.dtype))
|
| 107 |
-
x = x + position_embedding(grid.coords[:, 1:], x.shape[-1]).astype(x.dtype)
|
| 108 |
-
for block in self.blocks:
|
| 109 |
-
x = block(x, grid)
|
| 110 |
-
return x
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
class GaussianDecoder(DecoderBase):
|
| 114 |
-
def __init__(self, config, count=32):
|
| 115 |
-
super().__init__(config)
|
| 116 |
-
self.out_layer = nn.Linear(config.decoder_channels, 14 * count)
|
| 117 |
-
self.offset_perturbation = mx.zeros((count, 3))
|
| 118 |
-
self._count = count
|
| 119 |
-
|
| 120 |
-
def __call__(self, x, grid):
|
| 121 |
-
h = self.out_layer(layer_norm(self.encode(x, grid))).astype(mx.float32)
|
| 122 |
-
n = self._count
|
| 123 |
-
xyz, color, scaling, rotation, opacity = mx.split(
|
| 124 |
-
h, [n * 3, n * 6, n * 9, n * 13], axis=-1
|
| 125 |
-
)
|
| 126 |
-
xyz = (
|
| 127 |
-
grid.coords[:, None, 1:].astype(mx.float32) + 0.5
|
| 128 |
-
) / grid.resolution + mx.tanh(
|
| 129 |
-
xyz.reshape(-1, n, 3) + self.offset_perturbation
|
| 130 |
-
) * (
|
| 131 |
-
0.75 / grid.resolution
|
| 132 |
-
)
|
| 133 |
-
scale = nn.softplus(scaling.reshape(-1, 3) + math.log(math.expm1(0.004)))
|
| 134 |
-
scale = mx.sqrt(scale * scale + 0.0009**2)
|
| 135 |
-
rotation = rotation.reshape(-1, 4) * 0.1 + mx.array([1, 0, 0, 0])
|
| 136 |
-
rotation = rotation * mx.rsqrt(
|
| 137 |
-
mx.maximum(mx.sum(rotation * rotation, axis=-1, keepdims=True), 1e-24)
|
| 138 |
-
)
|
| 139 |
-
opacity = mx.sigmoid(opacity.reshape(-1, 1) + math.log(0.1 / 0.9))
|
| 140 |
-
return {
|
| 141 |
-
"positions": xyz.reshape(-1, 3) - 0.5,
|
| 142 |
-
"sh_dc": color.reshape(-1, 3),
|
| 143 |
-
"scales": scale,
|
| 144 |
-
"rotations": rotation,
|
| 145 |
-
"opacities": opacity,
|
| 146 |
-
}
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
class SubdivideBlock(nn.Module):
|
| 150 |
-
def __init__(self, input_channels, channels):
|
| 151 |
-
super().__init__()
|
| 152 |
-
self.act_layers = Sequential(SparseGroupNorm(input_channels), nn.SiLU())
|
| 153 |
-
self.out_layers = Sequential(
|
| 154 |
-
SparseConv(input_channels, channels),
|
| 155 |
-
SparseGroupNorm(channels),
|
| 156 |
-
nn.SiLU(),
|
| 157 |
-
SparseConv(channels, channels),
|
| 158 |
-
)
|
| 159 |
-
self.skip_connection = SparseConv(input_channels, channels, kernel=1)
|
| 160 |
-
|
| 161 |
-
def __call__(self, x, grid):
|
| 162 |
-
h = mx.repeat(self.act_layers(x), 8, axis=0)
|
| 163 |
-
x = mx.repeat(x, 8, axis=0)
|
| 164 |
-
grid = grid.subdivide()
|
| 165 |
-
h = self.out_layers["0"](h, grid)
|
| 166 |
-
h = self.out_layers["2"](self.out_layers["1"](h))
|
| 167 |
-
h = self.out_layers["3"](h, grid)
|
| 168 |
-
return h + self.skip_connection(x, grid), grid
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
class MeshDecoder(DecoderBase):
|
| 172 |
-
def __init__(self, config):
|
| 173 |
-
super().__init__(config)
|
| 174 |
-
c = config.decoder_channels
|
| 175 |
-
self.upsample = [SubdivideBlock(c, c // 4), SubdivideBlock(c // 4, c // 8)]
|
| 176 |
-
self.out_layer = nn.Linear(c // 8, 101)
|
| 177 |
-
|
| 178 |
-
def __call__(self, x, grid):
|
| 179 |
-
x = self.encode(x, grid)
|
| 180 |
-
for block in self.upsample:
|
| 181 |
-
x, grid = block(x, grid)
|
| 182 |
-
return self.out_layer(x), grid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/depth.py
DELETED
|
@@ -1,210 +0,0 @@
|
|
| 1 |
-
# Adapted from microsoft/MoGe (Apache-2.0). See LICENSE-APACHE in this directory.
|
| 2 |
-
"""Frozen MoGe v1 inference used by the released SAM 3D pipeline."""
|
| 3 |
-
|
| 4 |
-
import math
|
| 5 |
-
from types import SimpleNamespace
|
| 6 |
-
|
| 7 |
-
import mlx.core as mx
|
| 8 |
-
import mlx.nn as nn
|
| 9 |
-
|
| 10 |
-
from .layers import Sequential
|
| 11 |
-
from .resize import resize, resize_bicubic
|
| 12 |
-
from .sparse import nonzero
|
| 13 |
-
from .vision import DINOv2
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
def view_plane(height, width, aspect=None):
|
| 17 |
-
aspect = width / height if aspect is None else aspect
|
| 18 |
-
x = aspect / math.sqrt(1 + aspect * aspect)
|
| 19 |
-
y = 1 / math.sqrt(1 + aspect * aspect)
|
| 20 |
-
u = mx.linspace(-x * (width - 1) / width, x * (width - 1) / width, width)
|
| 21 |
-
v = mx.linspace(-y * (height - 1) / height, y * (height - 1) / height, height)
|
| 22 |
-
xx, yy = mx.meshgrid(u, v, indexing="xy")
|
| 23 |
-
return mx.stack([xx, yy], axis=-1)
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
class GroupNorm(nn.Module):
|
| 27 |
-
def __init__(self, channels, groups):
|
| 28 |
-
super().__init__()
|
| 29 |
-
self.weight = mx.ones(channels)
|
| 30 |
-
self.bias = mx.zeros(channels)
|
| 31 |
-
self._groups = groups
|
| 32 |
-
|
| 33 |
-
def __call__(self, x):
|
| 34 |
-
h = x.astype(mx.float32).reshape(
|
| 35 |
-
x.shape[0], -1, self._groups, x.shape[-1] // self._groups
|
| 36 |
-
)
|
| 37 |
-
mean = h.mean(axis=(1, 3), keepdims=True)
|
| 38 |
-
var = ((h - mean) ** 2).mean(axis=(1, 3), keepdims=True)
|
| 39 |
-
return (
|
| 40 |
-
((h - mean) * mx.rsqrt(var + 1e-5)).reshape(x.shape) * self.weight
|
| 41 |
-
+ self.bias
|
| 42 |
-
).astype(x.dtype)
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
class Conv(nn.Conv2d):
|
| 46 |
-
def __call__(self, x):
|
| 47 |
-
p = self.weight.shape[1] // 2
|
| 48 |
-
if p:
|
| 49 |
-
x = mx.pad(x, [(0, 0), (p, p), (p, p), (0, 0)], mode="edge")
|
| 50 |
-
return mx.conv2d(x, self.weight) + self.bias
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
class Residual(nn.Module):
|
| 54 |
-
def __init__(self, channels, multiplier=2):
|
| 55 |
-
super().__init__()
|
| 56 |
-
hidden = channels * multiplier
|
| 57 |
-
self.layers = Sequential(
|
| 58 |
-
GroupNorm(channels, 1),
|
| 59 |
-
nn.ReLU(),
|
| 60 |
-
Conv(channels, hidden, 3),
|
| 61 |
-
GroupNorm(hidden, hidden // 32),
|
| 62 |
-
nn.ReLU(),
|
| 63 |
-
Conv(hidden, channels, 3),
|
| 64 |
-
)
|
| 65 |
-
|
| 66 |
-
def __call__(self, x):
|
| 67 |
-
return x + self.layers(x)
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
class Head(nn.Module):
|
| 71 |
-
def __init__(self):
|
| 72 |
-
super().__init__()
|
| 73 |
-
self.projects = [nn.Conv2d(1024, 512, 1) for _ in range(4)]
|
| 74 |
-
self.upsample_blocks = [
|
| 75 |
-
Sequential(
|
| 76 |
-
Sequential(nn.ConvTranspose2d(i + 2, o, 2, stride=2), Conv(o, o, 3)),
|
| 77 |
-
Residual(o),
|
| 78 |
-
Residual(o),
|
| 79 |
-
)
|
| 80 |
-
for i, o in zip((512, 256, 128), (256, 128, 64))
|
| 81 |
-
]
|
| 82 |
-
self.output_block = [
|
| 83 |
-
Sequential(Conv(66, 32, 3), nn.ReLU(), Conv(32, out, 1)) for out in (3, 1)
|
| 84 |
-
]
|
| 85 |
-
|
| 86 |
-
def __call__(self, features, height, width):
|
| 87 |
-
x = sum(proj(f) for proj, f in zip(self.projects, features))
|
| 88 |
-
aspect = width / height
|
| 89 |
-
for block in self.upsample_blocks:
|
| 90 |
-
uv = view_plane(x.shape[1], x.shape[2], aspect)[None].astype(x.dtype)
|
| 91 |
-
x = block(mx.concatenate([x, uv], axis=-1))
|
| 92 |
-
x = resize(x, height, width)
|
| 93 |
-
x = mx.concatenate(
|
| 94 |
-
[x, view_plane(height, width, aspect)[None].astype(x.dtype)], axis=-1
|
| 95 |
-
)
|
| 96 |
-
return [block(x) for block in self.output_block]
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
class Backbone(DINOv2):
|
| 100 |
-
def __init__(self):
|
| 101 |
-
super().__init__(
|
| 102 |
-
SimpleNamespace(
|
| 103 |
-
dino_hidden_size=1024,
|
| 104 |
-
dino_image_size=518,
|
| 105 |
-
dino_heads=16,
|
| 106 |
-
dino_layers=24,
|
| 107 |
-
)
|
| 108 |
-
)
|
| 109 |
-
self.register_tokens = None
|
| 110 |
-
|
| 111 |
-
def __call__(self, image):
|
| 112 |
-
h, w = image.shape[1] // 14, image.shape[2] // 14
|
| 113 |
-
x = self.patch_embed(image)
|
| 114 |
-
pos = self.pos_embed[:, 1:].astype(mx.float32).reshape(1, 37, 37, 1024)
|
| 115 |
-
if h != 37 or w != 37:
|
| 116 |
-
pos = resize_bicubic(pos, h, w, offset=0.1)
|
| 117 |
-
pos = mx.concatenate([self.pos_embed[:, :1], pos.reshape(1, -1, 1024)], axis=1)
|
| 118 |
-
x = mx.concatenate([self.cls_token, x], axis=1) + pos.astype(x.dtype)
|
| 119 |
-
outputs = []
|
| 120 |
-
for i, block in enumerate(self.blocks):
|
| 121 |
-
x = block(x)
|
| 122 |
-
if i >= 20:
|
| 123 |
-
outputs.append(self.norm(x)[:, 1:].reshape(1, h, w, 1024))
|
| 124 |
-
return outputs
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
def recover_focal_shift(points, valid):
|
| 128 |
-
"""One-dimensional damped least squares, with an analytic MLX Jacobian."""
|
| 129 |
-
h, w = points.shape[:2]
|
| 130 |
-
selected = nonzero(
|
| 131 |
-
resize(valid[None, ..., None].astype(mx.float32), 64, 64, nearest=True)[
|
| 132 |
-
0, ..., 0
|
| 133 |
-
]
|
| 134 |
-
> 0
|
| 135 |
-
)
|
| 136 |
-
if selected.size < 2:
|
| 137 |
-
return mx.array(1.0), mx.array(0.0)
|
| 138 |
-
xyz = resize(points[None], 64, 64, nearest=True)[0].reshape(-1, 3)[selected]
|
| 139 |
-
uv = resize(view_plane(h, w)[None], 64, 64, nearest=True)[0].reshape(-1, 2)[
|
| 140 |
-
selected
|
| 141 |
-
]
|
| 142 |
-
|
| 143 |
-
def residual(shift):
|
| 144 |
-
z = xyz[:, 2:3] + shift
|
| 145 |
-
p = xyz[:, :2] / z
|
| 146 |
-
dp = -p / z
|
| 147 |
-
a, b = mx.sum(p * uv), mx.sum(p * p)
|
| 148 |
-
focal = a / b
|
| 149 |
-
df = (mx.sum(dp * uv) * b - 2 * a * mx.sum(p * dp)) / (b * b)
|
| 150 |
-
return focal * p - uv, df * p + focal * dp, focal
|
| 151 |
-
|
| 152 |
-
shift, damping = mx.array(0.0), 1e-3
|
| 153 |
-
error, jac, focal = residual(shift)
|
| 154 |
-
cost = float(mx.sum(error * error).item())
|
| 155 |
-
for _ in range(100):
|
| 156 |
-
a, g = mx.sum(jac * jac), mx.sum(jac * error)
|
| 157 |
-
improved = False
|
| 158 |
-
for _ in range(20):
|
| 159 |
-
candidate = shift - g / (a * (1 + damping) + 1e-12)
|
| 160 |
-
new_error, new_jac, new_focal = residual(candidate)
|
| 161 |
-
new_cost = float(mx.sum(new_error * new_error).item())
|
| 162 |
-
if math.isfinite(new_cost) and new_cost < cost:
|
| 163 |
-
shift, error, jac, focal = candidate, new_error, new_jac, new_focal
|
| 164 |
-
if cost - new_cost < 1e-3 * max(cost, 1e-12):
|
| 165 |
-
return focal, shift
|
| 166 |
-
cost, damping, improved = new_cost, max(damping / 10, 1e-12), True
|
| 167 |
-
break
|
| 168 |
-
damping *= 10
|
| 169 |
-
if not improved:
|
| 170 |
-
break
|
| 171 |
-
return focal, shift
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
class DepthModel(nn.Module):
|
| 175 |
-
def __init__(self):
|
| 176 |
-
super().__init__()
|
| 177 |
-
self.backbone = Backbone()
|
| 178 |
-
self.head = Head()
|
| 179 |
-
self.image_mean = mx.array([0.485, 0.456, 0.406]).reshape(1, 3, 1, 1)
|
| 180 |
-
self.image_std = mx.array([0.229, 0.224, 0.225]).reshape(1, 3, 1, 1)
|
| 181 |
-
|
| 182 |
-
def forward(self, image, num_tokens=2551):
|
| 183 |
-
h, w = image.shape[:2]
|
| 184 |
-
factor = math.sqrt(num_tokens * 14 * 14 / (h * w))
|
| 185 |
-
rh, rw = int(h * factor), int(w * factor)
|
| 186 |
-
x = resize_bicubic(image[None].astype(mx.float32), rh, rw, antialias=True)
|
| 187 |
-
x = (x - self.image_mean.transpose(0, 2, 3, 1)) / self.image_std.transpose(
|
| 188 |
-
0, 2, 3, 1
|
| 189 |
-
)
|
| 190 |
-
x14 = resize(x, rh // 14 * 14, rw // 14 * 14, antialias=True)
|
| 191 |
-
features = self.backbone(x14.astype(self.backbone.cls_token.dtype))
|
| 192 |
-
points, mask = self.head(features, rh, rw)
|
| 193 |
-
points, mask = (
|
| 194 |
-
resize(points.astype(mx.float32), h, w)[0],
|
| 195 |
-
resize(mask.astype(mx.float32), h, w)[0, ..., 0],
|
| 196 |
-
)
|
| 197 |
-
z = mx.exp(points[..., 2:])
|
| 198 |
-
points = mx.concatenate([points[..., :2] * z, z], axis=-1)
|
| 199 |
-
return points, mask
|
| 200 |
-
|
| 201 |
-
def __call__(self, image, num_tokens=2551):
|
| 202 |
-
image = image[..., :3]
|
| 203 |
-
if image.dtype == mx.uint8:
|
| 204 |
-
image = image.astype(mx.float32) / 255
|
| 205 |
-
points, mask = self.forward(image, num_tokens)
|
| 206 |
-
valid = mask > 0.5
|
| 207 |
-
focal, shift = recover_focal_shift(points, valid)
|
| 208 |
-
points = points + mx.stack([mx.array(0.0), mx.array(0.0), shift])
|
| 209 |
-
# MoGe/OpenCV to SAM's PyTorch3D camera convention.
|
| 210 |
-
return mx.where(valid[..., None], points * mx.array([-1, -1, 1]), float("nan"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/flow.py
DELETED
|
@@ -1,132 +0,0 @@
|
|
| 1 |
-
# Adapted from Meta SAM 3D Objects. See LICENSE in this directory.
|
| 2 |
-
"""Structure/pose and sparse-latent flow networks."""
|
| 3 |
-
|
| 4 |
-
import mlx.core as mx
|
| 5 |
-
import mlx.nn as nn
|
| 6 |
-
|
| 7 |
-
from .layers import (
|
| 8 |
-
LayerNorm,
|
| 9 |
-
ModulatedBlock,
|
| 10 |
-
Sequential,
|
| 11 |
-
TimestepEmbedder,
|
| 12 |
-
layer_norm,
|
| 13 |
-
position_embedding,
|
| 14 |
-
)
|
| 15 |
-
from .sparse import SparseConv, pool
|
| 16 |
-
|
| 17 |
-
LATENTS = {
|
| 18 |
-
"6drotation_normalized": 6,
|
| 19 |
-
"scale": 3,
|
| 20 |
-
"shape": 8,
|
| 21 |
-
"translation": 3,
|
| 22 |
-
"translation_scale": 1,
|
| 23 |
-
}
|
| 24 |
-
POSE_NAMES = ("6drotation_normalized", "translation", "scale", "translation_scale")
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
class Latent(nn.Module):
|
| 28 |
-
def __init__(self, input_channels, channels, length):
|
| 29 |
-
super().__init__()
|
| 30 |
-
self.input_layer = nn.Linear(input_channels, channels)
|
| 31 |
-
self.out_layer = nn.Linear(channels, input_channels)
|
| 32 |
-
self.pos_emb = mx.zeros((length, channels))
|
| 33 |
-
|
| 34 |
-
def encode(self, x):
|
| 35 |
-
return self.input_layer(x) + self.pos_emb[None]
|
| 36 |
-
|
| 37 |
-
def decode(self, x):
|
| 38 |
-
return self.out_layer(layer_norm(x))
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
class StructureFlow(nn.Module):
|
| 42 |
-
def __init__(self, config):
|
| 43 |
-
super().__init__()
|
| 44 |
-
c = config.hidden_size
|
| 45 |
-
self.d_embedder = TimestepEmbedder(c)
|
| 46 |
-
self.t_embedder = TimestepEmbedder(c)
|
| 47 |
-
self.latent_mapping = {
|
| 48 |
-
n: Latent(ch, c, config.latent_resolution**3 if n == "shape" else 1)
|
| 49 |
-
for n, ch in LATENTS.items()
|
| 50 |
-
}
|
| 51 |
-
self.blocks = [
|
| 52 |
-
ModulatedBlock(
|
| 53 |
-
c,
|
| 54 |
-
config.num_heads,
|
| 55 |
-
config.cond_channels,
|
| 56 |
-
names=("shape", "6drotation_normalized"),
|
| 57 |
-
)
|
| 58 |
-
for _ in range(config.num_blocks)
|
| 59 |
-
]
|
| 60 |
-
|
| 61 |
-
def __call__(self, latents, time, condition, delta=None):
|
| 62 |
-
emb = self.t_embedder(time)
|
| 63 |
-
if delta is not None:
|
| 64 |
-
emb = emb + self.d_embedder(delta)
|
| 65 |
-
x = {
|
| 66 |
-
n: m.encode(latents[n].astype(m.input_layer.weight.dtype))
|
| 67 |
-
for n, m in self.latent_mapping.items()
|
| 68 |
-
}
|
| 69 |
-
h = {
|
| 70 |
-
"6drotation_normalized": mx.concatenate([x[n] for n in POSE_NAMES], axis=1),
|
| 71 |
-
"shape": x["shape"],
|
| 72 |
-
}
|
| 73 |
-
for block in self.blocks:
|
| 74 |
-
h = block(h, emb, condition)
|
| 75 |
-
outputs = {
|
| 76 |
-
n: self.latent_mapping[n].decode(h["6drotation_normalized"][:, i : i + 1])
|
| 77 |
-
for i, n in enumerate(POSE_NAMES)
|
| 78 |
-
}
|
| 79 |
-
outputs["shape"] = self.latent_mapping["shape"].decode(h["shape"])
|
| 80 |
-
return outputs
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
class SparseResBlock(nn.Module):
|
| 84 |
-
def __init__(self, input_channels, channels, time_channels):
|
| 85 |
-
super().__init__()
|
| 86 |
-
self.norm1 = LayerNorm(input_channels, eps=1e-6)
|
| 87 |
-
self.conv1 = SparseConv(input_channels, channels)
|
| 88 |
-
self.conv2 = SparseConv(channels, channels)
|
| 89 |
-
self.emb_layers = Sequential(nn.SiLU(), nn.Linear(time_channels, 2 * channels))
|
| 90 |
-
self.skip_connection = (
|
| 91 |
-
nn.Linear(input_channels, channels)
|
| 92 |
-
if channels != input_channels
|
| 93 |
-
else nn.Identity()
|
| 94 |
-
)
|
| 95 |
-
|
| 96 |
-
def __call__(self, x, grid, time):
|
| 97 |
-
scale, shift = mx.split(self.emb_layers(time), 2, axis=-1)
|
| 98 |
-
h = self.conv1(nn.silu(self.norm1(x)), grid)
|
| 99 |
-
h = layer_norm(h, 1e-6) * (1 + scale) + shift
|
| 100 |
-
return self.conv2(nn.silu(h), grid) + self.skip_connection(x)
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
class LatentFlow(nn.Module):
|
| 104 |
-
def __init__(self, config):
|
| 105 |
-
super().__init__()
|
| 106 |
-
c, io = config.hidden_size, config.io_channels
|
| 107 |
-
self.t_embedder = TimestepEmbedder(c)
|
| 108 |
-
self.input_layer = nn.Linear(config.latent_channels, io)
|
| 109 |
-
self.input_blocks = [SparseResBlock(io, io, c), SparseResBlock(io, c, c)]
|
| 110 |
-
self.blocks = [
|
| 111 |
-
ModulatedBlock(c, config.num_heads, config.cond_channels)
|
| 112 |
-
for _ in range(config.num_blocks)
|
| 113 |
-
]
|
| 114 |
-
self.out_blocks = [SparseResBlock(2 * c, io, c), SparseResBlock(2 * io, io, c)]
|
| 115 |
-
self.out_layer = nn.Linear(io, config.latent_channels)
|
| 116 |
-
|
| 117 |
-
def __call__(self, x, grid, time, condition):
|
| 118 |
-
x = x.astype(self.input_layer.weight.dtype)
|
| 119 |
-
h = self.input_layer(x)
|
| 120 |
-
emb = self.t_embedder(time)
|
| 121 |
-
skip = self.input_blocks[0](h, grid, emb)
|
| 122 |
-
h, child, parent = pool(skip, grid)
|
| 123 |
-
h = self.input_blocks[1](h, child, emb)
|
| 124 |
-
skip_low = h
|
| 125 |
-
h = h + position_embedding(child.coords[:, 1:], h.shape[-1]).astype(h.dtype)
|
| 126 |
-
h = h[None]
|
| 127 |
-
for block in self.blocks:
|
| 128 |
-
h = block(h, emb, condition)
|
| 129 |
-
h = mx.concatenate([h[0], skip_low], axis=-1)[parent]
|
| 130 |
-
h = self.out_blocks[0](h, grid, emb)
|
| 131 |
-
h = self.out_blocks[1](mx.concatenate([h, skip], axis=-1), grid, emb)
|
| 132 |
-
return self.out_layer(layer_norm(h))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/generate.py
DELETED
|
@@ -1,122 +0,0 @@
|
|
| 1 |
-
"""CLI for single requests or a JSONL stream of image-to-3D requests."""
|
| 2 |
-
|
| 3 |
-
import argparse
|
| 4 |
-
import asyncio
|
| 5 |
-
import json
|
| 6 |
-
import sys
|
| 7 |
-
from pathlib import Path
|
| 8 |
-
|
| 9 |
-
import mlx.core as mx
|
| 10 |
-
from mlx.utils import tree_flatten
|
| 11 |
-
|
| 12 |
-
from .io import read_mask, read_png, write_gaussians, write_obj
|
| 13 |
-
from .pipeline import Pipeline, Request
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
def _request(values, defaults):
|
| 17 |
-
image = read_png(values["image"])
|
| 18 |
-
mask = read_mask(values["mask"]) if values.get("mask") else None
|
| 19 |
-
pointmap = mx.load(values["pointmap"])["points"] if values.get("pointmap") else None
|
| 20 |
-
return Request(
|
| 21 |
-
image,
|
| 22 |
-
mask,
|
| 23 |
-
pointmap,
|
| 24 |
-
request_id=str(values.get("id", "0")),
|
| 25 |
-
seed=int(values.get("seed", defaults.seed)),
|
| 26 |
-
ss_steps=defaults.ss_steps,
|
| 27 |
-
slat_steps=defaults.slat_steps,
|
| 28 |
-
formats=tuple(defaults.formats),
|
| 29 |
-
estimate_depth=not defaults.no_depth,
|
| 30 |
-
)
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
def _save(result, root):
|
| 34 |
-
root.mkdir(parents=True, exist_ok=True)
|
| 35 |
-
tensors = {k: v for k, v in tree_flatten(result) if isinstance(v, mx.array)}
|
| 36 |
-
mx.save_safetensors(str(root / "result.safetensors"), tensors)
|
| 37 |
-
for kind in ("gaussian", "gaussian_4"):
|
| 38 |
-
if kind in result:
|
| 39 |
-
write_gaussians(root / f"{kind}.ply", result[kind])
|
| 40 |
-
if "mesh" in result:
|
| 41 |
-
write_obj(root / "mesh.obj", result["mesh"])
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
def main():
|
| 45 |
-
parser = argparse.ArgumentParser(description=__doc__)
|
| 46 |
-
parser.add_argument("--model", required=True, help="Local converted BF16 bundle")
|
| 47 |
-
parser.add_argument("--image", help="PNG RGB or RGBA image")
|
| 48 |
-
parser.add_argument("--mask", help="PNG object mask")
|
| 49 |
-
parser.add_argument(
|
| 50 |
-
"--pointmap", help="Safetensors file with an HWC 'points' array"
|
| 51 |
-
)
|
| 52 |
-
parser.add_argument(
|
| 53 |
-
"--jsonl",
|
| 54 |
-
action="store_true",
|
| 55 |
-
help="Read JSON requests from stdin and stream JSON progress to stdout",
|
| 56 |
-
)
|
| 57 |
-
parser.add_argument("--output", required=True, help="Output directory")
|
| 58 |
-
parser.add_argument("--seed", type=int, default=42)
|
| 59 |
-
parser.add_argument("--ss-steps", type=int)
|
| 60 |
-
parser.add_argument("--slat-steps", type=int)
|
| 61 |
-
parser.add_argument(
|
| 62 |
-
"--formats",
|
| 63 |
-
nargs="+",
|
| 64 |
-
choices=("gaussian", "gaussian_4", "mesh"),
|
| 65 |
-
default=["gaussian", "mesh"],
|
| 66 |
-
)
|
| 67 |
-
parser.add_argument(
|
| 68 |
-
"--no-depth",
|
| 69 |
-
action="store_true",
|
| 70 |
-
help="Use trained point-map dropout when no map is supplied",
|
| 71 |
-
)
|
| 72 |
-
args = parser.parse_args()
|
| 73 |
-
if not args.jsonl and not args.image:
|
| 74 |
-
parser.error("Provide --image or --jsonl")
|
| 75 |
-
pipeline = Pipeline.from_pretrained(args.model)
|
| 76 |
-
if not args.jsonl:
|
| 77 |
-
request = _request(
|
| 78 |
-
{"image": args.image, "mask": args.mask, "pointmap": args.pointmap}, args
|
| 79 |
-
)
|
| 80 |
-
for event in pipeline.stream(request):
|
| 81 |
-
print(
|
| 82 |
-
json.dumps(
|
| 83 |
-
{
|
| 84 |
-
"id": event.request_id,
|
| 85 |
-
"stage": event.stage,
|
| 86 |
-
"step": event.step,
|
| 87 |
-
"total_steps": event.total_steps,
|
| 88 |
-
}
|
| 89 |
-
),
|
| 90 |
-
flush=True,
|
| 91 |
-
)
|
| 92 |
-
if event.stage == "complete":
|
| 93 |
-
_save(event.data, Path(args.output))
|
| 94 |
-
return
|
| 95 |
-
|
| 96 |
-
async def run():
|
| 97 |
-
async def requests():
|
| 98 |
-
while line := await asyncio.to_thread(sys.stdin.readline):
|
| 99 |
-
if line.strip():
|
| 100 |
-
yield _request(json.loads(line), args)
|
| 101 |
-
|
| 102 |
-
request_index = 0
|
| 103 |
-
async for event in pipeline.astream(requests()):
|
| 104 |
-
record = {
|
| 105 |
-
"id": event.request_id,
|
| 106 |
-
"stage": event.stage,
|
| 107 |
-
"step": event.step,
|
| 108 |
-
"total_steps": event.total_steps,
|
| 109 |
-
}
|
| 110 |
-
if event.stage == "complete":
|
| 111 |
-
# Input IDs are labels, never filesystem paths.
|
| 112 |
-
output = Path(args.output) / f"{request_index:06d}"
|
| 113 |
-
await asyncio.to_thread(_save, event.data, output)
|
| 114 |
-
record["output"] = str(output)
|
| 115 |
-
request_index += 1
|
| 116 |
-
print(json.dumps(record), flush=True)
|
| 117 |
-
|
| 118 |
-
asyncio.run(run())
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
if __name__ == "__main__":
|
| 122 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/io.py
DELETED
|
@@ -1,154 +0,0 @@
|
|
| 1 |
-
"""PNG input and binary PLY/OBJ output using only the standard library."""
|
| 2 |
-
|
| 3 |
-
import struct
|
| 4 |
-
import zlib
|
| 5 |
-
from pathlib import Path
|
| 6 |
-
|
| 7 |
-
import mlx.core as mx
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def read_png(path):
|
| 11 |
-
"""Read non-interlaced 8-bit grayscale, RGB, RGBA, or indexed PNG."""
|
| 12 |
-
raw = Path(path).read_bytes()
|
| 13 |
-
if raw[:8] != b"\x89PNG\r\n\x1a\n":
|
| 14 |
-
raise ValueError("Expected a PNG image; other codecs need an external decoder")
|
| 15 |
-
offset, compressed, palette, transparency = 8, bytearray(), None, None
|
| 16 |
-
header = None
|
| 17 |
-
while offset + 12 <= len(raw):
|
| 18 |
-
length = struct.unpack_from(">I", raw, offset)[0]
|
| 19 |
-
kind = raw[offset + 4 : offset + 8]
|
| 20 |
-
data = raw[offset + 8 : offset + 8 + length]
|
| 21 |
-
if len(data) != length or offset + 12 + length > len(raw):
|
| 22 |
-
raise ValueError("Truncated PNG chunk")
|
| 23 |
-
crc = struct.unpack_from(">I", raw, offset + 8 + length)[0]
|
| 24 |
-
if zlib.crc32(kind + data) & 0xFFFFFFFF != crc:
|
| 25 |
-
raise ValueError("PNG checksum mismatch")
|
| 26 |
-
if kind == b"IHDR":
|
| 27 |
-
header = struct.unpack(">IIBBBBB", data)
|
| 28 |
-
elif kind == b"IDAT":
|
| 29 |
-
compressed.extend(data)
|
| 30 |
-
elif kind == b"PLTE":
|
| 31 |
-
palette = data
|
| 32 |
-
elif kind == b"tRNS":
|
| 33 |
-
transparency = data
|
| 34 |
-
elif kind == b"IEND":
|
| 35 |
-
break
|
| 36 |
-
offset += length + 12
|
| 37 |
-
if header is None:
|
| 38 |
-
raise ValueError("PNG has no header")
|
| 39 |
-
width, height, bits, color, compression, filtering, interlace = header
|
| 40 |
-
channels = {0: 1, 2: 3, 3: 1, 4: 2, 6: 4}.get(color)
|
| 41 |
-
if bits != 8 or channels is None or compression or filtering or interlace:
|
| 42 |
-
raise ValueError("Only non-interlaced 8-bit PNG images are supported")
|
| 43 |
-
stride = width * channels
|
| 44 |
-
data = zlib.decompress(compressed)
|
| 45 |
-
if len(data) != height * (stride + 1):
|
| 46 |
-
raise ValueError("PNG pixel data has an invalid size")
|
| 47 |
-
output = bytearray(height * stride)
|
| 48 |
-
for y in range(height):
|
| 49 |
-
mode = data[y * (stride + 1)]
|
| 50 |
-
if mode > 4:
|
| 51 |
-
raise ValueError("Invalid PNG filter")
|
| 52 |
-
for x in range(stride):
|
| 53 |
-
value = data[y * (stride + 1) + x + 1]
|
| 54 |
-
a = output[y * stride + x - channels] if x >= channels else 0
|
| 55 |
-
b = output[(y - 1) * stride + x] if y else 0
|
| 56 |
-
c = output[(y - 1) * stride + x - channels] if y and x >= channels else 0
|
| 57 |
-
if mode == 1:
|
| 58 |
-
value += a
|
| 59 |
-
elif mode == 2:
|
| 60 |
-
value += b
|
| 61 |
-
elif mode == 3:
|
| 62 |
-
value += (a + b) // 2
|
| 63 |
-
elif mode == 4:
|
| 64 |
-
p = a + b - c
|
| 65 |
-
pa, pb, pc = abs(p - a), abs(p - b), abs(p - c)
|
| 66 |
-
value += a if pa <= pb and pa <= pc else b if pb <= pc else c
|
| 67 |
-
output[y * stride + x] = value & 255
|
| 68 |
-
pixels = mx.array(memoryview(output)).reshape(height, width, channels)
|
| 69 |
-
if color == 3:
|
| 70 |
-
if palette is None or len(palette) % 3:
|
| 71 |
-
raise ValueError("Invalid PNG palette")
|
| 72 |
-
colors = mx.array(memoryview(palette)).reshape(-1, 3)
|
| 73 |
-
indices = pixels[..., 0].astype(mx.int32)
|
| 74 |
-
if int(indices.max().item()) >= colors.shape[0]:
|
| 75 |
-
raise ValueError("PNG palette index out of bounds")
|
| 76 |
-
pixels = colors[indices]
|
| 77 |
-
if transparency is not None:
|
| 78 |
-
alpha = mx.array(
|
| 79 |
-
list(transparency) + [255] * (colors.shape[0] - len(transparency)),
|
| 80 |
-
mx.uint8,
|
| 81 |
-
)
|
| 82 |
-
pixels = mx.concatenate([pixels, alpha[indices, None]], axis=-1)
|
| 83 |
-
return pixels
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
def read_mask(path):
|
| 87 |
-
"""Read grayscale masks or the alpha channel of RGBA object cutouts."""
|
| 88 |
-
pixels = read_png(path)
|
| 89 |
-
channel = -1 if pixels.shape[-1] in (2, 4) else 0
|
| 90 |
-
return pixels[..., channel] > 0
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
def write_gaussians(path, gaussian):
|
| 94 |
-
"""Write the standard Gaussian-splat PLY fields (log-scales/logit opacity)."""
|
| 95 |
-
xyz, scale, opacity = (
|
| 96 |
-
gaussian["positions"],
|
| 97 |
-
gaussian["scales"],
|
| 98 |
-
gaussian["opacities"],
|
| 99 |
-
)
|
| 100 |
-
opacity = mx.clip(opacity, 1e-7, 1 - 1e-7)
|
| 101 |
-
values = mx.concatenate(
|
| 102 |
-
[
|
| 103 |
-
xyz,
|
| 104 |
-
mx.zeros_like(xyz),
|
| 105 |
-
gaussian["sh_dc"],
|
| 106 |
-
mx.log(opacity / (1 - opacity)),
|
| 107 |
-
mx.log(scale),
|
| 108 |
-
gaussian["rotations"],
|
| 109 |
-
],
|
| 110 |
-
axis=-1,
|
| 111 |
-
).astype(mx.float32)
|
| 112 |
-
fields = [
|
| 113 |
-
"x",
|
| 114 |
-
"y",
|
| 115 |
-
"z",
|
| 116 |
-
"nx",
|
| 117 |
-
"ny",
|
| 118 |
-
"nz",
|
| 119 |
-
"f_dc_0",
|
| 120 |
-
"f_dc_1",
|
| 121 |
-
"f_dc_2",
|
| 122 |
-
"opacity",
|
| 123 |
-
"scale_0",
|
| 124 |
-
"scale_1",
|
| 125 |
-
"scale_2",
|
| 126 |
-
"rot_0",
|
| 127 |
-
"rot_1",
|
| 128 |
-
"rot_2",
|
| 129 |
-
"rot_3",
|
| 130 |
-
]
|
| 131 |
-
header = (
|
| 132 |
-
"ply\nformat binary_little_endian 1.0\n"
|
| 133 |
-
+ f"element vertex {values.shape[0]}\n"
|
| 134 |
-
+ "".join(f"property float {f}\n" for f in fields)
|
| 135 |
-
+ "end_header\n"
|
| 136 |
-
)
|
| 137 |
-
with open(path, "wb") as out:
|
| 138 |
-
out.write(header.encode())
|
| 139 |
-
for start in range(0, values.shape[0], 16384):
|
| 140 |
-
for row in values[start : start + 16384].tolist():
|
| 141 |
-
out.write(struct.pack("<17f", *row))
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
def write_obj(path, mesh):
|
| 145 |
-
with open(path, "w") as out:
|
| 146 |
-
vertices = mx.concatenate(
|
| 147 |
-
[mesh["vertices"], mesh["vertex_colors"][:, :3]], axis=-1
|
| 148 |
-
)
|
| 149 |
-
for start in range(0, vertices.shape[0], 16384):
|
| 150 |
-
for row in vertices[start : start + 16384].tolist():
|
| 151 |
-
out.write("v " + " ".join(f"{v:.8g}" for v in row) + "\n")
|
| 152 |
-
for start in range(0, mesh["faces"].shape[0], 16384):
|
| 153 |
-
for row in mesh["faces"][start : start + 16384].tolist():
|
| 154 |
-
out.write("f " + " ".join(str(v + 1) for v in row) + "\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/layers.py
DELETED
|
@@ -1,194 +0,0 @@
|
|
| 1 |
-
# Adapted from Meta SAM 3D Objects. See LICENSE in this directory.
|
| 2 |
-
"""Dense inference layers; all tensors and computation use MLX."""
|
| 3 |
-
|
| 4 |
-
import math
|
| 5 |
-
|
| 6 |
-
import mlx.core as mx
|
| 7 |
-
import mlx.nn as nn
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
class Sequential(nn.Module):
|
| 11 |
-
"""Keep the upstream numbered state-dict names."""
|
| 12 |
-
|
| 13 |
-
def __init__(self, *layers):
|
| 14 |
-
super().__init__()
|
| 15 |
-
for i, layer in enumerate(layers):
|
| 16 |
-
self[str(i)] = layer
|
| 17 |
-
|
| 18 |
-
def __call__(self, x):
|
| 19 |
-
for layer in self.values():
|
| 20 |
-
x = layer(x)
|
| 21 |
-
return x
|
| 22 |
-
|
| 23 |
-
def __getitem__(self, key):
|
| 24 |
-
return super().__getitem__(str(key) if isinstance(key, int) else key)
|
| 25 |
-
|
| 26 |
-
def __setitem__(self, key, value):
|
| 27 |
-
super().__setitem__(str(key) if isinstance(key, int) else key, value)
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
def layer_norm(x, eps=1e-5):
|
| 31 |
-
return mx.fast.layer_norm(x, None, None, eps)
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
class LayerNorm(nn.LayerNorm):
|
| 35 |
-
def __call__(self, x):
|
| 36 |
-
y = super().__call__(x.astype(mx.float32))
|
| 37 |
-
return y.astype(x.dtype)
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
def position_embedding(coords, channels):
|
| 41 |
-
dim = channels // 6
|
| 42 |
-
freq = mx.exp(-math.log(10000) * mx.arange(dim, dtype=mx.float32) / dim)
|
| 43 |
-
phase = coords.astype(mx.float32)[..., None] * freq
|
| 44 |
-
out = mx.concatenate([mx.sin(phase), mx.cos(phase)], axis=-1)
|
| 45 |
-
out = out.reshape(coords.shape[0], -1)
|
| 46 |
-
return mx.pad(out, [(0, 0), (0, channels - out.shape[-1])])
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
class TimestepEmbedder(nn.Module):
|
| 50 |
-
def __init__(self, channels):
|
| 51 |
-
super().__init__()
|
| 52 |
-
self.mlp = Sequential(
|
| 53 |
-
nn.Linear(256, channels), nn.SiLU(), nn.Linear(channels, channels)
|
| 54 |
-
)
|
| 55 |
-
|
| 56 |
-
def __call__(self, t):
|
| 57 |
-
phase = t.reshape(-1, 1).astype(mx.float32) * mx.exp(
|
| 58 |
-
-math.log(10000) * mx.arange(128, dtype=mx.float32) / 128
|
| 59 |
-
)
|
| 60 |
-
x = mx.concatenate([mx.cos(phase), mx.sin(phase)], axis=-1)
|
| 61 |
-
return self.mlp(x.astype(self.mlp["0"].weight.dtype))
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
class FeedForward(nn.Module):
|
| 65 |
-
def __init__(self, channels, ratio=4):
|
| 66 |
-
super().__init__()
|
| 67 |
-
self.mlp = Sequential(
|
| 68 |
-
nn.Linear(channels, int(channels * ratio)),
|
| 69 |
-
nn.GELU(approx="tanh"),
|
| 70 |
-
nn.Linear(int(channels * ratio), channels),
|
| 71 |
-
)
|
| 72 |
-
|
| 73 |
-
def __call__(self, x):
|
| 74 |
-
return self.mlp(x)
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
class HeadNorm(nn.Module):
|
| 78 |
-
def __init__(self, heads, dim):
|
| 79 |
-
super().__init__()
|
| 80 |
-
self.gamma = mx.ones((heads, dim))
|
| 81 |
-
|
| 82 |
-
def __call__(self, x):
|
| 83 |
-
xf = x.astype(mx.float32)
|
| 84 |
-
y = xf * mx.rsqrt(mx.maximum(mx.sum(xf * xf, axis=-1, keepdims=True), 1e-24))
|
| 85 |
-
return (y * self.gamma * math.sqrt(x.shape[-1])).astype(x.dtype)
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
def attend(q, k, v, mask=None):
|
| 89 |
-
y = mx.fast.scaled_dot_product_attention(
|
| 90 |
-
q.transpose(0, 2, 1, 3),
|
| 91 |
-
k.transpose(0, 2, 1, 3),
|
| 92 |
-
v.transpose(0, 2, 1, 3),
|
| 93 |
-
scale=q.shape[-1] ** -0.5,
|
| 94 |
-
mask=mask,
|
| 95 |
-
)
|
| 96 |
-
return y.transpose(0, 2, 1, 3).reshape(q.shape[0], q.shape[1], -1)
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
class Attention(nn.Module):
|
| 100 |
-
def __init__(self, channels, heads, context_channels=None, qk_norm=False):
|
| 101 |
-
super().__init__()
|
| 102 |
-
self.heads = heads
|
| 103 |
-
if context_channels is None:
|
| 104 |
-
self.to_qkv = nn.Linear(channels, channels * 3)
|
| 105 |
-
else:
|
| 106 |
-
self.to_q = nn.Linear(channels, channels)
|
| 107 |
-
self.to_kv = nn.Linear(context_channels, channels * 2)
|
| 108 |
-
if qk_norm:
|
| 109 |
-
self.q_rms_norm = HeadNorm(heads, channels // heads)
|
| 110 |
-
self.k_rms_norm = HeadNorm(heads, channels // heads)
|
| 111 |
-
self.to_out = nn.Linear(channels, channels)
|
| 112 |
-
|
| 113 |
-
def __call__(self, x, context=None, mask=None):
|
| 114 |
-
b, n, c = x.shape
|
| 115 |
-
if context is None:
|
| 116 |
-
qkv = self.to_qkv(x).reshape(b, n, 3, self.heads, -1)
|
| 117 |
-
q, k, v = (qkv[:, :, i] for i in range(3))
|
| 118 |
-
else:
|
| 119 |
-
q = self.to_q(x).reshape(b, n, self.heads, -1)
|
| 120 |
-
kv = self.to_kv(context).reshape(b, -1, 2, self.heads, c // self.heads)
|
| 121 |
-
k, v = kv[:, :, 0], kv[:, :, 1]
|
| 122 |
-
if "q_rms_norm" in self:
|
| 123 |
-
q, k = self.q_rms_norm(q), self.k_rms_norm(k)
|
| 124 |
-
return self.to_out(attend(q, k, v, mask))
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
class MOTAttention(nn.Module):
|
| 128 |
-
def __init__(self, channels, heads, names):
|
| 129 |
-
super().__init__()
|
| 130 |
-
self.heads = heads
|
| 131 |
-
self.to_qkv = {n: nn.Linear(channels, 3 * channels) for n in names}
|
| 132 |
-
self.to_out = {n: nn.Linear(channels, channels) for n in names}
|
| 133 |
-
self.q_rms_norm = {n: HeadNorm(heads, channels // heads) for n in names}
|
| 134 |
-
self.k_rms_norm = {n: HeadNorm(heads, channels // heads) for n in names}
|
| 135 |
-
|
| 136 |
-
def __call__(self, x):
|
| 137 |
-
q, k, v = {}, {}, {}
|
| 138 |
-
for name, value in x.items():
|
| 139 |
-
qkv = self.to_qkv[name](value).reshape(*value.shape[:2], 3, self.heads, -1)
|
| 140 |
-
q[name] = self.q_rms_norm[name](qkv[:, :, 0])
|
| 141 |
-
k[name] = self.k_rms_norm[name](qkv[:, :, 1])
|
| 142 |
-
v[name] = qkv[:, :, 2]
|
| 143 |
-
out = {
|
| 144 |
-
"shape": self.to_out["shape"](attend(q["shape"], k["shape"], v["shape"]))
|
| 145 |
-
}
|
| 146 |
-
others = [n for n in x if n != "shape"]
|
| 147 |
-
keys = mx.concatenate([k[n] for n in others] + [k["shape"]], axis=1)
|
| 148 |
-
vals = mx.concatenate([v[n] for n in others] + [v["shape"]], axis=1)
|
| 149 |
-
for n in others:
|
| 150 |
-
out[n] = self.to_out[n](attend(q[n], keys, vals))
|
| 151 |
-
return out
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
class ModulatedBlock(nn.Module):
|
| 155 |
-
def __init__(self, channels, heads, context_channels, names=None):
|
| 156 |
-
super().__init__()
|
| 157 |
-
self.adaLN_modulation = Sequential(nn.SiLU(), nn.Linear(channels, 6 * channels))
|
| 158 |
-
if names is None:
|
| 159 |
-
self.norm2 = LayerNorm(channels, eps=1e-6)
|
| 160 |
-
self.self_attn = Attention(channels, heads, qk_norm=True)
|
| 161 |
-
self.cross_attn = Attention(channels, heads, context_channels)
|
| 162 |
-
self.mlp = FeedForward(channels)
|
| 163 |
-
else:
|
| 164 |
-
self.norm2 = {n: LayerNorm(channels, eps=1e-6) for n in names}
|
| 165 |
-
self.self_attn = MOTAttention(channels, heads, names)
|
| 166 |
-
self.cross_attn = {
|
| 167 |
-
n: Attention(channels, heads, context_channels) for n in names
|
| 168 |
-
}
|
| 169 |
-
self.mlp = {n: FeedForward(channels) for n in names}
|
| 170 |
-
|
| 171 |
-
def __call__(self, x, time, context):
|
| 172 |
-
shift, scale, gate, shift_mlp, scale_mlp, gate_mlp = [
|
| 173 |
-
v[:, None] for v in mx.split(self.adaLN_modulation(time), 6, axis=-1)
|
| 174 |
-
]
|
| 175 |
-
if isinstance(x, dict):
|
| 176 |
-
h = self.self_attn(
|
| 177 |
-
{n: layer_norm(v, 1e-6) * (1 + scale) + shift for n, v in x.items()}
|
| 178 |
-
)
|
| 179 |
-
x = {n: v + h[n] * gate for n, v in x.items()}
|
| 180 |
-
x = {
|
| 181 |
-
n: v + self.cross_attn[n](self.norm2[n](v), context)
|
| 182 |
-
for n, v in x.items()
|
| 183 |
-
}
|
| 184 |
-
return {
|
| 185 |
-
n: v
|
| 186 |
-
+ self.mlp[n](layer_norm(v, 1e-6) * (1 + scale_mlp) + shift_mlp)
|
| 187 |
-
* gate_mlp
|
| 188 |
-
for n, v in x.items()
|
| 189 |
-
}
|
| 190 |
-
x = x + self.self_attn(layer_norm(x, 1e-6) * (1 + scale) + shift) * gate
|
| 191 |
-
x = x + self.cross_attn(self.norm2(x), context)
|
| 192 |
-
return (
|
| 193 |
-
x + self.mlp(layer_norm(x, 1e-6) * (1 + scale_mlp) + shift_mlp) * gate_mlp
|
| 194 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/mesh.py
DELETED
|
@@ -1,223 +0,0 @@
|
|
| 1 |
-
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
-
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
| 3 |
-
# FlexiCubes portions adapted under Apache-2.0; see mesh_tables.py.
|
| 4 |
-
"""Inference-only FlexiCubes extraction on a sparse MLX grid."""
|
| 5 |
-
|
| 6 |
-
import mlx.core as mx
|
| 7 |
-
|
| 8 |
-
from .mesh_tables import check_table, dmc_table, num_vd_table
|
| 9 |
-
from .sparse import nonzero
|
| 10 |
-
|
| 11 |
-
CORNERS = (
|
| 12 |
-
(0, 0, 0),
|
| 13 |
-
(1, 0, 0),
|
| 14 |
-
(0, 1, 0),
|
| 15 |
-
(1, 1, 0),
|
| 16 |
-
(0, 0, 1),
|
| 17 |
-
(1, 0, 1),
|
| 18 |
-
(0, 1, 1),
|
| 19 |
-
(1, 1, 1),
|
| 20 |
-
)
|
| 21 |
-
EDGES = (0, 1, 1, 5, 4, 5, 0, 4, 2, 3, 3, 7, 6, 7, 2, 6, 2, 0, 3, 1, 7, 5, 6, 4)
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
def _keys(x, resolution):
|
| 25 |
-
return (x[..., 0] * resolution + x[..., 1]) * resolution + x[..., 2]
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
def _decode(keys, resolution):
|
| 29 |
-
return mx.stack(
|
| 30 |
-
[
|
| 31 |
-
keys // (resolution * resolution),
|
| 32 |
-
keys // resolution % resolution,
|
| 33 |
-
keys % resolution,
|
| 34 |
-
],
|
| 35 |
-
axis=-1,
|
| 36 |
-
)
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
def unique(keys):
|
| 40 |
-
"""Sorted unique keys and inverse indices, without NumPy."""
|
| 41 |
-
order = mx.argsort(keys)
|
| 42 |
-
sorted_keys = keys[order]
|
| 43 |
-
start = mx.concatenate([mx.array([True]), sorted_keys[1:] != sorted_keys[:-1]])
|
| 44 |
-
first = nonzero(start)
|
| 45 |
-
groups = mx.cumsum(start.astype(mx.int32)) - 1
|
| 46 |
-
inverse = mx.zeros(keys.size, mx.int32).at[order].add(groups)
|
| 47 |
-
return sorted_keys[first], inverse
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
def _lookup(keys, query):
|
| 51 |
-
idx = mx.minimum(mx.searchsorted(keys, query.reshape(-1)), keys.size - 1).reshape(
|
| 52 |
-
query.shape
|
| 53 |
-
)
|
| 54 |
-
return mx.where(keys[idx] == query, idx, keys.size)
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
def _empty():
|
| 58 |
-
return {
|
| 59 |
-
"vertices": mx.zeros((0, 3)),
|
| 60 |
-
"faces": mx.zeros((0, 3), mx.int32),
|
| 61 |
-
"vertex_colors": mx.zeros((0, 6)),
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
def extract_mesh(features, grid):
|
| 66 |
-
"""Decode all learned SDF, deformation, alpha/beta/gamma and color values.
|
| 67 |
-
|
| 68 |
-
Candidate cubes include neighbors of predicted vertices. This matches
|
| 69 |
-
the dense reference's default +1 SDF outside the sparse prediction.
|
| 70 |
-
"""
|
| 71 |
-
if not features.shape[0]:
|
| 72 |
-
return _empty()
|
| 73 |
-
r = grid.resolution
|
| 74 |
-
coords = grid.coords[:, 1:]
|
| 75 |
-
f = features.astype(mx.float32)
|
| 76 |
-
corner = mx.array(CORNERS, dtype=mx.int32)
|
| 77 |
-
vkeys, inverse = unique(_keys(coords[:, None] + corner[None], r + 1).reshape(-1))
|
| 78 |
-
values = mx.concatenate(
|
| 79 |
-
[
|
| 80 |
-
f[:, :8, None] - 1 / r,
|
| 81 |
-
f[:, 8:32].reshape(-1, 8, 3),
|
| 82 |
-
f[:, 53:].reshape(-1, 8, 6),
|
| 83 |
-
],
|
| 84 |
-
axis=-1,
|
| 85 |
-
).reshape(-1, 10)
|
| 86 |
-
sums = mx.zeros((vkeys.size, 10)).at[inverse].add(values)
|
| 87 |
-
counts = mx.zeros((vkeys.size, 1)).at[inverse].add(mx.ones((inverse.size, 1)))
|
| 88 |
-
attrs = sums / counts
|
| 89 |
-
vcoords = _decode(vkeys, r + 1)
|
| 90 |
-
candidates = (vcoords[:, None] - corner[None]).reshape(-1, 3)
|
| 91 |
-
valid = nonzero(mx.all((candidates >= 0) & (candidates < r), axis=-1))
|
| 92 |
-
ckeys, _ = unique(_keys(candidates[valid], r))
|
| 93 |
-
ccoords = _decode(ckeys, r)
|
| 94 |
-
corners_keys = _keys(ccoords[:, None] + corner[None], r + 1)
|
| 95 |
-
lookup = _lookup(vkeys, corners_keys)
|
| 96 |
-
sdf = mx.concatenate([attrs[:, 0], mx.ones(1)])
|
| 97 |
-
occupancy = sdf[lookup] < 0
|
| 98 |
-
sums_occ = occupancy.sum(axis=-1)
|
| 99 |
-
surface = nonzero((sums_occ > 0) & (sums_occ < 8))
|
| 100 |
-
if not surface.size:
|
| 101 |
-
return _empty()
|
| 102 |
-
ccoords, ckeys = ccoords[surface], ckeys[surface]
|
| 103 |
-
corners_keys = corners_keys[surface]
|
| 104 |
-
cases = mx.sum(
|
| 105 |
-
occupancy[surface] * mx.array([1, 2, 4, 8, 16, 32, 64, 128]), axis=-1
|
| 106 |
-
)
|
| 107 |
-
# Resolve the ambiguous C16/C19 cases against adjacent surface cubes.
|
| 108 |
-
checks = mx.array(check_table, mx.int32)[cases]
|
| 109 |
-
adjacent = ccoords + checks[:, 1:4]
|
| 110 |
-
adjacent_index = _lookup(ckeys, _keys(adjacent, r))
|
| 111 |
-
problem_flags = mx.concatenate([checks[:, 0], mx.zeros(1, mx.int32)])
|
| 112 |
-
invert = (
|
| 113 |
-
(checks[:, 0] == 1)
|
| 114 |
-
& mx.all((adjacent >= 0) & (adjacent < r), axis=-1)
|
| 115 |
-
& (problem_flags[adjacent_index] == 1)
|
| 116 |
-
)
|
| 117 |
-
cases = mx.where(invert, checks[:, -1], cases)
|
| 118 |
-
|
| 119 |
-
# Retain the dense reference's vertex IDs, including default vertices.
|
| 120 |
-
all_vkeys, cube_idx = unique(corners_keys.reshape(-1))
|
| 121 |
-
cube_idx = cube_idx.reshape(-1, 8)
|
| 122 |
-
attr_indices = _lookup(vkeys, all_vkeys)
|
| 123 |
-
default_attr = mx.array([[1.0] + [0.0] * 9])
|
| 124 |
-
attrs = mx.concatenate([attrs, default_attr])[attr_indices]
|
| 125 |
-
vertices = (
|
| 126 |
-
_decode(all_vkeys, r + 1).astype(mx.float32) / r
|
| 127 |
-
- 0.5
|
| 128 |
-
+ mx.tanh(attrs[:, 1:4]) * ((1 - 1e-8) / (r * 2))
|
| 129 |
-
)
|
| 130 |
-
sdf, colors = attrs[:, 0], mx.sigmoid(attrs[:, 4:])
|
| 131 |
-
source_keys = _keys(coords, r)
|
| 132 |
-
source_order = mx.argsort(source_keys)
|
| 133 |
-
weight_indices = _lookup(source_keys[source_order], ckeys)
|
| 134 |
-
weights = mx.concatenate([f[source_order, 32:53], mx.zeros((1, 21))])[
|
| 135 |
-
weight_indices
|
| 136 |
-
]
|
| 137 |
-
beta, alpha = 1 + 0.99 * mx.tanh(weights[:, :12]), 1 + 0.99 * mx.tanh(
|
| 138 |
-
weights[:, 12:20]
|
| 139 |
-
)
|
| 140 |
-
gamma = 0.99 * mx.sigmoid(weights[:, 20]) + 0.005
|
| 141 |
-
edges = mx.array(EDGES, mx.int32)
|
| 142 |
-
all_edges = cube_idx[:, edges].reshape(-1, 2)
|
| 143 |
-
edge_keys = all_edges[:, 0].astype(mx.int64) * all_vkeys.size + all_edges[:, 1]
|
| 144 |
-
unique_edge_keys, edge_inverse = unique(edge_keys)
|
| 145 |
-
unique_edges = mx.stack(
|
| 146 |
-
[unique_edge_keys // all_vkeys.size, unique_edge_keys % all_vkeys.size], axis=-1
|
| 147 |
-
).astype(mx.int32)
|
| 148 |
-
crossing = mx.sum(sdf[unique_edges] < 0, axis=-1) == 1
|
| 149 |
-
cross_ids = nonzero(crossing)
|
| 150 |
-
surface_edges = unique_edges[cross_ids]
|
| 151 |
-
mapping = mx.full((unique_edges.shape[0],), -1, mx.int32)
|
| 152 |
-
mapping[cross_ids] = mx.arange(cross_ids.size)
|
| 153 |
-
idx_map = mapping[edge_inverse].reshape(-1, 12)
|
| 154 |
-
edge_counts = (
|
| 155 |
-
mx.zeros((unique_edges.shape[0],), mx.int32)
|
| 156 |
-
.at[edge_inverse]
|
| 157 |
-
.add(mx.ones(edge_inverse.size, mx.int32))[edge_inverse]
|
| 158 |
-
)
|
| 159 |
-
|
| 160 |
-
# Each topology emits one to four dual vertices; seven edges per group.
|
| 161 |
-
table = mx.array(dmc_table, mx.int32)
|
| 162 |
-
numbers = mx.array(num_vd_table, mx.int32)[cases]
|
| 163 |
-
edge_group, group_vertex, group_cube, gamma_parts = [], [], [], []
|
| 164 |
-
total = 0
|
| 165 |
-
for number in range(1, 5):
|
| 166 |
-
cubes = nonzero(numbers == number)
|
| 167 |
-
if not cubes.size:
|
| 168 |
-
continue
|
| 169 |
-
group = table[cases[cubes], :number].reshape(-1, 7)
|
| 170 |
-
valid = nonzero(group >= 0)
|
| 171 |
-
edge_group.append(group.reshape(-1)[valid])
|
| 172 |
-
group_vertex.append(mx.repeat(mx.arange(group.shape[0]) + total, 7)[valid])
|
| 173 |
-
group_cube.append(mx.repeat(cubes, number * 7)[valid])
|
| 174 |
-
gamma_parts.append(mx.repeat(gamma[cubes], number))
|
| 175 |
-
total += group.shape[0]
|
| 176 |
-
edge_group, group_vertex, group_cube = (
|
| 177 |
-
mx.concatenate(x) for x in (edge_group, group_vertex, group_cube)
|
| 178 |
-
)
|
| 179 |
-
vd_gamma = mx.concatenate(gamma_parts)
|
| 180 |
-
selected = idx_map[group_cube, edge_group]
|
| 181 |
-
pair = surface_edges[selected]
|
| 182 |
-
alpha_pair = alpha[:, edges].reshape(-1, 12, 2)[group_cube, edge_group]
|
| 183 |
-
signed = sdf[pair] * alpha_pair
|
| 184 |
-
interp = mx.stack([signed[:, 1], -signed[:, 0]], axis=-1)
|
| 185 |
-
interp = interp / interp.sum(axis=-1, keepdims=True)
|
| 186 |
-
crossing_vertices = mx.sum(vertices[pair] * interp[..., None], axis=1)
|
| 187 |
-
crossing_colors = mx.sum(colors[pair] * interp[..., None], axis=1)
|
| 188 |
-
weight = beta[group_cube, edge_group, None]
|
| 189 |
-
denominator = mx.zeros((total, 1)).at[group_vertex].add(weight)
|
| 190 |
-
vd = (
|
| 191 |
-
mx.zeros((total, 3)).at[group_vertex].add(crossing_vertices * weight)
|
| 192 |
-
/ denominator
|
| 193 |
-
)
|
| 194 |
-
vd_colors = (
|
| 195 |
-
mx.zeros((total, colors.shape[-1]))
|
| 196 |
-
.at[group_vertex]
|
| 197 |
-
.add(crossing_colors * weight)
|
| 198 |
-
/ denominator
|
| 199 |
-
)
|
| 200 |
-
vd_idx = mx.zeros((cases.size * 12,), mx.int32)
|
| 201 |
-
vd_idx[group_cube * 12 + edge_group] = group_vertex
|
| 202 |
-
|
| 203 |
-
group_mask = nonzero((edge_counts == 4) & crossing[edge_inverse])
|
| 204 |
-
group = idx_map.reshape(-1)[group_mask]
|
| 205 |
-
# Explicit tie breaker gives the stable edge order used by the reference.
|
| 206 |
-
order = mx.argsort(group.astype(mx.int64) * group.size + mx.arange(group.size))
|
| 207 |
-
quads = vd_idx[group_mask][order].reshape(-1, 4)
|
| 208 |
-
edge_ids = group[order].reshape(-1, 4)[:, 0]
|
| 209 |
-
flip = sdf[surface_edges[edge_ids, 0]] > 0
|
| 210 |
-
quads = mx.concatenate(
|
| 211 |
-
[
|
| 212 |
-
quads[nonzero(flip)][:, mx.array([0, 1, 3, 2])],
|
| 213 |
-
quads[nonzero(~flip)][:, mx.array([2, 3, 1, 0])],
|
| 214 |
-
]
|
| 215 |
-
)
|
| 216 |
-
g = vd_gamma[quads]
|
| 217 |
-
split = g[:, 0] * g[:, 2] > g[:, 1] * g[:, 3]
|
| 218 |
-
faces = mx.where(
|
| 219 |
-
split[:, None],
|
| 220 |
-
quads[:, mx.array([0, 1, 2, 0, 2, 3])],
|
| 221 |
-
quads[:, mx.array([0, 1, 3, 3, 1, 2])],
|
| 222 |
-
).reshape(-1, 3)
|
| 223 |
-
return {"vertices": vd, "faces": faces.astype(mx.int32), "vertex_colors": vd_colors}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/mesh_tables.py
DELETED
|
@@ -1,2327 +0,0 @@
|
|
| 1 |
-
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
-
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
| 3 |
-
# All rights reserved.
|
| 4 |
-
#
|
| 5 |
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 6 |
-
# you may not use this file except in compliance with the License.
|
| 7 |
-
# You may obtain a copy of the License at
|
| 8 |
-
#
|
| 9 |
-
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
-
#
|
| 11 |
-
# Unless required by applicable law or agreed to in writing, software
|
| 12 |
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 13 |
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 14 |
-
# See the License for the specific language governing permissions and
|
| 15 |
-
# limitations under the License.
|
| 16 |
-
dmc_table = [
|
| 17 |
-
[
|
| 18 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 19 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 20 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 21 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 22 |
-
],
|
| 23 |
-
[
|
| 24 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 25 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 26 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 27 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 28 |
-
],
|
| 29 |
-
[
|
| 30 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 31 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 32 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 33 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 34 |
-
],
|
| 35 |
-
[
|
| 36 |
-
[1, 3, 8, 9, -1, -1, -1],
|
| 37 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 38 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 39 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 40 |
-
],
|
| 41 |
-
[
|
| 42 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 43 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 44 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 45 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 46 |
-
],
|
| 47 |
-
[
|
| 48 |
-
[0, 3, 4, 7, -1, -1, -1],
|
| 49 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 50 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 51 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 52 |
-
],
|
| 53 |
-
[
|
| 54 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 55 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 56 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 57 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 58 |
-
],
|
| 59 |
-
[
|
| 60 |
-
[1, 3, 4, 7, 9, -1, -1],
|
| 61 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 62 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 63 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 64 |
-
],
|
| 65 |
-
[
|
| 66 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 67 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 68 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 69 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 70 |
-
],
|
| 71 |
-
[
|
| 72 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 73 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 74 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 75 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 76 |
-
],
|
| 77 |
-
[
|
| 78 |
-
[0, 1, 4, 5, -1, -1, -1],
|
| 79 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 80 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 81 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 82 |
-
],
|
| 83 |
-
[
|
| 84 |
-
[1, 3, 4, 5, 8, -1, -1],
|
| 85 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 86 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 87 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 88 |
-
],
|
| 89 |
-
[
|
| 90 |
-
[5, 7, 8, 9, -1, -1, -1],
|
| 91 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 92 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 93 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 94 |
-
],
|
| 95 |
-
[
|
| 96 |
-
[0, 3, 5, 7, 9, -1, -1],
|
| 97 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 98 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 99 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 100 |
-
],
|
| 101 |
-
[
|
| 102 |
-
[0, 1, 5, 7, 8, -1, -1],
|
| 103 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 104 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 105 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 106 |
-
],
|
| 107 |
-
[
|
| 108 |
-
[1, 3, 5, 7, -1, -1, -1],
|
| 109 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 110 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 111 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 112 |
-
],
|
| 113 |
-
[
|
| 114 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 115 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 116 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 117 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 118 |
-
],
|
| 119 |
-
[
|
| 120 |
-
[0, 2, 8, 11, -1, -1, -1],
|
| 121 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 122 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 123 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 124 |
-
],
|
| 125 |
-
[
|
| 126 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 127 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 128 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 129 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 130 |
-
],
|
| 131 |
-
[
|
| 132 |
-
[1, 2, 8, 9, 11, -1, -1],
|
| 133 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 134 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 135 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 136 |
-
],
|
| 137 |
-
[
|
| 138 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 139 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 140 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 141 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 142 |
-
],
|
| 143 |
-
[
|
| 144 |
-
[0, 2, 4, 7, 11, -1, -1],
|
| 145 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 146 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 147 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 148 |
-
],
|
| 149 |
-
[
|
| 150 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 151 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 152 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 153 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 154 |
-
],
|
| 155 |
-
[
|
| 156 |
-
[1, 2, 4, 7, 9, 11, -1],
|
| 157 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 158 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 159 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 160 |
-
],
|
| 161 |
-
[
|
| 162 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 163 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 164 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 165 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 166 |
-
],
|
| 167 |
-
[
|
| 168 |
-
[0, 2, 8, 11, -1, -1, -1],
|
| 169 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 170 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 171 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 172 |
-
],
|
| 173 |
-
[
|
| 174 |
-
[0, 1, 4, 5, -1, -1, -1],
|
| 175 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 176 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 177 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 178 |
-
],
|
| 179 |
-
[
|
| 180 |
-
[1, 2, 4, 5, 8, 11, -1],
|
| 181 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 182 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 183 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 184 |
-
],
|
| 185 |
-
[
|
| 186 |
-
[5, 7, 8, 9, -1, -1, -1],
|
| 187 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 188 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 189 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 190 |
-
],
|
| 191 |
-
[
|
| 192 |
-
[0, 2, 5, 7, 9, 11, -1],
|
| 193 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 194 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 195 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 196 |
-
],
|
| 197 |
-
[
|
| 198 |
-
[0, 1, 5, 7, 8, -1, -1],
|
| 199 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 200 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 201 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 202 |
-
],
|
| 203 |
-
[
|
| 204 |
-
[1, 2, 5, 7, 11, -1, -1],
|
| 205 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 206 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 207 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 208 |
-
],
|
| 209 |
-
[
|
| 210 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 211 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 212 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 213 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 214 |
-
],
|
| 215 |
-
[
|
| 216 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 217 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 218 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 219 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 220 |
-
],
|
| 221 |
-
[
|
| 222 |
-
[0, 2, 9, 10, -1, -1, -1],
|
| 223 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 224 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 225 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 226 |
-
],
|
| 227 |
-
[
|
| 228 |
-
[2, 3, 8, 9, 10, -1, -1],
|
| 229 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 230 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 231 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 232 |
-
],
|
| 233 |
-
[
|
| 234 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 235 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 236 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 237 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 238 |
-
],
|
| 239 |
-
[
|
| 240 |
-
[0, 3, 4, 7, -1, -1, -1],
|
| 241 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 242 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 243 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 244 |
-
],
|
| 245 |
-
[
|
| 246 |
-
[0, 2, 9, 10, -1, -1, -1],
|
| 247 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 248 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 249 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 250 |
-
],
|
| 251 |
-
[
|
| 252 |
-
[2, 3, 4, 7, 9, 10, -1],
|
| 253 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 254 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 255 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 256 |
-
],
|
| 257 |
-
[
|
| 258 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 259 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 260 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 261 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 262 |
-
],
|
| 263 |
-
[
|
| 264 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 265 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 266 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 267 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 268 |
-
],
|
| 269 |
-
[
|
| 270 |
-
[0, 2, 4, 5, 10, -1, -1],
|
| 271 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 272 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 273 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 274 |
-
],
|
| 275 |
-
[
|
| 276 |
-
[2, 3, 4, 5, 8, 10, -1],
|
| 277 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 278 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 279 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 280 |
-
],
|
| 281 |
-
[
|
| 282 |
-
[5, 7, 8, 9, -1, -1, -1],
|
| 283 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 284 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 285 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 286 |
-
],
|
| 287 |
-
[
|
| 288 |
-
[0, 3, 5, 7, 9, -1, -1],
|
| 289 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 290 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 291 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 292 |
-
],
|
| 293 |
-
[
|
| 294 |
-
[0, 2, 5, 7, 8, 10, -1],
|
| 295 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 296 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 297 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 298 |
-
],
|
| 299 |
-
[
|
| 300 |
-
[2, 3, 5, 7, 10, -1, -1],
|
| 301 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 302 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 303 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 304 |
-
],
|
| 305 |
-
[
|
| 306 |
-
[1, 3, 10, 11, -1, -1, -1],
|
| 307 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 308 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 309 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 310 |
-
],
|
| 311 |
-
[
|
| 312 |
-
[0, 1, 8, 10, 11, -1, -1],
|
| 313 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 314 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 315 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 316 |
-
],
|
| 317 |
-
[
|
| 318 |
-
[0, 3, 9, 10, 11, -1, -1],
|
| 319 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 320 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 321 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 322 |
-
],
|
| 323 |
-
[
|
| 324 |
-
[8, 9, 10, 11, -1, -1, -1],
|
| 325 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 326 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 327 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 328 |
-
],
|
| 329 |
-
[
|
| 330 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 331 |
-
[1, 3, 10, 11, -1, -1, -1],
|
| 332 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 333 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 334 |
-
],
|
| 335 |
-
[
|
| 336 |
-
[0, 1, 4, 7, 10, 11, -1],
|
| 337 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 338 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 339 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 340 |
-
],
|
| 341 |
-
[
|
| 342 |
-
[0, 3, 9, 10, 11, -1, -1],
|
| 343 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 344 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 345 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 346 |
-
],
|
| 347 |
-
[
|
| 348 |
-
[4, 7, 9, 10, 11, -1, -1],
|
| 349 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 350 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 351 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 352 |
-
],
|
| 353 |
-
[
|
| 354 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 355 |
-
[1, 3, 10, 11, -1, -1, -1],
|
| 356 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 357 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 358 |
-
],
|
| 359 |
-
[
|
| 360 |
-
[0, 1, 8, 10, 11, -1, -1],
|
| 361 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 362 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 363 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 364 |
-
],
|
| 365 |
-
[
|
| 366 |
-
[0, 3, 4, 5, 10, 11, -1],
|
| 367 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 368 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 369 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 370 |
-
],
|
| 371 |
-
[
|
| 372 |
-
[4, 5, 8, 10, 11, -1, -1],
|
| 373 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 374 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 375 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 376 |
-
],
|
| 377 |
-
[
|
| 378 |
-
[5, 7, 8, 9, -1, -1, -1],
|
| 379 |
-
[1, 3, 10, 11, -1, -1, -1],
|
| 380 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 381 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 382 |
-
],
|
| 383 |
-
[
|
| 384 |
-
[0, 1, 5, 7, 9, 10, 11],
|
| 385 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 386 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 387 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 388 |
-
],
|
| 389 |
-
[
|
| 390 |
-
[0, 3, 5, 7, 8, 10, 11],
|
| 391 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 392 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 393 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 394 |
-
],
|
| 395 |
-
[
|
| 396 |
-
[5, 7, 10, 11, -1, -1, -1],
|
| 397 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 398 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 399 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 400 |
-
],
|
| 401 |
-
[
|
| 402 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 403 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 404 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 405 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 406 |
-
],
|
| 407 |
-
[
|
| 408 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 409 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 410 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 411 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 412 |
-
],
|
| 413 |
-
[
|
| 414 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 415 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 416 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 417 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 418 |
-
],
|
| 419 |
-
[
|
| 420 |
-
[1, 3, 8, 9, -1, -1, -1],
|
| 421 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 422 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 423 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 424 |
-
],
|
| 425 |
-
[
|
| 426 |
-
[4, 6, 8, 11, -1, -1, -1],
|
| 427 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 428 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 429 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 430 |
-
],
|
| 431 |
-
[
|
| 432 |
-
[0, 3, 4, 6, 11, -1, -1],
|
| 433 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 434 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 435 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 436 |
-
],
|
| 437 |
-
[
|
| 438 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 439 |
-
[4, 6, 8, 11, -1, -1, -1],
|
| 440 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 441 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 442 |
-
],
|
| 443 |
-
[
|
| 444 |
-
[1, 3, 4, 6, 9, 11, -1],
|
| 445 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 446 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 447 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 448 |
-
],
|
| 449 |
-
[
|
| 450 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 451 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 452 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 453 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 454 |
-
],
|
| 455 |
-
[
|
| 456 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 457 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 458 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 459 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 460 |
-
],
|
| 461 |
-
[
|
| 462 |
-
[0, 1, 4, 5, -1, -1, -1],
|
| 463 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 464 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 465 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 466 |
-
],
|
| 467 |
-
[
|
| 468 |
-
[1, 3, 4, 5, 8, -1, -1],
|
| 469 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 470 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 471 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 472 |
-
],
|
| 473 |
-
[
|
| 474 |
-
[5, 6, 8, 9, 11, -1, -1],
|
| 475 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 476 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 477 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 478 |
-
],
|
| 479 |
-
[
|
| 480 |
-
[0, 3, 5, 6, 9, 11, -1],
|
| 481 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 482 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 483 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 484 |
-
],
|
| 485 |
-
[
|
| 486 |
-
[0, 1, 5, 6, 8, 11, -1],
|
| 487 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 488 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 489 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 490 |
-
],
|
| 491 |
-
[
|
| 492 |
-
[1, 3, 5, 6, 11, -1, -1],
|
| 493 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 494 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 495 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 496 |
-
],
|
| 497 |
-
[
|
| 498 |
-
[2, 3, 6, 7, -1, -1, -1],
|
| 499 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 500 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 501 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 502 |
-
],
|
| 503 |
-
[
|
| 504 |
-
[0, 2, 6, 7, 8, -1, -1],
|
| 505 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 506 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 507 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 508 |
-
],
|
| 509 |
-
[
|
| 510 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 511 |
-
[2, 3, 6, 7, -1, -1, -1],
|
| 512 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 513 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 514 |
-
],
|
| 515 |
-
[
|
| 516 |
-
[1, 2, 6, 7, 8, 9, -1],
|
| 517 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 518 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 519 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 520 |
-
],
|
| 521 |
-
[
|
| 522 |
-
[2, 3, 4, 6, 8, -1, -1],
|
| 523 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 524 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 525 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 526 |
-
],
|
| 527 |
-
[
|
| 528 |
-
[0, 2, 4, 6, -1, -1, -1],
|
| 529 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 530 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 531 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 532 |
-
],
|
| 533 |
-
[
|
| 534 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 535 |
-
[2, 3, 4, 6, 8, -1, -1],
|
| 536 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 537 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 538 |
-
],
|
| 539 |
-
[
|
| 540 |
-
[1, 2, 4, 6, 9, -1, -1],
|
| 541 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 542 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 543 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 544 |
-
],
|
| 545 |
-
[
|
| 546 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 547 |
-
[2, 3, 6, 7, -1, -1, -1],
|
| 548 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 549 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 550 |
-
],
|
| 551 |
-
[
|
| 552 |
-
[0, 2, 6, 7, 8, -1, -1],
|
| 553 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 554 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 555 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 556 |
-
],
|
| 557 |
-
[
|
| 558 |
-
[0, 1, 4, 5, -1, -1, -1],
|
| 559 |
-
[2, 3, 6, 7, -1, -1, -1],
|
| 560 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 561 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 562 |
-
],
|
| 563 |
-
[
|
| 564 |
-
[1, 2, 4, 5, 6, 7, 8],
|
| 565 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 566 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 567 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 568 |
-
],
|
| 569 |
-
[
|
| 570 |
-
[2, 3, 5, 6, 8, 9, -1],
|
| 571 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 572 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 573 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 574 |
-
],
|
| 575 |
-
[
|
| 576 |
-
[0, 2, 5, 6, 9, -1, -1],
|
| 577 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 578 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 579 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 580 |
-
],
|
| 581 |
-
[
|
| 582 |
-
[0, 1, 2, 3, 5, 6, 8],
|
| 583 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 584 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 585 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 586 |
-
],
|
| 587 |
-
[
|
| 588 |
-
[1, 2, 5, 6, -1, -1, -1],
|
| 589 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 590 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 591 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 592 |
-
],
|
| 593 |
-
[
|
| 594 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 595 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 596 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 597 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 598 |
-
],
|
| 599 |
-
[
|
| 600 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 601 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 602 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 603 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 604 |
-
],
|
| 605 |
-
[
|
| 606 |
-
[0, 2, 9, 10, -1, -1, -1],
|
| 607 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 608 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 609 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 610 |
-
],
|
| 611 |
-
[
|
| 612 |
-
[2, 3, 8, 9, 10, -1, -1],
|
| 613 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 614 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 615 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 616 |
-
],
|
| 617 |
-
[
|
| 618 |
-
[4, 6, 8, 11, -1, -1, -1],
|
| 619 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 620 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 621 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 622 |
-
],
|
| 623 |
-
[
|
| 624 |
-
[0, 3, 4, 6, 11, -1, -1],
|
| 625 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 626 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 627 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 628 |
-
],
|
| 629 |
-
[
|
| 630 |
-
[0, 2, 9, 10, -1, -1, -1],
|
| 631 |
-
[4, 6, 8, 11, -1, -1, -1],
|
| 632 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 633 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 634 |
-
],
|
| 635 |
-
[
|
| 636 |
-
[2, 3, 4, 6, 9, 10, 11],
|
| 637 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 638 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 639 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 640 |
-
],
|
| 641 |
-
[
|
| 642 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 643 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 644 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 645 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 646 |
-
],
|
| 647 |
-
[
|
| 648 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 649 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 650 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 651 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 652 |
-
],
|
| 653 |
-
[
|
| 654 |
-
[0, 2, 4, 5, 10, -1, -1],
|
| 655 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 656 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 657 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 658 |
-
],
|
| 659 |
-
[
|
| 660 |
-
[2, 3, 4, 5, 8, 10, -1],
|
| 661 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 662 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 663 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 664 |
-
],
|
| 665 |
-
[
|
| 666 |
-
[5, 6, 8, 9, 11, -1, -1],
|
| 667 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 668 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 669 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 670 |
-
],
|
| 671 |
-
[
|
| 672 |
-
[0, 3, 5, 6, 9, 11, -1],
|
| 673 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 674 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 675 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 676 |
-
],
|
| 677 |
-
[
|
| 678 |
-
[0, 2, 5, 6, 8, 10, 11],
|
| 679 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 680 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 681 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 682 |
-
],
|
| 683 |
-
[
|
| 684 |
-
[2, 3, 5, 6, 10, 11, -1],
|
| 685 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 686 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 687 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 688 |
-
],
|
| 689 |
-
[
|
| 690 |
-
[1, 3, 6, 7, 10, -1, -1],
|
| 691 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 692 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 693 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 694 |
-
],
|
| 695 |
-
[
|
| 696 |
-
[0, 1, 6, 7, 8, 10, -1],
|
| 697 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 698 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 699 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 700 |
-
],
|
| 701 |
-
[
|
| 702 |
-
[0, 3, 6, 7, 9, 10, -1],
|
| 703 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 704 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 705 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 706 |
-
],
|
| 707 |
-
[
|
| 708 |
-
[6, 7, 8, 9, 10, -1, -1],
|
| 709 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 710 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 711 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 712 |
-
],
|
| 713 |
-
[
|
| 714 |
-
[1, 3, 4, 6, 8, 10, -1],
|
| 715 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 716 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 717 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 718 |
-
],
|
| 719 |
-
[
|
| 720 |
-
[0, 1, 4, 6, 10, -1, -1],
|
| 721 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 722 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 723 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 724 |
-
],
|
| 725 |
-
[
|
| 726 |
-
[0, 3, 4, 6, 8, 9, 10],
|
| 727 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 728 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 729 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 730 |
-
],
|
| 731 |
-
[
|
| 732 |
-
[4, 6, 9, 10, -1, -1, -1],
|
| 733 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 734 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 735 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 736 |
-
],
|
| 737 |
-
[
|
| 738 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 739 |
-
[1, 3, 6, 7, 10, -1, -1],
|
| 740 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 741 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 742 |
-
],
|
| 743 |
-
[
|
| 744 |
-
[0, 1, 6, 7, 8, 10, -1],
|
| 745 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 746 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 747 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 748 |
-
],
|
| 749 |
-
[
|
| 750 |
-
[0, 3, 4, 5, 6, 7, 10],
|
| 751 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 752 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 753 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 754 |
-
],
|
| 755 |
-
[
|
| 756 |
-
[4, 5, 6, 7, 8, 10, -1],
|
| 757 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 758 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 759 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 760 |
-
],
|
| 761 |
-
[
|
| 762 |
-
[1, 3, 5, 6, 8, 9, 10],
|
| 763 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 764 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 765 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 766 |
-
],
|
| 767 |
-
[
|
| 768 |
-
[0, 1, 5, 6, 9, 10, -1],
|
| 769 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 770 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 771 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 772 |
-
],
|
| 773 |
-
[
|
| 774 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 775 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 776 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 777 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 778 |
-
],
|
| 779 |
-
[
|
| 780 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 781 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 782 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 783 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 784 |
-
],
|
| 785 |
-
[
|
| 786 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 787 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 788 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 789 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 790 |
-
],
|
| 791 |
-
[
|
| 792 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 793 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 794 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 795 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 796 |
-
],
|
| 797 |
-
[
|
| 798 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 799 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 800 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 801 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 802 |
-
],
|
| 803 |
-
[
|
| 804 |
-
[1, 3, 8, 9, -1, -1, -1],
|
| 805 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 806 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 807 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 808 |
-
],
|
| 809 |
-
[
|
| 810 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 811 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 812 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 813 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 814 |
-
],
|
| 815 |
-
[
|
| 816 |
-
[0, 3, 4, 7, -1, -1, -1],
|
| 817 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 818 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 819 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 820 |
-
],
|
| 821 |
-
[
|
| 822 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 823 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 824 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 825 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 826 |
-
],
|
| 827 |
-
[
|
| 828 |
-
[1, 3, 4, 7, 9, -1, -1],
|
| 829 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 830 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 831 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 832 |
-
],
|
| 833 |
-
[
|
| 834 |
-
[4, 6, 9, 10, -1, -1, -1],
|
| 835 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 836 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 837 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 838 |
-
],
|
| 839 |
-
[
|
| 840 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 841 |
-
[4, 6, 9, 10, -1, -1, -1],
|
| 842 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 843 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 844 |
-
],
|
| 845 |
-
[
|
| 846 |
-
[0, 1, 4, 6, 10, -1, -1],
|
| 847 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 848 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 849 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 850 |
-
],
|
| 851 |
-
[
|
| 852 |
-
[1, 3, 4, 6, 8, 10, -1],
|
| 853 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 854 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 855 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 856 |
-
],
|
| 857 |
-
[
|
| 858 |
-
[6, 7, 8, 9, 10, -1, -1],
|
| 859 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 860 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 861 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 862 |
-
],
|
| 863 |
-
[
|
| 864 |
-
[0, 3, 6, 7, 9, 10, -1],
|
| 865 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 866 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 867 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 868 |
-
],
|
| 869 |
-
[
|
| 870 |
-
[0, 1, 6, 7, 8, 10, -1],
|
| 871 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 872 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 873 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 874 |
-
],
|
| 875 |
-
[
|
| 876 |
-
[1, 3, 6, 7, 10, -1, -1],
|
| 877 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 878 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 879 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 880 |
-
],
|
| 881 |
-
[
|
| 882 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 883 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 884 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 885 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 886 |
-
],
|
| 887 |
-
[
|
| 888 |
-
[0, 2, 8, 11, -1, -1, -1],
|
| 889 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 890 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 891 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 892 |
-
],
|
| 893 |
-
[
|
| 894 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 895 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 896 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 897 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 898 |
-
],
|
| 899 |
-
[
|
| 900 |
-
[1, 2, 8, 9, 11, -1, -1],
|
| 901 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 902 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 903 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 904 |
-
],
|
| 905 |
-
[
|
| 906 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 907 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 908 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 909 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 910 |
-
],
|
| 911 |
-
[
|
| 912 |
-
[0, 2, 4, 7, 11, -1, -1],
|
| 913 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 914 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 915 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 916 |
-
],
|
| 917 |
-
[
|
| 918 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 919 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 920 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 921 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 922 |
-
],
|
| 923 |
-
[
|
| 924 |
-
[1, 2, 4, 7, 9, 11, -1],
|
| 925 |
-
[5, 6, 10, -1, -1, -1, -1],
|
| 926 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 927 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 928 |
-
],
|
| 929 |
-
[
|
| 930 |
-
[4, 6, 9, 10, -1, -1, -1],
|
| 931 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 932 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 933 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 934 |
-
],
|
| 935 |
-
[
|
| 936 |
-
[0, 2, 8, 11, -1, -1, -1],
|
| 937 |
-
[4, 6, 9, 10, -1, -1, -1],
|
| 938 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 939 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 940 |
-
],
|
| 941 |
-
[
|
| 942 |
-
[0, 1, 4, 6, 10, -1, -1],
|
| 943 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 944 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 945 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 946 |
-
],
|
| 947 |
-
[
|
| 948 |
-
[1, 2, 4, 6, 8, 10, 11],
|
| 949 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 950 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 951 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 952 |
-
],
|
| 953 |
-
[
|
| 954 |
-
[6, 7, 8, 9, 10, -1, -1],
|
| 955 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 956 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 957 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 958 |
-
],
|
| 959 |
-
[
|
| 960 |
-
[0, 2, 6, 7, 9, 10, 11],
|
| 961 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 962 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 963 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 964 |
-
],
|
| 965 |
-
[
|
| 966 |
-
[0, 1, 6, 7, 8, 10, -1],
|
| 967 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 968 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 969 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 970 |
-
],
|
| 971 |
-
[
|
| 972 |
-
[1, 2, 6, 7, 10, 11, -1],
|
| 973 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 974 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 975 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 976 |
-
],
|
| 977 |
-
[
|
| 978 |
-
[1, 2, 5, 6, -1, -1, -1],
|
| 979 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 980 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 981 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 982 |
-
],
|
| 983 |
-
[
|
| 984 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 985 |
-
[1, 2, 5, 6, -1, -1, -1],
|
| 986 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 987 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 988 |
-
],
|
| 989 |
-
[
|
| 990 |
-
[0, 2, 5, 6, 9, -1, -1],
|
| 991 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 992 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 993 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 994 |
-
],
|
| 995 |
-
[
|
| 996 |
-
[2, 3, 5, 6, 8, 9, -1],
|
| 997 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 998 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 999 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1000 |
-
],
|
| 1001 |
-
[
|
| 1002 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 1003 |
-
[1, 2, 5, 6, -1, -1, -1],
|
| 1004 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1005 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1006 |
-
],
|
| 1007 |
-
[
|
| 1008 |
-
[0, 3, 4, 7, -1, -1, -1],
|
| 1009 |
-
[1, 2, 5, 6, -1, -1, -1],
|
| 1010 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1011 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1012 |
-
],
|
| 1013 |
-
[
|
| 1014 |
-
[0, 2, 5, 6, 9, -1, -1],
|
| 1015 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 1016 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1017 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1018 |
-
],
|
| 1019 |
-
[
|
| 1020 |
-
[2, 3, 4, 5, 6, 7, 9],
|
| 1021 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1022 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1023 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1024 |
-
],
|
| 1025 |
-
[
|
| 1026 |
-
[1, 2, 4, 6, 9, -1, -1],
|
| 1027 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1028 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1029 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1030 |
-
],
|
| 1031 |
-
[
|
| 1032 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 1033 |
-
[1, 2, 4, 6, 9, -1, -1],
|
| 1034 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1035 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1036 |
-
],
|
| 1037 |
-
[
|
| 1038 |
-
[0, 2, 4, 6, -1, -1, -1],
|
| 1039 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1040 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1041 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1042 |
-
],
|
| 1043 |
-
[
|
| 1044 |
-
[2, 3, 4, 6, 8, -1, -1],
|
| 1045 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1046 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1047 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1048 |
-
],
|
| 1049 |
-
[
|
| 1050 |
-
[1, 2, 6, 7, 8, 9, -1],
|
| 1051 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1052 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1053 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1054 |
-
],
|
| 1055 |
-
[
|
| 1056 |
-
[0, 1, 2, 3, 6, 7, 9],
|
| 1057 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1058 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1059 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1060 |
-
],
|
| 1061 |
-
[
|
| 1062 |
-
[0, 2, 6, 7, 8, -1, -1],
|
| 1063 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1064 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1065 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1066 |
-
],
|
| 1067 |
-
[
|
| 1068 |
-
[2, 3, 6, 7, -1, -1, -1],
|
| 1069 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1070 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1071 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1072 |
-
],
|
| 1073 |
-
[
|
| 1074 |
-
[1, 3, 5, 6, 11, -1, -1],
|
| 1075 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1076 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1077 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1078 |
-
],
|
| 1079 |
-
[
|
| 1080 |
-
[0, 1, 5, 6, 8, 11, -1],
|
| 1081 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1082 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1083 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1084 |
-
],
|
| 1085 |
-
[
|
| 1086 |
-
[0, 3, 5, 6, 9, 11, -1],
|
| 1087 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1088 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1089 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1090 |
-
],
|
| 1091 |
-
[
|
| 1092 |
-
[5, 6, 8, 9, 11, -1, -1],
|
| 1093 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1094 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1095 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1096 |
-
],
|
| 1097 |
-
[
|
| 1098 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 1099 |
-
[1, 3, 5, 6, 11, -1, -1],
|
| 1100 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1101 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1102 |
-
],
|
| 1103 |
-
[
|
| 1104 |
-
[0, 1, 4, 5, 6, 7, 11],
|
| 1105 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1106 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1107 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1108 |
-
],
|
| 1109 |
-
[
|
| 1110 |
-
[0, 3, 5, 6, 9, 11, -1],
|
| 1111 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 1112 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1113 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1114 |
-
],
|
| 1115 |
-
[
|
| 1116 |
-
[4, 5, 6, 7, 9, 11, -1],
|
| 1117 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1118 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1119 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1120 |
-
],
|
| 1121 |
-
[
|
| 1122 |
-
[1, 3, 4, 6, 9, 11, -1],
|
| 1123 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1124 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1125 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1126 |
-
],
|
| 1127 |
-
[
|
| 1128 |
-
[0, 1, 4, 6, 8, 9, 11],
|
| 1129 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1130 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1131 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1132 |
-
],
|
| 1133 |
-
[
|
| 1134 |
-
[0, 3, 4, 6, 11, -1, -1],
|
| 1135 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1136 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1137 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1138 |
-
],
|
| 1139 |
-
[
|
| 1140 |
-
[4, 6, 8, 11, -1, -1, -1],
|
| 1141 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1142 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1143 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1144 |
-
],
|
| 1145 |
-
[
|
| 1146 |
-
[1, 3, 6, 7, 8, 9, 11],
|
| 1147 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1148 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1149 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1150 |
-
],
|
| 1151 |
-
[
|
| 1152 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 1153 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 1154 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1155 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1156 |
-
],
|
| 1157 |
-
[
|
| 1158 |
-
[0, 3, 6, 7, 8, 11, -1],
|
| 1159 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1160 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1161 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1162 |
-
],
|
| 1163 |
-
[
|
| 1164 |
-
[6, 7, 11, -1, -1, -1, -1],
|
| 1165 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1166 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1167 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1168 |
-
],
|
| 1169 |
-
[
|
| 1170 |
-
[5, 7, 10, 11, -1, -1, -1],
|
| 1171 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1172 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1173 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1174 |
-
],
|
| 1175 |
-
[
|
| 1176 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 1177 |
-
[5, 7, 10, 11, -1, -1, -1],
|
| 1178 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1179 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1180 |
-
],
|
| 1181 |
-
[
|
| 1182 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 1183 |
-
[5, 7, 10, 11, -1, -1, -1],
|
| 1184 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1185 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1186 |
-
],
|
| 1187 |
-
[
|
| 1188 |
-
[1, 3, 8, 9, -1, -1, -1],
|
| 1189 |
-
[5, 7, 10, 11, -1, -1, -1],
|
| 1190 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1191 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1192 |
-
],
|
| 1193 |
-
[
|
| 1194 |
-
[4, 5, 8, 10, 11, -1, -1],
|
| 1195 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1196 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1197 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1198 |
-
],
|
| 1199 |
-
[
|
| 1200 |
-
[0, 3, 4, 5, 10, 11, -1],
|
| 1201 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1202 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1203 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1204 |
-
],
|
| 1205 |
-
[
|
| 1206 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 1207 |
-
[4, 5, 8, 10, 11, -1, -1],
|
| 1208 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1209 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1210 |
-
],
|
| 1211 |
-
[
|
| 1212 |
-
[1, 3, 4, 5, 9, 10, 11],
|
| 1213 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1214 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1215 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1216 |
-
],
|
| 1217 |
-
[
|
| 1218 |
-
[4, 7, 9, 10, 11, -1, -1],
|
| 1219 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1220 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1221 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1222 |
-
],
|
| 1223 |
-
[
|
| 1224 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 1225 |
-
[4, 7, 9, 10, 11, -1, -1],
|
| 1226 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1227 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1228 |
-
],
|
| 1229 |
-
[
|
| 1230 |
-
[0, 1, 4, 7, 10, 11, -1],
|
| 1231 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1232 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1233 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1234 |
-
],
|
| 1235 |
-
[
|
| 1236 |
-
[1, 3, 4, 7, 8, 10, 11],
|
| 1237 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1238 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1239 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1240 |
-
],
|
| 1241 |
-
[
|
| 1242 |
-
[8, 9, 10, 11, -1, -1, -1],
|
| 1243 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1244 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1245 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1246 |
-
],
|
| 1247 |
-
[
|
| 1248 |
-
[0, 3, 9, 10, 11, -1, -1],
|
| 1249 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1250 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1251 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1252 |
-
],
|
| 1253 |
-
[
|
| 1254 |
-
[0, 1, 8, 10, 11, -1, -1],
|
| 1255 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1256 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1257 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1258 |
-
],
|
| 1259 |
-
[
|
| 1260 |
-
[1, 3, 10, 11, -1, -1, -1],
|
| 1261 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1262 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1263 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1264 |
-
],
|
| 1265 |
-
[
|
| 1266 |
-
[2, 3, 5, 7, 10, -1, -1],
|
| 1267 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1268 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1269 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1270 |
-
],
|
| 1271 |
-
[
|
| 1272 |
-
[0, 2, 5, 7, 8, 10, -1],
|
| 1273 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1274 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1275 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1276 |
-
],
|
| 1277 |
-
[
|
| 1278 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 1279 |
-
[2, 3, 5, 7, 10, -1, -1],
|
| 1280 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1281 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1282 |
-
],
|
| 1283 |
-
[
|
| 1284 |
-
[1, 2, 5, 7, 8, 9, 10],
|
| 1285 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1286 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1287 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1288 |
-
],
|
| 1289 |
-
[
|
| 1290 |
-
[2, 3, 4, 5, 8, 10, -1],
|
| 1291 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1292 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1293 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1294 |
-
],
|
| 1295 |
-
[
|
| 1296 |
-
[0, 2, 4, 5, 10, -1, -1],
|
| 1297 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1298 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1299 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1300 |
-
],
|
| 1301 |
-
[
|
| 1302 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 1303 |
-
[2, 3, 4, 5, 8, 10, -1],
|
| 1304 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1305 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1306 |
-
],
|
| 1307 |
-
[
|
| 1308 |
-
[1, 2, 4, 5, 9, 10, -1],
|
| 1309 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1310 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1311 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1312 |
-
],
|
| 1313 |
-
[
|
| 1314 |
-
[2, 3, 4, 7, 9, 10, -1],
|
| 1315 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1316 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1317 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1318 |
-
],
|
| 1319 |
-
[
|
| 1320 |
-
[0, 2, 4, 7, 8, 9, 10],
|
| 1321 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1322 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1323 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1324 |
-
],
|
| 1325 |
-
[
|
| 1326 |
-
[0, 1, 2, 3, 4, 7, 10],
|
| 1327 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1328 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1329 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1330 |
-
],
|
| 1331 |
-
[
|
| 1332 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 1333 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 1334 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1335 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1336 |
-
],
|
| 1337 |
-
[
|
| 1338 |
-
[2, 3, 8, 9, 10, -1, -1],
|
| 1339 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1340 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1341 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1342 |
-
],
|
| 1343 |
-
[
|
| 1344 |
-
[0, 2, 9, 10, -1, -1, -1],
|
| 1345 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1346 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1347 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1348 |
-
],
|
| 1349 |
-
[
|
| 1350 |
-
[0, 1, 2, 3, 8, 10, -1],
|
| 1351 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1352 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1353 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1354 |
-
],
|
| 1355 |
-
[
|
| 1356 |
-
[1, 2, 10, -1, -1, -1, -1],
|
| 1357 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1358 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1359 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1360 |
-
],
|
| 1361 |
-
[
|
| 1362 |
-
[1, 2, 5, 7, 11, -1, -1],
|
| 1363 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1364 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1365 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1366 |
-
],
|
| 1367 |
-
[
|
| 1368 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 1369 |
-
[1, 2, 5, 7, 11, -1, -1],
|
| 1370 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1371 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1372 |
-
],
|
| 1373 |
-
[
|
| 1374 |
-
[0, 2, 5, 7, 9, 11, -1],
|
| 1375 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1376 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1377 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1378 |
-
],
|
| 1379 |
-
[
|
| 1380 |
-
[2, 3, 5, 7, 8, 9, 11],
|
| 1381 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1382 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1383 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1384 |
-
],
|
| 1385 |
-
[
|
| 1386 |
-
[1, 2, 4, 5, 8, 11, -1],
|
| 1387 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1388 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1389 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1390 |
-
],
|
| 1391 |
-
[
|
| 1392 |
-
[0, 1, 2, 3, 4, 5, 11],
|
| 1393 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1394 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1395 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1396 |
-
],
|
| 1397 |
-
[
|
| 1398 |
-
[0, 2, 4, 5, 8, 9, 11],
|
| 1399 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1400 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1401 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1402 |
-
],
|
| 1403 |
-
[
|
| 1404 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 1405 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 1406 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1407 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1408 |
-
],
|
| 1409 |
-
[
|
| 1410 |
-
[1, 2, 4, 7, 9, 11, -1],
|
| 1411 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1412 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1413 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1414 |
-
],
|
| 1415 |
-
[
|
| 1416 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 1417 |
-
[1, 2, 4, 7, 9, 11, -1],
|
| 1418 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1419 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1420 |
-
],
|
| 1421 |
-
[
|
| 1422 |
-
[0, 2, 4, 7, 11, -1, -1],
|
| 1423 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1424 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1425 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1426 |
-
],
|
| 1427 |
-
[
|
| 1428 |
-
[2, 3, 4, 7, 8, 11, -1],
|
| 1429 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1430 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1431 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1432 |
-
],
|
| 1433 |
-
[
|
| 1434 |
-
[1, 2, 8, 9, 11, -1, -1],
|
| 1435 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1436 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1437 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1438 |
-
],
|
| 1439 |
-
[
|
| 1440 |
-
[0, 1, 2, 3, 9, 11, -1],
|
| 1441 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1442 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1443 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1444 |
-
],
|
| 1445 |
-
[
|
| 1446 |
-
[0, 2, 8, 11, -1, -1, -1],
|
| 1447 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1448 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1449 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1450 |
-
],
|
| 1451 |
-
[
|
| 1452 |
-
[2, 3, 11, -1, -1, -1, -1],
|
| 1453 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1454 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1455 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1456 |
-
],
|
| 1457 |
-
[
|
| 1458 |
-
[1, 3, 5, 7, -1, -1, -1],
|
| 1459 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1460 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1461 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1462 |
-
],
|
| 1463 |
-
[
|
| 1464 |
-
[0, 1, 5, 7, 8, -1, -1],
|
| 1465 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1466 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1467 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1468 |
-
],
|
| 1469 |
-
[
|
| 1470 |
-
[0, 3, 5, 7, 9, -1, -1],
|
| 1471 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1472 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1473 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1474 |
-
],
|
| 1475 |
-
[
|
| 1476 |
-
[5, 7, 8, 9, -1, -1, -1],
|
| 1477 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1478 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1479 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1480 |
-
],
|
| 1481 |
-
[
|
| 1482 |
-
[1, 3, 4, 5, 8, -1, -1],
|
| 1483 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1484 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1485 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1486 |
-
],
|
| 1487 |
-
[
|
| 1488 |
-
[0, 1, 4, 5, -1, -1, -1],
|
| 1489 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1490 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1491 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1492 |
-
],
|
| 1493 |
-
[
|
| 1494 |
-
[0, 3, 4, 5, 8, 9, -1],
|
| 1495 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1496 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1497 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1498 |
-
],
|
| 1499 |
-
[
|
| 1500 |
-
[4, 5, 9, -1, -1, -1, -1],
|
| 1501 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1502 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1503 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1504 |
-
],
|
| 1505 |
-
[
|
| 1506 |
-
[1, 3, 4, 7, 9, -1, -1],
|
| 1507 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1508 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1509 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1510 |
-
],
|
| 1511 |
-
[
|
| 1512 |
-
[0, 1, 4, 7, 8, 9, -1],
|
| 1513 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1514 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1515 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1516 |
-
],
|
| 1517 |
-
[
|
| 1518 |
-
[0, 3, 4, 7, -1, -1, -1],
|
| 1519 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1520 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1521 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1522 |
-
],
|
| 1523 |
-
[
|
| 1524 |
-
[4, 7, 8, -1, -1, -1, -1],
|
| 1525 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1526 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1527 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1528 |
-
],
|
| 1529 |
-
[
|
| 1530 |
-
[1, 3, 8, 9, -1, -1, -1],
|
| 1531 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1532 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1533 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1534 |
-
],
|
| 1535 |
-
[
|
| 1536 |
-
[0, 1, 9, -1, -1, -1, -1],
|
| 1537 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1538 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1539 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1540 |
-
],
|
| 1541 |
-
[
|
| 1542 |
-
[0, 3, 8, -1, -1, -1, -1],
|
| 1543 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1544 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1545 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1546 |
-
],
|
| 1547 |
-
[
|
| 1548 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1549 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1550 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1551 |
-
[-1, -1, -1, -1, -1, -1, -1],
|
| 1552 |
-
],
|
| 1553 |
-
]
|
| 1554 |
-
num_vd_table = [
|
| 1555 |
-
0,
|
| 1556 |
-
1,
|
| 1557 |
-
1,
|
| 1558 |
-
1,
|
| 1559 |
-
1,
|
| 1560 |
-
1,
|
| 1561 |
-
2,
|
| 1562 |
-
1,
|
| 1563 |
-
1,
|
| 1564 |
-
2,
|
| 1565 |
-
1,
|
| 1566 |
-
1,
|
| 1567 |
-
1,
|
| 1568 |
-
1,
|
| 1569 |
-
1,
|
| 1570 |
-
1,
|
| 1571 |
-
1,
|
| 1572 |
-
1,
|
| 1573 |
-
2,
|
| 1574 |
-
1,
|
| 1575 |
-
2,
|
| 1576 |
-
1,
|
| 1577 |
-
3,
|
| 1578 |
-
1,
|
| 1579 |
-
2,
|
| 1580 |
-
2,
|
| 1581 |
-
2,
|
| 1582 |
-
1,
|
| 1583 |
-
2,
|
| 1584 |
-
1,
|
| 1585 |
-
2,
|
| 1586 |
-
1,
|
| 1587 |
-
1,
|
| 1588 |
-
2,
|
| 1589 |
-
1,
|
| 1590 |
-
1,
|
| 1591 |
-
2,
|
| 1592 |
-
2,
|
| 1593 |
-
2,
|
| 1594 |
-
1,
|
| 1595 |
-
2,
|
| 1596 |
-
3,
|
| 1597 |
-
1,
|
| 1598 |
-
1,
|
| 1599 |
-
2,
|
| 1600 |
-
2,
|
| 1601 |
-
1,
|
| 1602 |
-
1,
|
| 1603 |
-
1,
|
| 1604 |
-
1,
|
| 1605 |
-
1,
|
| 1606 |
-
1,
|
| 1607 |
-
2,
|
| 1608 |
-
1,
|
| 1609 |
-
2,
|
| 1610 |
-
1,
|
| 1611 |
-
2,
|
| 1612 |
-
2,
|
| 1613 |
-
1,
|
| 1614 |
-
1,
|
| 1615 |
-
2,
|
| 1616 |
-
1,
|
| 1617 |
-
1,
|
| 1618 |
-
1,
|
| 1619 |
-
1,
|
| 1620 |
-
2,
|
| 1621 |
-
2,
|
| 1622 |
-
2,
|
| 1623 |
-
1,
|
| 1624 |
-
1,
|
| 1625 |
-
2,
|
| 1626 |
-
1,
|
| 1627 |
-
2,
|
| 1628 |
-
3,
|
| 1629 |
-
2,
|
| 1630 |
-
2,
|
| 1631 |
-
1,
|
| 1632 |
-
1,
|
| 1633 |
-
1,
|
| 1634 |
-
1,
|
| 1635 |
-
1,
|
| 1636 |
-
1,
|
| 1637 |
-
2,
|
| 1638 |
-
1,
|
| 1639 |
-
1,
|
| 1640 |
-
1,
|
| 1641 |
-
2,
|
| 1642 |
-
1,
|
| 1643 |
-
2,
|
| 1644 |
-
2,
|
| 1645 |
-
2,
|
| 1646 |
-
1,
|
| 1647 |
-
1,
|
| 1648 |
-
1,
|
| 1649 |
-
1,
|
| 1650 |
-
1,
|
| 1651 |
-
2,
|
| 1652 |
-
3,
|
| 1653 |
-
2,
|
| 1654 |
-
2,
|
| 1655 |
-
2,
|
| 1656 |
-
2,
|
| 1657 |
-
2,
|
| 1658 |
-
1,
|
| 1659 |
-
3,
|
| 1660 |
-
4,
|
| 1661 |
-
2,
|
| 1662 |
-
2,
|
| 1663 |
-
2,
|
| 1664 |
-
2,
|
| 1665 |
-
1,
|
| 1666 |
-
1,
|
| 1667 |
-
1,
|
| 1668 |
-
1,
|
| 1669 |
-
1,
|
| 1670 |
-
1,
|
| 1671 |
-
1,
|
| 1672 |
-
1,
|
| 1673 |
-
1,
|
| 1674 |
-
1,
|
| 1675 |
-
2,
|
| 1676 |
-
2,
|
| 1677 |
-
1,
|
| 1678 |
-
1,
|
| 1679 |
-
1,
|
| 1680 |
-
1,
|
| 1681 |
-
2,
|
| 1682 |
-
1,
|
| 1683 |
-
1,
|
| 1684 |
-
2,
|
| 1685 |
-
2,
|
| 1686 |
-
2,
|
| 1687 |
-
2,
|
| 1688 |
-
2,
|
| 1689 |
-
3,
|
| 1690 |
-
2,
|
| 1691 |
-
1,
|
| 1692 |
-
2,
|
| 1693 |
-
1,
|
| 1694 |
-
1,
|
| 1695 |
-
1,
|
| 1696 |
-
1,
|
| 1697 |
-
1,
|
| 1698 |
-
1,
|
| 1699 |
-
2,
|
| 1700 |
-
2,
|
| 1701 |
-
3,
|
| 1702 |
-
2,
|
| 1703 |
-
3,
|
| 1704 |
-
2,
|
| 1705 |
-
4,
|
| 1706 |
-
2,
|
| 1707 |
-
2,
|
| 1708 |
-
2,
|
| 1709 |
-
2,
|
| 1710 |
-
1,
|
| 1711 |
-
2,
|
| 1712 |
-
1,
|
| 1713 |
-
2,
|
| 1714 |
-
1,
|
| 1715 |
-
1,
|
| 1716 |
-
2,
|
| 1717 |
-
1,
|
| 1718 |
-
1,
|
| 1719 |
-
2,
|
| 1720 |
-
2,
|
| 1721 |
-
2,
|
| 1722 |
-
1,
|
| 1723 |
-
1,
|
| 1724 |
-
2,
|
| 1725 |
-
1,
|
| 1726 |
-
1,
|
| 1727 |
-
1,
|
| 1728 |
-
1,
|
| 1729 |
-
1,
|
| 1730 |
-
1,
|
| 1731 |
-
1,
|
| 1732 |
-
1,
|
| 1733 |
-
1,
|
| 1734 |
-
1,
|
| 1735 |
-
2,
|
| 1736 |
-
1,
|
| 1737 |
-
2,
|
| 1738 |
-
1,
|
| 1739 |
-
1,
|
| 1740 |
-
1,
|
| 1741 |
-
1,
|
| 1742 |
-
1,
|
| 1743 |
-
1,
|
| 1744 |
-
2,
|
| 1745 |
-
1,
|
| 1746 |
-
1,
|
| 1747 |
-
1,
|
| 1748 |
-
2,
|
| 1749 |
-
2,
|
| 1750 |
-
2,
|
| 1751 |
-
1,
|
| 1752 |
-
1,
|
| 1753 |
-
2,
|
| 1754 |
-
1,
|
| 1755 |
-
1,
|
| 1756 |
-
2,
|
| 1757 |
-
1,
|
| 1758 |
-
1,
|
| 1759 |
-
1,
|
| 1760 |
-
1,
|
| 1761 |
-
1,
|
| 1762 |
-
1,
|
| 1763 |
-
1,
|
| 1764 |
-
1,
|
| 1765 |
-
2,
|
| 1766 |
-
1,
|
| 1767 |
-
1,
|
| 1768 |
-
1,
|
| 1769 |
-
2,
|
| 1770 |
-
1,
|
| 1771 |
-
1,
|
| 1772 |
-
1,
|
| 1773 |
-
1,
|
| 1774 |
-
2,
|
| 1775 |
-
1,
|
| 1776 |
-
1,
|
| 1777 |
-
1,
|
| 1778 |
-
1,
|
| 1779 |
-
1,
|
| 1780 |
-
2,
|
| 1781 |
-
1,
|
| 1782 |
-
1,
|
| 1783 |
-
1,
|
| 1784 |
-
1,
|
| 1785 |
-
1,
|
| 1786 |
-
2,
|
| 1787 |
-
1,
|
| 1788 |
-
2,
|
| 1789 |
-
1,
|
| 1790 |
-
1,
|
| 1791 |
-
1,
|
| 1792 |
-
1,
|
| 1793 |
-
1,
|
| 1794 |
-
1,
|
| 1795 |
-
1,
|
| 1796 |
-
1,
|
| 1797 |
-
1,
|
| 1798 |
-
1,
|
| 1799 |
-
1,
|
| 1800 |
-
1,
|
| 1801 |
-
1,
|
| 1802 |
-
1,
|
| 1803 |
-
1,
|
| 1804 |
-
1,
|
| 1805 |
-
1,
|
| 1806 |
-
1,
|
| 1807 |
-
1,
|
| 1808 |
-
1,
|
| 1809 |
-
1,
|
| 1810 |
-
0,
|
| 1811 |
-
]
|
| 1812 |
-
check_table = [
|
| 1813 |
-
[0, 0, 0, 0, 0],
|
| 1814 |
-
[0, 0, 0, 0, 0],
|
| 1815 |
-
[0, 0, 0, 0, 0],
|
| 1816 |
-
[0, 0, 0, 0, 0],
|
| 1817 |
-
[0, 0, 0, 0, 0],
|
| 1818 |
-
[0, 0, 0, 0, 0],
|
| 1819 |
-
[0, 0, 0, 0, 0],
|
| 1820 |
-
[0, 0, 0, 0, 0],
|
| 1821 |
-
[0, 0, 0, 0, 0],
|
| 1822 |
-
[0, 0, 0, 0, 0],
|
| 1823 |
-
[0, 0, 0, 0, 0],
|
| 1824 |
-
[0, 0, 0, 0, 0],
|
| 1825 |
-
[0, 0, 0, 0, 0],
|
| 1826 |
-
[0, 0, 0, 0, 0],
|
| 1827 |
-
[0, 0, 0, 0, 0],
|
| 1828 |
-
[0, 0, 0, 0, 0],
|
| 1829 |
-
[0, 0, 0, 0, 0],
|
| 1830 |
-
[0, 0, 0, 0, 0],
|
| 1831 |
-
[0, 0, 0, 0, 0],
|
| 1832 |
-
[0, 0, 0, 0, 0],
|
| 1833 |
-
[0, 0, 0, 0, 0],
|
| 1834 |
-
[0, 0, 0, 0, 0],
|
| 1835 |
-
[0, 0, 0, 0, 0],
|
| 1836 |
-
[0, 0, 0, 0, 0],
|
| 1837 |
-
[0, 0, 0, 0, 0],
|
| 1838 |
-
[0, 0, 0, 0, 0],
|
| 1839 |
-
[0, 0, 0, 0, 0],
|
| 1840 |
-
[0, 0, 0, 0, 0],
|
| 1841 |
-
[0, 0, 0, 0, 0],
|
| 1842 |
-
[0, 0, 0, 0, 0],
|
| 1843 |
-
[0, 0, 0, 0, 0],
|
| 1844 |
-
[0, 0, 0, 0, 0],
|
| 1845 |
-
[0, 0, 0, 0, 0],
|
| 1846 |
-
[0, 0, 0, 0, 0],
|
| 1847 |
-
[0, 0, 0, 0, 0],
|
| 1848 |
-
[0, 0, 0, 0, 0],
|
| 1849 |
-
[0, 0, 0, 0, 0],
|
| 1850 |
-
[0, 0, 0, 0, 0],
|
| 1851 |
-
[0, 0, 0, 0, 0],
|
| 1852 |
-
[0, 0, 0, 0, 0],
|
| 1853 |
-
[0, 0, 0, 0, 0],
|
| 1854 |
-
[0, 0, 0, 0, 0],
|
| 1855 |
-
[0, 0, 0, 0, 0],
|
| 1856 |
-
[0, 0, 0, 0, 0],
|
| 1857 |
-
[0, 0, 0, 0, 0],
|
| 1858 |
-
[0, 0, 0, 0, 0],
|
| 1859 |
-
[0, 0, 0, 0, 0],
|
| 1860 |
-
[0, 0, 0, 0, 0],
|
| 1861 |
-
[0, 0, 0, 0, 0],
|
| 1862 |
-
[0, 0, 0, 0, 0],
|
| 1863 |
-
[0, 0, 0, 0, 0],
|
| 1864 |
-
[0, 0, 0, 0, 0],
|
| 1865 |
-
[0, 0, 0, 0, 0],
|
| 1866 |
-
[0, 0, 0, 0, 0],
|
| 1867 |
-
[0, 0, 0, 0, 0],
|
| 1868 |
-
[0, 0, 0, 0, 0],
|
| 1869 |
-
[0, 0, 0, 0, 0],
|
| 1870 |
-
[0, 0, 0, 0, 0],
|
| 1871 |
-
[0, 0, 0, 0, 0],
|
| 1872 |
-
[0, 0, 0, 0, 0],
|
| 1873 |
-
[0, 0, 0, 0, 0],
|
| 1874 |
-
[1, 1, 0, 0, 194],
|
| 1875 |
-
[1, -1, 0, 0, 193],
|
| 1876 |
-
[0, 0, 0, 0, 0],
|
| 1877 |
-
[0, 0, 0, 0, 0],
|
| 1878 |
-
[0, 0, 0, 0, 0],
|
| 1879 |
-
[0, 0, 0, 0, 0],
|
| 1880 |
-
[0, 0, 0, 0, 0],
|
| 1881 |
-
[0, 0, 0, 0, 0],
|
| 1882 |
-
[0, 0, 0, 0, 0],
|
| 1883 |
-
[0, 0, 0, 0, 0],
|
| 1884 |
-
[0, 0, 0, 0, 0],
|
| 1885 |
-
[0, 0, 0, 0, 0],
|
| 1886 |
-
[0, 0, 0, 0, 0],
|
| 1887 |
-
[0, 0, 0, 0, 0],
|
| 1888 |
-
[0, 0, 0, 0, 0],
|
| 1889 |
-
[0, 0, 0, 0, 0],
|
| 1890 |
-
[0, 0, 0, 0, 0],
|
| 1891 |
-
[0, 0, 0, 0, 0],
|
| 1892 |
-
[0, 0, 0, 0, 0],
|
| 1893 |
-
[0, 0, 0, 0, 0],
|
| 1894 |
-
[0, 0, 0, 0, 0],
|
| 1895 |
-
[0, 0, 0, 0, 0],
|
| 1896 |
-
[0, 0, 0, 0, 0],
|
| 1897 |
-
[0, 0, 0, 0, 0],
|
| 1898 |
-
[0, 0, 0, 0, 0],
|
| 1899 |
-
[0, 0, 0, 0, 0],
|
| 1900 |
-
[0, 0, 0, 0, 0],
|
| 1901 |
-
[0, 0, 0, 0, 0],
|
| 1902 |
-
[0, 0, 0, 0, 0],
|
| 1903 |
-
[0, 0, 0, 0, 0],
|
| 1904 |
-
[1, 0, 1, 0, 164],
|
| 1905 |
-
[0, 0, 0, 0, 0],
|
| 1906 |
-
[0, 0, 0, 0, 0],
|
| 1907 |
-
[1, 0, -1, 0, 161],
|
| 1908 |
-
[0, 0, 0, 0, 0],
|
| 1909 |
-
[0, 0, 0, 0, 0],
|
| 1910 |
-
[0, 0, 0, 0, 0],
|
| 1911 |
-
[0, 0, 0, 0, 0],
|
| 1912 |
-
[0, 0, 0, 0, 0],
|
| 1913 |
-
[0, 0, 0, 0, 0],
|
| 1914 |
-
[0, 0, 0, 0, 0],
|
| 1915 |
-
[0, 0, 0, 0, 0],
|
| 1916 |
-
[1, 0, 0, 1, 152],
|
| 1917 |
-
[0, 0, 0, 0, 0],
|
| 1918 |
-
[0, 0, 0, 0, 0],
|
| 1919 |
-
[0, 0, 0, 0, 0],
|
| 1920 |
-
[0, 0, 0, 0, 0],
|
| 1921 |
-
[0, 0, 0, 0, 0],
|
| 1922 |
-
[0, 0, 0, 0, 0],
|
| 1923 |
-
[1, 0, 0, 1, 145],
|
| 1924 |
-
[1, 0, 0, 1, 144],
|
| 1925 |
-
[0, 0, 0, 0, 0],
|
| 1926 |
-
[0, 0, 0, 0, 0],
|
| 1927 |
-
[0, 0, 0, 0, 0],
|
| 1928 |
-
[0, 0, 0, 0, 0],
|
| 1929 |
-
[0, 0, 0, 0, 0],
|
| 1930 |
-
[0, 0, 0, 0, 0],
|
| 1931 |
-
[1, 0, 0, -1, 137],
|
| 1932 |
-
[0, 0, 0, 0, 0],
|
| 1933 |
-
[0, 0, 0, 0, 0],
|
| 1934 |
-
[0, 0, 0, 0, 0],
|
| 1935 |
-
[1, 0, 1, 0, 133],
|
| 1936 |
-
[1, 0, 1, 0, 132],
|
| 1937 |
-
[1, 1, 0, 0, 131],
|
| 1938 |
-
[1, 1, 0, 0, 130],
|
| 1939 |
-
[0, 0, 0, 0, 0],
|
| 1940 |
-
[0, 0, 0, 0, 0],
|
| 1941 |
-
[0, 0, 0, 0, 0],
|
| 1942 |
-
[0, 0, 0, 0, 0],
|
| 1943 |
-
[0, 0, 0, 0, 0],
|
| 1944 |
-
[0, 0, 0, 0, 0],
|
| 1945 |
-
[0, 0, 0, 0, 0],
|
| 1946 |
-
[0, 0, 0, 0, 0],
|
| 1947 |
-
[0, 0, 0, 0, 0],
|
| 1948 |
-
[0, 0, 0, 0, 0],
|
| 1949 |
-
[0, 0, 0, 0, 0],
|
| 1950 |
-
[0, 0, 0, 0, 0],
|
| 1951 |
-
[0, 0, 0, 0, 0],
|
| 1952 |
-
[0, 0, 0, 0, 0],
|
| 1953 |
-
[0, 0, 0, 0, 0],
|
| 1954 |
-
[0, 0, 0, 0, 0],
|
| 1955 |
-
[0, 0, 0, 0, 0],
|
| 1956 |
-
[0, 0, 0, 0, 0],
|
| 1957 |
-
[0, 0, 0, 0, 0],
|
| 1958 |
-
[0, 0, 0, 0, 0],
|
| 1959 |
-
[0, 0, 0, 0, 0],
|
| 1960 |
-
[0, 0, 0, 0, 0],
|
| 1961 |
-
[0, 0, 0, 0, 0],
|
| 1962 |
-
[0, 0, 0, 0, 0],
|
| 1963 |
-
[0, 0, 0, 0, 0],
|
| 1964 |
-
[0, 0, 0, 0, 0],
|
| 1965 |
-
[0, 0, 0, 0, 0],
|
| 1966 |
-
[0, 0, 0, 0, 0],
|
| 1967 |
-
[0, 0, 0, 0, 0],
|
| 1968 |
-
[1, 0, 0, 1, 100],
|
| 1969 |
-
[0, 0, 0, 0, 0],
|
| 1970 |
-
[1, 0, 0, 1, 98],
|
| 1971 |
-
[0, 0, 0, 0, 0],
|
| 1972 |
-
[1, 0, 0, 1, 96],
|
| 1973 |
-
[0, 0, 0, 0, 0],
|
| 1974 |
-
[0, 0, 0, 0, 0],
|
| 1975 |
-
[0, 0, 0, 0, 0],
|
| 1976 |
-
[0, 0, 0, 0, 0],
|
| 1977 |
-
[0, 0, 0, 0, 0],
|
| 1978 |
-
[0, 0, 0, 0, 0],
|
| 1979 |
-
[0, 0, 0, 0, 0],
|
| 1980 |
-
[1, 0, 1, 0, 88],
|
| 1981 |
-
[0, 0, 0, 0, 0],
|
| 1982 |
-
[0, 0, 0, 0, 0],
|
| 1983 |
-
[0, 0, 0, 0, 0],
|
| 1984 |
-
[0, 0, 0, 0, 0],
|
| 1985 |
-
[0, 0, 0, 0, 0],
|
| 1986 |
-
[1, 0, -1, 0, 82],
|
| 1987 |
-
[0, 0, 0, 0, 0],
|
| 1988 |
-
[0, 0, 0, 0, 0],
|
| 1989 |
-
[0, 0, 0, 0, 0],
|
| 1990 |
-
[0, 0, 0, 0, 0],
|
| 1991 |
-
[0, 0, 0, 0, 0],
|
| 1992 |
-
[0, 0, 0, 0, 0],
|
| 1993 |
-
[0, 0, 0, 0, 0],
|
| 1994 |
-
[1, 0, 1, 0, 74],
|
| 1995 |
-
[0, 0, 0, 0, 0],
|
| 1996 |
-
[1, 0, 1, 0, 72],
|
| 1997 |
-
[0, 0, 0, 0, 0],
|
| 1998 |
-
[1, 0, 0, -1, 70],
|
| 1999 |
-
[0, 0, 0, 0, 0],
|
| 2000 |
-
[0, 0, 0, 0, 0],
|
| 2001 |
-
[1, -1, 0, 0, 67],
|
| 2002 |
-
[0, 0, 0, 0, 0],
|
| 2003 |
-
[1, -1, 0, 0, 65],
|
| 2004 |
-
[0, 0, 0, 0, 0],
|
| 2005 |
-
[0, 0, 0, 0, 0],
|
| 2006 |
-
[0, 0, 0, 0, 0],
|
| 2007 |
-
[0, 0, 0, 0, 0],
|
| 2008 |
-
[0, 0, 0, 0, 0],
|
| 2009 |
-
[0, 0, 0, 0, 0],
|
| 2010 |
-
[0, 0, 0, 0, 0],
|
| 2011 |
-
[0, 0, 0, 0, 0],
|
| 2012 |
-
[1, 1, 0, 0, 56],
|
| 2013 |
-
[0, 0, 0, 0, 0],
|
| 2014 |
-
[0, 0, 0, 0, 0],
|
| 2015 |
-
[0, 0, 0, 0, 0],
|
| 2016 |
-
[1, -1, 0, 0, 52],
|
| 2017 |
-
[0, 0, 0, 0, 0],
|
| 2018 |
-
[0, 0, 0, 0, 0],
|
| 2019 |
-
[0, 0, 0, 0, 0],
|
| 2020 |
-
[0, 0, 0, 0, 0],
|
| 2021 |
-
[0, 0, 0, 0, 0],
|
| 2022 |
-
[0, 0, 0, 0, 0],
|
| 2023 |
-
[0, 0, 0, 0, 0],
|
| 2024 |
-
[1, 1, 0, 0, 44],
|
| 2025 |
-
[0, 0, 0, 0, 0],
|
| 2026 |
-
[0, 0, 0, 0, 0],
|
| 2027 |
-
[0, 0, 0, 0, 0],
|
| 2028 |
-
[1, 1, 0, 0, 40],
|
| 2029 |
-
[0, 0, 0, 0, 0],
|
| 2030 |
-
[1, 0, 0, -1, 38],
|
| 2031 |
-
[1, 0, -1, 0, 37],
|
| 2032 |
-
[0, 0, 0, 0, 0],
|
| 2033 |
-
[0, 0, 0, 0, 0],
|
| 2034 |
-
[0, 0, 0, 0, 0],
|
| 2035 |
-
[1, 0, -1, 0, 33],
|
| 2036 |
-
[0, 0, 0, 0, 0],
|
| 2037 |
-
[0, 0, 0, 0, 0],
|
| 2038 |
-
[0, 0, 0, 0, 0],
|
| 2039 |
-
[0, 0, 0, 0, 0],
|
| 2040 |
-
[1, -1, 0, 0, 28],
|
| 2041 |
-
[0, 0, 0, 0, 0],
|
| 2042 |
-
[1, 0, -1, 0, 26],
|
| 2043 |
-
[1, 0, 0, -1, 25],
|
| 2044 |
-
[0, 0, 0, 0, 0],
|
| 2045 |
-
[0, 0, 0, 0, 0],
|
| 2046 |
-
[0, 0, 0, 0, 0],
|
| 2047 |
-
[0, 0, 0, 0, 0],
|
| 2048 |
-
[1, -1, 0, 0, 20],
|
| 2049 |
-
[0, 0, 0, 0, 0],
|
| 2050 |
-
[1, 0, -1, 0, 18],
|
| 2051 |
-
[0, 0, 0, 0, 0],
|
| 2052 |
-
[0, 0, 0, 0, 0],
|
| 2053 |
-
[0, 0, 0, 0, 0],
|
| 2054 |
-
[0, 0, 0, 0, 0],
|
| 2055 |
-
[0, 0, 0, 0, 0],
|
| 2056 |
-
[0, 0, 0, 0, 0],
|
| 2057 |
-
[0, 0, 0, 0, 0],
|
| 2058 |
-
[0, 0, 0, 0, 0],
|
| 2059 |
-
[1, 0, 0, -1, 9],
|
| 2060 |
-
[0, 0, 0, 0, 0],
|
| 2061 |
-
[0, 0, 0, 0, 0],
|
| 2062 |
-
[1, 0, 0, -1, 6],
|
| 2063 |
-
[0, 0, 0, 0, 0],
|
| 2064 |
-
[0, 0, 0, 0, 0],
|
| 2065 |
-
[0, 0, 0, 0, 0],
|
| 2066 |
-
[0, 0, 0, 0, 0],
|
| 2067 |
-
[0, 0, 0, 0, 0],
|
| 2068 |
-
[0, 0, 0, 0, 0],
|
| 2069 |
-
]
|
| 2070 |
-
tet_table = [
|
| 2071 |
-
[-1, -1, -1, -1, -1, -1],
|
| 2072 |
-
[0, 0, 0, 0, 0, 0],
|
| 2073 |
-
[0, 0, 0, 0, 0, 0],
|
| 2074 |
-
[1, 1, 1, 1, 1, 1],
|
| 2075 |
-
[4, 4, 4, 4, 4, 4],
|
| 2076 |
-
[0, 0, 0, 0, 0, 0],
|
| 2077 |
-
[4, 0, 0, 4, 4, -1],
|
| 2078 |
-
[1, 1, 1, 1, 1, 1],
|
| 2079 |
-
[4, 4, 4, 4, 4, 4],
|
| 2080 |
-
[0, 4, 0, 4, 4, -1],
|
| 2081 |
-
[0, 0, 0, 0, 0, 0],
|
| 2082 |
-
[1, 1, 1, 1, 1, 1],
|
| 2083 |
-
[5, 5, 5, 5, 5, 5],
|
| 2084 |
-
[0, 0, 0, 0, 0, 0],
|
| 2085 |
-
[0, 0, 0, 0, 0, 0],
|
| 2086 |
-
[1, 1, 1, 1, 1, 1],
|
| 2087 |
-
[2, 2, 2, 2, 2, 2],
|
| 2088 |
-
[0, 0, 0, 0, 0, 0],
|
| 2089 |
-
[2, 0, 2, -1, 0, 2],
|
| 2090 |
-
[1, 1, 1, 1, 1, 1],
|
| 2091 |
-
[2, -1, 2, 4, 4, 2],
|
| 2092 |
-
[0, 0, 0, 0, 0, 0],
|
| 2093 |
-
[2, 0, 2, 4, 4, 2],
|
| 2094 |
-
[1, 1, 1, 1, 1, 1],
|
| 2095 |
-
[2, 4, 2, 4, 4, 2],
|
| 2096 |
-
[0, 4, 0, 4, 4, 0],
|
| 2097 |
-
[2, 0, 2, 0, 0, 2],
|
| 2098 |
-
[1, 1, 1, 1, 1, 1],
|
| 2099 |
-
[2, 5, 2, 5, 5, 2],
|
| 2100 |
-
[0, 0, 0, 0, 0, 0],
|
| 2101 |
-
[2, 0, 2, 0, 0, 2],
|
| 2102 |
-
[1, 1, 1, 1, 1, 1],
|
| 2103 |
-
[1, 1, 1, 1, 1, 1],
|
| 2104 |
-
[0, 1, 1, -1, 0, 1],
|
| 2105 |
-
[0, 0, 0, 0, 0, 0],
|
| 2106 |
-
[2, 2, 2, 2, 2, 2],
|
| 2107 |
-
[4, 1, 1, 4, 4, 1],
|
| 2108 |
-
[0, 1, 1, 0, 0, 1],
|
| 2109 |
-
[4, 0, 0, 4, 4, 0],
|
| 2110 |
-
[2, 2, 2, 2, 2, 2],
|
| 2111 |
-
[-1, 1, 1, 4, 4, 1],
|
| 2112 |
-
[0, 1, 1, 4, 4, 1],
|
| 2113 |
-
[0, 0, 0, 0, 0, 0],
|
| 2114 |
-
[2, 2, 2, 2, 2, 2],
|
| 2115 |
-
[5, 1, 1, 5, 5, 1],
|
| 2116 |
-
[0, 1, 1, 0, 0, 1],
|
| 2117 |
-
[0, 0, 0, 0, 0, 0],
|
| 2118 |
-
[2, 2, 2, 2, 2, 2],
|
| 2119 |
-
[1, 1, 1, 1, 1, 1],
|
| 2120 |
-
[0, 0, 0, 0, 0, 0],
|
| 2121 |
-
[0, 0, 0, 0, 0, 0],
|
| 2122 |
-
[8, 8, 8, 8, 8, 8],
|
| 2123 |
-
[1, 1, 1, 4, 4, 1],
|
| 2124 |
-
[0, 0, 0, 0, 0, 0],
|
| 2125 |
-
[4, 0, 0, 4, 4, 0],
|
| 2126 |
-
[4, 4, 4, 4, 4, 4],
|
| 2127 |
-
[1, 1, 1, 4, 4, 1],
|
| 2128 |
-
[0, 4, 0, 4, 4, 0],
|
| 2129 |
-
[0, 0, 0, 0, 0, 0],
|
| 2130 |
-
[4, 4, 4, 4, 4, 4],
|
| 2131 |
-
[1, 1, 1, 5, 5, 1],
|
| 2132 |
-
[0, 0, 0, 0, 0, 0],
|
| 2133 |
-
[0, 0, 0, 0, 0, 0],
|
| 2134 |
-
[5, 5, 5, 5, 5, 5],
|
| 2135 |
-
[6, 6, 6, 6, 6, 6],
|
| 2136 |
-
[6, -1, 0, 6, 0, 6],
|
| 2137 |
-
[6, 0, 0, 6, 0, 6],
|
| 2138 |
-
[6, 1, 1, 6, 1, 6],
|
| 2139 |
-
[4, 4, 4, 4, 4, 4],
|
| 2140 |
-
[0, 0, 0, 0, 0, 0],
|
| 2141 |
-
[4, 0, 0, 4, 4, 4],
|
| 2142 |
-
[1, 1, 1, 1, 1, 1],
|
| 2143 |
-
[6, 4, -1, 6, 4, 6],
|
| 2144 |
-
[6, 4, 0, 6, 4, 6],
|
| 2145 |
-
[6, 0, 0, 6, 0, 6],
|
| 2146 |
-
[6, 1, 1, 6, 1, 6],
|
| 2147 |
-
[5, 5, 5, 5, 5, 5],
|
| 2148 |
-
[0, 0, 0, 0, 0, 0],
|
| 2149 |
-
[0, 0, 0, 0, 0, 0],
|
| 2150 |
-
[1, 1, 1, 1, 1, 1],
|
| 2151 |
-
[2, 2, 2, 2, 2, 2],
|
| 2152 |
-
[0, 0, 0, 0, 0, 0],
|
| 2153 |
-
[2, 0, 2, 2, 0, 2],
|
| 2154 |
-
[1, 1, 1, 1, 1, 1],
|
| 2155 |
-
[2, 2, 2, 2, 2, 2],
|
| 2156 |
-
[0, 0, 0, 0, 0, 0],
|
| 2157 |
-
[2, 0, 2, 2, 2, 2],
|
| 2158 |
-
[1, 1, 1, 1, 1, 1],
|
| 2159 |
-
[2, 4, 2, 2, 4, 2],
|
| 2160 |
-
[0, 4, 0, 4, 4, 0],
|
| 2161 |
-
[2, 0, 2, 2, 0, 2],
|
| 2162 |
-
[1, 1, 1, 1, 1, 1],
|
| 2163 |
-
[2, 2, 2, 2, 2, 2],
|
| 2164 |
-
[0, 0, 0, 0, 0, 0],
|
| 2165 |
-
[0, 0, 0, 0, 0, 0],
|
| 2166 |
-
[1, 1, 1, 1, 1, 1],
|
| 2167 |
-
[6, 1, 1, 6, -1, 6],
|
| 2168 |
-
[6, 1, 1, 6, 0, 6],
|
| 2169 |
-
[6, 0, 0, 6, 0, 6],
|
| 2170 |
-
[6, 2, 2, 6, 2, 6],
|
| 2171 |
-
[4, 1, 1, 4, 4, 1],
|
| 2172 |
-
[0, 1, 1, 0, 0, 1],
|
| 2173 |
-
[4, 0, 0, 4, 4, 4],
|
| 2174 |
-
[2, 2, 2, 2, 2, 2],
|
| 2175 |
-
[6, 1, 1, 6, 4, 6],
|
| 2176 |
-
[6, 1, 1, 6, 4, 6],
|
| 2177 |
-
[6, 0, 0, 6, 0, 6],
|
| 2178 |
-
[6, 2, 2, 6, 2, 6],
|
| 2179 |
-
[5, 1, 1, 5, 5, 1],
|
| 2180 |
-
[0, 1, 1, 0, 0, 1],
|
| 2181 |
-
[0, 0, 0, 0, 0, 0],
|
| 2182 |
-
[2, 2, 2, 2, 2, 2],
|
| 2183 |
-
[1, 1, 1, 1, 1, 1],
|
| 2184 |
-
[0, 0, 0, 0, 0, 0],
|
| 2185 |
-
[0, 0, 0, 0, 0, 0],
|
| 2186 |
-
[6, 6, 6, 6, 6, 6],
|
| 2187 |
-
[1, 1, 1, 1, 1, 1],
|
| 2188 |
-
[0, 0, 0, 0, 0, 0],
|
| 2189 |
-
[0, 0, 0, 0, 0, 0],
|
| 2190 |
-
[4, 4, 4, 4, 4, 4],
|
| 2191 |
-
[1, 1, 1, 1, 4, 1],
|
| 2192 |
-
[0, 4, 0, 4, 4, 0],
|
| 2193 |
-
[0, 0, 0, 0, 0, 0],
|
| 2194 |
-
[4, 4, 4, 4, 4, 4],
|
| 2195 |
-
[1, 1, 1, 1, 1, 1],
|
| 2196 |
-
[0, 0, 0, 0, 0, 0],
|
| 2197 |
-
[0, 5, 0, 5, 0, 5],
|
| 2198 |
-
[5, 5, 5, 5, 5, 5],
|
| 2199 |
-
[5, 5, 5, 5, 5, 5],
|
| 2200 |
-
[0, 5, 0, 5, 0, 5],
|
| 2201 |
-
[-1, 5, 0, 5, 0, 5],
|
| 2202 |
-
[1, 5, 1, 5, 1, 5],
|
| 2203 |
-
[4, 5, -1, 5, 4, 5],
|
| 2204 |
-
[0, 5, 0, 5, 0, 5],
|
| 2205 |
-
[4, 5, 0, 5, 4, 5],
|
| 2206 |
-
[1, 5, 1, 5, 1, 5],
|
| 2207 |
-
[4, 4, 4, 4, 4, 4],
|
| 2208 |
-
[0, 4, 0, 4, 4, 4],
|
| 2209 |
-
[0, 0, 0, 0, 0, 0],
|
| 2210 |
-
[1, 1, 1, 1, 1, 1],
|
| 2211 |
-
[6, 6, 6, 6, 6, 6],
|
| 2212 |
-
[0, 0, 0, 0, 0, 0],
|
| 2213 |
-
[0, 0, 0, 0, 0, 0],
|
| 2214 |
-
[1, 1, 1, 1, 1, 1],
|
| 2215 |
-
[2, 5, 2, 5, -1, 5],
|
| 2216 |
-
[0, 5, 0, 5, 0, 5],
|
| 2217 |
-
[2, 5, 2, 5, 0, 5],
|
| 2218 |
-
[1, 5, 1, 5, 1, 5],
|
| 2219 |
-
[2, 5, 2, 5, 4, 5],
|
| 2220 |
-
[0, 5, 0, 5, 0, 5],
|
| 2221 |
-
[2, 5, 2, 5, 4, 5],
|
| 2222 |
-
[1, 5, 1, 5, 1, 5],
|
| 2223 |
-
[2, 4, 2, 4, 4, 2],
|
| 2224 |
-
[0, 4, 0, 4, 4, 4],
|
| 2225 |
-
[2, 0, 2, 0, 0, 2],
|
| 2226 |
-
[1, 1, 1, 1, 1, 1],
|
| 2227 |
-
[2, 6, 2, 6, 6, 2],
|
| 2228 |
-
[0, 0, 0, 0, 0, 0],
|
| 2229 |
-
[2, 0, 2, 0, 0, 2],
|
| 2230 |
-
[1, 1, 1, 1, 1, 1],
|
| 2231 |
-
[1, 1, 1, 1, 1, 1],
|
| 2232 |
-
[0, 1, 1, 1, 0, 1],
|
| 2233 |
-
[0, 0, 0, 0, 0, 0],
|
| 2234 |
-
[2, 2, 2, 2, 2, 2],
|
| 2235 |
-
[4, 1, 1, 1, 4, 1],
|
| 2236 |
-
[0, 1, 1, 1, 0, 1],
|
| 2237 |
-
[4, 0, 0, 4, 4, 0],
|
| 2238 |
-
[2, 2, 2, 2, 2, 2],
|
| 2239 |
-
[1, 1, 1, 1, 1, 1],
|
| 2240 |
-
[0, 1, 1, 1, 1, 1],
|
| 2241 |
-
[0, 0, 0, 0, 0, 0],
|
| 2242 |
-
[2, 2, 2, 2, 2, 2],
|
| 2243 |
-
[1, 1, 1, 1, 1, 1],
|
| 2244 |
-
[0, 0, 0, 0, 0, 0],
|
| 2245 |
-
[0, 0, 0, 0, 0, 0],
|
| 2246 |
-
[2, 2, 2, 2, 2, 2],
|
| 2247 |
-
[1, 1, 1, 1, 1, 1],
|
| 2248 |
-
[0, 0, 0, 0, 0, 0],
|
| 2249 |
-
[0, 0, 0, 0, 0, 0],
|
| 2250 |
-
[5, 5, 5, 5, 5, 5],
|
| 2251 |
-
[1, 1, 1, 1, 4, 1],
|
| 2252 |
-
[0, 0, 0, 0, 0, 0],
|
| 2253 |
-
[4, 0, 0, 4, 4, 0],
|
| 2254 |
-
[4, 4, 4, 4, 4, 4],
|
| 2255 |
-
[1, 1, 1, 1, 1, 1],
|
| 2256 |
-
[0, 0, 0, 0, 0, 0],
|
| 2257 |
-
[0, 0, 0, 0, 0, 0],
|
| 2258 |
-
[4, 4, 4, 4, 4, 4],
|
| 2259 |
-
[1, 1, 1, 1, 1, 1],
|
| 2260 |
-
[6, 0, 0, 6, 0, 6],
|
| 2261 |
-
[0, 0, 0, 0, 0, 0],
|
| 2262 |
-
[6, 6, 6, 6, 6, 6],
|
| 2263 |
-
[5, 5, 5, 5, 5, 5],
|
| 2264 |
-
[5, 5, 0, 5, 0, 5],
|
| 2265 |
-
[5, 5, 0, 5, 0, 5],
|
| 2266 |
-
[5, 5, 1, 5, 1, 5],
|
| 2267 |
-
[4, 4, 4, 4, 4, 4],
|
| 2268 |
-
[0, 0, 0, 0, 0, 0],
|
| 2269 |
-
[4, 4, 0, 4, 4, 4],
|
| 2270 |
-
[1, 1, 1, 1, 1, 1],
|
| 2271 |
-
[4, 4, 4, 4, 4, 4],
|
| 2272 |
-
[4, 4, 0, 4, 4, 4],
|
| 2273 |
-
[0, 0, 0, 0, 0, 0],
|
| 2274 |
-
[1, 1, 1, 1, 1, 1],
|
| 2275 |
-
[8, 8, 8, 8, 8, 8],
|
| 2276 |
-
[0, 0, 0, 0, 0, 0],
|
| 2277 |
-
[0, 0, 0, 0, 0, 0],
|
| 2278 |
-
[1, 1, 1, 1, 1, 1],
|
| 2279 |
-
[2, 2, 2, 2, 2, 2],
|
| 2280 |
-
[0, 0, 0, 0, 0, 0],
|
| 2281 |
-
[2, 2, 2, 2, 0, 2],
|
| 2282 |
-
[1, 1, 1, 1, 1, 1],
|
| 2283 |
-
[2, 2, 2, 2, 2, 2],
|
| 2284 |
-
[0, 0, 0, 0, 0, 0],
|
| 2285 |
-
[2, 2, 2, 2, 2, 2],
|
| 2286 |
-
[1, 1, 1, 1, 1, 1],
|
| 2287 |
-
[2, 2, 2, 2, 2, 2],
|
| 2288 |
-
[0, 0, 0, 0, 0, 0],
|
| 2289 |
-
[0, 0, 0, 0, 0, 0],
|
| 2290 |
-
[4, 1, 1, 4, 4, 1],
|
| 2291 |
-
[2, 2, 2, 2, 2, 2],
|
| 2292 |
-
[0, 0, 0, 0, 0, 0],
|
| 2293 |
-
[0, 0, 0, 0, 0, 0],
|
| 2294 |
-
[1, 1, 1, 1, 1, 1],
|
| 2295 |
-
[1, 1, 1, 1, 1, 1],
|
| 2296 |
-
[1, 1, 1, 1, 0, 1],
|
| 2297 |
-
[0, 0, 0, 0, 0, 0],
|
| 2298 |
-
[2, 2, 2, 2, 2, 2],
|
| 2299 |
-
[1, 1, 1, 1, 1, 1],
|
| 2300 |
-
[0, 0, 0, 0, 0, 0],
|
| 2301 |
-
[0, 0, 0, 0, 0, 0],
|
| 2302 |
-
[2, 4, 2, 4, 4, 2],
|
| 2303 |
-
[1, 1, 1, 1, 1, 1],
|
| 2304 |
-
[1, 1, 1, 1, 1, 1],
|
| 2305 |
-
[0, 0, 0, 0, 0, 0],
|
| 2306 |
-
[2, 2, 2, 2, 2, 2],
|
| 2307 |
-
[1, 1, 1, 1, 1, 1],
|
| 2308 |
-
[0, 0, 0, 0, 0, 0],
|
| 2309 |
-
[0, 0, 0, 0, 0, 0],
|
| 2310 |
-
[2, 2, 2, 2, 2, 2],
|
| 2311 |
-
[1, 1, 1, 1, 1, 1],
|
| 2312 |
-
[0, 0, 0, 0, 0, 0],
|
| 2313 |
-
[0, 0, 0, 0, 0, 0],
|
| 2314 |
-
[5, 5, 5, 5, 5, 5],
|
| 2315 |
-
[1, 1, 1, 1, 1, 1],
|
| 2316 |
-
[0, 0, 0, 0, 0, 0],
|
| 2317 |
-
[0, 0, 0, 0, 0, 0],
|
| 2318 |
-
[4, 4, 4, 4, 4, 4],
|
| 2319 |
-
[1, 1, 1, 1, 1, 1],
|
| 2320 |
-
[0, 0, 0, 0, 0, 0],
|
| 2321 |
-
[0, 0, 0, 0, 0, 0],
|
| 2322 |
-
[4, 4, 4, 4, 4, 4],
|
| 2323 |
-
[1, 1, 1, 1, 1, 1],
|
| 2324 |
-
[0, 0, 0, 0, 0, 0],
|
| 2325 |
-
[0, 0, 0, 0, 0, 0],
|
| 2326 |
-
[12, 12, 12, 12, 12, 12],
|
| 2327 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/pipeline.py
DELETED
|
@@ -1,311 +0,0 @@
|
|
| 1 |
-
"""Bounded streaming inference over image/mask/point-map requests."""
|
| 2 |
-
|
| 3 |
-
import asyncio
|
| 4 |
-
import threading
|
| 5 |
-
from concurrent.futures import ThreadPoolExecutor
|
| 6 |
-
from dataclasses import dataclass
|
| 7 |
-
from typing import Optional
|
| 8 |
-
|
| 9 |
-
import mlx.core as mx
|
| 10 |
-
|
| 11 |
-
from .flow import LATENTS
|
| 12 |
-
from .mesh import extract_mesh, unique
|
| 13 |
-
from .processing import decode_pose, prepare_inputs
|
| 14 |
-
from .sam3d_objects import Model
|
| 15 |
-
from .sparse import Grid, nonzero
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
@dataclass(frozen=True)
|
| 19 |
-
class Request:
|
| 20 |
-
image: mx.array
|
| 21 |
-
mask: Optional[mx.array] = None
|
| 22 |
-
pointmap: Optional[mx.array] = None
|
| 23 |
-
request_id: str = ""
|
| 24 |
-
seed: int = 42
|
| 25 |
-
ss_steps: Optional[int] = None
|
| 26 |
-
slat_steps: Optional[int] = None
|
| 27 |
-
formats: tuple = ("gaussian", "mesh")
|
| 28 |
-
estimate_depth: bool = True
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
@dataclass(frozen=True)
|
| 32 |
-
class Event:
|
| 33 |
-
request_id: str
|
| 34 |
-
stage: str
|
| 35 |
-
step: int
|
| 36 |
-
total_steps: int
|
| 37 |
-
data: dict
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
def schedule(steps, rescale):
|
| 41 |
-
if not isinstance(steps, int) or isinstance(steps, bool) or steps < 1:
|
| 42 |
-
raise ValueError("Inference step counts must be positive integers")
|
| 43 |
-
return [
|
| 44 |
-
(i / steps) / (1 + (rescale - 1) * (1 - i / steps)) for i in range(steps + 1)
|
| 45 |
-
]
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def sample(flow, state, steps, rescale, strength, condition, *, grid=None, cancel=None):
|
| 49 |
-
"""Euler flow with upstream's additive CFG on timestamps [0, 500]."""
|
| 50 |
-
times = schedule(steps, rescale)
|
| 51 |
-
for i, (t0, t1) in enumerate(zip(times, times[1:]), 1):
|
| 52 |
-
if cancel is not None and cancel.is_set():
|
| 53 |
-
return
|
| 54 |
-
time = mx.array([t0 * 1000], mx.float32)
|
| 55 |
-
if isinstance(state, dict):
|
| 56 |
-
velocity = flow(state, time, condition, mx.zeros(1))
|
| 57 |
-
if strength > 0 and t0 <= 0.5:
|
| 58 |
-
uncond = flow(state, time, mx.zeros_like(condition), mx.zeros(1))
|
| 59 |
-
velocity = {
|
| 60 |
-
n: (1 + strength) * v.astype(mx.float32)
|
| 61 |
-
- strength * uncond[n].astype(mx.float32)
|
| 62 |
-
for n, v in velocity.items()
|
| 63 |
-
}
|
| 64 |
-
state = {
|
| 65 |
-
n: x + (t1 - t0) * velocity[n].astype(mx.float32)
|
| 66 |
-
for n, x in state.items()
|
| 67 |
-
}
|
| 68 |
-
else:
|
| 69 |
-
velocity = flow(state, grid, time, condition)
|
| 70 |
-
if strength > 0 and t0 <= 0.5:
|
| 71 |
-
uncond = flow(state, grid, time, mx.zeros_like(condition))
|
| 72 |
-
velocity = (1 + strength) * velocity.astype(
|
| 73 |
-
mx.float32
|
| 74 |
-
) - strength * uncond.astype(mx.float32)
|
| 75 |
-
state = state + (t1 - t0) * velocity.astype(mx.float32)
|
| 76 |
-
mx.async_eval(state)
|
| 77 |
-
yield i, state
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
def occupancy_grid(logits, prune=1):
|
| 81 |
-
r = logits.shape[1]
|
| 82 |
-
active = nonzero(logits[0, ..., 0] > 0)
|
| 83 |
-
if not active.size:
|
| 84 |
-
raise RuntimeError("The structure decoder produced no occupied voxels")
|
| 85 |
-
coords = mx.stack(
|
| 86 |
-
[mx.zeros_like(active), active // (r * r), active // r % r, active % r], axis=-1
|
| 87 |
-
).astype(mx.int32)
|
| 88 |
-
grid = Grid(coords, r)
|
| 89 |
-
if prune:
|
| 90 |
-
if prune != 1:
|
| 91 |
-
raise ValueError("Only the released one-voxel pruning radius is supported")
|
| 92 |
-
surface = nonzero(mx.any(grid.neighbors() == coords.shape[0], axis=-1))
|
| 93 |
-
coords = coords[surface]
|
| 94 |
-
factor = 1
|
| 95 |
-
if coords.shape[0] > 42000:
|
| 96 |
-
xyz = coords[:, 1:].astype(mx.float32)
|
| 97 |
-
low, high = xyz.min(axis=0), xyz.max(axis=0)
|
| 98 |
-
size = high - low + 1
|
| 99 |
-
target_size = size / 2
|
| 100 |
-
target_low = low + (size - target_size) / 2
|
| 101 |
-
target_high = target_low + target_size - 1
|
| 102 |
-
xyz = mx.round(
|
| 103 |
-
(xyz - low) / mx.maximum(high - low, 1) * (target_size - 1) + target_low
|
| 104 |
-
)
|
| 105 |
-
xyz = mx.clip(
|
| 106 |
-
xyz, target_low.astype(mx.int32), target_high.astype(mx.int32)
|
| 107 |
-
).astype(mx.int32)
|
| 108 |
-
codes, _ = unique((xyz[:, 0] * r + xyz[:, 1]) * r + xyz[:, 2])
|
| 109 |
-
coords = mx.stack(
|
| 110 |
-
[mx.zeros_like(codes), codes // (r * r), codes // r % r, codes % r], axis=-1
|
| 111 |
-
)
|
| 112 |
-
if coords.shape[0] > 42000:
|
| 113 |
-
raise RuntimeError(
|
| 114 |
-
"Occupancy remains too large after upstream downsampling"
|
| 115 |
-
)
|
| 116 |
-
factor = 2
|
| 117 |
-
return Grid(coords, r), factor
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
class Pipeline:
|
| 121 |
-
"""One model, one active stream; input backpressure is one request.
|
| 122 |
-
|
| 123 |
-
GPU work is submitted with async_eval. Dynamic sparse topology requires
|
| 124 |
-
scalar synchronization. Async iteration runs submissions on one worker,
|
| 125 |
-
leaving the caller's event loop responsive; it never buffers whole videos.
|
| 126 |
-
"""
|
| 127 |
-
|
| 128 |
-
def __init__(self, model):
|
| 129 |
-
self.model = model
|
| 130 |
-
self._lock = threading.Lock()
|
| 131 |
-
|
| 132 |
-
@classmethod
|
| 133 |
-
def from_pretrained(cls, path):
|
| 134 |
-
return cls(Model.from_pretrained(path))
|
| 135 |
-
|
| 136 |
-
def _run(self, request, cancel):
|
| 137 |
-
config, model = self.model.config, self.model
|
| 138 |
-
formats = tuple(request.formats)
|
| 139 |
-
if not formats or set(formats) - {"gaussian", "gaussian_4", "mesh"}:
|
| 140 |
-
raise ValueError("formats must contain gaussian, gaussian_4, or mesh")
|
| 141 |
-
ss_steps = config.ss_steps if request.ss_steps is None else request.ss_steps
|
| 142 |
-
slat_steps = (
|
| 143 |
-
config.slat_steps if request.slat_steps is None else request.slat_steps
|
| 144 |
-
)
|
| 145 |
-
schedule(ss_steps, config.ss_rescale_t)
|
| 146 |
-
schedule(slat_steps, config.slat_rescale_t)
|
| 147 |
-
pointmap = request.pointmap
|
| 148 |
-
if pointmap is None and request.estimate_depth and config.depth_model:
|
| 149 |
-
pointmap = model.depth_model(request.image, config.depth_num_tokens)
|
| 150 |
-
mx.async_eval(pointmap)
|
| 151 |
-
yield Event(request.request_id, "depth", 1, 1, {"pointmap": pointmap})
|
| 152 |
-
inputs, metadata = prepare_inputs(
|
| 153 |
-
request.image, request.mask, pointmap, size=config.image_size
|
| 154 |
-
)
|
| 155 |
-
condition = model.ss_condition_embedder(inputs)
|
| 156 |
-
mx.async_eval(condition)
|
| 157 |
-
yield Event(
|
| 158 |
-
request.request_id,
|
| 159 |
-
"conditioning",
|
| 160 |
-
1,
|
| 161 |
-
1,
|
| 162 |
-
{"pointmap_conditioned": metadata["pointmap_conditioned"]},
|
| 163 |
-
)
|
| 164 |
-
keys = mx.random.split(mx.random.key(request.seed), len(LATENTS) + 1)
|
| 165 |
-
state = {
|
| 166 |
-
name: mx.random.normal(
|
| 167 |
-
(1, config.latent_resolution**3 if name == "shape" else 1, channels),
|
| 168 |
-
key=keys[i],
|
| 169 |
-
)
|
| 170 |
-
for i, (name, channels) in enumerate(LATENTS.items())
|
| 171 |
-
}
|
| 172 |
-
for step, state in sample(
|
| 173 |
-
model.ss_generator,
|
| 174 |
-
state,
|
| 175 |
-
ss_steps,
|
| 176 |
-
config.ss_rescale_t,
|
| 177 |
-
config.ss_guidance,
|
| 178 |
-
condition,
|
| 179 |
-
cancel=cancel,
|
| 180 |
-
):
|
| 181 |
-
yield Event(
|
| 182 |
-
request.request_id, "structure", step, ss_steps, {"latents": state}
|
| 183 |
-
)
|
| 184 |
-
if cancel.is_set():
|
| 185 |
-
return
|
| 186 |
-
logits = model.ss_decoder(state["shape"])
|
| 187 |
-
mx.async_eval(logits)
|
| 188 |
-
grid, factor = occupancy_grid(logits, config.downsample_ss_dist)
|
| 189 |
-
pose = decode_pose(state, metadata, factor)
|
| 190 |
-
yield Event(
|
| 191 |
-
request.request_id, "occupancy", 1, 1, {"coords": grid.coords, "pose": pose}
|
| 192 |
-
)
|
| 193 |
-
condition = model.slat_condition_embedder(inputs)
|
| 194 |
-
mx.async_eval(condition)
|
| 195 |
-
latent = mx.random.normal(
|
| 196 |
-
(grid.coords.shape[0], config.latent_channels), key=keys[-1]
|
| 197 |
-
)
|
| 198 |
-
for step, latent in sample(
|
| 199 |
-
model.slat_generator,
|
| 200 |
-
latent,
|
| 201 |
-
slat_steps,
|
| 202 |
-
config.slat_rescale_t,
|
| 203 |
-
config.slat_guidance,
|
| 204 |
-
condition,
|
| 205 |
-
grid=grid,
|
| 206 |
-
cancel=cancel,
|
| 207 |
-
):
|
| 208 |
-
yield Event(
|
| 209 |
-
request.request_id,
|
| 210 |
-
"latent",
|
| 211 |
-
step,
|
| 212 |
-
slat_steps,
|
| 213 |
-
{"features": latent, "coords": grid.coords},
|
| 214 |
-
)
|
| 215 |
-
if cancel.is_set():
|
| 216 |
-
return
|
| 217 |
-
latent = latent * mx.array(config.slat_std) + mx.array(config.slat_mean)
|
| 218 |
-
result = {
|
| 219 |
-
"coords": grid.coords,
|
| 220 |
-
"latents": latent,
|
| 221 |
-
"pose": pose,
|
| 222 |
-
"pointmap_conditioned": metadata["pointmap_conditioned"],
|
| 223 |
-
}
|
| 224 |
-
for index, kind in enumerate(formats, 1):
|
| 225 |
-
if cancel.is_set():
|
| 226 |
-
return
|
| 227 |
-
if kind == "mesh":
|
| 228 |
-
features, mesh_grid = model.slat_decoder_mesh(latent, grid)
|
| 229 |
-
mx.async_eval(features)
|
| 230 |
-
output = extract_mesh(features, mesh_grid)
|
| 231 |
-
else:
|
| 232 |
-
decoder = (
|
| 233 |
-
model.slat_decoder_gs
|
| 234 |
-
if kind == "gaussian"
|
| 235 |
-
else model.slat_decoder_gs_4
|
| 236 |
-
)
|
| 237 |
-
output = decoder(latent, grid)
|
| 238 |
-
mx.async_eval(output)
|
| 239 |
-
result[kind] = output
|
| 240 |
-
yield Event(request.request_id, kind, index, len(formats), output)
|
| 241 |
-
mx.async_eval(result)
|
| 242 |
-
yield Event(request.request_id, "complete", 1, 1, result)
|
| 243 |
-
|
| 244 |
-
def stream(self, request):
|
| 245 |
-
if not self._lock.acquire(blocking=False):
|
| 246 |
-
raise RuntimeError("A stream is already using this pipeline")
|
| 247 |
-
cancel = threading.Event()
|
| 248 |
-
try:
|
| 249 |
-
yield from self._run(request, cancel)
|
| 250 |
-
finally:
|
| 251 |
-
cancel.set()
|
| 252 |
-
self._lock.release()
|
| 253 |
-
|
| 254 |
-
def generate(self, image, mask=None, pointmap=None, **kwargs):
|
| 255 |
-
for event in self.stream(Request(image, mask, pointmap, **kwargs)):
|
| 256 |
-
if event.stage == "complete":
|
| 257 |
-
mx.eval(event.data)
|
| 258 |
-
return event.data
|
| 259 |
-
|
| 260 |
-
async def astream(self, requests):
|
| 261 |
-
"""Consume an iterable or async iterable, yielding ordered Event objects.
|
| 262 |
-
|
| 263 |
-
Cancellation stops further submissions and closes the active request.
|
| 264 |
-
Already submitted GPU commands finish before worker stream cleanup.
|
| 265 |
-
"""
|
| 266 |
-
if not self._lock.acquire(blocking=False):
|
| 267 |
-
raise RuntimeError("A stream is already using this pipeline")
|
| 268 |
-
executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="sam3d-mlx")
|
| 269 |
-
loop = asyncio.get_running_loop()
|
| 270 |
-
cancel = threading.Event()
|
| 271 |
-
iterator = None
|
| 272 |
-
|
| 273 |
-
def advance():
|
| 274 |
-
return next(iterator, None)
|
| 275 |
-
|
| 276 |
-
async def inputs():
|
| 277 |
-
if hasattr(requests, "__aiter__"):
|
| 278 |
-
async for item in requests:
|
| 279 |
-
yield item
|
| 280 |
-
else:
|
| 281 |
-
for item in requests:
|
| 282 |
-
yield item
|
| 283 |
-
|
| 284 |
-
def cleanup():
|
| 285 |
-
if iterator is not None:
|
| 286 |
-
iterator.close()
|
| 287 |
-
mx.synchronize()
|
| 288 |
-
clear = getattr(mx, "clear_streams", None)
|
| 289 |
-
if clear is not None:
|
| 290 |
-
clear()
|
| 291 |
-
|
| 292 |
-
try:
|
| 293 |
-
async for request in inputs():
|
| 294 |
-
iterator = self._run(request, cancel)
|
| 295 |
-
while True:
|
| 296 |
-
event = await loop.run_in_executor(executor, advance)
|
| 297 |
-
if event is None:
|
| 298 |
-
break
|
| 299 |
-
yield event
|
| 300 |
-
iterator = None
|
| 301 |
-
finally:
|
| 302 |
-
cancel.set()
|
| 303 |
-
# Cleanup is queued behind any in-flight advance on the same worker.
|
| 304 |
-
pending_cleanup = loop.run_in_executor(executor, cleanup)
|
| 305 |
-
|
| 306 |
-
def release(_):
|
| 307 |
-
executor.shutdown(wait=False)
|
| 308 |
-
self._lock.release()
|
| 309 |
-
|
| 310 |
-
pending_cleanup.add_done_callback(release)
|
| 311 |
-
await asyncio.shield(pending_cleanup)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/processing.py
DELETED
|
@@ -1,213 +0,0 @@
|
|
| 1 |
-
# Adapted from Meta SAM 3D Objects. See LICENSE in this directory.
|
| 2 |
-
"""MLX image/mask/point-map preprocessing and layout decoding."""
|
| 3 |
-
|
| 4 |
-
import mlx.core as mx
|
| 5 |
-
|
| 6 |
-
from .resize import resize
|
| 7 |
-
from .sparse import nonzero
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def _square(x, fill=0):
|
| 11 |
-
h, w = x.shape[:2]
|
| 12 |
-
side = max(h, w)
|
| 13 |
-
top, left = (side - h) // 2, (side - w) // 2
|
| 14 |
-
return mx.pad(
|
| 15 |
-
x,
|
| 16 |
-
[(top, side - h - top), (left, side - w - left), (0, 0)],
|
| 17 |
-
constant_values=fill,
|
| 18 |
-
)
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
def _crop(x, box):
|
| 22 |
-
left, top, right, bottom = box
|
| 23 |
-
h, w = x.shape[:2]
|
| 24 |
-
pads = [
|
| 25 |
-
(max(0, -top), max(0, bottom - h)),
|
| 26 |
-
(max(0, -left), max(0, right - w)),
|
| 27 |
-
(0, 0),
|
| 28 |
-
]
|
| 29 |
-
x = mx.pad(x, pads)
|
| 30 |
-
y, z = max(top, 0), max(left, 0)
|
| 31 |
-
return x[y : y + bottom - top, z : z + right - left]
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
def _median(x):
|
| 35 |
-
x = x.reshape(-1)
|
| 36 |
-
valid = ~mx.isnan(x)
|
| 37 |
-
count = int(valid.sum().item())
|
| 38 |
-
if not count:
|
| 39 |
-
return mx.array(float("nan"))
|
| 40 |
-
return mx.sort(mx.where(valid, x, float("inf")))[(count - 1) // 2]
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
def prepare_inputs(image, mask, pointmap=None, *, size=518):
|
| 44 |
-
"""Accept HWC RGB/RGBA and HW masks; floating RGB must be in [0, 1].
|
| 45 |
-
|
| 46 |
-
Point maps use the upstream PyTorch3D camera convention (+X left,
|
| 47 |
-
+Y up, +Z forward). Omitted maps use the trained point-map dropout.
|
| 48 |
-
"""
|
| 49 |
-
if image.ndim != 3 or image.shape[-1] not in (3, 4):
|
| 50 |
-
raise ValueError("Expected an HWC RGB or RGBA image")
|
| 51 |
-
if mask is None:
|
| 52 |
-
if image.shape[-1] != 4:
|
| 53 |
-
raise ValueError("Provide an object mask or an RGBA image")
|
| 54 |
-
mask = image[..., 3]
|
| 55 |
-
image = image[..., :3]
|
| 56 |
-
if image.dtype == mx.uint8:
|
| 57 |
-
image = image.astype(mx.float32) / 255
|
| 58 |
-
else:
|
| 59 |
-
image = image.astype(mx.float32)
|
| 60 |
-
if not bool(mx.all(mx.isfinite(image) & (image >= 0) & (image <= 1)).item()):
|
| 61 |
-
raise ValueError("Floating-point image values must be finite and in [0, 1]")
|
| 62 |
-
if mask.ndim == 3 and mask.shape[-1] == 1:
|
| 63 |
-
mask = mask[..., 0]
|
| 64 |
-
if mask.shape != image.shape[:2]:
|
| 65 |
-
raise ValueError("The mask must have the same height and width as the image")
|
| 66 |
-
threshold = 127 if mask.dtype == mx.uint8 and int(mask.max().item()) > 1 else 0.5
|
| 67 |
-
mask = (mask > threshold).astype(mx.float32)[..., None]
|
| 68 |
-
ys, xs = nonzero(mx.any(mask[..., 0] > 0, axis=1)), nonzero(
|
| 69 |
-
mx.any(mask[..., 0] > 0, axis=0)
|
| 70 |
-
)
|
| 71 |
-
if ys.size < 2 or xs.size < 2:
|
| 72 |
-
raise ValueError("The object mask must span at least two rows and columns")
|
| 73 |
-
x0, x1, y0, y1 = (int(v.item()) for v in (xs[0], xs[-1], ys[0], ys[-1]))
|
| 74 |
-
side = int(max(x1 - x0, y1 - y0, 2) * 1.2)
|
| 75 |
-
cx, cy = (x0 + x1) / 2, (y0 + y1) / 2
|
| 76 |
-
box = (
|
| 77 |
-
int(cx - side // 2),
|
| 78 |
-
int(cy - side // 2),
|
| 79 |
-
int(cx + side // 2),
|
| 80 |
-
int(cy + side // 2),
|
| 81 |
-
)
|
| 82 |
-
result = {}
|
| 83 |
-
for name, value in (("image", image), ("mask", mask)):
|
| 84 |
-
for output, raw in (
|
| 85 |
-
(name, _crop(value, box)),
|
| 86 |
-
("rgb_image" if name == "image" else "rgb_image_mask", value),
|
| 87 |
-
):
|
| 88 |
-
result[output] = resize(
|
| 89 |
-
_square(raw)[None],
|
| 90 |
-
size,
|
| 91 |
-
size,
|
| 92 |
-
nearest=name == "mask",
|
| 93 |
-
antialias=name == "image",
|
| 94 |
-
)
|
| 95 |
-
shift, scale = mx.zeros(3), mx.ones(3)
|
| 96 |
-
if pointmap is not None:
|
| 97 |
-
if pointmap.ndim != 3 or pointmap.shape[-1] != 3:
|
| 98 |
-
raise ValueError("Expected an HWC point map with XYZ channels")
|
| 99 |
-
pointmap = resize(
|
| 100 |
-
pointmap[None].astype(mx.float32),
|
| 101 |
-
image.shape[0],
|
| 102 |
-
image.shape[1],
|
| 103 |
-
nearest=True,
|
| 104 |
-
)[0]
|
| 105 |
-
selected = pointmap.reshape(-1, 3)[nonzero(mask[..., 0] > 0)]
|
| 106 |
-
if not bool(mx.any(mx.isfinite(selected)).item()):
|
| 107 |
-
raise ValueError("The object mask contains no finite point-map values")
|
| 108 |
-
shift = mx.stack([_median(selected[:, c]) for c in range(3)])
|
| 109 |
-
scale_value = _median(mx.max(mx.abs(pointmap - shift), axis=-1))
|
| 110 |
-
if (
|
| 111 |
-
not bool(mx.all(mx.isfinite(shift)).item())
|
| 112 |
-
or not bool(mx.isfinite(scale_value).item())
|
| 113 |
-
or float(scale_value.item()) <= 0
|
| 114 |
-
):
|
| 115 |
-
raise ValueError("The point map has invalid or zero spatial scale")
|
| 116 |
-
scale = mx.broadcast_to(scale_value, (3,))
|
| 117 |
-
normalized = (pointmap - shift) / scale
|
| 118 |
-
result["pointmap"] = resize(
|
| 119 |
-
_square(_crop(normalized, box), float("nan"))[None],
|
| 120 |
-
size,
|
| 121 |
-
size,
|
| 122 |
-
nearest=True,
|
| 123 |
-
)
|
| 124 |
-
result["rgb_pointmap"] = resize(
|
| 125 |
-
_square(normalized)[None], size, size, nearest=True
|
| 126 |
-
)
|
| 127 |
-
else:
|
| 128 |
-
result["pointmap"] = result["rgb_pointmap"] = None
|
| 129 |
-
return result, {
|
| 130 |
-
"pointmap_scale": scale,
|
| 131 |
-
"pointmap_shift": shift,
|
| 132 |
-
"pointmap_conditioned": pointmap is not None,
|
| 133 |
-
}
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
def _normalize(x):
|
| 137 |
-
return x / mx.maximum(mx.sqrt(mx.sum(x * x, axis=-1, keepdims=True)), 1e-12)
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
def _cross(a, b):
|
| 141 |
-
return mx.stack(
|
| 142 |
-
[
|
| 143 |
-
a[..., 1] * b[..., 2] - a[..., 2] * b[..., 1],
|
| 144 |
-
a[..., 2] * b[..., 0] - a[..., 0] * b[..., 2],
|
| 145 |
-
a[..., 0] * b[..., 1] - a[..., 1] * b[..., 0],
|
| 146 |
-
],
|
| 147 |
-
axis=-1,
|
| 148 |
-
)
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
def decode_pose(latents, metadata, downsample_factor=1):
|
| 152 |
-
mean = mx.array(
|
| 153 |
-
[
|
| 154 |
-
-0.06366084883674913,
|
| 155 |
-
0.008438224692279752,
|
| 156 |
-
0.00017084786438302483,
|
| 157 |
-
0.0007126610473540038,
|
| 158 |
-
-0.0030916726538816417,
|
| 159 |
-
0.5166093753457688,
|
| 160 |
-
]
|
| 161 |
-
)
|
| 162 |
-
std = mx.array(
|
| 163 |
-
[
|
| 164 |
-
0.6656971967514863,
|
| 165 |
-
0.6787012271867754,
|
| 166 |
-
0.30345010594844524,
|
| 167 |
-
0.4394504420678794,
|
| 168 |
-
0.39817973931717104,
|
| 169 |
-
0.6176286868761914,
|
| 170 |
-
]
|
| 171 |
-
)
|
| 172 |
-
rot = latents["6drotation_normalized"].astype(mx.float32).reshape(6) * std + mean
|
| 173 |
-
a = _normalize(rot[:3])
|
| 174 |
-
b = _normalize(rot[3:] - mx.sum(a * rot[3:]) * a)
|
| 175 |
-
matrix = mx.stack([a, b, _cross(a, b)], axis=-1)
|
| 176 |
-
m = matrix
|
| 177 |
-
qabs = mx.sqrt(
|
| 178 |
-
mx.maximum(
|
| 179 |
-
mx.array([1.0, 1.0, 1.0, 1.0])
|
| 180 |
-
+ mx.stack(
|
| 181 |
-
[
|
| 182 |
-
m[0, 0] + m[1, 1] + m[2, 2],
|
| 183 |
-
m[0, 0] - m[1, 1] - m[2, 2],
|
| 184 |
-
-m[0, 0] + m[1, 1] - m[2, 2],
|
| 185 |
-
-m[0, 0] - m[1, 1] + m[2, 2],
|
| 186 |
-
]
|
| 187 |
-
),
|
| 188 |
-
0,
|
| 189 |
-
)
|
| 190 |
-
)
|
| 191 |
-
qw, qx, qy, qz = qabs * qabs
|
| 192 |
-
candidates = mx.stack(
|
| 193 |
-
[
|
| 194 |
-
mx.stack([qw, m[2, 1] - m[1, 2], m[0, 2] - m[2, 0], m[1, 0] - m[0, 1]]),
|
| 195 |
-
mx.stack([m[2, 1] - m[1, 2], qx, m[1, 0] + m[0, 1], m[0, 2] + m[2, 0]]),
|
| 196 |
-
mx.stack([m[0, 2] - m[2, 0], m[1, 0] + m[0, 1], qy, m[2, 1] + m[1, 2]]),
|
| 197 |
-
mx.stack([m[1, 0] - m[0, 1], m[2, 0] + m[0, 2], m[2, 1] + m[1, 2], qz]),
|
| 198 |
-
]
|
| 199 |
-
)
|
| 200 |
-
quaternion = (candidates / (2 * mx.maximum(qabs[:, None], 0.1)))[mx.argmax(qabs)]
|
| 201 |
-
quaternion = mx.where(quaternion[0] < 0, -quaternion, quaternion)
|
| 202 |
-
scale = mx.exp(latents["scale"].reshape(3)) * metadata["pointmap_scale"]
|
| 203 |
-
scale = mx.broadcast_to(mx.mean(scale) * downsample_factor, (3,))
|
| 204 |
-
translation = (
|
| 205 |
-
latents["translation"].reshape(3) * metadata["pointmap_scale"]
|
| 206 |
-
+ metadata["pointmap_shift"]
|
| 207 |
-
)
|
| 208 |
-
return {
|
| 209 |
-
"rotation": quaternion,
|
| 210 |
-
"rotation_matrix": matrix,
|
| 211 |
-
"translation": translation,
|
| 212 |
-
"scale": scale,
|
| 213 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/resize.py
DELETED
|
@@ -1,70 +0,0 @@
|
|
| 1 |
-
"""Channel-last resizing without image or array dependencies."""
|
| 2 |
-
|
| 3 |
-
import mlx.core as mx
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
def resize_bicubic(x, height, width, *, antialias=False, offset=0.0):
|
| 7 |
-
"""PyTorch bicubic coefficients, including the DINO scale-factor offset."""
|
| 8 |
-
for axis, size in ((2, width), (1, height)):
|
| 9 |
-
old = x.shape[axis]
|
| 10 |
-
if old == size and not offset:
|
| 11 |
-
continue
|
| 12 |
-
scale = old / (size + offset)
|
| 13 |
-
center = (mx.arange(size, dtype=mx.float32) + 0.5) * scale - 0.5
|
| 14 |
-
support = 2 * max(scale, 1) if antialias else 2
|
| 15 |
-
taps = int(support) + 1
|
| 16 |
-
indices = mx.floor(center).astype(mx.int32)[:, None] + mx.arange(
|
| 17 |
-
-taps, taps + 1
|
| 18 |
-
)
|
| 19 |
-
distance = mx.abs(indices - center[:, None]) / (
|
| 20 |
-
max(scale, 1) if antialias else 1
|
| 21 |
-
)
|
| 22 |
-
a = -0.5 if antialias else -0.75
|
| 23 |
-
weights = mx.where(
|
| 24 |
-
distance < 1,
|
| 25 |
-
((a + 2) * distance - (a + 3)) * distance**2 + 1,
|
| 26 |
-
mx.where(
|
| 27 |
-
distance < 2,
|
| 28 |
-
((a * distance - 5 * a) * distance + 8 * a) * distance - 4 * a,
|
| 29 |
-
0,
|
| 30 |
-
),
|
| 31 |
-
)
|
| 32 |
-
if antialias:
|
| 33 |
-
weights = mx.where((indices >= 0) & (indices < old), weights, 0)
|
| 34 |
-
weights = weights / weights.sum(axis=-1, keepdims=True)
|
| 35 |
-
gathered = mx.take(x, mx.clip(indices, 0, old - 1), axis=axis)
|
| 36 |
-
shape = [1] * gathered.ndim
|
| 37 |
-
shape[axis : axis + 2] = weights.shape
|
| 38 |
-
x = mx.sum(gathered * weights.reshape(shape).astype(x.dtype), axis=axis + 1)
|
| 39 |
-
return x
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def resize(x, height, width, *, nearest=False, antialias=False):
|
| 43 |
-
"""Match PyTorch interpolate with align_corners=False (NHWC)."""
|
| 44 |
-
for axis, size in ((1, height), (2, width)):
|
| 45 |
-
old = x.shape[axis]
|
| 46 |
-
if old == size:
|
| 47 |
-
continue
|
| 48 |
-
if nearest:
|
| 49 |
-
idx = mx.minimum(mx.arange(size) * old // size, old - 1)
|
| 50 |
-
x = mx.take(x, idx, axis=axis)
|
| 51 |
-
continue
|
| 52 |
-
scale = old / size
|
| 53 |
-
center = (mx.arange(size, dtype=mx.float32) + 0.5) * scale - 0.5
|
| 54 |
-
if antialias and scale > 1:
|
| 55 |
-
support = int(scale) + 1
|
| 56 |
-
offsets = mx.arange(-support, support + 1)
|
| 57 |
-
indices = mx.floor(center).astype(mx.int32)[:, None] + offsets
|
| 58 |
-
weights = mx.maximum(1 - mx.abs(indices - center[:, None]) / scale, 0)
|
| 59 |
-
weights = mx.where((indices >= 0) & (indices < old), weights, 0)
|
| 60 |
-
weights = weights / weights.sum(axis=-1, keepdims=True)
|
| 61 |
-
else:
|
| 62 |
-
low = mx.floor(center).astype(mx.int32)
|
| 63 |
-
indices = mx.stack([low, low + 1], axis=-1)
|
| 64 |
-
f = center - low
|
| 65 |
-
weights = mx.stack([1 - f, f], axis=-1)
|
| 66 |
-
gathered = mx.take(x, mx.clip(indices, 0, old - 1), axis=axis)
|
| 67 |
-
shape = [1] * gathered.ndim
|
| 68 |
-
shape[axis : axis + 2] = weights.shape
|
| 69 |
-
x = mx.sum(gathered * weights.reshape(shape).astype(x.dtype), axis=axis + 1)
|
| 70 |
-
return x
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/sam3d_objects.py
DELETED
|
@@ -1,72 +0,0 @@
|
|
| 1 |
-
# Adapted from Meta SAM 3D Objects. See LICENSE in this directory.
|
| 2 |
-
"""Frozen inference models for SAM 3D Objects."""
|
| 3 |
-
|
| 4 |
-
import json
|
| 5 |
-
from pathlib import Path
|
| 6 |
-
|
| 7 |
-
import mlx.core as mx
|
| 8 |
-
import mlx.nn as nn
|
| 9 |
-
|
| 10 |
-
from .config import ModelConfig
|
| 11 |
-
from .decoders import GaussianDecoder, MeshDecoder, StructureDecoder
|
| 12 |
-
from .flow import LatentFlow, StructureFlow
|
| 13 |
-
from .vision import ConditionEncoder
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
class Model(nn.Module):
|
| 17 |
-
def __init__(self, config):
|
| 18 |
-
super().__init__()
|
| 19 |
-
self.config = config
|
| 20 |
-
self.ss_generator = StructureFlow(config)
|
| 21 |
-
self.slat_generator = LatentFlow(config)
|
| 22 |
-
self.ss_condition_embedder = ConditionEncoder(config, pointmap=True)
|
| 23 |
-
self.slat_condition_embedder = ConditionEncoder(config)
|
| 24 |
-
self.ss_decoder = StructureDecoder(config)
|
| 25 |
-
self.slat_decoder_gs = GaussianDecoder(config)
|
| 26 |
-
self.slat_decoder_gs_4 = GaussianDecoder(config, count=4)
|
| 27 |
-
self.slat_decoder_mesh = MeshDecoder(config)
|
| 28 |
-
if config.depth_model:
|
| 29 |
-
from .depth import DepthModel
|
| 30 |
-
|
| 31 |
-
self.depth_model = DepthModel()
|
| 32 |
-
self.eval()
|
| 33 |
-
self.freeze()
|
| 34 |
-
|
| 35 |
-
def train(self, mode=True):
|
| 36 |
-
if mode:
|
| 37 |
-
raise ValueError("SAM 3D Objects is an inference-only model")
|
| 38 |
-
return super().train(False)
|
| 39 |
-
|
| 40 |
-
@classmethod
|
| 41 |
-
def from_pretrained(cls, path):
|
| 42 |
-
"""Load a local converted bundle using MLX alone, with strict weights."""
|
| 43 |
-
root = Path(path)
|
| 44 |
-
config = ModelConfig.from_dict(json.loads((root / "config.json").read_text()))
|
| 45 |
-
model = cls(config)
|
| 46 |
-
index = root / "model.safetensors.index.json"
|
| 47 |
-
if index.exists():
|
| 48 |
-
files = sorted(set(json.loads(index.read_text())["weight_map"].values()))
|
| 49 |
-
else:
|
| 50 |
-
files = ["model.safetensors"]
|
| 51 |
-
weights = {}
|
| 52 |
-
for name in files:
|
| 53 |
-
if Path(name).name != name:
|
| 54 |
-
raise ValueError("Checkpoint shards must be in the model directory")
|
| 55 |
-
shard = mx.load(str(root / name))
|
| 56 |
-
if weights.keys() & shard.keys():
|
| 57 |
-
raise ValueError("Duplicate tensor names across checkpoint shards")
|
| 58 |
-
weights.update(shard)
|
| 59 |
-
model.load_weights(list(weights.items()), strict=True)
|
| 60 |
-
model.freeze()
|
| 61 |
-
model.eval()
|
| 62 |
-
mx.async_eval(model.parameters())
|
| 63 |
-
return model
|
| 64 |
-
|
| 65 |
-
@staticmethod
|
| 66 |
-
def sanitize(weights):
|
| 67 |
-
return weights
|
| 68 |
-
|
| 69 |
-
def __call__(self, *args, **kwargs):
|
| 70 |
-
from .pipeline import Pipeline
|
| 71 |
-
|
| 72 |
-
return Pipeline(self).generate(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/sparse.py
DELETED
|
@@ -1,172 +0,0 @@
|
|
| 1 |
-
# Adapted from mlx_vlm.models.moge3.sparse and Meta SAM 3D Objects.
|
| 2 |
-
"""Sparse inference operators using MLX gathers, reductions, and attention."""
|
| 3 |
-
|
| 4 |
-
from dataclasses import dataclass, field
|
| 5 |
-
from itertools import product
|
| 6 |
-
|
| 7 |
-
import mlx.core as mx
|
| 8 |
-
import mlx.nn as nn
|
| 9 |
-
|
| 10 |
-
from .layers import attend
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
def nonzero(mask):
|
| 14 |
-
mask = mask.reshape(-1)
|
| 15 |
-
count = int(mx.sum(mask).item())
|
| 16 |
-
return mx.sort(mx.where(mask, mx.arange(mask.size), mask.size))[:count]
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def coord_keys(coords, resolution):
|
| 20 |
-
return (
|
| 21 |
-
(coords[:, 0] * resolution + coords[:, 1]) * resolution + coords[:, 2]
|
| 22 |
-
) * resolution + coords[:, 3]
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
@dataclass
|
| 26 |
-
class Grid:
|
| 27 |
-
coords: mx.array
|
| 28 |
-
resolution: int
|
| 29 |
-
cache: dict = field(default_factory=dict)
|
| 30 |
-
|
| 31 |
-
def neighbors(self):
|
| 32 |
-
if "neighbors" not in self.cache:
|
| 33 |
-
offsets = mx.array(list(product((-1, 0, 1), repeat=3)), dtype=mx.int32)
|
| 34 |
-
positions = self.coords[:, None, 1:] + offsets[None]
|
| 35 |
-
valid = mx.all((positions >= 0) & (positions < self.resolution), axis=-1)
|
| 36 |
-
r = self.resolution
|
| 37 |
-
nkeys = (
|
| 38 |
-
(self.coords[:, :1] * r + positions[:, :, 0]) * r + positions[:, :, 1]
|
| 39 |
-
) * r + positions[:, :, 2]
|
| 40 |
-
keys = coord_keys(self.coords, r)
|
| 41 |
-
order = mx.argsort(keys)
|
| 42 |
-
sorted_keys = keys[order]
|
| 43 |
-
index = mx.minimum(
|
| 44 |
-
mx.searchsorted(sorted_keys, nkeys.reshape(-1)), keys.size - 1
|
| 45 |
-
).reshape(nkeys.shape)
|
| 46 |
-
found = valid & (sorted_keys[index] == nkeys)
|
| 47 |
-
self.cache["neighbors"] = mx.where(found, order[index], keys.size)
|
| 48 |
-
return self.cache["neighbors"]
|
| 49 |
-
|
| 50 |
-
def downsample(self):
|
| 51 |
-
if "downsample" not in self.cache:
|
| 52 |
-
coords = self.coords // mx.array([1, 2, 2, 2])
|
| 53 |
-
r = (self.resolution + 1) // 2
|
| 54 |
-
keys = coord_keys(coords, r)
|
| 55 |
-
order = mx.argsort(keys)
|
| 56 |
-
sorted_keys = keys[order]
|
| 57 |
-
start = mx.concatenate(
|
| 58 |
-
[mx.array([True]), sorted_keys[1:] != sorted_keys[:-1]]
|
| 59 |
-
)
|
| 60 |
-
first = nonzero(start)
|
| 61 |
-
groups = mx.cumsum(start.astype(mx.int32)) - 1
|
| 62 |
-
parent = mx.zeros(keys.size, mx.int32).at[order].add(groups)
|
| 63 |
-
child = Grid(coords[order[first]], r)
|
| 64 |
-
self.cache["downsample"] = (child, parent)
|
| 65 |
-
return self.cache["downsample"]
|
| 66 |
-
|
| 67 |
-
def subdivide(self):
|
| 68 |
-
if "subdivide" not in self.cache:
|
| 69 |
-
offsets = mx.array(
|
| 70 |
-
[(0, *p) for p in product((0, 1), repeat=3)], dtype=mx.int32
|
| 71 |
-
)
|
| 72 |
-
coords = self.coords[:, None] * mx.array([1, 2, 2, 2]) + offsets[None]
|
| 73 |
-
self.cache["subdivide"] = Grid(coords.reshape(-1, 4), self.resolution * 2)
|
| 74 |
-
return self.cache["subdivide"]
|
| 75 |
-
|
| 76 |
-
def windows(self, size, shift):
|
| 77 |
-
key = ("windows", size, shift)
|
| 78 |
-
if key not in self.cache:
|
| 79 |
-
coords = mx.concatenate(
|
| 80 |
-
[self.coords[:, :1], (self.coords[:, 1:] + shift) // size], axis=-1
|
| 81 |
-
)
|
| 82 |
-
keys = coord_keys(coords, (self.resolution + shift + size - 1) // size)
|
| 83 |
-
order = mx.argsort(keys)
|
| 84 |
-
sorted_keys = keys[order]
|
| 85 |
-
starts = nonzero(
|
| 86 |
-
mx.concatenate([mx.array([True]), sorted_keys[1:] != sorted_keys[:-1]])
|
| 87 |
-
).tolist()
|
| 88 |
-
ends = starts[1:] + [keys.size]
|
| 89 |
-
buckets = {}
|
| 90 |
-
for start, end in zip(starts, ends):
|
| 91 |
-
width = 1 << (end - start - 1).bit_length()
|
| 92 |
-
buckets.setdefault(width, []).append((start, end - start))
|
| 93 |
-
packed = []
|
| 94 |
-
for width, ranges in sorted(buckets.items()):
|
| 95 |
-
first = mx.array([s for s, _ in ranges])[:, None]
|
| 96 |
-
lengths = mx.array([n for _, n in ranges])[:, None]
|
| 97 |
-
offset = mx.arange(width)[None]
|
| 98 |
-
valid = offset < lengths
|
| 99 |
-
indices = mx.where(
|
| 100 |
-
valid, order[mx.minimum(first + offset, keys.size - 1)], keys.size
|
| 101 |
-
)
|
| 102 |
-
packed.append((indices, valid))
|
| 103 |
-
self.cache[key] = packed
|
| 104 |
-
return self.cache[key]
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
class SparseConv(nn.Module):
|
| 108 |
-
def __init__(self, input_channels, output_channels, kernel=3):
|
| 109 |
-
super().__init__()
|
| 110 |
-
self.conv = nn.Conv3d(
|
| 111 |
-
input_channels, output_channels, kernel, padding=kernel // 2
|
| 112 |
-
)
|
| 113 |
-
|
| 114 |
-
def __call__(self, x, grid):
|
| 115 |
-
w, bias = self.conv.weight, self.conv.bias
|
| 116 |
-
if w.shape[1] == 1:
|
| 117 |
-
return mx.addmm(bias, x, w[:, 0, 0, 0].T)
|
| 118 |
-
indices = grid.neighbors()
|
| 119 |
-
padded = mx.concatenate([x, mx.zeros((1, x.shape[-1]), x.dtype)])
|
| 120 |
-
# Limit temporary im2col storage to 16 MiB per matrix product.
|
| 121 |
-
rows = max(1, (16 << 20) // (27 * x.shape[-1] * x.dtype.size))
|
| 122 |
-
weight = w.reshape(w.shape[0], -1).T
|
| 123 |
-
outputs = []
|
| 124 |
-
for start in range(0, x.shape[0], rows):
|
| 125 |
-
values = padded[indices[start : start + rows]].reshape(-1, weight.shape[0])
|
| 126 |
-
outputs.append(mx.addmm(bias, values, weight))
|
| 127 |
-
return mx.concatenate(outputs, axis=0)
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
def pool(x, grid):
|
| 131 |
-
child, parent = grid.downsample()
|
| 132 |
-
sums = (
|
| 133 |
-
mx.zeros((child.coords.shape[0], x.shape[-1]), mx.float32)
|
| 134 |
-
.at[parent]
|
| 135 |
-
.add(x.astype(mx.float32))
|
| 136 |
-
)
|
| 137 |
-
# Upstream torch.scatter_reduce(mean) includes the initial zero value.
|
| 138 |
-
counts = (
|
| 139 |
-
mx.ones((child.coords.shape[0], 1), mx.float32)
|
| 140 |
-
.at[parent]
|
| 141 |
-
.add(mx.ones((x.shape[0], 1)))
|
| 142 |
-
)
|
| 143 |
-
return (sums / counts).astype(x.dtype), child, parent
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
class SparseGroupNorm(nn.Module):
|
| 147 |
-
def __init__(self, channels, groups=32):
|
| 148 |
-
super().__init__()
|
| 149 |
-
self.weight = mx.ones(channels)
|
| 150 |
-
self.bias = mx.zeros(channels)
|
| 151 |
-
self.groups = min(groups, channels)
|
| 152 |
-
|
| 153 |
-
def __call__(self, x):
|
| 154 |
-
# Each streamed request has one object; normalize across all its voxels.
|
| 155 |
-
h = x.astype(mx.float32).reshape(x.shape[0], self.groups, -1)
|
| 156 |
-
mean = h.mean(axis=(0, 2), keepdims=True)
|
| 157 |
-
var = ((h - mean) ** 2).mean(axis=(0, 2), keepdims=True)
|
| 158 |
-
h = ((h - mean) * mx.rsqrt(var + 1e-5)).reshape(x.shape)
|
| 159 |
-
return (h * self.weight + self.bias).astype(x.dtype)
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
def window_attention(qkv, grid, size, shift):
|
| 163 |
-
n, _, heads, dim = qkv.shape
|
| 164 |
-
padded = mx.concatenate([qkv, mx.zeros((1, 3, heads, dim), qkv.dtype)])
|
| 165 |
-
result = mx.zeros((n + 1, heads * dim), qkv.dtype)
|
| 166 |
-
for indices, valid in grid.windows(size, shift):
|
| 167 |
-
values = padded[indices]
|
| 168 |
-
out = attend(*(values[:, :, i] for i in range(3)), mask=valid[:, None, None, :])
|
| 169 |
-
result = result.at[indices.reshape(-1)].add(
|
| 170 |
-
mx.where(valid[..., None], out, 0).reshape(-1, heads * dim)
|
| 171 |
-
)
|
| 172 |
-
return result[:n]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sam3d_objects_mlx/vision.py
DELETED
|
@@ -1,215 +0,0 @@
|
|
| 1 |
-
# Adapted from mlx_vlm.models.dinov2 and Meta SAM 3D Objects.
|
| 2 |
-
# See LICENSE in this directory for the SAM components.
|
| 3 |
-
"""DINOv2 register-token image encoders and point-map conditioning."""
|
| 4 |
-
|
| 5 |
-
import mlx.core as mx
|
| 6 |
-
import mlx.nn as nn
|
| 7 |
-
|
| 8 |
-
from .layers import LayerNorm, Sequential, attend, layer_norm
|
| 9 |
-
from .resize import resize
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
class PatchEmbed(nn.Module):
|
| 13 |
-
def __init__(self, channels):
|
| 14 |
-
super().__init__()
|
| 15 |
-
self.proj = nn.Conv2d(3, channels, 14, stride=14)
|
| 16 |
-
|
| 17 |
-
def __call__(self, x):
|
| 18 |
-
x = self.proj(x)
|
| 19 |
-
return x.reshape(x.shape[0], -1, x.shape[-1])
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
class VisionAttention(nn.Module):
|
| 23 |
-
def __init__(self, channels, heads):
|
| 24 |
-
super().__init__()
|
| 25 |
-
self.heads = heads
|
| 26 |
-
self.qkv = nn.Linear(channels, 3 * channels)
|
| 27 |
-
self.proj = nn.Linear(channels, channels)
|
| 28 |
-
|
| 29 |
-
def __call__(self, x):
|
| 30 |
-
qkv = self.qkv(x).reshape(*x.shape[:2], 3, self.heads, -1)
|
| 31 |
-
return self.proj(attend(*(qkv[:, :, i] for i in range(3))))
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
class VisionMLP(nn.Module):
|
| 35 |
-
def __init__(self, channels, ratio=4):
|
| 36 |
-
super().__init__()
|
| 37 |
-
self.fc1 = nn.Linear(channels, channels * ratio)
|
| 38 |
-
self.fc2 = nn.Linear(channels * ratio, channels)
|
| 39 |
-
|
| 40 |
-
def __call__(self, x):
|
| 41 |
-
return self.fc2(nn.gelu(self.fc1(x)))
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
class LayerScale(nn.Module):
|
| 45 |
-
def __init__(self, channels):
|
| 46 |
-
super().__init__()
|
| 47 |
-
self.gamma = mx.ones(channels)
|
| 48 |
-
|
| 49 |
-
def __call__(self, x):
|
| 50 |
-
return x * self.gamma
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
class VisionBlock(nn.Module):
|
| 54 |
-
def __init__(self, channels, heads, *, layer_scale=True, ratio=4):
|
| 55 |
-
super().__init__()
|
| 56 |
-
self.norm1 = LayerNorm(channels, eps=1e-6)
|
| 57 |
-
self.attn = VisionAttention(channels, heads)
|
| 58 |
-
self.norm2 = LayerNorm(channels, eps=1e-6)
|
| 59 |
-
self.mlp = VisionMLP(channels, ratio)
|
| 60 |
-
self.ls1 = LayerScale(channels) if layer_scale else nn.Identity()
|
| 61 |
-
self.ls2 = LayerScale(channels) if layer_scale else nn.Identity()
|
| 62 |
-
|
| 63 |
-
def __call__(self, x):
|
| 64 |
-
x = x + self.ls1(self.attn(self.norm1(x)))
|
| 65 |
-
return x + self.ls2(self.mlp(self.norm2(x)))
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
class DINOv2(nn.Module):
|
| 69 |
-
def __init__(self, config):
|
| 70 |
-
super().__init__()
|
| 71 |
-
c = config.dino_hidden_size
|
| 72 |
-
n = (config.dino_image_size // 14) ** 2
|
| 73 |
-
self.patch_embed = PatchEmbed(c)
|
| 74 |
-
self.cls_token = mx.zeros((1, 1, c))
|
| 75 |
-
self.mask_token = mx.zeros((1, c))
|
| 76 |
-
self.pos_embed = mx.zeros((1, n + 1, c))
|
| 77 |
-
self.register_tokens = mx.zeros((1, 4, c))
|
| 78 |
-
self.blocks = [
|
| 79 |
-
VisionBlock(c, config.dino_heads) for _ in range(config.dino_layers)
|
| 80 |
-
]
|
| 81 |
-
self.norm = LayerNorm(c, eps=1e-6)
|
| 82 |
-
|
| 83 |
-
def __call__(self, image, prenorm=False):
|
| 84 |
-
x = self.patch_embed(image)
|
| 85 |
-
if x.shape[1] + 1 != self.pos_embed.shape[1]:
|
| 86 |
-
raise ValueError("DINO input must match the checkpoint image size")
|
| 87 |
-
x = (
|
| 88 |
-
mx.concatenate(
|
| 89 |
-
[mx.broadcast_to(self.cls_token, (x.shape[0], 1, x.shape[-1])), x],
|
| 90 |
-
axis=1,
|
| 91 |
-
)
|
| 92 |
-
+ self.pos_embed
|
| 93 |
-
)
|
| 94 |
-
x = mx.concatenate(
|
| 95 |
-
[
|
| 96 |
-
x[:, :1],
|
| 97 |
-
mx.broadcast_to(self.register_tokens, (x.shape[0], 4, x.shape[-1])),
|
| 98 |
-
x[:, 1:],
|
| 99 |
-
],
|
| 100 |
-
axis=1,
|
| 101 |
-
)
|
| 102 |
-
for block in self.blocks:
|
| 103 |
-
x = block(x)
|
| 104 |
-
if prenorm:
|
| 105 |
-
return layer_norm(x)
|
| 106 |
-
x = self.norm(x)
|
| 107 |
-
return mx.concatenate([x[:, :1], x[:, 5:]], axis=1)
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
class Dino(nn.Module):
|
| 111 |
-
def __init__(self, config, prenorm=False):
|
| 112 |
-
super().__init__()
|
| 113 |
-
self.backbone = DINOv2(config)
|
| 114 |
-
self._size = config.image_size
|
| 115 |
-
self._prenorm = prenorm
|
| 116 |
-
|
| 117 |
-
def __call__(self, image):
|
| 118 |
-
x = resize(image, self._size, self._size)
|
| 119 |
-
if x.shape[-1] == 1:
|
| 120 |
-
x = mx.repeat(x, 3, axis=-1)
|
| 121 |
-
x = (x - mx.array([0.485, 0.456, 0.406])) / mx.array([0.229, 0.224, 0.225])
|
| 122 |
-
return self.backbone(x.astype(self.backbone.cls_token.dtype), self._prenorm)
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
class PointPatchEmbed(nn.Module):
|
| 126 |
-
def __init__(self, config):
|
| 127 |
-
super().__init__()
|
| 128 |
-
c, p, s = config.point_channels, config.point_patch_size, config.point_size
|
| 129 |
-
self._patch, self._size = p, s
|
| 130 |
-
self.point_proj = nn.Linear(3, c)
|
| 131 |
-
self.invalid_xyz_token = mx.zeros(c)
|
| 132 |
-
self.pos_embed = mx.zeros((1, c, s // p, s // p))
|
| 133 |
-
self.pos_embed_window = mx.zeros((1, 1 + p * p, c))
|
| 134 |
-
self.cls_token = mx.zeros((1, 1, c))
|
| 135 |
-
self.blocks = [VisionBlock(c, config.point_heads, layer_scale=False, ratio=2)]
|
| 136 |
-
|
| 137 |
-
def __call__(self, points):
|
| 138 |
-
points = resize(points, self._size, self._size, nearest=True)
|
| 139 |
-
valid = mx.all(mx.isfinite(points), axis=-1, keepdims=True)
|
| 140 |
-
x = self.point_proj(
|
| 141 |
-
mx.where(valid, points, 0).astype(self.point_proj.weight.dtype)
|
| 142 |
-
)
|
| 143 |
-
x = mx.where(valid, x, self.invalid_xyz_token)
|
| 144 |
-
b, h, w, c = x.shape
|
| 145 |
-
p = self._patch
|
| 146 |
-
x = (
|
| 147 |
-
x.reshape(b, h // p, p, w // p, p, c)
|
| 148 |
-
.transpose(0, 1, 3, 2, 4, 5)
|
| 149 |
-
.reshape(-1, p * p, c)
|
| 150 |
-
)
|
| 151 |
-
x = (
|
| 152 |
-
mx.concatenate(
|
| 153 |
-
[mx.broadcast_to(self.cls_token, (x.shape[0], 1, c)), x], axis=1
|
| 154 |
-
)
|
| 155 |
-
+ self.pos_embed_window
|
| 156 |
-
)
|
| 157 |
-
for block in self.blocks:
|
| 158 |
-
x = block(x)
|
| 159 |
-
return x[:, 0].reshape(b, -1, c) + self.pos_embed.transpose(0, 2, 3, 1).reshape(
|
| 160 |
-
1, -1, c
|
| 161 |
-
)
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
class ProjectionFFN(nn.Module):
|
| 165 |
-
def __init__(self, input_dim, output_dim):
|
| 166 |
-
super().__init__()
|
| 167 |
-
hidden = ((int(8 * output_dim / 3) + 255) // 256) * 256
|
| 168 |
-
self.w1 = nn.Linear(input_dim, hidden, bias=False)
|
| 169 |
-
self.w2 = nn.Linear(hidden, output_dim, bias=False)
|
| 170 |
-
self.w3 = nn.Linear(input_dim, hidden, bias=False)
|
| 171 |
-
|
| 172 |
-
def __call__(self, x):
|
| 173 |
-
return self.w2(nn.silu(self.w1(x)) * self.w3(x))
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
class ConditionEncoder(nn.Module):
|
| 177 |
-
def __init__(self, config, *, pointmap=False):
|
| 178 |
-
super().__init__()
|
| 179 |
-
self.module_list = [
|
| 180 |
-
Dino(config, prenorm=not pointmap),
|
| 181 |
-
Dino(config, prenorm=not pointmap),
|
| 182 |
-
]
|
| 183 |
-
dims = [config.dino_hidden_size] * 2
|
| 184 |
-
if pointmap:
|
| 185 |
-
self.module_list.append(PointPatchEmbed(config))
|
| 186 |
-
dims.append(config.point_channels)
|
| 187 |
-
self.idx_emb = mx.zeros((3, config.cond_channels))
|
| 188 |
-
self.projection_nets = [
|
| 189 |
-
Sequential(LayerNorm(d), ProjectionFFN(d, config.cond_channels))
|
| 190 |
-
for d in dims
|
| 191 |
-
]
|
| 192 |
-
|
| 193 |
-
def __call__(self, inputs):
|
| 194 |
-
groups = [
|
| 195 |
-
("image", "rgb_image"),
|
| 196 |
-
("mask", "rgb_image_mask"),
|
| 197 |
-
("pointmap", "rgb_pointmap"),
|
| 198 |
-
]
|
| 199 |
-
tokens = []
|
| 200 |
-
for i, module in enumerate(self.module_list):
|
| 201 |
-
for pos, name in enumerate(groups[i]):
|
| 202 |
-
if i == 2 and inputs.get(name) is None:
|
| 203 |
-
# Match the trained condition dropout: zero complete tokens,
|
| 204 |
-
# including their learned positional embedding.
|
| 205 |
-
count = (module._size // module._patch) ** 2
|
| 206 |
-
tokens.append(
|
| 207 |
-
mx.zeros(
|
| 208 |
-
(inputs["image"].shape[0], count, self.idx_emb.shape[-1]),
|
| 209 |
-
self.idx_emb.dtype,
|
| 210 |
-
)
|
| 211 |
-
)
|
| 212 |
-
continue
|
| 213 |
-
x = self.projection_nets[i](module(inputs[name]))
|
| 214 |
-
tokens.append(x + self.idx_emb[pos : pos + 1, None])
|
| 215 |
-
return mx.concatenate(tokens, axis=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
validation.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
| 13 |
"external_runtime_imports": [],
|
| 14 |
"regression_tests": {
|
| 15 |
"class": "TestSAM3DObjects",
|
| 16 |
-
"passed":
|
| 17 |
},
|
| 18 |
"reference_comparison": {
|
| 19 |
"precision": "float32",
|
|
@@ -60,30 +60,30 @@
|
|
| 60 |
],
|
| 61 |
"samples": [
|
| 62 |
{
|
| 63 |
-
"seconds":
|
| 64 |
-
"peak_memory_gb": 10.
|
| 65 |
},
|
| 66 |
{
|
| 67 |
-
"seconds":
|
| 68 |
-
"peak_memory_gb": 10.
|
| 69 |
},
|
| 70 |
{
|
| 71 |
-
"seconds":
|
| 72 |
-
"peak_memory_gb": 10.
|
| 73 |
}
|
| 74 |
],
|
| 75 |
-
"median_seconds":
|
| 76 |
-
"peak_memory_gb": 10.
|
| 77 |
-
"gaussians":
|
| 78 |
-
"mesh_vertices":
|
| 79 |
-
"mesh_faces":
|
| 80 |
"pointmap_conditioned": true,
|
| 81 |
"async_validation": {
|
| 82 |
"request_ids": [
|
| 83 |
"0",
|
| 84 |
"1"
|
| 85 |
],
|
| 86 |
-
"event_loop_heartbeats":
|
| 87 |
}
|
| 88 |
}
|
| 89 |
}
|
|
|
|
| 13 |
"external_runtime_imports": [],
|
| 14 |
"regression_tests": {
|
| 15 |
"class": "TestSAM3DObjects",
|
| 16 |
+
"passed": 13
|
| 17 |
},
|
| 18 |
"reference_comparison": {
|
| 19 |
"precision": "float32",
|
|
|
|
| 60 |
],
|
| 61 |
"samples": [
|
| 62 |
{
|
| 63 |
+
"seconds": 14.864514124987181,
|
| 64 |
+
"peak_memory_gb": 10.87792566
|
| 65 |
},
|
| 66 |
{
|
| 67 |
+
"seconds": 15.67705433399533,
|
| 68 |
+
"peak_memory_gb": 10.878777628
|
| 69 |
},
|
| 70 |
{
|
| 71 |
+
"seconds": 15.963315250002779,
|
| 72 |
+
"peak_memory_gb": 10.976393304
|
| 73 |
}
|
| 74 |
],
|
| 75 |
+
"median_seconds": 15.67705433399533,
|
| 76 |
+
"peak_memory_gb": 10.976393304,
|
| 77 |
+
"gaussians": 845184,
|
| 78 |
+
"mesh_vertices": 629536,
|
| 79 |
+
"mesh_faces": 1250780,
|
| 80 |
"pointmap_conditioned": true,
|
| 81 |
"async_validation": {
|
| 82 |
"request_ids": [
|
| 83 |
"0",
|
| 84 |
"1"
|
| 85 |
],
|
| 86 |
+
"event_loop_heartbeats": 2810
|
| 87 |
}
|
| 88 |
}
|
| 89 |
}
|