inline-core 1.2.53__tar.gz → 1.2.62__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.
- {inline_core-1.2.53 → inline_core-1.2.62}/CLAUDE.md +85 -4
- {inline_core-1.2.53 → inline_core-1.2.62}/PKG-INFO +30 -17
- {inline_core-1.2.53 → inline_core-1.2.62}/README.md +26 -14
- {inline_core-1.2.53 → inline_core-1.2.62}/pyproject.toml +16 -4
- inline_core-1.2.62/scripts/flux2_train_matrix.py +204 -0
- inline_core-1.2.62/scripts/minimax_h3_lora_check.py +145 -0
- inline_core-1.2.62/scripts/minimax_h3_train_matrix.py +203 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/memory.py +15 -3
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/registry.py +4 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/catalog.py +21 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/checkpoint.py +5 -0
- inline_core-1.2.62/src/inline_core/models/flux2/__init__.py +1 -0
- inline_core-1.2.62/src/inline_core/models/flux2/controlnet.py +234 -0
- inline_core-1.2.62/src/inline_core/models/flux2/embeds.py +165 -0
- inline_core-1.2.62/src/inline_core/models/flux2/provider.py +84 -0
- inline_core-1.2.62/src/inline_core/models/flux2/requirements.py +414 -0
- inline_core-1.2.62/src/inline_core/models/flux2/runner.py +677 -0
- inline_core-1.2.62/src/inline_core/models/flux2/variants.py +334 -0
- inline_core-1.2.62/src/inline_core/models/keymap.py +304 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/provider.py +11 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/runner.py +3 -3
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/loaders.py +466 -4
- inline_core-1.2.62/src/inline_core/models/minimaxh3/__init__.py +7 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/adaln.py +146 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/keys.py +134 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/load.py +350 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/pipeline.py +831 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/provider.py +102 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/requirements.py +295 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/runner.py +410 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vae_keys.py +125 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/__init__.py +46 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/autoencoder_kl_minimax_h3.py +922 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/autoencoder_kl_minimax_h3_audio.py +679 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/before_denoise.py +425 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/before_encoder.py +408 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/decoders.py +199 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/denoise.py +325 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/encoders.py +639 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/modular_blocks_minimax_h3.py +345 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/modular_pipeline.py +115 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/packing.py +538 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/packing_ref2va.py +841 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/scheduling_minimax_h3.py +288 -0
- inline_core-1.2.62/src/inline_core/models/minimaxh3/vendor/transformer_minimax_h3.py +644 -0
- inline_core-1.2.62/src/inline_core/models/offload.py +285 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/pipeline_runtime.py +89 -1
- inline_core-1.2.62/src/inline_core/models/prepared.py +151 -0
- inline_core-1.2.62/src/inline_core/models/references.py +125 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/requirements.py +54 -2
- inline_core-1.2.62/src/inline_core/models/video_params.py +144 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/provider.py +12 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/runner.py +3 -3
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/file_store.py +36 -6
- inline_core-1.2.62/src/inline_core/runtime/store.py +45 -0
- inline_core-1.2.62/src/inline_core/runtime/video_encode.py +204 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/app.py +6 -4
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/bootstrap.py +19 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/serialize.py +28 -4
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/fal.py +10 -1
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/frames.py +44 -18
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/generation.py +37 -4
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/graph_build.py +130 -28
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/handlers.py +31 -4
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/models.py +32 -2
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/moodboard.py +15 -3
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/schema.py +8 -2
- inline_core-1.2.62/src/inline_core/training/arch.py +372 -0
- inline_core-1.2.62/src/inline_core/training/cache.py +46 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/dataset.py +65 -10
- inline_core-1.2.62/src/inline_core/training/h3.py +384 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/models.py +137 -2
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/trainer.py +24 -19
- inline_core-1.2.62/tests/conftest.py +25 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_install.py +13 -2
- inline_core-1.2.62/tests/test_flux2_controlnet.py +159 -0
- inline_core-1.2.62/tests/test_flux2_folder.py +179 -0
- inline_core-1.2.62/tests/test_flux2_resolve.py +176 -0
- inline_core-1.2.62/tests/test_flux2_runner.py +126 -0
- inline_core-1.2.62/tests/test_flux2_training.py +199 -0
- inline_core-1.2.62/tests/test_flux2_variants.py +129 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_frontend_serving.py +47 -1
- inline_core-1.2.62/tests/test_keymap.py +268 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_memory_policy.py +39 -0
- inline_core-1.2.62/tests/test_minimaxh3_adaln.py +166 -0
- inline_core-1.2.62/tests/test_minimaxh3_keys.py +138 -0
- inline_core-1.2.62/tests/test_minimaxh3_load.py +257 -0
- inline_core-1.2.62/tests/test_minimaxh3_nodes.py +382 -0
- inline_core-1.2.62/tests/test_minimaxh3_training.py +306 -0
- inline_core-1.2.62/tests/test_offload_prepared.py +233 -0
- inline_core-1.2.62/tests/test_output_kind_contract.py +67 -0
- inline_core-1.2.62/tests/test_references.py +84 -0
- inline_core-1.2.62/tests/test_staged_residency.py +101 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_fal.py +46 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_generation.py +89 -4
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_graph_build.py +4 -4
- inline_core-1.2.62/tests/test_studio_multi_reference.py +163 -0
- inline_core-1.2.62/tests/test_studio_node_size.py +58 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_rpc.py +5 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_schema.py +19 -0
- inline_core-1.2.62/tests/test_video_encode.py +158 -0
- inline_core-1.2.62/tests/test_video_params.py +114 -0
- inline_core-1.2.62/tests/test_webui_install.py +154 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/uv.lock +31 -3
- {inline_core-1.2.53 → inline_core-1.2.62}/webui.bat +107 -15
- {inline_core-1.2.53 → inline_core-1.2.62}/webui.sh +92 -17
- inline_core-1.2.53/src/inline_core/runtime/store.py +0 -18
- inline_core-1.2.53/src/inline_core/training/arch.py +0 -184
- {inline_core-1.2.53 → inline_core-1.2.62}/.gitignore +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/.python-version +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/main.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/scripts/reference.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/components/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/components/conditioning.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/components/interfaces.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/config.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/auto.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/detect.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/policy.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/device/types.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/errors.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/api.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/constraints.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/fetch.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/handlers.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/importer.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/install.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/loader.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/manifest.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/models.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/paths.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/resolve.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/scanner.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/state.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/extensions/tools.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/ffmpeg.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/cache.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/descriptor.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/executor.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/loader_runners.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/primitives.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/runners.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/schema.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/topo.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/graph/validate.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/media.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/controlspace.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/convert.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/depth_control.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/img2img.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/krea2/requirements.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/lora.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/preprocess/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/preprocess/requirements.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/preprocess/runner.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/sampling.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/primitives.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/models/zimage/requirements.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/config.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/group.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/launch.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/protocol.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/registry.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/parallel/worker.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/context.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/progress.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/runtime/run.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/sampling/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/sampling/batch.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/__main__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/assets.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/frontend.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/manager.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/rpc.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/server/run_store.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/assets.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/config.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/image_meta.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/peaks.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/recipe.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/store.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/system_stats.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/compose.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/ffmpeg.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/render.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/timeline/resolve.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/training.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/studio/training_store.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/takes.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/__init__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/__main__.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/caption.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/src/inline_core/training/protocol.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/helpers.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_cache.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_catalog.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_checkpoint.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_config.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_device_detect.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_executor.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_api.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_manifest.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_resolve.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_scanner.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_spine.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_extension_state.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_file_store.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_hidden_nodes.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_convert.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_depth_control.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_requirements.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_krea2_runner.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_loader_runners.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_loaders.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_lora.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_lora_download.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_model_requirements.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_parallel_group.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_pipeline_cache.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_primitives.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_recipe.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_rpc_bridge.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_run_store.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_sampling.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_schema.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_server.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_assets.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_frames.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_models.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_moodboard.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_peaks.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_store.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_timeline.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_studio_training.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_take_bytes.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_topo.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_arch.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_dataset.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_models.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_training_resolve.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_validate.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_xfuser_sampler.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_zimage_primitives.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_zimage_resolve.py +0 -0
- {inline_core-1.2.53 → inline_core-1.2.62}/tests/test_zimage_runner.py +0 -0
|
@@ -95,7 +95,16 @@ HTTP/WS → server/app.py → RunManager → Executor → Registry (desc
|
|
|
95
95
|
the ComfyUI-equivalent decomposed graph and the intended long-term surface. **Descriptor-only
|
|
96
96
|
today - their runners land in C2.** A graph built from them validates and type-checks but raises
|
|
97
97
|
`No runner registered` at execution.
|
|
98
|
-
- **Model runners** (`models/<name>/`) - high-level single generation nodes. **`
|
|
98
|
+
- **Model runners** (`models/<name>/`) - high-level single generation nodes. **`black-forest-labs/flux-2`
|
|
99
|
+
(`models/flux2/`) is the reference for a _family_:** one node covers klein 4B/9B, their base builds,
|
|
100
|
+
the KV variant and dev, because the picked checkpoint is identified from its own tensor shapes
|
|
101
|
+
(`flux2/variants.py`) and everything else follows. Adding a checkpoint is a row in that table.
|
|
102
|
+
Two rules it establishes: **identify a checkpoint by content, never by filename** (`diffusion_models/`
|
|
103
|
+
is shared across architectures, and Qwen3-4B and Qwen3-VL-4B have byte-identical embedding shapes),
|
|
104
|
+
and **derive geometry from the checkpoint** rather than bundling a config per variant, so a future
|
|
105
|
+
build loads with no code change. A **diffusers folder** is a valid checkpoint too, which is the only
|
|
106
|
+
way a 32B model reaches a 24 GB card: its NF4 shards stream through `from_pretrained`, where
|
|
107
|
+
`from_single_file` cannot quantize at all. **`alibaba/z-image-turbo`
|
|
99
108
|
(`models/zimage/`) is the one runnable generation path today** (prompt + optional image → one take,
|
|
100
109
|
backed by diffusers' `ZImagePipeline`/`ZImageImg2ImgPipeline`). This is the "Z-Image pipeline that
|
|
101
110
|
already works" - the primitives will reach parity in C2. It loads from a **single diffusion
|
|
@@ -112,6 +121,11 @@ between nodes and are never takes.
|
|
|
112
121
|
|
|
113
122
|
### Storage & configuration (all env, see `config.py`)
|
|
114
123
|
|
|
124
|
+
- **Never put weights on an instance's ephemeral/scratch disk.** On cloud GPU boxes (`/opt/dlami/nvme`,
|
|
125
|
+
`/mnt/resource`, and anything else labelled ephemeral or instance-store) the volume is **wiped on
|
|
126
|
+
every stop/start**, taking the models and leaving dangling symlinks in `models/`. This has cost two
|
|
127
|
+
full re-downloads of MiniMax H3 at ~130 GB each. Weights go on the persistent root volume, or on an
|
|
128
|
+
attached volume that survives a restart. Scratch is fine for logs and temporary output only.
|
|
115
129
|
- **Models root** - `INLINE_MODELS_DIR`, else `./models`. **Bring your own weights; nothing is
|
|
116
130
|
downloaded.** ComfyUI-style category subfolders (`diffusion_models/`, `vae/`, `text_encoders/`,
|
|
117
131
|
`loras/`, `controlnet/`, `checkpoints/`, `clip_vision/`, `upscale_models/`, `embeddings/`). The
|
|
@@ -143,6 +157,18 @@ between nodes and are never takes.
|
|
|
143
157
|
(Turing/Volta - compute capability < 8.0, e.g. a T4): same footprint, but it uses the fp16 tensor
|
|
144
158
|
cores instead of bf16's slow path. The **VAE stays upcast** (bf16, or fp32 when the denoiser is
|
|
145
159
|
fp16) because fp16 VAE decode can overflow to black/NaN images (`_compute_dtype` in `device/`).
|
|
160
|
+
- **Quantization rungs** - the fit ladder is full-precision resident → int8 resident → **NF4 resident**
|
|
161
|
+
→ sequential offload → wont-fit. NF4 is what makes a 32B model viable on a 24 GB card. Note int8
|
|
162
|
+
forces bf16 (torchao's weight-only int8 silently no-ops under fp16) while NF4 does not, so a Turing
|
|
163
|
+
card keeps its fp16 tensor cores under NF4.
|
|
164
|
+
- **Prequantized checkpoints must not be re-quantized.** A checkpoint that ships already quantized
|
|
165
|
+
(`flux2/variants.is_prequantized`) has an on-disk size that already _is_ its resident size, so the
|
|
166
|
+
ladder's assumption that quantization halves it does not hold, and handing diffusers a second,
|
|
167
|
+
different quantization config is a hard error. Pass `Quantization.NONE` for those.
|
|
168
|
+
- **Staged loading** - when the text encoder and the transformer cannot be co-resident (dev is a
|
|
169
|
+
15 GB encoder beside an 18 GB transformer), the prompt is encoded first and the encoder freed before
|
|
170
|
+
the transformer loads. The decision has to be made _before_ the load: by the time an OOM fires there
|
|
171
|
+
is nothing left to free.
|
|
146
172
|
- **Multi-GPU** - `INLINE_PARALLEL` (e.g. `pipefusion=2`, `pipefusion=2,ulysses=2`); degrees multiply
|
|
147
173
|
to the world size, which must equal the GPU count.
|
|
148
174
|
|
|
@@ -202,6 +228,11 @@ real codec that moves tensors lives with the model runner.
|
|
|
202
228
|
Don't scatter it.
|
|
203
229
|
- **Bring-your-own models.** Nothing is downloaded by the engine. The catalog scans; the user places
|
|
204
230
|
files. A model picker is a `SELECT` param with `options_from="<category>"`.
|
|
231
|
+
- **Verify image models by rendering.** The FLUX.2 work shipped five bugs past a green test suite,
|
|
232
|
+
and every one produced a _wrong image rather than an error_: a mis-keyed checkpoint, a
|
|
233
|
+
vision-language encoder loaded in place of a text one, an unnormalized latent, and a control context
|
|
234
|
+
cast to a quantized weight's `uint8` storage dtype. A unit test cannot see a plausible-but-wrong
|
|
235
|
+
image. Render something and look at it.
|
|
205
236
|
- **Tests (pytest).** Cover the logic that matters: graph validate/topo/executor/cache, the catalog
|
|
206
237
|
scan, the run store + server contract, the device/memory policy, the parallel group + xfuser seam,
|
|
207
238
|
and each model runner (import-guarded, no GPU needed). See `tests/`.
|
|
@@ -211,14 +242,17 @@ real codec that moves tensors lives with the model runner.
|
|
|
211
242
|
|
|
212
243
|
```
|
|
213
244
|
uv venv # create ./.venv
|
|
214
|
-
|
|
215
|
-
uv pip install -e ".[
|
|
216
|
-
uv pip install -e ".[runtime
|
|
245
|
+
# --python pins the target: without it uv installs into an activated venv/conda env, not ./.venv
|
|
246
|
+
uv pip install --python .venv/bin/python -e ".[server,dev]" # engine + server + test tooling
|
|
247
|
+
uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
|
|
248
|
+
uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, multi-GPU denoise
|
|
217
249
|
|
|
218
250
|
./webui.sh # run (loopback:8848); friendly flags → INLINE_* env
|
|
219
251
|
./webui.sh --listen --port 9000 # bind all interfaces
|
|
220
252
|
./webui.sh --lowvram # tight-VRAM profile
|
|
221
253
|
./webui.sh --install --extra runtime # set up ./.venv with the model runtime, then exit
|
|
254
|
+
# (reuses an existing ./.venv; --recreate rebuilds it, and
|
|
255
|
+
# an activated foreign env is reported, never modified)
|
|
222
256
|
python -m inline_core.server # run the server directly (INLINE_HOST / INLINE_PORT)
|
|
223
257
|
|
|
224
258
|
ruff check . # lint (zero warnings)
|
|
@@ -227,6 +261,53 @@ uv run pytest -q # tests (no GPU; model code is import-
|
|
|
227
261
|
|
|
228
262
|
## Where to add things
|
|
229
263
|
|
|
264
|
+
- **New video model** → do **not** rediscover the plumbing; it exists as shared seams, and
|
|
265
|
+
`models/minimaxh3/` is the reference caller:
|
|
266
|
+
- `runtime/video_encode.py` + `TakeStore.save_video` / `save_audio` - frames plus a waveform to one
|
|
267
|
+
playable MP4. A model that generates video and its soundtrack jointly returns **both** takes;
|
|
268
|
+
only the one matching the descriptor's `output_kind` claims the node's canvas slot (see
|
|
269
|
+
`studio/generation._save_take`, and `tests/test_output_kind_contract.py` which keeps the
|
|
270
|
+
declarations honest).
|
|
271
|
+
- `models/video_params.py` - `VideoGrid` + `video_param_fields(...)`, the way
|
|
272
|
+
`sampling_param_fields(...)` already works. A duration snaps **up** onto the model's frame grid
|
|
273
|
+
and is then clamped into the model's window, which is what both reference implementations do:
|
|
274
|
+
asking H3 for 10 seconds gives 10.125, not 9.417. **fps is a model constant, never a param**,
|
|
275
|
+
or it desyncs from the grid.
|
|
276
|
+
- `models/references.py` - wired image/video/audio ports as one ordered, numbered list. Wiring
|
|
277
|
+
order is what the prompt addresses, so it is meaning, not decoration.
|
|
278
|
+
- `models/keymap.py` - load a checkpoint written for another implementation. Declare a key plan
|
|
279
|
+
(rename / split / swap halves / drop / assert-equal) and apply it while weights stream in. The
|
|
280
|
+
transforms it performs are the ones that fail **silently**, so a plan declares its expected row
|
|
281
|
+
layout and the detector measures the real one. It needs the **whole tensor**: one head's worth of
|
|
282
|
+
rows cannot tell the layouts apart, and it raises rather than guessing.
|
|
283
|
+
- `models/prepared.py` - cache a quantised model once. Everything that changes the bytes goes in
|
|
284
|
+
the hash, including model-specific flags, or switching a flag serves a stale artifact.
|
|
285
|
+
- `models/offload.py` - the device policy's plan to a concrete torchao + group-offload recipe,
|
|
286
|
+
plus **split residency**: group offload holds the whole model in host RAM, so a model bigger
|
|
287
|
+
than the RAM available has nowhere to sit and the kernel swaps it. `blocks_to_place` sizes the
|
|
288
|
+
overflow and those leading blocks go on the accelerator instead, placed as they land rather
|
|
289
|
+
than after the load. It moves the minimum, because every block left resident is VRAM the
|
|
290
|
+
render wanted for activations.
|
|
291
|
+
- **A group-offloaded model's host footprint is reclaimable at load and unreclaimable one step
|
|
292
|
+
later, so never size a split from free memory during the load.** Streaming from a safetensors
|
|
293
|
+
mmap leaves the CPU-side weights as clean file-backed pages the kernel can drop and re-read for
|
|
294
|
+
free. The first denoising step ends that: group offload returns each block with
|
|
295
|
+
`module.to("cpu")`, which allocates fresh anonymous memory and drops the file-backed storage.
|
|
296
|
+
A planner reading `available` mid-load is reading a number that is about to stop being true,
|
|
297
|
+
and the failure mode is not an exception. It is the machine resetting with the page cache
|
|
298
|
+
converted out from under it, no OOM message and no shutdown sequence. Budget the full
|
|
299
|
+
post-conversion footprint, and count what other components will claim from the same RAM
|
|
300
|
+
afterwards (a leaf-offloaded VAE lands there too).
|
|
301
|
+
- **Ordering, when a load both transforms and quantises:** structural transform first,
|
|
302
|
+
quantisation last, and a prequantized source takes no structural transform at all. The three
|
|
303
|
+
clauses and why they are not negotiable are in `models/offload.py`'s docstring.
|
|
304
|
+
- **Vendoring unreleased upstream code** → `models/<name>/vendor/`, **verbatim, import rewrites
|
|
305
|
+
only**. Put a provenance header in its `__init__.py` naming the repo, PR, branch, commit sha and
|
|
306
|
+
date. `models/*/vendor/` is already excluded from ruff and pyright by a glob, because editing it to
|
|
307
|
+
satisfy our linters destroys the one property that makes a re-sync reviewable. Never patch
|
|
308
|
+
installed diffusers: construct components directly and pass them in, so nothing resolves a class by
|
|
309
|
+
name through a registry we do not own. Pin, don't floor, any dependency whose experimental surface
|
|
310
|
+
the vendored code imports from.
|
|
230
311
|
- **New model runner** → a subpackage `models/<name>/` with `runner.py` (a `NodeDescriptor` + a
|
|
231
312
|
`NodeRunner` + `register_<name>(registry, store, policy)`) and an `__init__.py` re-exporting it;
|
|
232
313
|
add a `try/except ImportError` block in `server/bootstrap.py`; add an optional-deps extra in
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: inline-core
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.62
|
|
4
4
|
Summary: The generation engine behind Inline Studio.
|
|
5
5
|
License-Expression: GPL-3.0-or-later
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -10,7 +10,7 @@ Provides-Extra: all
|
|
|
10
10
|
Requires-Dist: accelerate>=0.30; extra == 'all'
|
|
11
11
|
Requires-Dist: bitsandbytes>=0.43; (platform_system != 'Darwin') and extra == 'all'
|
|
12
12
|
Requires-Dist: controlnet-aux>=0.0.7; extra == 'all'
|
|
13
|
-
Requires-Dist: diffusers
|
|
13
|
+
Requires-Dist: diffusers==0.39.0; extra == 'all'
|
|
14
14
|
Requires-Dist: einops>=0.7; extra == 'all'
|
|
15
15
|
Requires-Dist: fastapi>=0.110; extra == 'all'
|
|
16
16
|
Requires-Dist: huggingface-hub>=0.23; extra == 'all'
|
|
@@ -37,8 +37,9 @@ Requires-Dist: nvidia-ml-py>=12; extra == 'parallel'
|
|
|
37
37
|
Requires-Dist: xfuser>=0.4; extra == 'parallel'
|
|
38
38
|
Provides-Extra: runtime
|
|
39
39
|
Requires-Dist: accelerate>=0.30; extra == 'runtime'
|
|
40
|
+
Requires-Dist: av>=12; extra == 'runtime'
|
|
40
41
|
Requires-Dist: controlnet-aux>=0.0.7; extra == 'runtime'
|
|
41
|
-
Requires-Dist: diffusers
|
|
42
|
+
Requires-Dist: diffusers==0.39.0; extra == 'runtime'
|
|
42
43
|
Requires-Dist: huggingface-hub>=0.23; extra == 'runtime'
|
|
43
44
|
Requires-Dist: onnxruntime>=1.17; extra == 'runtime'
|
|
44
45
|
Requires-Dist: safetensors>=0.4; extra == 'runtime'
|
|
@@ -67,17 +68,24 @@ The generation engine behind Inline. It takes a typed node graph (JSON) and retu
|
|
|
67
68
|
low-VRAM laptops up to multi-GPU machines that split a single image's sampling across GPUs (via
|
|
68
69
|
xDiT). It is Inline Studio's built-in render backend.
|
|
69
70
|
|
|
70
|
-
Models today: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow
|
|
71
|
-
xDiT already supports, so the multi-GPU split works on it from the
|
|
72
|
-
a 12.9B single-stream MMDiT released as an undistilled RAW base plus an
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
Models today, all running locally on your own GPU: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow
|
|
72
|
+
diffusion transformer and the model xDiT already supports, so the multi-GPU split works on it from the
|
|
73
|
+
start; **Krea 2** (Krea AI), a 12.9B single-stream MMDiT released as an undistilled RAW base plus an
|
|
74
|
+
8-step distilled Turbo; **FLUX.2** (Black Forest Labs); and **MiniMax H3**, which generates video and
|
|
75
|
+
its soundtrack in a single pass.
|
|
76
|
+
|
|
77
|
+
Core also runs the **LoRA trainer** behind Inline Studio's Trainer canvas, so the same engine that
|
|
78
|
+
generates can fine-tune Z-Image, Krea 2, FLUX.2 and MiniMax H3 on your own images without a cloud
|
|
79
|
+
step. Training is cheaper than generating: Krea 2 fits a 16GB card at 512px with a 4-bit base. Its
|
|
80
|
+
dependencies sit behind the `training` extra. See the
|
|
81
|
+
[LoRA training guide](https://inlinestudio.art/lora-training) for the measured VRAM table.
|
|
82
|
+
|
|
83
|
+
> Status: the graph engine, the typed `/v1` HTTP + websocket API (durable runs, streamed progress,
|
|
84
|
+
> coalescing), the model-dir scan, the device + memory policy (profiles, dtype, offload, int8), the
|
|
85
|
+
> low-level primitive node vocabulary, the model runners above, and the LoRA trainer all run on real
|
|
86
|
+
> hardware. Cross-request batching, single-image multi-GPU (an xDiT worker group behind the sampler
|
|
87
|
+
> seam, with the policy and IPC round-trip tested), and out-of-process custom nodes are built as
|
|
88
|
+
> seams but are not yet exercised on real hardware.
|
|
81
89
|
|
|
82
90
|
## Engine design
|
|
83
91
|
|
|
@@ -101,13 +109,18 @@ a 6 GB laptop, pure CPU, or split across several GPUs, without touching the grap
|
|
|
101
109
|
|
|
102
110
|
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
103
111
|
|
|
112
|
+
`--python` pins each install to `./.venv`; without it uv targets whatever venv or conda env is
|
|
113
|
+
activated in your shell, and installs land there instead.
|
|
114
|
+
|
|
104
115
|
```
|
|
105
116
|
uv venv
|
|
106
|
-
uv pip install -e ".[server]"
|
|
107
|
-
uv pip install -e ".[runtime]"
|
|
108
|
-
uv pip install -e ".[runtime,parallel]" # + xfuser,
|
|
117
|
+
uv pip install --python .venv/bin/python -e ".[server]" # engine + HTTP/websocket API
|
|
118
|
+
uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
|
|
119
|
+
uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, 2+ GPUs
|
|
109
120
|
```
|
|
110
121
|
|
|
122
|
+
Or let the launcher do it: `./webui.sh --install --extra runtime` (Windows: `.\webui.bat`).
|
|
123
|
+
|
|
111
124
|
## Models
|
|
112
125
|
|
|
113
126
|
Drop files into the models dir (default `./models`, override with `INLINE_MODELS_DIR`), ComfyUI-style,
|
|
@@ -5,17 +5,24 @@ The generation engine behind Inline. It takes a typed node graph (JSON) and retu
|
|
|
5
5
|
low-VRAM laptops up to multi-GPU machines that split a single image's sampling across GPUs (via
|
|
6
6
|
xDiT). It is Inline Studio's built-in render backend.
|
|
7
7
|
|
|
8
|
-
Models today: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow
|
|
9
|
-
xDiT already supports, so the multi-GPU split works on it from the
|
|
10
|
-
a 12.9B single-stream MMDiT released as an undistilled RAW base plus an
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
Models today, all running locally on your own GPU: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow
|
|
9
|
+
diffusion transformer and the model xDiT already supports, so the multi-GPU split works on it from the
|
|
10
|
+
start; **Krea 2** (Krea AI), a 12.9B single-stream MMDiT released as an undistilled RAW base plus an
|
|
11
|
+
8-step distilled Turbo; **FLUX.2** (Black Forest Labs); and **MiniMax H3**, which generates video and
|
|
12
|
+
its soundtrack in a single pass.
|
|
13
|
+
|
|
14
|
+
Core also runs the **LoRA trainer** behind Inline Studio's Trainer canvas, so the same engine that
|
|
15
|
+
generates can fine-tune Z-Image, Krea 2, FLUX.2 and MiniMax H3 on your own images without a cloud
|
|
16
|
+
step. Training is cheaper than generating: Krea 2 fits a 16GB card at 512px with a 4-bit base. Its
|
|
17
|
+
dependencies sit behind the `training` extra. See the
|
|
18
|
+
[LoRA training guide](https://inlinestudio.art/lora-training) for the measured VRAM table.
|
|
19
|
+
|
|
20
|
+
> Status: the graph engine, the typed `/v1` HTTP + websocket API (durable runs, streamed progress,
|
|
21
|
+
> coalescing), the model-dir scan, the device + memory policy (profiles, dtype, offload, int8), the
|
|
22
|
+
> low-level primitive node vocabulary, the model runners above, and the LoRA trainer all run on real
|
|
23
|
+
> hardware. Cross-request batching, single-image multi-GPU (an xDiT worker group behind the sampler
|
|
24
|
+
> seam, with the policy and IPC round-trip tested), and out-of-process custom nodes are built as
|
|
25
|
+
> seams but are not yet exercised on real hardware.
|
|
19
26
|
|
|
20
27
|
## Engine design
|
|
21
28
|
|
|
@@ -39,13 +46,18 @@ a 6 GB laptop, pure CPU, or split across several GPUs, without touching the grap
|
|
|
39
46
|
|
|
40
47
|
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
41
48
|
|
|
49
|
+
`--python` pins each install to `./.venv`; without it uv targets whatever venv or conda env is
|
|
50
|
+
activated in your shell, and installs land there instead.
|
|
51
|
+
|
|
42
52
|
```
|
|
43
53
|
uv venv
|
|
44
|
-
uv pip install -e ".[server]"
|
|
45
|
-
uv pip install -e ".[runtime]"
|
|
46
|
-
uv pip install -e ".[runtime,parallel]" # + xfuser,
|
|
54
|
+
uv pip install --python .venv/bin/python -e ".[server]" # engine + HTTP/websocket API
|
|
55
|
+
uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
|
|
56
|
+
uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, 2+ GPUs
|
|
47
57
|
```
|
|
48
58
|
|
|
59
|
+
Or let the launcher do it: `./webui.sh --install --extra runtime` (Windows: `.\webui.bat`).
|
|
60
|
+
|
|
49
61
|
## Models
|
|
50
62
|
|
|
51
63
|
Drop files into the models dir (default `./models`, override with `INLINE_MODELS_DIR`), ComfyUI-style,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
# PyPI name; the import package is `inline_core` (src/inline_core).
|
|
3
3
|
name = "inline-core"
|
|
4
|
-
version = "1.2.
|
|
4
|
+
version = "1.2.62"
|
|
5
5
|
description = "The generation engine behind Inline Studio."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "GPL-3.0-or-later"
|
|
@@ -18,7 +18,9 @@ runtime = [
|
|
|
18
18
|
# A bare `torch` is CPU-only on Windows; see [tool.uv] below and requirements.txt.
|
|
19
19
|
"torch>=2.2",
|
|
20
20
|
# Krea 2 needs diffusers >= 0.39 (Krea2Pipeline); Z-Image needs >= 0.36 (ZImagePipeline).
|
|
21
|
-
|
|
21
|
+
# Pinned, not floored: MiniMax H3 is vendored from an unmerged PR and imports six symbols
|
|
22
|
+
# from the experimental Modular Diffusers surface, which a minor release may rename.
|
|
23
|
+
"diffusers==0.39.0",
|
|
22
24
|
"transformers>=4.44",
|
|
23
25
|
"accelerate>=0.30",
|
|
24
26
|
"safetensors>=0.4",
|
|
@@ -32,6 +34,10 @@ runtime = [
|
|
|
32
34
|
# HED, lineart, MLSD, scribble, normal. DWPose runs its detector on ONNX Runtime.
|
|
33
35
|
"controlnet-aux>=0.0.7",
|
|
34
36
|
"onnxruntime>=1.17",
|
|
37
|
+
# MiniMax H3's reference node decodes a wired video or audio clip when it builds the reference.
|
|
38
|
+
# The blocks raise a plain ImportError without it, so the node would advertise two ports it
|
|
39
|
+
# cannot read. Video output goes out through ffmpeg, not this.
|
|
40
|
+
"av>=12",
|
|
35
41
|
]
|
|
36
42
|
server = [
|
|
37
43
|
"fastapi>=0.110",
|
|
@@ -71,7 +77,7 @@ dev = [
|
|
|
71
77
|
all = [
|
|
72
78
|
# runtime
|
|
73
79
|
"torch>=2.2",
|
|
74
|
-
"diffusers
|
|
80
|
+
"diffusers==0.39.0",
|
|
75
81
|
"transformers>=4.44",
|
|
76
82
|
"accelerate>=0.30",
|
|
77
83
|
"safetensors>=0.4",
|
|
@@ -116,15 +122,21 @@ packages = ["src/inline_core"]
|
|
|
116
122
|
[tool.ruff]
|
|
117
123
|
line-length = 100
|
|
118
124
|
target-version = "py311"
|
|
125
|
+
# Vendored upstream code (see models/minimaxh3/vendor/__init__.py). Editing it to satisfy our
|
|
126
|
+
# linters would destroy the one property that makes a re-sync reviewable: it is verbatim.
|
|
127
|
+
extend-exclude = ["src/inline_core/models/*/vendor"]
|
|
119
128
|
|
|
120
129
|
[tool.ruff.lint]
|
|
121
130
|
select = ["E", "F", "I", "UP", "B"]
|
|
122
131
|
|
|
123
132
|
[tool.pyright]
|
|
124
133
|
include = ["src", "tests"]
|
|
134
|
+
exclude = ["**/models/*/vendor"]
|
|
125
135
|
pythonVersion = "3.11"
|
|
126
136
|
typeCheckingMode = "strict"
|
|
127
137
|
|
|
128
138
|
[tool.pytest.ini_options]
|
|
129
139
|
testpaths = ["tests"]
|
|
130
|
-
|
|
140
|
+
# "." so `tests` imports as a package: several suites share fixtures via `from tests.x import y`,
|
|
141
|
+
# and without it those modules fail to collect and silently stop running.
|
|
142
|
+
pythonpath = ["src", "."]
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""VRAM + step-time sweep for FLUX.2 LoRA training: the cells behind the README benchmark table.
|
|
2
|
+
|
|
3
|
+
cd core && PYTHONPATH=src .venv/bin/python scripts/flux2_train_matrix.py --dataset <dir>
|
|
4
|
+
|
|
5
|
+
One cell = one real run of `python -m inline_core.training`, the same entry point the Trainer tab
|
|
6
|
+
spawns, so a number here is a number a user would see. Anything else (importing `train` in-process,
|
|
7
|
+
or a hand-rolled loop) would measure a different program.
|
|
8
|
+
|
|
9
|
+
Held fixed at the settings the existing Z-Image and Krea 2 rows used: 12 steps, rank 16, batch 1,
|
|
10
|
+
gradient checkpointing on. What varies is resolution and base precision. Peak VRAM is the trainer's
|
|
11
|
+
own `torch.cuda.max_memory_allocated` reading off the last progress line; an OOM is recorded as a
|
|
12
|
+
cell rather than aborting the sweep, because "does not fit" is a result the table needs.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import subprocess
|
|
21
|
+
import sys
|
|
22
|
+
import time
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
_REPO = Path(__file__).resolve().parent.parent.parent
|
|
26
|
+
_CORE = _REPO / "core"
|
|
27
|
+
_DEFAULT_OUT = _REPO / "outputs" / "flux2-train-matrix"
|
|
28
|
+
|
|
29
|
+
# (resolution, baseQuant). `none` is the bf16 base; `nf4` is the 4-bit (QLoRA) base.
|
|
30
|
+
CELLS: tuple[tuple[int, str], ...] = (
|
|
31
|
+
(512, "none"),
|
|
32
|
+
(512, "nf4"),
|
|
33
|
+
(1024, "none"),
|
|
34
|
+
(1024, "nf4"),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
_STEPS = 12
|
|
38
|
+
_RANK = 16
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _manifest(work: Path, dataset: Path, models: Path, resolution: int, quant: str) -> Path:
|
|
42
|
+
"""The same manifest shape `studio/training.py::_prepare` writes."""
|
|
43
|
+
checkpoints = work / "checkpoints"
|
|
44
|
+
checkpoints.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
manifest = {
|
|
46
|
+
"runId": work.name,
|
|
47
|
+
"workingDir": str(work),
|
|
48
|
+
"datasetDir": str(dataset),
|
|
49
|
+
"checkpointDir": str(checkpoints),
|
|
50
|
+
"outputPath": str(work / "lora.safetensors"),
|
|
51
|
+
"resumeFrom": None,
|
|
52
|
+
"modelsDir": str(models),
|
|
53
|
+
"arch": "flux2",
|
|
54
|
+
# FLUX.2 offers one base mode: the undistilled klein base. `raw` is that mode's key.
|
|
55
|
+
"baseMode": "raw",
|
|
56
|
+
"triggerWord": "",
|
|
57
|
+
"hyperparams": {
|
|
58
|
+
"arch": "flux2",
|
|
59
|
+
"baseMode": "raw",
|
|
60
|
+
"baseQuant": quant,
|
|
61
|
+
# Explicit, not `auto`: the sweep is measuring what each precision costs, and auto would
|
|
62
|
+
# silently swap a bf16 cell for NF4 the moment it predicted a bad fit.
|
|
63
|
+
"offload": "off",
|
|
64
|
+
"loraScope": "full",
|
|
65
|
+
"captionDropout": 0.0,
|
|
66
|
+
"flipAugment": False,
|
|
67
|
+
"rank": _RANK,
|
|
68
|
+
"alpha": _RANK,
|
|
69
|
+
"learningRate": 1e-4,
|
|
70
|
+
"batchSize": 1,
|
|
71
|
+
"steps": _STEPS,
|
|
72
|
+
"saveEvery": _STEPS,
|
|
73
|
+
"resolution": resolution,
|
|
74
|
+
},
|
|
75
|
+
"gpuIds": [],
|
|
76
|
+
}
|
|
77
|
+
path = work / "manifest.json"
|
|
78
|
+
path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
|
|
79
|
+
return path
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _run_cell(python: str, manifest: Path, log: Path) -> dict[str, object]:
|
|
83
|
+
"""Drain the JSON-line protocol, keeping the last VRAM reading and the wall time from the first
|
|
84
|
+
training step onward - loading and latent precache are not what the table reports."""
|
|
85
|
+
env = {**os.environ, "PYTHONPATH": str(_CORE / "src")}
|
|
86
|
+
proc = subprocess.Popen(
|
|
87
|
+
[python, "-m", "inline_core.training", str(manifest)],
|
|
88
|
+
cwd=str(_CORE),
|
|
89
|
+
env=env,
|
|
90
|
+
stdout=subprocess.PIPE,
|
|
91
|
+
stderr=subprocess.STDOUT,
|
|
92
|
+
text=True,
|
|
93
|
+
bufsize=1,
|
|
94
|
+
)
|
|
95
|
+
vram: float | None = None
|
|
96
|
+
error: str | None = None
|
|
97
|
+
first_step_at: float | None = None
|
|
98
|
+
last_step_at: float | None = None
|
|
99
|
+
steps_seen = 0
|
|
100
|
+
started = time.perf_counter()
|
|
101
|
+
lines: list[str] = []
|
|
102
|
+
assert proc.stdout is not None
|
|
103
|
+
for line in proc.stdout:
|
|
104
|
+
lines.append(line)
|
|
105
|
+
line = line.strip()
|
|
106
|
+
if not line.startswith("{"):
|
|
107
|
+
continue
|
|
108
|
+
try:
|
|
109
|
+
message = json.loads(line)
|
|
110
|
+
except json.JSONDecodeError:
|
|
111
|
+
continue
|
|
112
|
+
kind = message.get("type")
|
|
113
|
+
if kind == "progress":
|
|
114
|
+
if message.get("vram") is not None:
|
|
115
|
+
vram = float(message["vram"])
|
|
116
|
+
if message.get("step"):
|
|
117
|
+
steps_seen = int(message["step"])
|
|
118
|
+
now = time.perf_counter()
|
|
119
|
+
if first_step_at is None:
|
|
120
|
+
first_step_at = now
|
|
121
|
+
last_step_at = now
|
|
122
|
+
elif kind == "error":
|
|
123
|
+
error = str(message.get("message") or "")
|
|
124
|
+
proc.wait()
|
|
125
|
+
log.write_text("".join(lines), encoding="utf-8")
|
|
126
|
+
|
|
127
|
+
oom = bool(error) and ("out of gpu memory" in error.lower() or "out of memory" in error.lower())
|
|
128
|
+
# Step 1 pays for the first graph build, so time the interval after it and scale by the gap.
|
|
129
|
+
per_step: float | None = None
|
|
130
|
+
if first_step_at is not None and last_step_at is not None and steps_seen > 1:
|
|
131
|
+
per_step = (last_step_at - first_step_at) / (steps_seen - 1)
|
|
132
|
+
return {
|
|
133
|
+
"peak_vram_gb": vram,
|
|
134
|
+
"seconds_per_step": round(per_step, 2) if per_step else None,
|
|
135
|
+
"seconds_12_steps": round(per_step * _STEPS, 1) if per_step else None,
|
|
136
|
+
"total_seconds": round(time.perf_counter() - started, 1),
|
|
137
|
+
"steps_completed": steps_seen,
|
|
138
|
+
"status": "oom" if oom else ("ok" if proc.returncode == 0 else "failed"),
|
|
139
|
+
"error": error,
|
|
140
|
+
"log": log.name,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def main() -> int:
|
|
145
|
+
parser = argparse.ArgumentParser()
|
|
146
|
+
parser.add_argument("--dataset", type=Path, required=True, help="dir of NNNN.jpg + NNNN.txt")
|
|
147
|
+
parser.add_argument("--out", type=Path, default=_DEFAULT_OUT)
|
|
148
|
+
parser.add_argument("--models", type=Path, default=_CORE / "models")
|
|
149
|
+
parser.add_argument("--python", default=str(_CORE / ".venv" / "bin" / "python"))
|
|
150
|
+
parser.add_argument("--gpu", default="", help="label for the results file, e.g. 'L40S (46GB)'")
|
|
151
|
+
parser.add_argument("--only", default="", help="substring of a cell id, to redo one row")
|
|
152
|
+
args = parser.parse_args()
|
|
153
|
+
|
|
154
|
+
if not args.dataset.is_dir():
|
|
155
|
+
raise SystemExit(f"dataset not found: {args.dataset}")
|
|
156
|
+
|
|
157
|
+
args.out.mkdir(parents=True, exist_ok=True)
|
|
158
|
+
results_path = args.out / "results.json"
|
|
159
|
+
results: dict[str, dict[str, object]] = {}
|
|
160
|
+
if results_path.exists():
|
|
161
|
+
results = json.loads(results_path.read_text()).get("cells", {})
|
|
162
|
+
|
|
163
|
+
label = args.gpu
|
|
164
|
+
if not label:
|
|
165
|
+
try:
|
|
166
|
+
name = subprocess.run(
|
|
167
|
+
["nvidia-smi", "--query-gpu=name,memory.total", "--format=csv,noheader"],
|
|
168
|
+
capture_output=True,
|
|
169
|
+
text=True,
|
|
170
|
+
check=True,
|
|
171
|
+
).stdout.strip()
|
|
172
|
+
label = name.splitlines()[0]
|
|
173
|
+
except Exception: # noqa: BLE001 - the label is cosmetic
|
|
174
|
+
label = "unknown GPU"
|
|
175
|
+
|
|
176
|
+
def write() -> None:
|
|
177
|
+
results_path.write_text(
|
|
178
|
+
json.dumps(
|
|
179
|
+
{"gpu": label, "steps": _STEPS, "rank": _RANK, "cells": results},
|
|
180
|
+
indent=2,
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
for resolution, quant in CELLS:
|
|
185
|
+
cell_id = f"{resolution}-{quant}"
|
|
186
|
+
if args.only and args.only not in cell_id:
|
|
187
|
+
continue
|
|
188
|
+
work = args.out / cell_id
|
|
189
|
+
work.mkdir(parents=True, exist_ok=True)
|
|
190
|
+
manifest = _manifest(work, args.dataset, args.models, resolution, quant)
|
|
191
|
+
print(f"--- {cell_id}: {resolution}px, base {quant} ---", flush=True)
|
|
192
|
+
result = _run_cell(args.python, manifest, args.out / f"{cell_id}.log")
|
|
193
|
+
result.update({"resolution": resolution, "base_quant": quant})
|
|
194
|
+
results[cell_id] = result
|
|
195
|
+
print(json.dumps(result, indent=2), flush=True)
|
|
196
|
+
write()
|
|
197
|
+
|
|
198
|
+
write()
|
|
199
|
+
print(f"\n{results_path}")
|
|
200
|
+
return 0
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
raise SystemExit(main())
|