inline-core 1.2.62__tar.gz → 1.2.63__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.
Files changed (255) hide show
  1. {inline_core-1.2.62 → inline_core-1.2.63}/PKG-INFO +1 -1
  2. {inline_core-1.2.62 → inline_core-1.2.63}/pyproject.toml +1 -1
  3. {inline_core-1.2.62 → inline_core-1.2.63}/scripts/minimax_h3_train_matrix.py +7 -4
  4. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/load.py +5 -8
  5. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/arch.py +10 -28
  6. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/h3.py +69 -28
  7. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/models.py +7 -0
  8. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/trainer.py +3 -4
  9. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_minimaxh3_training.py +55 -0
  10. {inline_core-1.2.62 → inline_core-1.2.63}/.gitignore +0 -0
  11. {inline_core-1.2.62 → inline_core-1.2.63}/.python-version +0 -0
  12. {inline_core-1.2.62 → inline_core-1.2.63}/CLAUDE.md +0 -0
  13. {inline_core-1.2.62 → inline_core-1.2.63}/README.md +0 -0
  14. {inline_core-1.2.62 → inline_core-1.2.63}/main.py +0 -0
  15. {inline_core-1.2.62 → inline_core-1.2.63}/scripts/flux2_train_matrix.py +0 -0
  16. {inline_core-1.2.62 → inline_core-1.2.63}/scripts/minimax_h3_lora_check.py +0 -0
  17. {inline_core-1.2.62 → inline_core-1.2.63}/scripts/reference.py +0 -0
  18. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/__init__.py +0 -0
  19. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/components/__init__.py +0 -0
  20. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/components/conditioning.py +0 -0
  21. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/components/interfaces.py +0 -0
  22. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/config.py +0 -0
  23. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/device/__init__.py +0 -0
  24. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/device/auto.py +0 -0
  25. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/device/detect.py +0 -0
  26. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/device/memory.py +0 -0
  27. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/device/policy.py +0 -0
  28. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/device/types.py +0 -0
  29. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/errors.py +0 -0
  30. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/__init__.py +0 -0
  31. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/api.py +0 -0
  32. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/constraints.py +0 -0
  33. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/fetch.py +0 -0
  34. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/handlers.py +0 -0
  35. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/importer.py +0 -0
  36. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/install.py +0 -0
  37. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/loader.py +0 -0
  38. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/manifest.py +0 -0
  39. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/models.py +0 -0
  40. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/paths.py +0 -0
  41. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/resolve.py +0 -0
  42. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/scanner.py +0 -0
  43. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/state.py +0 -0
  44. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/extensions/tools.py +0 -0
  45. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/ffmpeg.py +0 -0
  46. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/__init__.py +0 -0
  47. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/cache.py +0 -0
  48. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/descriptor.py +0 -0
  49. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/executor.py +0 -0
  50. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/loader_runners.py +0 -0
  51. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/primitives.py +0 -0
  52. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/registry.py +0 -0
  53. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/runners.py +0 -0
  54. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/schema.py +0 -0
  55. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/topo.py +0 -0
  56. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/graph/validate.py +0 -0
  57. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/media.py +0 -0
  58. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/__init__.py +0 -0
  59. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/catalog.py +0 -0
  60. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/checkpoint.py +0 -0
  61. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/controlspace.py +0 -0
  62. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/__init__.py +0 -0
  63. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/controlnet.py +0 -0
  64. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/embeds.py +0 -0
  65. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/provider.py +0 -0
  66. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/requirements.py +0 -0
  67. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/runner.py +0 -0
  68. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/flux2/variants.py +0 -0
  69. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/keymap.py +0 -0
  70. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/__init__.py +0 -0
  71. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/convert.py +0 -0
  72. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/depth_control.py +0 -0
  73. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/img2img.py +0 -0
  74. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/provider.py +0 -0
  75. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/requirements.py +0 -0
  76. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/krea2/runner.py +0 -0
  77. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/loaders.py +0 -0
  78. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/lora.py +0 -0
  79. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/__init__.py +0 -0
  80. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/adaln.py +0 -0
  81. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/keys.py +0 -0
  82. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/pipeline.py +0 -0
  83. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/provider.py +0 -0
  84. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/requirements.py +0 -0
  85. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/runner.py +0 -0
  86. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vae_keys.py +0 -0
  87. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/__init__.py +0 -0
  88. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/autoencoder_kl_minimax_h3.py +0 -0
  89. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/autoencoder_kl_minimax_h3_audio.py +0 -0
  90. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/before_denoise.py +0 -0
  91. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/before_encoder.py +0 -0
  92. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/decoders.py +0 -0
  93. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/denoise.py +0 -0
  94. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/encoders.py +0 -0
  95. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/modular_blocks_minimax_h3.py +0 -0
  96. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/modular_pipeline.py +0 -0
  97. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/packing.py +0 -0
  98. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/packing_ref2va.py +0 -0
  99. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/scheduling_minimax_h3.py +0 -0
  100. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/minimaxh3/vendor/transformer_minimax_h3.py +0 -0
  101. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/offload.py +0 -0
  102. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/pipeline_runtime.py +0 -0
  103. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/prepared.py +0 -0
  104. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/preprocess/__init__.py +0 -0
  105. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/preprocess/requirements.py +0 -0
  106. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/preprocess/runner.py +0 -0
  107. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/references.py +0 -0
  108. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/requirements.py +0 -0
  109. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/sampling.py +0 -0
  110. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/video_params.py +0 -0
  111. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/zimage/__init__.py +0 -0
  112. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/zimage/primitives.py +0 -0
  113. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/zimage/provider.py +0 -0
  114. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/zimage/requirements.py +0 -0
  115. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/models/zimage/runner.py +0 -0
  116. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/__init__.py +0 -0
  117. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/config.py +0 -0
  118. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/group.py +0 -0
  119. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/launch.py +0 -0
  120. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/protocol.py +0 -0
  121. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/registry.py +0 -0
  122. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/parallel/worker.py +0 -0
  123. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/__init__.py +0 -0
  124. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/context.py +0 -0
  125. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/file_store.py +0 -0
  126. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/progress.py +0 -0
  127. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/run.py +0 -0
  128. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/store.py +0 -0
  129. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/runtime/video_encode.py +0 -0
  130. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/sampling/__init__.py +0 -0
  131. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/sampling/batch.py +0 -0
  132. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/__init__.py +0 -0
  133. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/__main__.py +0 -0
  134. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/app.py +0 -0
  135. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/assets.py +0 -0
  136. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/bootstrap.py +0 -0
  137. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/frontend.py +0 -0
  138. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/manager.py +0 -0
  139. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/rpc.py +0 -0
  140. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/run_store.py +0 -0
  141. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/server/serialize.py +0 -0
  142. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/__init__.py +0 -0
  143. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/assets.py +0 -0
  144. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/config.py +0 -0
  145. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/fal.py +0 -0
  146. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/frames.py +0 -0
  147. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/generation.py +0 -0
  148. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/graph_build.py +0 -0
  149. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/handlers.py +0 -0
  150. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/image_meta.py +0 -0
  151. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/models.py +0 -0
  152. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/moodboard.py +0 -0
  153. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/peaks.py +0 -0
  154. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/recipe.py +0 -0
  155. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/schema.py +0 -0
  156. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/store.py +0 -0
  157. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/system_stats.py +0 -0
  158. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/timeline/__init__.py +0 -0
  159. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/timeline/compose.py +0 -0
  160. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/timeline/ffmpeg.py +0 -0
  161. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/timeline/render.py +0 -0
  162. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/timeline/resolve.py +0 -0
  163. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/training.py +0 -0
  164. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/studio/training_store.py +0 -0
  165. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/takes.py +0 -0
  166. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/__init__.py +0 -0
  167. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/__main__.py +0 -0
  168. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/cache.py +0 -0
  169. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/caption.py +0 -0
  170. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/dataset.py +0 -0
  171. {inline_core-1.2.62 → inline_core-1.2.63}/src/inline_core/training/protocol.py +0 -0
  172. {inline_core-1.2.62 → inline_core-1.2.63}/tests/conftest.py +0 -0
  173. {inline_core-1.2.62 → inline_core-1.2.63}/tests/helpers.py +0 -0
  174. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_cache.py +0 -0
  175. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_catalog.py +0 -0
  176. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_checkpoint.py +0 -0
  177. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_config.py +0 -0
  178. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_device_detect.py +0 -0
  179. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_executor.py +0 -0
  180. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_api.py +0 -0
  181. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_install.py +0 -0
  182. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_manifest.py +0 -0
  183. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_resolve.py +0 -0
  184. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_scanner.py +0 -0
  185. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_spine.py +0 -0
  186. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_extension_state.py +0 -0
  187. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_file_store.py +0 -0
  188. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_flux2_controlnet.py +0 -0
  189. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_flux2_folder.py +0 -0
  190. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_flux2_resolve.py +0 -0
  191. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_flux2_runner.py +0 -0
  192. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_flux2_training.py +0 -0
  193. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_flux2_variants.py +0 -0
  194. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_frontend_serving.py +0 -0
  195. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_hidden_nodes.py +0 -0
  196. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_keymap.py +0 -0
  197. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_krea2_convert.py +0 -0
  198. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_krea2_depth_control.py +0 -0
  199. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_krea2_requirements.py +0 -0
  200. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_krea2_runner.py +0 -0
  201. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_loader_runners.py +0 -0
  202. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_loaders.py +0 -0
  203. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_lora.py +0 -0
  204. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_lora_download.py +0 -0
  205. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_memory_policy.py +0 -0
  206. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_minimaxh3_adaln.py +0 -0
  207. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_minimaxh3_keys.py +0 -0
  208. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_minimaxh3_load.py +0 -0
  209. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_minimaxh3_nodes.py +0 -0
  210. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_model_requirements.py +0 -0
  211. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_offload_prepared.py +0 -0
  212. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_output_kind_contract.py +0 -0
  213. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_parallel_group.py +0 -0
  214. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_pipeline_cache.py +0 -0
  215. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_primitives.py +0 -0
  216. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_recipe.py +0 -0
  217. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_references.py +0 -0
  218. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_rpc_bridge.py +0 -0
  219. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_run_store.py +0 -0
  220. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_sampling.py +0 -0
  221. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_schema.py +0 -0
  222. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_server.py +0 -0
  223. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_staged_residency.py +0 -0
  224. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_assets.py +0 -0
  225. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_fal.py +0 -0
  226. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_frames.py +0 -0
  227. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_generation.py +0 -0
  228. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_graph_build.py +0 -0
  229. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_models.py +0 -0
  230. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_moodboard.py +0 -0
  231. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_multi_reference.py +0 -0
  232. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_node_size.py +0 -0
  233. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_peaks.py +0 -0
  234. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_rpc.py +0 -0
  235. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_schema.py +0 -0
  236. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_store.py +0 -0
  237. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_timeline.py +0 -0
  238. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_studio_training.py +0 -0
  239. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_take_bytes.py +0 -0
  240. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_topo.py +0 -0
  241. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_training_arch.py +0 -0
  242. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_training_dataset.py +0 -0
  243. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_training_models.py +0 -0
  244. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_training_resolve.py +0 -0
  245. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_validate.py +0 -0
  246. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_video_encode.py +0 -0
  247. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_video_params.py +0 -0
  248. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_webui_install.py +0 -0
  249. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_xfuser_sampler.py +0 -0
  250. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_zimage_primitives.py +0 -0
  251. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_zimage_resolve.py +0 -0
  252. {inline_core-1.2.62 → inline_core-1.2.63}/tests/test_zimage_runner.py +0 -0
  253. {inline_core-1.2.62 → inline_core-1.2.63}/uv.lock +0 -0
  254. {inline_core-1.2.62 → inline_core-1.2.63}/webui.bat +0 -0
  255. {inline_core-1.2.62 → inline_core-1.2.63}/webui.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inline-core
3
- Version: 1.2.62
3
+ Version: 1.2.63
4
4
  Summary: The generation engine behind Inline Studio.
5
5
  License-Expression: GPL-3.0-or-later
6
6
  Requires-Python: >=3.11
@@ -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.62"
4
+ version = "1.2.63"
5
5
  description = "The generation engine behind Inline Studio."
6
6
  readme = "README.md"
7
7
  license = "GPL-3.0-or-later"
@@ -34,7 +34,9 @@ _STEPS = 12
34
34
  _RANK = 16
35
35
 
36
36
 
37
- def _manifest(work: Path, dataset: Path, models: Path, resolution: int) -> Path:
37
+ def _manifest(
38
+ work: Path, dataset: Path, models: Path, resolution: int, steps: int = _STEPS
39
+ ) -> Path:
38
40
  """The same manifest shape `studio/training.py::_prepare` writes."""
39
41
  checkpoints = work / "checkpoints"
40
42
  checkpoints.mkdir(parents=True, exist_ok=True)
@@ -62,8 +64,8 @@ def _manifest(work: Path, dataset: Path, models: Path, resolution: int) -> Path:
62
64
  "alpha": _RANK,
63
65
  "learningRate": 1e-4,
64
66
  "batchSize": 1,
65
- "steps": _STEPS,
66
- "saveEvery": _STEPS,
67
+ "steps": steps,
68
+ "saveEvery": steps,
67
69
  "resolution": resolution,
68
70
  },
69
71
  "gpuIds": [],
@@ -152,6 +154,7 @@ def main() -> int:
152
154
  parser.add_argument("--python", default=str(_CORE / ".venv" / "bin" / "python"))
153
155
  parser.add_argument("--gpu", default="", help="label for the results file, e.g. 'L40S (46GB)'")
154
156
  parser.add_argument("--only", default="", help="one resolution, to redo a single row")
157
+ parser.add_argument("--steps", type=int, default=_STEPS, help="override for a smoke run")
155
158
  args = parser.parse_args()
156
159
 
157
160
  if not args.dataset.is_dir():
@@ -186,7 +189,7 @@ def main() -> int:
186
189
  continue
187
190
  work = args.out / cell_id
188
191
  work.mkdir(parents=True, exist_ok=True)
189
- manifest = _manifest(work, args.dataset, args.models, resolution)
192
+ manifest = _manifest(work, args.dataset, args.models, resolution, args.steps)
190
193
  print(f"--- {cell_id}px, 4-bit base ---", flush=True)
191
194
  result = _run_cell(args.python, manifest, args.out / f"{cell_id}.log")
192
195
  result.update({"resolution": resolution, "base_quant": "nf4"})
@@ -165,9 +165,8 @@ def load_transformer(
165
165
  def _fusing_shrink(plan: Any, fused: set[str], inner: Any) -> Any:
166
166
  """Fuse a block's share of the LoRA stack the moment it lands, then hand off to ``shrink``.
167
167
 
168
- Order matters both ways: after the stream the block's weights exist, and before ``shrink`` they
169
- are still unquantised, which is the only window in which a full-precision delta can be added
170
- in place.
168
+ The only window that works: after the stream the weights exist, before ``shrink`` they are
169
+ still unquantised, and a full-precision delta cannot be added to a quantised weight.
171
170
  """
172
171
 
173
172
  def shrink(model: Any, prefix: str) -> None:
@@ -195,11 +194,9 @@ def _fuse_subtree(module: Any, plan: Any, prefix: str) -> set[str]:
195
194
  def _finish_fuse(model: Any, plan: Any, fused: set[str]) -> None:
196
195
  """Fuse what the block callback never saw, then prove nothing was missed.
197
196
 
198
- The callback only fires for ``transformer_blocks.N``, so ``context_embedder``, the token
199
- refiner and the output heads would silently keep their base weights - and silently is the whole
200
- problem. ``plan_loras`` only raises when a key matches *no* module in the model, and these
201
- modules do exist, so a partial fuse validates clean and then degrades the output without ever
202
- erroring. The residual pass covers them and the check makes any remaining gap loud.
197
+ The callback fires only for ``transformer_blocks.N``, so ``context_embedder`` and the token
198
+ refiner would keep their base weights. ``plan_loras`` raises only when a key matches *no*
199
+ module, and these exist, so a partial fuse validates clean and then degrades output silently.
203
200
  """
204
201
  residual = {name: deltas for name, deltas in plan.items() if name not in fused}
205
202
  if residual:
@@ -76,21 +76,12 @@ _FLUX2_TARGETS = [
76
76
  ]
77
77
 
78
78
 
79
- #: MiniMax H3: the attention and SwiGLU feed-forward Linears of all 50 blocks, plus the text
80
- #: projection. Confirmed against MiniMaxH3Transformer3DModel.named_modules(): a block's Linears are
81
- #: exactly to_q/to_k/to_v/to_out.0, ff.net.0.proj, ff.net.2 and adaln_proj.linear.
79
+ #: MiniMax H3: every Linear in a block except ``adaln_proj``, plus the text projection.
82
80
  #:
83
- #: ``adaln_proj.linear`` is deliberately absent. It is replaced at load by the rank-8 factorisation
84
- #: (``minimaxh3/adaln.py``) that takes the checkpoint from 66GB to 40GB, so the module a LoRA would
85
- #: attach to carries the whole modulation signal through eight columns - the same reason
86
- #: ``minimaxh3/pipeline.py`` refuses to quantize it.
87
- #:
88
- #: The fp32-pinned modules are absent for a different reason: H3 ships a mixed-precision checkpoint
89
- #: where the patch projections, the timestep MLP and the two output heads stay float32
90
- #: (``_keep_in_fp32_modules``), and adapting those fights the precision split, not the model.
91
- #:
92
- #: PEFT matches by name suffix, so this also adapts the two token-refiner blocks. That is wanted,
93
- #: and it is why the loader must fuse outside the block stack too - see ``minimaxh3/load.py``.
81
+ #: ``adaln_proj`` is out because the load factorises it to rank 8, so a LoRA would attach to eight
82
+ #: columns carrying the whole modulation signal. The fp32-pinned heads are out because adapting them
83
+ #: fights the checkpoint's precision split. PEFT matches by suffix, so this also reaches the two
84
+ #: token-refiner blocks, which is why the loader has to fuse outside the block stack.
94
85
  _MINIMAX_H3_TARGETS = [
95
86
  "to_q",
96
87
  "to_k",
@@ -270,13 +261,8 @@ _H3_PATCH = (1, 2, 2)
270
261
  def _h3_forward(transformer: Any, noisy: Any, timestep: Any, item: dict[str, Any]) -> Any:
271
262
  """One prediction from MiniMaxH3Transformer3DModel, mirroring the vendored denoise block.
272
263
 
273
- H3 runs one packed 1-D sequence holding text, audio and video rows rather than separate streams,
274
- and the caller owns that layout. The precache builds it once per image (it only depends on the
275
- caption length and the latent grid) and caches the tensors, so a step just patchifies, assigns
276
- every row this step's timestep, and selects the video rows back out.
277
-
278
- A still is one latent frame with no audio rows at all, which the model accepts: the audio head
279
- runs over an empty index and returns empty.
264
+ H3 packs text, audio and video into one 1-D sequence and the caller owns that layout, so the
265
+ precache builds it per image and a step only patchifies and selects the video rows back out.
280
266
  """
281
267
  from ..models.minimaxh3.vendor.packing import patchify_video_latents, unpatchify_video_tokens
282
268
 
@@ -336,14 +322,10 @@ ARCHS: dict[str, TrainingArch] = {
336
322
  MINIMAX_H3: TrainingArch(
337
323
  key=MINIMAX_H3,
338
324
  target_modules=_MINIMAX_H3_TARGETS,
339
- # H3's shift is the same expression Z-Image uses, at the scheduler's video shift of 12.0
340
- # (MiniMaxH3Scheduler builds its grid as shift * s / (1 + (shift - 1) * s)), so the
341
- # generic sigma applies unchanged.
325
+ # Same shift expression as Z-Image, at the scheduler's video shift of 12.0.
342
326
  sigma=_zimage_sigma,
343
- # Z-Image's convention exactly, and worth a test rather than a comment because Krea 2 and
344
- # FLUX.2 use the opposite one: MiniMaxH3Scheduler.scale_noise is
345
- # x_t = t * clean + (1 - t) * noise at t = 1 - sigma, and its step reconstructs
346
- # x0 = x_t + sigma * v, so the velocity the model predicts is clean - noise.
327
+ # Z-Image's convention, opposite to Krea 2 and FLUX.2, and pinned against the vendored
328
+ # scheduler in test_minimaxh3_training.py rather than restated here.
347
329
  timestep=lambda sigma: 1.0 - sigma,
348
330
  target=lambda clean, noise: clean - noise,
349
331
  forward=_h3_forward,
@@ -25,11 +25,8 @@ PATCH = (1, 2, 2)
25
25
  AUDIO_LATENT_CHANNELS = 32
26
26
 
27
27
  #: What an absent caption becomes. H3 tokenises with ``add_special_tokens=False`` and has no BOS,
28
- #: so the empty string is genuinely zero tokens and the conditioner reshapes a (1, 0) sequence into
29
- #: an attention head and raises. A single space is one real token and the closest thing this model
30
- #: has to no caption: it is guidance-distilled, so inference never encodes an unconditional prompt
31
- #: and there is no established unconditional embedding to match. Covers caption dropout and an
32
- #: image whose ``.txt`` is missing or blank.
28
+ #: so an empty string is zero tokens and the conditioner raises on the (1, 0) sequence. Covers both
29
+ #: caption dropout and an image whose ``.txt`` is missing.
33
30
  _EMPTY_CAPTION = " "
34
31
 
35
32
 
@@ -117,6 +114,12 @@ def _encode_captions(
117
114
  from ..models.minimaxh3.vendor.encoders import MiniMaxH3TextEncoderStep
118
115
 
119
116
  pipeline = _load_conditioner(root, device, dtype)
117
+ # Encode wherever it landed. It spills to host RAM on a card too small for 20.5GB, and the
118
+ # vendored step builds its input ids on the device it is handed, so CUDA ids against a
119
+ # CPU-resident encoder fail in `index_select`.
120
+ where = next(pipeline.text_encoder.parameters()).device
121
+ if where.type != torch.device(device).type:
122
+ logger.info("MiniMax H3: conditioner is on %s, encoding captions there", where)
120
123
  out: list[tuple[Any, Any]] = []
121
124
  try:
122
125
  for caption in captions:
@@ -126,7 +129,7 @@ def _encode_captions(
126
129
  # is not optional here: it defaults to `components.transformer.dtype`, and this
127
130
  # pipeline deliberately has no transformer.
128
131
  embeds, tags = MiniMaxH3TextEncoderStep.encode_prompt(
129
- pipeline, caption, None, device=torch.device(device), dtype=dtype
132
+ pipeline, caption, None, device=where, dtype=dtype
130
133
  )
131
134
  out.append((embeds[0].cpu(), tags.cpu()))
132
135
  finally:
@@ -151,10 +154,8 @@ def _conditioning(embed: Any, tags: Any, latent: Any) -> dict[str, Any]:
151
154
  patch_size=PATCH,
152
155
  keyframe_anchors=(),
153
156
  )
154
- # Training pins no conditioning rows and a still has no audio rows, so every row shares one
155
- # noise level and this vector is constant across steps. Derived from the vendored planner and
156
- # then checked, so a change upstream is caught here rather than silently mis-addressing the
157
- # AdaLN table.
157
+ # Every row shares one noise level here, so this vector is constant across steps. Derived from
158
+ # the vendored planner and checked, or a change upstream would mis-address the AdaLN table.
158
159
  unique, indices = build_row_timesteps(layout, 1.0, 1.0, 1.0, 1.0)
159
160
  if unique.numel() != 1 or bool(indices.any()):
160
161
  raise RuntimeError(
@@ -212,7 +213,7 @@ def _load_conditioner(root: Path, device: str, dtype: Any) -> Any:
212
213
  "popup; the conditioner cannot tokenise a caption without them."
213
214
  )
214
215
 
215
- quant, placement = _conditioner_plan(device)
216
+ quant, placement = _conditioner_plan(device, encoder_dir)
216
217
  text_encoder = Qwen3VLForConditionalGeneration.from_pretrained(
217
218
  str(encoder_dir),
218
219
  dtype=dtype,
@@ -228,7 +229,54 @@ def _load_conditioner(root: Path, device: str, dtype: Any) -> Any:
228
229
  return pipeline
229
230
 
230
231
 
231
- def _conditioner_plan(device: str) -> tuple[Any, dict[str, Any]]:
232
+ #: What the 4-bit conditioner occupies wherever it lands, measured on an L40S.
233
+ _CONDITIONER_GB = 20.5
234
+
235
+ #: Left free for the process, the page cache and everything else on the box.
236
+ _RAM_HEADROOM_GB = 4.0
237
+
238
+
239
+ def _check_conditioner_fits(placement: Any, encoder_dir: Path) -> None:
240
+ """Refuse a caption pass with nowhere to put the conditioner, and warn when it will crawl.
241
+
242
+ The 4-bit figure only holds on the card: bitsandbytes quantises during the move to CUDA, so a
243
+ CPU placement pages the full bf16 folder instead, measured at 59GB and 42s a caption on a T4.
244
+ Those pages are evictable, so a short machine thrashes rather than raising.
245
+ """
246
+ from ..device.memory import MemoryPolicy
247
+ from ..models import pipeline_runtime as rt
248
+
249
+ free_vram = (rt.free_vram_bytes(placement.device) or 0) / 1e9
250
+ if free_vram >= _CONDITIONER_GB:
251
+ return
252
+ free_ram_mb = MemoryPolicy().free_ram_mb()
253
+ if not free_ram_mb:
254
+ return # unmeasurable; better to attempt the load than to refuse on no evidence
255
+ free_ram = free_ram_mb / 1024
256
+ on_disk = _folder_bytes(encoder_dir) / 1e9
257
+ # Half the folder is a floor, not a fit: only 64 GB has actually been measured, and the pages
258
+ # are evictable, so less RAM buys thrashing rather than a clean failure.
259
+ floor = max(on_disk * 0.5, _CONDITIONER_GB + _RAM_HEADROOM_GB)
260
+ if free_ram < floor:
261
+ raise RuntimeError(
262
+ f"MiniMax H3 conditions on a 32B text encoder. It needs about {_CONDITIONER_GB:.0f} GB "
263
+ f"on the card, or roughly {on_disk:.0f} GB paged through system RAM when the card "
264
+ f"cannot hold it. This machine has {free_vram:.0f} GB free on the card and "
265
+ f"{free_ram:.0f} GB of free RAM, which is not enough for either. Training H3 needs a "
266
+ "larger GPU or more RAM."
267
+ )
268
+ logger.warning(
269
+ "MiniMax H3: the conditioner does not fit %0.0f GB of VRAM, so the caption pass runs "
270
+ "unquantised on the CPU. Expect roughly 40 seconds a caption instead of 2.",
271
+ free_vram,
272
+ )
273
+
274
+
275
+ def _folder_bytes(path: Path) -> int:
276
+ return sum(f.stat().st_size for f in path.rglob("*") if f.is_file())
277
+
278
+
279
+ def _conditioner_plan(device: str, encoder_dir: Path) -> tuple[Any, dict[str, Any]]:
232
280
  """4-bit, and on the card only if it fits, reusing the generation path's own decision."""
233
281
  from ..device.memory import MemoryPolicy
234
282
  from ..models.minimaxh3.pipeline import _encoder_config, _encoder_placement
@@ -240,6 +288,7 @@ def _conditioner_plan(device: str) -> tuple[Any, dict[str, Any]]:
240
288
  quant = _encoder_config(recipe)
241
289
  if quant is None: # bitsandbytes absent: nothing to place, and the load will speak for itself
242
290
  return None, {}
291
+ _check_conditioner_fits(placement, encoder_dir)
243
292
  del device
244
293
  return quant, _encoder_placement(placement)
245
294
 
@@ -305,10 +354,8 @@ def _shrinker(basis: Any, quant: Any, device: str, dtype: Any) -> Any:
305
354
  def _keeps_precision(path: str) -> bool:
306
355
  """Whether a Linear is spared the 4-bit swap.
307
356
 
308
- Only the factorised AdaLN projection. Unfactorised it is [96768, 2688] and quantising it is
309
- ordinary; factorised it is [96768, 8] and those eight columns carry the entire modulation
310
- signal, so the error concentrates instead of averaging. It is 1.5 MB a block, 75 MB across the
311
- stack, which is not worth that.
357
+ Only the factorised AdaLN projection: at rank 8 its eight columns carry the whole modulation
358
+ signal, so quantisation error concentrates rather than averaging, for 75MB across the stack.
312
359
  """
313
360
  return "adaln_proj" in path
314
361
 
@@ -316,12 +363,8 @@ def _keeps_precision(path: str) -> bool:
316
363
  def _swap_to_4bit(module: Any, keep: Any = None, prefix: str = "") -> None:
317
364
  """Replace every ``nn.Linear`` under ``module`` with a bitsandbytes NF4 layer.
318
365
 
319
- The QLoRA arrangement: the base is frozen and 4-bit, gradients still flow through it to the
320
- adapter on top, and quantization itself happens when the layer moves to CUDA.
321
-
322
- Deliberately not ``loaders._swap_to_4bit``, which takes no keep-predicate and would convert the
323
- factorised AdaLN projection along with everything else. Kept local rather than widening the
324
- shared loader, so the two shipping architectures that use it are untouched.
366
+ Deliberately not ``loaders._swap_to_4bit``: that takes no keep-predicate and would convert the
367
+ factorised AdaLN projection too. Local rather than widening a loader two other archs use.
325
368
  """
326
369
  import bitsandbytes as bnb
327
370
  import torch
@@ -349,9 +392,8 @@ def _swap_to_4bit(module: Any, keep: Any = None, prefix: str = "") -> None:
349
392
  def _place_unstreamed(model: Any, device: str) -> None:
350
393
  """Move what the block callback never sees.
351
394
 
352
- ``load.py`` fires ``shrink`` only for ``transformer_blocks.N``, so the embedders, the token
353
- refiner, the norms and the two output heads are still wherever the stream staged them. Left on
354
- the CPU they meet CUDA activations in the first forward.
395
+ ``load.py`` fires ``shrink`` only for ``transformer_blocks.N``, so the embedders, refiner and
396
+ output heads are still wherever the stream staged them, and meet CUDA activations if left.
355
397
  """
356
398
  stack = model.transformer_blocks
357
399
  for child in model.children():
@@ -362,9 +404,8 @@ def _place_unstreamed(model: Any, device: str) -> None:
362
404
 
363
405
 
364
406
  def _sample(moments: Any) -> Any:
365
- """Sample the posterior. Unlike the conditioning path this takes no fixed seed and no fp16
366
- round trip: those exist to make a *reference* reproducible, and baking them into training
367
- latents would narrow what the LoRA ever sees."""
407
+ """Sample the posterior, without the conditioning path's fixed seed and fp16 round trip: those
408
+ make a *reference* reproducible and would narrow what the LoRA sees."""
368
409
  from diffusers.models.autoencoders.vae import DiagonalGaussianDistribution
369
410
 
370
411
  return DiagonalGaussianDistribution(moments).sample()
@@ -178,6 +178,13 @@ _ADAPTER_SOURCE = {
178
178
 
179
179
 
180
180
  def compute_dtype() -> Any:
181
+ """bf16 wherever torch will take it, deliberately including Turing.
182
+
183
+ The device policy prefers fp16 below compute 8.0, where bf16 has no tensor cores. That argument
184
+ is about GPU matmuls and does not transfer here: this dtype also reaches the caption pass, which
185
+ runs on the CPU when the text encoder will not fit the card, and CPU fp16 upcasts. Switching a
186
+ T4 to fp16 hung the machine mid-caption. Narrow it to the GPU compute before revisiting.
187
+ """
181
188
  import torch
182
189
 
183
190
  if torch.cuda.is_available():
@@ -132,10 +132,9 @@ def _activation_offload(enabled: bool) -> Any:
132
132
  return torch.autograd.graph.save_on_cpu(pin_memory=True)
133
133
 
134
134
 
135
- #: The cached-item keys that carry activations and take the compute dtype. Everything else moves to
136
- #: the device unchanged: a boolean mask would become weights, integer row tags and index tensors
137
- #: would stop addressing anything, and H3's float64 rotary position grid would lose most of its
138
- #: mantissa - none of which raises, they just train against the wrong thing.
135
+ #: The cached-item keys that carry activations and take the compute dtype. Everything else moves
136
+ #: unchanged: a bool mask would become weights, index tensors would stop addressing anything, and
137
+ #: H3's float64 rotary grid would lose its mantissa. None of it raises.
139
138
  _ACTIVATION_KEYS = frozenset({"latent", "embed", "audio"})
140
139
 
141
140
 
@@ -8,6 +8,8 @@ scheduler is ever re-synced from upstream and its convention moves, these fail.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ from pathlib import Path
12
+
11
13
  import pytest
12
14
 
13
15
  from inline_core.training import arch as archs
@@ -210,6 +212,59 @@ def test_the_swap_keeps_biases_and_frozen_base_weights() -> None:
210
212
  assert not module.proj.bias.requires_grad
211
213
 
212
214
 
215
+ class _Placement:
216
+ device = "cuda:0"
217
+
218
+
219
+ def _fit_check(
220
+ monkeypatch: pytest.MonkeyPatch, vram_gb: float, ram_gb: float, encoder_gb: float = 63.0
221
+ ) -> None:
222
+ from inline_core.device import memory
223
+ from inline_core.models import pipeline_runtime as rt
224
+ from inline_core.training import h3
225
+
226
+ monkeypatch.setattr(rt, "free_vram_bytes", lambda _d: int(vram_gb * 1e9))
227
+ monkeypatch.setattr(memory.MemoryPolicy, "free_ram_mb", lambda _s: int(ram_gb * 1024))
228
+ monkeypatch.setattr(h3, "_folder_bytes", lambda _p: int(encoder_gb * 1e9))
229
+
230
+
231
+ def test_the_conditioner_fits_on_a_big_card(monkeypatch: pytest.MonkeyPatch) -> None:
232
+ from inline_core.training import h3
233
+
234
+ _fit_check(monkeypatch, vram_gb=45.0, ram_gb=8.0)
235
+ h3._check_conditioner_fits(_Placement(), Path("/enc")) # card holds it, RAM is moot
236
+
237
+
238
+ def test_the_conditioner_may_stream_from_host_ram(monkeypatch: pytest.MonkeyPatch) -> None:
239
+ """A 16GB card is fine given RAM for the spill. Only 64GB has been measured, so the
240
+ guard's floor is half the folder rather than a fit."""
241
+ from inline_core.training import h3
242
+
243
+ _fit_check(monkeypatch, vram_gb=15.0, ram_gb=64.0)
244
+ h3._check_conditioner_fits(_Placement(), Path("/enc"))
245
+
246
+
247
+ def test_a_machine_with_room_in_neither_is_refused(monkeypatch: pytest.MonkeyPatch) -> None:
248
+ """The failure this prevents is a host-RAM OOM, which kills the process rather than raising."""
249
+ from inline_core.training import h3
250
+
251
+ _fit_check(monkeypatch, vram_gb=15.0, ram_gb=15.0)
252
+ with pytest.raises(RuntimeError, match="larger GPU or more RAM"):
253
+ h3._check_conditioner_fits(_Placement(), Path("/enc"))
254
+
255
+
256
+ def test_an_unmeasurable_machine_is_attempted_rather_than_refused(
257
+ monkeypatch: pytest.MonkeyPatch,
258
+ ) -> None:
259
+ from inline_core.device import memory
260
+ from inline_core.models import pipeline_runtime as rt
261
+ from inline_core.training import h3
262
+
263
+ monkeypatch.setattr(rt, "free_vram_bytes", lambda _d: 0)
264
+ monkeypatch.setattr(memory.MemoryPolicy, "free_ram_mb", lambda _s: None)
265
+ h3._check_conditioner_fits(_Placement(), Path("/enc")) # no evidence is not evidence
266
+
267
+
213
268
  def test_the_residual_fuse_reaches_modules_outside_the_block_stack() -> None:
214
269
  """The load callback only fires for ``transformer_blocks.N``, so a per-block fuse silently
215
270
  misses ``context_embedder`` and the token refiner - both of which are LoRA targets and both of
File without changes
File without changes
File without changes
File without changes