coreml-diffusion 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coreml_diffusion-0.1.0/.github/workflows/publish-pypi.yml +29 -0
- coreml_diffusion-0.1.0/.github/workflows/tier0.yml +31 -0
- coreml_diffusion-0.1.0/.github/workflows/tier1.yml +25 -0
- coreml_diffusion-0.1.0/.gitignore +8 -0
- coreml_diffusion-0.1.0/LICENSE +21 -0
- coreml_diffusion-0.1.0/PKG-INFO +98 -0
- coreml_diffusion-0.1.0/README.md +69 -0
- coreml_diffusion-0.1.0/coreml_diffusion/__init__.py +108 -0
- coreml_diffusion-0.1.0/coreml_diffusion/attention.py +5 -0
- coreml_diffusion-0.1.0/coreml_diffusion/cli.py +114 -0
- coreml_diffusion-0.1.0/coreml_diffusion/conversion/__init__.py +9 -0
- coreml_diffusion-0.1.0/coreml_diffusion/conversion/attention.py +245 -0
- coreml_diffusion-0.1.0/coreml_diffusion/conversion/shapes.py +20 -0
- coreml_diffusion-0.1.0/coreml_diffusion/conversion/trace.py +61 -0
- coreml_diffusion-0.1.0/coreml_diffusion/conversion/unet.py +54 -0
- coreml_diffusion-0.1.0/coreml_diffusion/convert.py +348 -0
- coreml_diffusion-0.1.0/coreml_diffusion/logger.py +5 -0
- coreml_diffusion-0.1.0/coreml_diffusion/model_version.py +8 -0
- coreml_diffusion-0.1.0/coreml_diffusion/naming.py +73 -0
- coreml_diffusion-0.1.0/pyproject.toml +77 -0
- coreml_diffusion-0.1.0/tests/conftest.py +46 -0
- coreml_diffusion-0.1.0/tests/inference/test_pipeline_inference.py +26 -0
- coreml_diffusion-0.1.0/tests/smoke/test_split_einsum_attention.py +40 -0
- coreml_diffusion-0.1.0/tests/smoke/test_synthetic_unet.py +129 -0
- coreml_diffusion-0.1.0/tests/unit/test_characterization_out_name.py +226 -0
- coreml_diffusion-0.1.0/tests/unit/test_cli.py +111 -0
- coreml_diffusion-0.1.0/tests/unit/test_conversion_helpers.py +187 -0
- coreml_diffusion-0.1.0/tests/unit/test_discovery_api.py +71 -0
- coreml_diffusion-0.1.0/tests/unit/test_tier0_purity.py +37 -0
- coreml_diffusion-0.1.0/uv.lock +980 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Trusted Publishing (OIDC) — no API token stored. Configure a PyPI publisher
|
|
4
|
+
# for this repo/workflow first (see https://docs.pypi.org/trusted-publishers/).
|
|
5
|
+
# Fires when a GitHub Release is published; the release tag must match the
|
|
6
|
+
# version in pyproject.toml (e.g. tag v0.1.0 -> version 0.1.0).
|
|
7
|
+
on:
|
|
8
|
+
release:
|
|
9
|
+
types: [published]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment: pypi
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # required for Trusted Publishing
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: astral-sh/setup-uv@v7
|
|
22
|
+
with:
|
|
23
|
+
enable-cache: true
|
|
24
|
+
|
|
25
|
+
- name: Build
|
|
26
|
+
run: uv build
|
|
27
|
+
|
|
28
|
+
- name: Publish
|
|
29
|
+
run: uv publish
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Tier 0 — Unit (Linux)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
# Framework-free unit lane. The in-tree purity gate
|
|
9
|
+
# (tests/unit/test_tier0_purity.py) enforces that the unit tests do not import
|
|
10
|
+
# coremltools / diffusers / any ComfyUI module.
|
|
11
|
+
jobs:
|
|
12
|
+
unit:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 15
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: astral-sh/setup-uv@v7
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
|
|
22
|
+
- name: uv sync
|
|
23
|
+
run: uv sync
|
|
24
|
+
|
|
25
|
+
- name: Lint (ruff)
|
|
26
|
+
run: |
|
|
27
|
+
uv run ruff check .
|
|
28
|
+
uv run ruff format --check .
|
|
29
|
+
|
|
30
|
+
- name: Run Tier 0
|
|
31
|
+
run: uv run pytest -m unit tests/ -v
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Tier 1 — Smoke (macOS)
|
|
2
|
+
|
|
3
|
+
# Converts a synthetic micro-UNet through coremltools on a hosted Apple Silicon
|
|
4
|
+
# runner — catches coremltools API breakage without a real checkpoint or the ANE.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
smoke:
|
|
12
|
+
runs-on: macos-14
|
|
13
|
+
timeout-minutes: 20
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- uses: astral-sh/setup-uv@v7
|
|
18
|
+
with:
|
|
19
|
+
enable-cache: true
|
|
20
|
+
|
|
21
|
+
- name: uv sync
|
|
22
|
+
run: uv sync
|
|
23
|
+
|
|
24
|
+
- name: Run Tier 1
|
|
25
|
+
run: uv run pytest -m smoke tests/ -v
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2026 Adrian Szczepański
|
|
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.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coreml-diffusion
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert diffusion-model checkpoints (SD1.5/SDXL) to Core ML for Apple Neural Engine — framework-free, ComfyUI-independent.
|
|
5
|
+
Project-URL: Homepage, https://github.com/aszc-dev/coreml-diffusion
|
|
6
|
+
Project-URL: Repository, https://github.com/aszc-dev/coreml-diffusion
|
|
7
|
+
Project-URL: Issues, https://github.com/aszc-dev/coreml-diffusion/issues
|
|
8
|
+
Author-email: Adrian Szczepański <hi@aszc.dev>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ane,apple-neural-engine,comfyui,core-ml,coreml,diffusers,diffusion,sdxl,stable-diffusion
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: <3.13,>=3.12
|
|
21
|
+
Requires-Dist: coremltools<10,>=9
|
|
22
|
+
Requires-Dist: diffusers>=0.30
|
|
23
|
+
Requires-Dist: numpy<3,>=2
|
|
24
|
+
Requires-Dist: omegaconf>=2.3
|
|
25
|
+
Requires-Dist: peft>=0.13
|
|
26
|
+
Requires-Dist: torch<2.8,>=2.7
|
|
27
|
+
Requires-Dist: transformers>=4.44
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# coreml-diffusion
|
|
31
|
+
|
|
32
|
+
Convert diffusion-model checkpoints into Core ML `.mlpackage` artifacts for the
|
|
33
|
+
Apple Neural Engine (ANE) — framework-free and independent of ComfyUI.
|
|
34
|
+
|
|
35
|
+
`coreml-diffusion` takes a single-file Stable Diffusion checkpoint and produces a
|
|
36
|
+
Core ML UNet you can run on-device (macOS/iOS) or load back into ComfyUI via
|
|
37
|
+
[ComfyUI-CoreMLSuite](https://github.com/aszc-dev/ComfyUI-CoreMLSuite), which
|
|
38
|
+
depends on this package for its conversion path.
|
|
39
|
+
|
|
40
|
+
## Positioning
|
|
41
|
+
|
|
42
|
+
The niche is **diffusion models on the Apple Neural Engine via Core ML** — inside
|
|
43
|
+
ComfyUI and on-device. ANE is the differentiator: low-power, GPU-free, embeddable
|
|
44
|
+
in a Swift/iOS app. This is about feasibility and power efficiency for SD1.5/SDXL
|
|
45
|
+
on ANE, not a raw-throughput claim against desktop GPUs.
|
|
46
|
+
|
|
47
|
+
Supported today: SD1.5 and SDXL (verified). SDXL refiner and LCM convert but are
|
|
48
|
+
not yet golden-verified (experimental). The scope is diffusion architectures
|
|
49
|
+
generally, not Stable Diffusion specifically.
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
uv pip install coreml-diffusion # from PyPI (planned)
|
|
55
|
+
uv pip install -e . # from a checkout
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Requires Python 3.12 and (for conversion) `coremltools` 9 — conversion runs on
|
|
59
|
+
macOS; the package imports and its CLI parse on any platform.
|
|
60
|
+
|
|
61
|
+
## CLI
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
coreml-diffusion convert \
|
|
65
|
+
--ckpt path/to/model.safetensors \
|
|
66
|
+
--model-version SD15 \
|
|
67
|
+
--out unet.mlpackage \
|
|
68
|
+
--height 512 --width 512 \
|
|
69
|
+
--attn-impl SPLIT_EINSUM \
|
|
70
|
+
--quantize none
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Options: `--batch-size`, `--controlnet`, `--lora PATH[:STRENGTH]` (repeatable),
|
|
74
|
+
`--config` (original-config YAML). `--quantize {none,8,6,4}` applies k-means
|
|
75
|
+
weight palettization. Run `coreml-diffusion convert --help` for the full list.
|
|
76
|
+
|
|
77
|
+
The output `.mlpackage` is the deliverable: load it natively in Swift/Core ML, or
|
|
78
|
+
through ComfyUI-CoreMLSuite.
|
|
79
|
+
|
|
80
|
+
## Library
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import coreml_diffusion
|
|
84
|
+
from coreml_diffusion import ModelVersion
|
|
85
|
+
|
|
86
|
+
coreml_diffusion.convert(
|
|
87
|
+
"model.safetensors", ModelVersion.SD15, "unet.mlpackage",
|
|
88
|
+
height=512, width=512, attn_impl="SPLIT_EINSUM",
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Discovery API (`list_model_versions`, `list_attention_impls`, `list_quant_modes`,
|
|
93
|
+
`CONTRACT_VERSION`) reports what this build can convert; the identifiers are an
|
|
94
|
+
additive-only contract (removing/renaming one is a major bump).
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# coreml-diffusion
|
|
2
|
+
|
|
3
|
+
Convert diffusion-model checkpoints into Core ML `.mlpackage` artifacts for the
|
|
4
|
+
Apple Neural Engine (ANE) — framework-free and independent of ComfyUI.
|
|
5
|
+
|
|
6
|
+
`coreml-diffusion` takes a single-file Stable Diffusion checkpoint and produces a
|
|
7
|
+
Core ML UNet you can run on-device (macOS/iOS) or load back into ComfyUI via
|
|
8
|
+
[ComfyUI-CoreMLSuite](https://github.com/aszc-dev/ComfyUI-CoreMLSuite), which
|
|
9
|
+
depends on this package for its conversion path.
|
|
10
|
+
|
|
11
|
+
## Positioning
|
|
12
|
+
|
|
13
|
+
The niche is **diffusion models on the Apple Neural Engine via Core ML** — inside
|
|
14
|
+
ComfyUI and on-device. ANE is the differentiator: low-power, GPU-free, embeddable
|
|
15
|
+
in a Swift/iOS app. This is about feasibility and power efficiency for SD1.5/SDXL
|
|
16
|
+
on ANE, not a raw-throughput claim against desktop GPUs.
|
|
17
|
+
|
|
18
|
+
Supported today: SD1.5 and SDXL (verified). SDXL refiner and LCM convert but are
|
|
19
|
+
not yet golden-verified (experimental). The scope is diffusion architectures
|
|
20
|
+
generally, not Stable Diffusion specifically.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
uv pip install coreml-diffusion # from PyPI (planned)
|
|
26
|
+
uv pip install -e . # from a checkout
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Requires Python 3.12 and (for conversion) `coremltools` 9 — conversion runs on
|
|
30
|
+
macOS; the package imports and its CLI parse on any platform.
|
|
31
|
+
|
|
32
|
+
## CLI
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
coreml-diffusion convert \
|
|
36
|
+
--ckpt path/to/model.safetensors \
|
|
37
|
+
--model-version SD15 \
|
|
38
|
+
--out unet.mlpackage \
|
|
39
|
+
--height 512 --width 512 \
|
|
40
|
+
--attn-impl SPLIT_EINSUM \
|
|
41
|
+
--quantize none
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Options: `--batch-size`, `--controlnet`, `--lora PATH[:STRENGTH]` (repeatable),
|
|
45
|
+
`--config` (original-config YAML). `--quantize {none,8,6,4}` applies k-means
|
|
46
|
+
weight palettization. Run `coreml-diffusion convert --help` for the full list.
|
|
47
|
+
|
|
48
|
+
The output `.mlpackage` is the deliverable: load it natively in Swift/Core ML, or
|
|
49
|
+
through ComfyUI-CoreMLSuite.
|
|
50
|
+
|
|
51
|
+
## Library
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import coreml_diffusion
|
|
55
|
+
from coreml_diffusion import ModelVersion
|
|
56
|
+
|
|
57
|
+
coreml_diffusion.convert(
|
|
58
|
+
"model.safetensors", ModelVersion.SD15, "unet.mlpackage",
|
|
59
|
+
height=512, width=512, attn_impl="SPLIT_EINSUM",
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Discovery API (`list_model_versions`, `list_attention_impls`, `list_quant_modes`,
|
|
64
|
+
`CONTRACT_VERSION`) reports what this build can convert; the identifiers are an
|
|
65
|
+
additive-only contract (removing/renaming one is a major bump).
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""coreml_diffusion — framework-free Core ML diffusion conversion.
|
|
2
|
+
|
|
3
|
+
Converts diffusion-model checkpoints (SD1.5/SDXL today) into Core ML
|
|
4
|
+
``.mlpackage`` artifacts for Apple Neural Engine, with no ComfyUI dependency.
|
|
5
|
+
Usable as a library, via the ``coreml-diffusion`` CLI, or embedded in on-device
|
|
6
|
+
(iOS) tooling. The public surface is the discovery API below plus ``convert``,
|
|
7
|
+
``compose_out_name`` and ``ModelVersion``.
|
|
8
|
+
|
|
9
|
+
This package MUST stay free of ``comfy`` / ``folder_paths`` / ``comfy_extras``;
|
|
10
|
+
``import coreml_diffusion`` works in a comfy-free environment.
|
|
11
|
+
|
|
12
|
+
Discovery contract (consumed by ComfyUI-CoreMLSuite): the node populates its
|
|
13
|
+
dropdowns by calling ``list_*`` here, so installing a newer ``coreml_diffusion``
|
|
14
|
+
surfaces new conversion types in the old node with no Suite change and no Suite
|
|
15
|
+
version bump. The identifiers returned here are an ADDITIVE-ONLY contract:
|
|
16
|
+
|
|
17
|
+
- adding an identifier, or promoting EXPERIMENTAL -> VERIFIED => minor bump
|
|
18
|
+
- removing/renaming an identifier, or demoting VERIFIED => MAJOR bump + note
|
|
19
|
+
|
|
20
|
+
because a saved workflow JSON references these strings verbatim.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from enum import Enum
|
|
24
|
+
|
|
25
|
+
from coreml_diffusion.attention import ATTENTION_IMPLEMENTATIONS
|
|
26
|
+
from coreml_diffusion.model_version import ModelVersion
|
|
27
|
+
from coreml_diffusion.naming import (
|
|
28
|
+
QUANT_NBITS_VALUES,
|
|
29
|
+
compose_out_name,
|
|
30
|
+
lora_names_from_params,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"ModelVersion",
|
|
35
|
+
"Status",
|
|
36
|
+
"list_model_versions",
|
|
37
|
+
"list_attention_impls",
|
|
38
|
+
"list_quant_modes",
|
|
39
|
+
"CONTRACT_VERSION",
|
|
40
|
+
"compose_out_name",
|
|
41
|
+
"lora_names_from_params",
|
|
42
|
+
"convert",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Status(Enum):
|
|
47
|
+
VERIFIED = "verified" # has a golden anchor + passing [M2-ANE] check
|
|
48
|
+
EXPERIMENTAL = "experimental" # convertible, not yet anchored/verified
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# Single source of truth for which conversions the Suite may surface. The Suite
|
|
52
|
+
# gates on this status, NOT on a hardcoded node list: promoting a model to
|
|
53
|
+
# VERIFIED expands the node's dropdown with no Suite change.
|
|
54
|
+
#
|
|
55
|
+
# Keyed by the ModelVersion MEMBER so ``list_model_versions`` can emit ``.name``
|
|
56
|
+
# ("SD15", "SDXL"). The node reverses the dropdown string via ``ModelVersion[...]``
|
|
57
|
+
# (name lookup, nodes.py), so emitting ``.value`` ("sd15") would raise KeyError on
|
|
58
|
+
# every saved workflow. See seam.md §5.
|
|
59
|
+
_MODEL_STATUS = {
|
|
60
|
+
ModelVersion.SD15: Status.VERIFIED,
|
|
61
|
+
ModelVersion.SDXL: Status.VERIFIED,
|
|
62
|
+
ModelVersion.SDXL_REFINER: Status.EXPERIMENTAL, # -> VERIFIED after a refiner golden anchor
|
|
63
|
+
ModelVersion.LCM: Status.EXPERIMENTAL, # -> VERIFIED after E-LCM golden anchor
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def list_model_versions(include_experimental: bool = False) -> list[str]:
|
|
68
|
+
"""Model versions by ``.name`` (e.g. ``["SD15", "SDXL"]``).
|
|
69
|
+
|
|
70
|
+
Returns VERIFIED versions only by default — the converter node calls this
|
|
71
|
+
plainly. A power-user/CLI path may pass ``include_experimental=True`` to also
|
|
72
|
+
list convertible-but-unanchored versions.
|
|
73
|
+
"""
|
|
74
|
+
return [
|
|
75
|
+
version.name
|
|
76
|
+
for version, status in _MODEL_STATUS.items()
|
|
77
|
+
if status is Status.VERIFIED
|
|
78
|
+
or (include_experimental and status is Status.EXPERIMENTAL)
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def list_attention_impls() -> list[str]:
|
|
83
|
+
"""Supported attention implementations, e.g. ``["SPLIT_EINSUM", ...]``."""
|
|
84
|
+
return list(ATTENTION_IMPLEMENTATIONS)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def list_quant_modes() -> list[str]:
|
|
88
|
+
"""Palettization modes, e.g. ``["none", "8", "6", "4"]`` ("none" = unquantized)."""
|
|
89
|
+
return list(QUANT_NBITS_VALUES)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# Discovery-contract version. Bump per the additive-only rules in this module's
|
|
93
|
+
# docstring and CONVERTER_EXTRACTION_SPEC.md "Interface contract".
|
|
94
|
+
CONTRACT_VERSION = "1.0"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def __getattr__(name):
|
|
98
|
+
"""Lazily expose the heavy conversion entrypoint.
|
|
99
|
+
|
|
100
|
+
``convert`` pulls coremltools/diffusers, so importing it eagerly would drag
|
|
101
|
+
the Mac/heavy stack into every ``import coreml_diffusion`` and break the
|
|
102
|
+
Tier-0 (Linux, framework-free) lane. Resolve it only on first access.
|
|
103
|
+
"""
|
|
104
|
+
if name == "convert":
|
|
105
|
+
from coreml_diffusion.convert import convert as _convert
|
|
106
|
+
|
|
107
|
+
return _convert
|
|
108
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Command-line entry point for coreml_diffusion.
|
|
2
|
+
|
|
3
|
+
Mirrors ``coreml_diffusion.convert`` so the package can produce a Core ML
|
|
4
|
+
``.mlpackage`` with no ComfyUI involved — for headless and on-device (iOS)
|
|
5
|
+
conversion workflows. The heavy import (coremltools/diffusers, pulled by
|
|
6
|
+
``convert``) is deferred into the handler, so ``--help`` and argument parsing
|
|
7
|
+
stay light and the arg→call mapping is testable on plain Linux.
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
coreml-diffusion convert --ckpt model.safetensors --model-version SD15 \\
|
|
11
|
+
--out unet.mlpackage --height 512 --width 512 --attn-impl SPLIT_EINSUM
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
|
|
16
|
+
import coreml_diffusion
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _parse_lora(spec):
|
|
20
|
+
"""Parse a ``PATH:STRENGTH`` lora spec into ``(path, float_strength)``.
|
|
21
|
+
|
|
22
|
+
Strength defaults to 1.0 when omitted. ``rsplit`` on the last ':' so Windows
|
|
23
|
+
drive letters / colons in the path survive.
|
|
24
|
+
"""
|
|
25
|
+
path, sep, strength = spec.rpartition(":")
|
|
26
|
+
if not sep:
|
|
27
|
+
return spec, 1.0
|
|
28
|
+
return path, float(strength)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _convert_cmd(args):
|
|
32
|
+
sample_size = (args.height // 8, args.width // 8)
|
|
33
|
+
lora_weights = [_parse_lora(spec) for spec in (args.lora or [])]
|
|
34
|
+
coreml_diffusion.convert(
|
|
35
|
+
args.ckpt,
|
|
36
|
+
coreml_diffusion.ModelVersion[args.model_version],
|
|
37
|
+
args.out,
|
|
38
|
+
batch_size=args.batch_size,
|
|
39
|
+
sample_size=sample_size,
|
|
40
|
+
controlnet_support=args.controlnet,
|
|
41
|
+
lora_weights=lora_weights or None,
|
|
42
|
+
attn_impl=args.attn_impl,
|
|
43
|
+
config_path=args.config,
|
|
44
|
+
quantize_nbits=args.quantize,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def build_parser():
|
|
49
|
+
parser = argparse.ArgumentParser(
|
|
50
|
+
prog="coreml-diffusion",
|
|
51
|
+
description="Convert diffusion checkpoints to Core ML for Apple Neural Engine.",
|
|
52
|
+
)
|
|
53
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
54
|
+
|
|
55
|
+
conv = sub.add_parser("convert", help="Convert a checkpoint's UNet to a .mlpackage")
|
|
56
|
+
conv.add_argument(
|
|
57
|
+
"--ckpt", required=True, help="Path to the source .safetensors checkpoint"
|
|
58
|
+
)
|
|
59
|
+
conv.add_argument(
|
|
60
|
+
"--model-version",
|
|
61
|
+
required=True,
|
|
62
|
+
# include experimental: the CLI is the power-user path. Experimental
|
|
63
|
+
# versions (LCM, SDXL_REFINER) convert but are not golden-verified.
|
|
64
|
+
choices=coreml_diffusion.list_model_versions(include_experimental=True),
|
|
65
|
+
help="Model architecture (verified: SD15, SDXL; experimental otherwise)",
|
|
66
|
+
)
|
|
67
|
+
conv.add_argument("--out", required=True, help="Output .mlpackage path to write")
|
|
68
|
+
conv.add_argument(
|
|
69
|
+
"--height", type=int, default=512, help="Target image height (default 512)"
|
|
70
|
+
)
|
|
71
|
+
conv.add_argument(
|
|
72
|
+
"--width", type=int, default=512, help="Target image width (default 512)"
|
|
73
|
+
)
|
|
74
|
+
conv.add_argument(
|
|
75
|
+
"--batch-size", type=int, default=1, help="Batch size (default 1)"
|
|
76
|
+
)
|
|
77
|
+
conv.add_argument(
|
|
78
|
+
"--attn-impl",
|
|
79
|
+
choices=coreml_diffusion.list_attention_impls(),
|
|
80
|
+
default=coreml_diffusion.list_attention_impls()[0],
|
|
81
|
+
help="Attention implementation (default SPLIT_EINSUM)",
|
|
82
|
+
)
|
|
83
|
+
conv.add_argument(
|
|
84
|
+
"--controlnet",
|
|
85
|
+
action="store_true",
|
|
86
|
+
help="Add ControlNet residual inputs to the converted UNet",
|
|
87
|
+
)
|
|
88
|
+
conv.add_argument(
|
|
89
|
+
"--lora",
|
|
90
|
+
action="append",
|
|
91
|
+
metavar="PATH[:STRENGTH]",
|
|
92
|
+
help="LoRA to fuse before conversion; repeatable. STRENGTH defaults to 1.0",
|
|
93
|
+
)
|
|
94
|
+
conv.add_argument(
|
|
95
|
+
"--config", default=None, help="Optional original-config YAML path"
|
|
96
|
+
)
|
|
97
|
+
conv.add_argument(
|
|
98
|
+
"--quantize",
|
|
99
|
+
choices=coreml_diffusion.list_quant_modes(),
|
|
100
|
+
default="none",
|
|
101
|
+
help="K-means weight palettization bits (default none = unquantized)",
|
|
102
|
+
)
|
|
103
|
+
conv.set_defaults(func=_convert_cmd)
|
|
104
|
+
return parser
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main(argv=None):
|
|
108
|
+
parser = build_parser()
|
|
109
|
+
args = parser.parse_args(argv)
|
|
110
|
+
return args.func(args)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
main()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Core ML conversion helpers.
|
|
2
|
+
|
|
3
|
+
The conversion approach originates from Apple's ml-stable-diffusion
|
|
4
|
+
(https://github.com/apple/ml-stable-diffusion). This implementation has since
|
|
5
|
+
diverged: it runs natively on diffusers' UNet2DConditionModel with its own
|
|
6
|
+
SPLIT_EINSUM / SPLIT_EINSUM_V2 attention processors and no longer depends on
|
|
7
|
+
that package. The intent is to keep iterating on these methods independently
|
|
8
|
+
while tracking current tooling.
|
|
9
|
+
"""
|