Project-Chronos 0.2.1__tar.gz → 0.3.1a0__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 (207) hide show
  1. project_chronos-0.3.1a0/CHANGELOG.md +150 -0
  2. project_chronos-0.3.1a0/MANIFEST.in +13 -0
  3. {project_chronos-0.2.1/Project_Chronos.egg-info → project_chronos-0.3.1a0}/PKG-INFO +252 -19
  4. project_chronos-0.2.1/README.md → project_chronos-0.3.1a0/Project_Chronos.egg-info/PKG-INFO +280 -12
  5. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/Project_Chronos.egg-info/SOURCES.txt +88 -0
  6. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/Project_Chronos.egg-info/requires.txt +15 -3
  7. project_chronos-0.2.1/PKG-INFO → project_chronos-0.3.1a0/README.md +232 -47
  8. project_chronos-0.3.1a0/README_zh.md +944 -0
  9. project_chronos-0.3.1a0/THIRD_PARTY_NOTICES.md +359 -0
  10. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/__init__.py +1 -1
  11. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/app.py +17 -1
  12. project_chronos-0.3.1a0/chronos/bundle/__init__.py +22 -0
  13. project_chronos-0.3.1a0/chronos/bundle/builder.py +342 -0
  14. project_chronos-0.3.1a0/chronos/bundle/cli.py +240 -0
  15. project_chronos-0.3.1a0/chronos/bundle/docs.py +343 -0
  16. project_chronos-0.3.1a0/chronos/bundle/finetune.py +134 -0
  17. project_chronos-0.3.1a0/chronos/bundle/recommend.py +268 -0
  18. project_chronos-0.3.1a0/chronos/bundle/runtime.py +272 -0
  19. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/cli.py +41 -0
  20. project_chronos-0.3.1a0/chronos/config_schema.py +225 -0
  21. project_chronos-0.3.1a0/chronos/data/__init__.py +11 -0
  22. project_chronos-0.3.1a0/chronos/data/corpus/__init__.py +7 -0
  23. project_chronos-0.3.1a0/chronos/data/corpus/clean.py +105 -0
  24. project_chronos-0.3.1a0/chronos/data/corpus/download.py +161 -0
  25. project_chronos-0.3.1a0/chronos/data/corpus/evalsets.py +65 -0
  26. project_chronos-0.3.1a0/chronos/data/corpus/pipeline.py +205 -0
  27. project_chronos-0.3.1a0/chronos/data/corpus/presets.py +63 -0
  28. project_chronos-0.3.1a0/chronos/data/corpus/readers.py +141 -0
  29. project_chronos-0.3.1a0/chronos/data/corpus/shards.py +237 -0
  30. project_chronos-0.3.1a0/chronos/data/corpus/sources.py +107 -0
  31. project_chronos-0.3.1a0/chronos/data/flexible_dataset.py +766 -0
  32. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/deps.py +8 -0
  33. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/eval/benchmark.py +9 -14
  34. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/eval/io_profiler.py +1 -1
  35. project_chronos-0.3.1a0/chronos/expert_clusters.py +121 -0
  36. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/export.py +75 -7
  37. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/io/async_prefetcher.py +46 -11
  38. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/io/cluster_layout.py +30 -7
  39. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/io/expert_store.py +340 -133
  40. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/io/storage.py +83 -8
  41. project_chronos-0.3.1a0/chronos/lazy_experts.py +387 -0
  42. project_chronos-0.3.1a0/chronos/migrate.py +51 -0
  43. project_chronos-0.3.1a0/chronos/mlx/attention.py +410 -0
  44. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/expert_store.py +171 -42
  45. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/inference.py +351 -30
  46. project_chronos-0.3.1a0/chronos/mlx/kv_quant.py +87 -0
  47. project_chronos-0.3.1a0/chronos/mlx/model.py +393 -0
  48. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/moe.py +88 -5
  49. project_chronos-0.3.1a0/chronos/mlx/moe_kernels.py +156 -0
  50. project_chronos-0.3.1a0/chronos/mlx/recurrent.py +89 -0
  51. project_chronos-0.3.1a0/chronos/mlx/speculative.py +227 -0
  52. project_chronos-0.3.1a0/chronos/mlx/training/inspect_checkpoint.py +179 -0
  53. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/training/io.py +15 -4
  54. project_chronos-0.3.1a0/chronos/mlx/training/longrun.py +730 -0
  55. project_chronos-0.3.1a0/chronos/mlx/training/optim.py +45 -0
  56. project_chronos-0.3.1a0/chronos/mlx/training/telemetry.py +236 -0
  57. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/training/trainer.py +382 -199
  58. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/model/__init__.py +3 -1
  59. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/model/checkpoint.py +102 -47
  60. project_chronos-0.3.1a0/chronos/model/config.py +251 -0
  61. project_chronos-0.3.1a0/chronos/model/factory.py +94 -0
  62. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/model/hf_io.py +3 -0
  63. project_chronos-0.3.1a0/chronos/model/hybrid_attention.py +397 -0
  64. project_chronos-0.3.1a0/chronos/model/kv_quant.py +108 -0
  65. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/model/lookahead_router.py +9 -4
  66. project_chronos-0.3.1a0/chronos/model/model_chronos.py +691 -0
  67. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/model/moe_chronos.py +109 -32
  68. project_chronos-0.3.1a0/chronos/model/multimodal.py +216 -0
  69. project_chronos-0.3.1a0/chronos/model/outputs.py +62 -0
  70. project_chronos-0.3.1a0/chronos/model/planner.py +686 -0
  71. project_chronos-0.3.1a0/chronos/model/precision_ops.py +144 -0
  72. project_chronos-0.3.1a0/chronos/model/recurrent.py +208 -0
  73. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/model/temporal_loss.py +123 -13
  74. project_chronos-0.3.1a0/chronos/monitor/__init__.py +17 -0
  75. project_chronos-0.3.1a0/chronos/monitor/evals.py +110 -0
  76. project_chronos-0.3.1a0/chronos/monitor/jsonl.py +81 -0
  77. project_chronos-0.3.1a0/chronos/monitor/process.py +179 -0
  78. project_chronos-0.3.1a0/chronos/monitor/server.py +253 -0
  79. project_chronos-0.3.1a0/chronos/monitor/snapshot.py +330 -0
  80. project_chronos-0.3.1a0/chronos/monitor/static/app.css +165 -0
  81. project_chronos-0.3.1a0/chronos/monitor/static/app.js +1036 -0
  82. project_chronos-0.3.1a0/chronos/monitor/static/index.html +49 -0
  83. project_chronos-0.3.1a0/chronos/precision.py +195 -0
  84. project_chronos-0.3.1a0/chronos/residency_planner.py +154 -0
  85. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/runtime/cache_manager.py +19 -9
  86. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/runtime/inference_engine.py +377 -55
  87. project_chronos-0.3.1a0/chronos/runtime/speculative.py +225 -0
  88. project_chronos-0.3.1a0/chronos/serving/__init__.py +24 -0
  89. project_chronos-0.3.1a0/chronos/serving/adapter.py +121 -0
  90. project_chronos-0.3.1a0/chronos/serving/api_compat.py +131 -0
  91. project_chronos-0.3.1a0/chronos/serving/ollama_server.py +359 -0
  92. project_chronos-0.3.1a0/chronos/serving/runtime.py +356 -0
  93. project_chronos-0.3.1a0/chronos/tokenizer/__init__.py +75 -0
  94. project_chronos-0.3.1a0/chronos/tokenizer/__main__.py +4 -0
  95. project_chronos-0.3.1a0/chronos/tokenizer/evaluate.py +40 -0
  96. project_chronos-0.3.1a0/chronos/tokenizer/extract.py +176 -0
  97. project_chronos-0.3.1a0/chronos/tokenizer/model.py +197 -0
  98. project_chronos-0.3.1a0/chronos/tokenizer/normalize.py +81 -0
  99. project_chronos-0.3.1a0/chronos/tokenizer/trainer.py +207 -0
  100. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/__init__.py +1 -0
  101. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/chronos_trainer.py +37 -10
  102. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/device_utils.py +34 -9
  103. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/distill_trainer.py +70 -15
  104. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/dpo_trainer.py +16 -5
  105. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/grpo_trainer.py +18 -6
  106. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/loss_mixin.py +93 -5
  107. project_chronos-0.3.1a0/chronos/trainer/optim_utils.py +354 -0
  108. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/orpo_trainer.py +15 -4
  109. project_chronos-0.3.1a0/chronos/trainer/paged_store.py +337 -0
  110. project_chronos-0.3.1a0/chronos/trainer/precision_training.py +170 -0
  111. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/sft_trainer.py +51 -11
  112. project_chronos-0.3.1a0/chronos/trainer/stage_utils.py +243 -0
  113. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/tuning/chronos_auto_tuner.py +1 -1
  114. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/verify.py +4 -4
  115. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/pyproject.toml +20 -7
  116. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/requirements.txt +1 -1
  117. project_chronos-0.3.1a0/setup.py +4 -0
  118. project_chronos-0.3.1a0/tests/test_bundle.py +258 -0
  119. project_chronos-0.3.1a0/tests/test_interface_regressions.py +230 -0
  120. project_chronos-0.3.1a0/tests/test_lazy_experts.py +285 -0
  121. project_chronos-0.3.1a0/tests/test_longrun.py +64 -0
  122. project_chronos-0.3.1a0/tests/test_mlx_speculative.py +208 -0
  123. project_chronos-0.3.1a0/tests/test_moe_dispatch.py +167 -0
  124. project_chronos-0.3.1a0/tests/test_monitor.py +301 -0
  125. project_chronos-0.3.1a0/tests/test_planner_ui.py +303 -0
  126. project_chronos-0.3.1a0/tests/test_precision_chain.py +458 -0
  127. project_chronos-0.3.1a0/tests/test_residency_cluster.py +265 -0
  128. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/tests/test_smoke.py +24 -4
  129. project_chronos-0.3.1a0/tests/test_speculative.py +123 -0
  130. project_chronos-0.3.1a0/tests/test_tokenizer_builder.py +103 -0
  131. project_chronos-0.3.1a0/tests/test_ui_event_browser.py +171 -0
  132. project_chronos-0.3.1a0/tests/test_ui_event_contract.py +95 -0
  133. project_chronos-0.3.1a0/tests/test_ui_generic.py +358 -0
  134. project_chronos-0.3.1a0/tests/test_v2_architecture.py +209 -0
  135. project_chronos-0.3.1a0/tests/test_v3_inference_options.py +388 -0
  136. project_chronos-0.3.1a0/tests/test_v3_kernel.py +283 -0
  137. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/train_chronos.py +34 -8
  138. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/train_chronos_distill.py +20 -3
  139. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/train_chronos_dpo.py +4 -2
  140. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/train_chronos_grpo.py +4 -2
  141. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/train_chronos_orpo.py +4 -2
  142. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/train_chronos_sft.py +20 -3
  143. project_chronos-0.3.1a0/ui/estimator.py +250 -0
  144. project_chronos-0.3.1a0/ui/event_contract.js +48 -0
  145. project_chronos-0.3.1a0/ui/event_contract.py +127 -0
  146. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/gradio_compat.py +11 -0
  147. project_chronos-0.3.1a0/ui/i18n.py +1172 -0
  148. project_chronos-0.3.1a0/ui/planner_panel.py +177 -0
  149. project_chronos-0.3.1a0/ui/presets.py +379 -0
  150. project_chronos-0.3.1a0/ui/presets_v3.json +700 -0
  151. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/autotune_tab.py +6 -4
  152. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/benchmark_tab.py +12 -11
  153. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/config_tab.py +246 -123
  154. project_chronos-0.3.1a0/ui/tabs/data_tab.py +217 -0
  155. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/export_tab.py +14 -1
  156. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/inference_tab.py +300 -480
  157. project_chronos-0.3.1a0/ui/tabs/monitor_tab.py +425 -0
  158. project_chronos-0.3.1a0/ui/tabs/serve_tab.py +202 -0
  159. project_chronos-0.3.1a0/ui/tabs/tokenizer_tab.py +191 -0
  160. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/train_tab.py +208 -87
  161. project_chronos-0.2.1/MANIFEST.in +0 -9
  162. project_chronos-0.2.1/chronos/data/__init__.py +0 -0
  163. project_chronos-0.2.1/chronos/data/flexible_dataset.py +0 -326
  164. project_chronos-0.2.1/chronos/mlx/attention.py +0 -275
  165. project_chronos-0.2.1/chronos/mlx/model.py +0 -233
  166. project_chronos-0.2.1/chronos/model/config.py +0 -72
  167. project_chronos-0.2.1/chronos/model/hybrid_attention.py +0 -269
  168. project_chronos-0.2.1/chronos/model/model_chronos.py +0 -291
  169. project_chronos-0.2.1/chronos/serving/__init__.py +0 -13
  170. project_chronos-0.2.1/chronos/trainer/optim_utils.py +0 -101
  171. project_chronos-0.2.1/chronos/trainer/stage_utils.py +0 -136
  172. project_chronos-0.2.1/setup.py +0 -23
  173. project_chronos-0.2.1/ui/estimator.py +0 -204
  174. project_chronos-0.2.1/ui/i18n.py +0 -664
  175. project_chronos-0.2.1/ui/presets.py +0 -237
  176. project_chronos-0.2.1/ui/tabs/data_tab.py +0 -148
  177. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/LICENSE +0 -0
  178. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/Project_Chronos.egg-info/dependency_links.txt +0 -0
  179. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/Project_Chronos.egg-info/entry_points.txt +0 -0
  180. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/Project_Chronos.egg-info/top_level.txt +0 -0
  181. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/_backend_legacy.py +0 -0
  182. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/backend/__init__.py +0 -0
  183. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/backend/dispatcher.py +0 -0
  184. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/backend/ext/__init__.py +0 -0
  185. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/backend/ext/opencl.py +0 -0
  186. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/backend/mac_diagnostics.py +0 -0
  187. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/eval/__init__.py +0 -0
  188. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/io/__init__.py +0 -0
  189. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/io/io_simulator.py +0 -0
  190. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/__init__.py +0 -0
  191. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/mlx/training/__init__.py +0 -0
  192. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/router/__init__.py +0 -0
  193. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/router/expert_predictor.py +0 -0
  194. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/router/intent_classifier.py +0 -0
  195. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/router/prefill_scheduler.py +0 -0
  196. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/runtime/__init__.py +0 -0
  197. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/runtime/metrics.py +0 -0
  198. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/serving/vllm_adapter.py +0 -0
  199. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/trainer/reward.py +0 -0
  200. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/tuning/__init__.py +0 -0
  201. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/chronos/tuning/_base_tuner.py +0 -0
  202. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/setup.cfg +0 -0
  203. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/tests/test_smoke_cuda.py +0 -0
  204. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/__init__.py +0 -0
  205. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/__init__.py +0 -0
  206. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/iomon_tab.py +0 -0
  207. {project_chronos-0.2.1 → project_chronos-0.3.1a0}/ui/tabs/pipeline_tab.py +0 -0
@@ -0,0 +1,150 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [0.3.1a0] — 2026-11-07 (beta)
6
+
7
+ Core half of 0.3.1: cluster-locality training on by default, inference that
8
+ adapts its expert paging to how the checkpoint was trained, and lazy experts in
9
+ the bundle. The rewritten Web UI follows in 0.3.1a1.
10
+
11
+ ### Changed
12
+ - Cluster locality is on by default for new training: `train_chronos*.py --lambda_cluster_locality` defaults to 0.3, the planner and presets set λ = 0.3 for MoE models with more than 2k experts, and the window follows the data (`recommended_window`: power of two nearest the median SFT record, clamped to [16, seq_len]; 32 without record lengths). The `ChronosConfig` class default stays 0.0, so a stored recipe without the field keeps its original objective on resume, and checkpoints written before the field existed load as λ = 0. The λ = 0.3 default comes from the synthetic sweep below (from-scratch training); its effect on real data and on fine-tuning has not been measured.
13
+ - Lazy-expert inference picks its page layout from the checkpoint (`paging="auto"`): weights trained with λ > 0 are paged one training cluster per SSD read, other weights one expert per read. `paging="cluster"|"expert"` forces a layout. The layout is part of the expert-cache directory name (`…_mlx_c2`, `…_c2`), so a cache written for one layout is never reused for the other. Per-expert cache names are unchanged.
14
+
15
+ ### Added
16
+ - `chronos/lazy_experts.py`: one lazy-expert implementation for the Web UI, bundle and server — `LazyOptions` (paging, residency, decay, decode/verify waits, RAM ratio; validated), `page_layout`, `checkpoint_cache_dir`, the expert budget, and `build_mlx_lazy_engine` (trunk only in memory, cache built or reused).
17
+ - Torch offload writes cluster layouts as `cluster_<c>.ctsr` files with a v2 manifest (`ClusterStorage.write_clusters_from_states`); `setup_from_state_dict/_reader(clusters=…)`.
18
+ - MLX `generate(decode_wait_s=0.012, verify_wait_s=0.02, repetition_penalty=1.0)`. The penalty uses the CTRL rule and is rejected together with `speculative=True`, which needs penalty 1.0 to stay exact.
19
+ - `chronos bundle translate|eval --lazy-experts` with `--paging`, `--residency`, `--decay`, `--ram-ratio`, `--decode-wait`, `--verify-wait`. The cache lives outside the bundle (`$CHRONOS_EXPERT_CACHE`, default `~/.cache/chronos/expert_cache`); `eval` also gains `--backend` and `--dtype`.
20
+ - `chronos bundle finetune --[no-]cluster-locality --lambda-cluster --cluster-window --clusters` (on by default; dense models and models with fewer than two clusters stay off). The spec records where each value came from (`extra.cluster_locality_source`); the window comes from the median SFT record length of `--data`.
21
+ - `chronos serve --paging auto|cluster|expert`; `/api/ps` metadata reports the resolved layout.
22
+ - Web UI Inference tab: paging, planner decay and the two prefetch waits, with four-language labels.
23
+
24
+ - Next-use residency planning for lazy MLX experts (`chronos/residency_planner.py`, `generate(residency="planned")`). The planner records the page-access trace of every forward, keyed by (layer, loop iteration). The previous forward of the same kind, and in speculative decoding the queue of draft traces since the last verify, then predicts when each page is needed next. The store evicts the page needed latest (`MLXExpertStore.set_eviction_ranker`). The running dispatch's pending experts are never evicted. Pages needed early are prefetched only into spare slots. Greedy output is unchanged. The Web UI Inference tab has a switch for it, on by default (MLX lazy only); the stats table shows the eviction policy.
25
+ - Cluster-locality training constraint `lambda_cluster_locality`, with `cluster_locality_clusters` (0 = ⌈E/2k⌉) and `cluster_locality_window`. The loss is 1 − I(window; cluster)/log C over every MoE dispatch, recurrent iterations included. It keeps a stream inside few expert clusters and spreads different streams over different clusters. The partition (`chronos/expert_clusters.py`) is the one lazy inference pages by. Torch and MLX trainers and all stage scripts take it.
26
+ - `tools/bench_residency.py`: LRU window vs planned residency, plain and speculative, on a real checkpoint.
27
+ - `tools/bench_cluster_locality.py`: a tiny-model training A/B of the constraint, reporting held-out CE, cluster entropies, topic purity and lazy-decode cluster reads.
28
+
29
+ ### Measured (reports/residency_20261107/)
30
+ - 50M s13996 checkpoint, 16 FLORES+ dev prompts, greedy, CPU, 12 hot / 12 RAM pages.
31
+ - Plain decoding: planned residency needs 4438 synchronous SSD loads instead of 6876 (−35%). Throughput is 22.47 vs 23.17 tok/s.
32
+ - Speculative decoding: 6258 vs 9297 loads (−33%), and 18.96 vs 16.03 tok/s.
33
+ - All outputs are identical to plain greedy (16/16).
34
+ - The checkpoint was trained without the constraint and routes near-uniformly over all 36 experts within a stream.
35
+ - Tiny model on synthetic 4-topic streams, 300 steps, λ=0.3 vs 0.
36
+ - Window cluster entropy falls from 0.49 to 0.005; topic→cluster purity rises from 0.81 to 0.999.
37
+ - Marginal cluster entropy rises from 0.71 to 0.99, and expert-usage entropy is unchanged (0.87).
38
+ - Held-out CE is 1.712 vs 1.703.
39
+ - Cluster-paged lazy decoding needs 0.023 vs 1.48 cluster reads per token.
40
+
41
+ ### Fixed
42
+ - MLX lazy store: an expert evicted by the prefetch thread between an SSD read and promotion raised "could not be loaded on demand". Reads now return the page they loaded.
43
+
44
+ ## [0.3.0] — 2026-11-06
45
+
46
+ v3 kernel: recurrent-depth MoE. Quality results for the 50M en→zh demo are not
47
+ included yet; they will be added after the 72-hour run and its ablations.
48
+
49
+ ### Added
50
+ - Web UI Inference tab: self-speculative switch, draft depth and γ. All four runner paths use it (Torch / MLX, full DRAM / lazy experts). The stats table shows acceptance, tokens per verify, and verify / draft forwards. Models without a shared KV stream (`per_iteration`, depth 1) decode plainly and say so.
51
+ - `ChronosInferenceEngine.generate_speculative`: self-speculative decoding with lazy experts. Every draft and verify forward runs under the current availability masks, and the lookahead prediction is prefetched before it. `chronos.runtime.speculative.speculative_supported(cfg)` tells callers whether a model can draft.
52
+ - `tools/bench_speculative.py`: plain vs speculative decoding on the real runtimes. Reports wall time, tokens/s, acceptance, identical-output count and SSD loads, with the environment and checkpoint hash.
53
+ - Recurrent-depth execution: prelude → shared recurrent groups looped `recurrent_depth` times with a contractive update → coda.
54
+ - `recurrent_attention_mode`: `shared_first` (default; attention every iteration, K/V from iteration 0), `per_iteration` (ablation), `first_only` (v2 semantics).
55
+ - Tensor-only ACT early exit, exact and batch-invariant; per-token decode exit without KV gaps.
56
+ - Recurrent-depth self-speculative decoding (`chronos/runtime/speculative.py`): greedy-exact, rejection sampling, cache rollback.
57
+ - MLX self-speculative decode loop (`chronos/mlx/speculative.py`), Torch parity: same invariant, rejection sampling with `mx.random` keys, cache truncation for MLA, SWA and int8 entries. `ChronosMLXInferenceEngine.generate(speculative=True, draft_depth=, gamma=)` runs it with the lazy-expert masks; experts each draft routes to are unioned with the lookahead prediction and prefetched before the verify forward. `SlidingWindowAttentionMLX.cache_slack` keeps `window + γ_max + 1` entries for rollback.
58
+ - `chronos bundle build|pack|check|probe|translate|eval|prepare-data|finetune|serve`: a self-contained model bundle (weights + sidecar, tokenizer, FLORES+ dev/devtest, vendored minimind, wheel, source recipe, recommended fine-tune tiers, launcher, setup script, EN/ZH README, NOTICE, SHA-256 file table). `bundle translate` takes `--backend torch|mlx` and `--speculative`.
59
+ - `CHRONOS_MINIMIND_DIR` points Chronos at a local minimind copy (bundles set it to `third_party/minimind`), so no git clone or network access is needed.
60
+ - Stage scripts take `--tokenizer_path`; `load_stage_tokenizer` loads the checkpoint's own tokenizer and refuses one that does not fit `vocab_size`.
61
+ - `chronos longrun` spec fields `init_checkpoint` (start from existing weights, checked against `model_config`) and `export_prefix`.
62
+ - Sorted grouped MoE dispatch: `mx.gather_mm` on MLX (requires mlx >= 0.32.4), `argsort` + `index_add_` on Torch; per-expert reference paths kept for parity tests.
63
+ - Single-dtype precision chain for CPU / CUDA / MPS / MLX with FP32 only in RMSNorm statistics, SDPA softmax, RoPE tables, router softmax, LM-head logits and optimizer masters; bit-exact MLX↔Torch bf16 bridge.
64
+ - `chronos serve`: Ollama/OpenAI protocol server on the native runtime (lazy experts, speculative decoding); optional `/monitor/` mount.
65
+ - `chronos tokenizer`: self-built byte-fallback BPE with language-balanced merges and HF-compatible `tokenizer.json`.
66
+ - `chronos corpus download|build|shards`: pinned downloads, cleaning, global dedup, eval-set leak removal, uint16 shards.
67
+ - `chronos longrun` (alias `run`): time-budgeted resumable MLX training with NaN rollback, validation and translation probes, and run telemetry (`status.json`, `runtime.json`, `parameters.jsonl`).
68
+ - `chronos monitor`: read-only training monitor page + JSON API (loopback by default; key login, session cookie, rate limiting off loopback); Training Monitor tab in the Web UI.
69
+ - `chronos.model.factory.fit_config`: parameter-budget configuration search.
70
+ - Optional extras `serve` and `translate` with pinned versions.
71
+ - Inference and memory options, all off by default: `kv_cache_dtype="int8"` (MLA `c_kv` and SWA k/v, 32-element groups), `mla_decode="absorbed"|"auto"` with optional `mla_cache_rope`, `router_scope="shared"`, the `draft_exit_kl_coef` / `draft_exit_depth` training term, and hard expert budgets `max_resident_experts` / `ram_budget_mb` with prediction-protected LRU and per-virtual-layer prefetch. Torch and MLX both implement them.
72
+ - Adaptive training planner (`chronos.model.planner`, Config tab → "Auto plan"). Inputs: target size, MoE on/off, experts, and either active experts or active parameters, plus a memory-saving level and datasets. Outputs: a v3 architecture, scaling-law LR/batch, a memory fit, and independent pretrain / SFT / DPO / ORPO / GRPO / distill values. Dataset profiling supplies vocabulary, sequence length, token count and tokenizer path.
73
+ - Per-stage overrides (`config["stage_overrides"]`); the Train tab merges the selected stage's values.
74
+ - Five v3 presets generated by the planner (`ui/presets_v3.json`, `python -m ui.presets`) replace the old presets; old names are aliases.
75
+ - Tokenizer and Serve tabs in the Web UI; the Train tab honours `tokenizer_path`.
76
+
77
+ ### Changed
78
+ - Routing defaults to top-2 plus a shared expert (top-1 with `norm_topk_prob=True` gave the gate no CE gradient).
79
+ - `--dtype auto` resolves to fp32 on MPS (native bf16 measured slower there).
80
+ - `lookahead_source` now comes from the prelude output.
81
+ - Repetition penalty divides positive logits and multiplies negative ones.
82
+ - `gradio` is constrained to `>=5.0,<6`; `tokenizers` is a declared dependency.
83
+ - `setup.py` is a shim; metadata lives only in `pyproject.toml`.
84
+ - `mla_decode` defaults to `expanded`. With `auto`, a bf16 prefill took the expanded path and the following decode took the absorbed path. Prefill+decode then differed from the full forward pass by 0.06 in max logit (measured). `absorbed` and `auto` are opt-in.
85
+ - Minimum torch is 2.6: transformers 5 disables its PyTorch backend below that version, which broke imports.
86
+ - CI installs torch 2.10.0 (CPU) and pins the rest in `.github/ci-constraints.txt`, tested on Python 3.10 and 3.11. The dead token-based publish job was removed; releases publish through `pypi.yml` (trusted publishing).
87
+ - The Web UI no longer assumes a task.
88
+ - The monitor (page and Gradio tab) discovers evaluation metrics from whatever numeric keys a run logs on validation / final events. Keys are grouped by metric name (`probe_en_zh_bleu`, `qa_accuracy`, `pass1` …) and charted per family, with an improvement direction for known metrics.
89
+ - Counts and durations are listed as context and not charted.
90
+ - Samples show input / reference / output for any schema (`src`/`prompt`/`question`, `ref`/`answer`, `hyp`/`response`/`prediction`). Other fields appear as tags.
91
+ - Offline inspection reports are flattened to every numeric leaf.
92
+ - Data tab: scans a file, directory or glob of jsonl / json / parquet / csv / tsv / txt. Reports record shapes (chat, preference, instruction, prompt–response, parallel pair, plain text), field presence and types, scripts, duplicates and per-record character lengths over all text fields.
93
+
94
+ ### Fixed
95
+ - The Inference tab loaded the minimind tokenizer for every checkpoint. It now uses the checkpoint's own tokenizer: the config `tokenizer_path`, the bundle's `tokenizer/` folder, or the sidecar path. Minimind is the last resort.
96
+ - MLX inference ran in training mode when the model was converted from a freshly built torch model (the Inference tab did this). MoE then masked experts at random (`fallback_mask_prob`), so repeated greedy runs disagreed. `ChronosMLXInferenceEngine` now puts its model in eval mode.
97
+ - The Torch lazy engine failed with "Inference tensors cannot be saved for backward" when a plain request followed a speculative one, because experts paged in under `torch.inference_mode` were reused. The decode paths now use `torch.no_grad`.
98
+ - The v2 every-iteration attention switch rewrote a single KV slot per iteration (prefill+decode vs full forward gap 0.94).
99
+ - CLI registered `serve`, `tokenizer` and `corpus` twice.
100
+ - Monitor CPU time on macOS: `rusage` times are Mach ticks, now scaled by `mach_timebase_info`.
101
+ - `apply_inference_overrides` validated overrides against a config that used class-default KV heads (4). Every serve/inference override on models with other head counts (e.g. the 50M demo, 6/2) raised.
102
+ - The UI estimator ignored `recurrent_groups` and `recurrent_attention_mode`; its counts now match `count_parameters`.
103
+ - Planner/dataset profiling counted GRPO prompt files (empty assistant turn) as SFT.
104
+ - Stage scripts loaded the minimind tokenizer (6,400 entries) for checkpoints trained with another vocabulary.
105
+ - A forward with `recurrent_depth` below `min_recurrent_depth` (a speculative draft) gave the last state zero ACT weight on MLX, so the coda saw zeros (max logit gap to Torch 16.6 on the 50M checkpoint, measured; draft acceptance 2 % instead of 45 %). Torch special-cased depth 1 but had the same fault for 2 ≤ depth < `min_recurrent_depth`. The minimum now clamps to the executed depth; training depths are unaffected.
106
+ - MLX ≥ 0.32 binds a lazy `mx.load` to the loading thread's stream; experts prefetched by the background thread raised "There is no Stream(cpu, N) in current thread" when promoted on the decode thread. Pages are now evaluated in the thread that loads them.
107
+
108
+ ### Known gaps
109
+ - Self-speculative decoding is exact but **not faster** for the 50M demo, on CPU, GPU or lazy experts. All figures are measured on the pretrain step-13,996 checkpoint, greedy, batch 1, FLORES+ dev en→zh, draft depth 1, γ 4. The 72-hour run was paused (SIGSTOP) for the GPU runs. Reports are in `reports/speculative/`.
110
+
111
+ | Runtime | Plain tok/s | Speculative tok/s | Ratio | Acceptance | Identical |
112
+ |---|---|---|---|---|---|
113
+ | MLX GPU bf16, all experts in DRAM | 112.0 | 107.4 | 0.96× | 42 % | 22/24 |
114
+ | MLX GPU bf16, lazy experts (12 of 216 pages) | 43.7 | 32.0 | 0.73× | 42 % | 22/24 |
115
+ | Torch MPS fp32, all experts | 32.1 | 25.9 | 0.81× | 40 % | 12/12 |
116
+ | Torch MPS fp32, lazy experts, sync misses | 17.0 | 14.7 | 0.86× | 40 % | 12/12 |
117
+
118
+ Draft depth 2 raised acceptance to 55–59 % but did not change the result (0.72–0.92×).
119
+
120
+ At this size one full-depth step costs about as much as a batched verify pass, so drafting at depth 1 of 4 does not save enough.
121
+
122
+ With lazy experts, drafts and verify passes route to different experts. Speculative decoding then read 1.4–1.6× more expert pages from SSD (12,092 vs 8,372 for MLX).
123
+
124
+ bf16 on the GPU flips near-tie tokens (the 2/24 and 3/24 mismatches). In GPU fp32 one sentence differed, at a top-1/top-2 logit margin of 0.0006. CPU fp32 matches exactly. The switch therefore stays off by default.
125
+ - At a 1280 px window, Gradio moves the Auto-Tune and IO Monitor tabs into its "…" overflow menu.
126
+ - Planner peak-memory figures are estimates; for the 50M recipe the estimate (16.4 GB) is about twice the measured MLX peak (8.72 GB).
127
+ - Gradio 5.35 does not render the LinePlot legend; colour keys are written into plot titles instead.
128
+
129
+ ## [0.1.0] — 2026-04-20
130
+
131
+ ### Added
132
+ - `ChronosConfig`: extends `MiniMindConfig` with lookahead, shared experts, λ1/λ2, hybrid attention params
133
+ - `LookaheadRouter`: lightweight dense predictor inserted after block 0, outputs [B, S, K+1, E] routing probs
134
+ - `TemporalLocalityLoss`: L_total = L_CE + λ1·L_balance + λ2·Σ‖E_t − E_{t-1}‖²
135
+ - `ChronosMOEFeedForward`: shared experts always in VRAM + soft gating fallback on cache miss
136
+ - `MLAAttention`: Multi-head Latent Attention — KV cache stores latent vectors (8-16x smaller)
137
+ - `SlidingWindowAttention`: KV cache capped at `window_size` tokens, O(1) memory per decode step
138
+ - Hybrid attention: even layers → MLA, odd layers → SlidingWindow
139
+ - `ExpertStore`: three-tier VRAM/RAM/SSD storage with dynamic pinned memory safety limit
140
+ - `AsyncPrefetcher`: background thread prefetches SSD→RAM driven by LookaheadRouter predictions
141
+ - `CacheManager`: unified cache interface for inference engine
142
+ - `ChronosInferenceEngine`: end-to-end decode loop with async prefetch + soft gating
143
+ - `cluster_layout.py`: co-occurrence matrix + Louvain/greedy clustering for sequential SSD layout
144
+ - `ChronosAutoTuner`: extends Optuna TPE search with λ1/λ2/lookahead_steps dimensions
145
+ - `chronos eval`: Phase 1 validation — t+1/t+2 lookahead accuracy + LRU cache hit rate
146
+ - `chronos benchmark`: Phase 3 — PPL, TPS, KV cache memory, layer-wise analysis
147
+ - `chronos export`: expert cluster layout generation
148
+ - 8-test smoke suite (`tests/test_smoke.py`)
149
+ - GitHub Actions CI (Python 3.10/3.11, lint + tests)
150
+ - PyPI packaging (`pyproject.toml`, `MANIFEST.in`)
@@ -0,0 +1,13 @@
1
+ include README.md README_zh.md LICENSE THIRD_PARTY_NOTICES.md CHANGELOG.md requirements.txt
2
+ recursive-include chronos/monitor/static *.html *.js *.css
3
+ include ui/event_contract.js
4
+ global-exclude __pycache__ *.py[cod] .DS_Store
5
+ prune runs
6
+ prune out
7
+ prune expert_cache
8
+ prune expert_cache_mlx
9
+ prune results
10
+ prune reports
11
+ prune .archive
12
+ prune Translation?Training?Data
13
+ prune chronos/mlx/training/recipes
@@ -1,37 +1,50 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Project_Chronos
3
- Version: 0.2.1
4
- Summary: On-device low-latency lookahead dual-layer MoE inference — Lookahead Routing + Async Prefetch + Hybrid Attention
3
+ Version: 0.3.1a0
4
+ Summary: Storage-aware recurrent-depth MoE: lookahead expert prefetch, SSD-lazy experts, hybrid MLA/SWA attention, self-speculative decoding
5
5
  License-Expression: Apache-2.0
6
- Keywords: llm,moe,inference,lookahead-routing,hybrid-attention,edge-ai
6
+ Project-URL: Homepage, https://github.com/FonaTech/Project_Chronos
7
+ Project-URL: Issues, https://github.com/FonaTech/Project_Chronos/issues
8
+ Keywords: llm,moe,inference,lookahead-routing,hybrid-attention,recurrent-depth,speculative-decoding,mlx,edge-ai
7
9
  Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Operating System :: OS Independent
8
11
  Classifier: Intended Audience :: Science/Research
9
12
  Classifier: Programming Language :: Python :: 3.10
10
13
  Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
11
15
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
12
16
  Requires-Python: >=3.10
13
17
  Description-Content-Type: text/markdown
14
18
  License-File: LICENSE
15
- Requires-Dist: torch>=2.4.0
19
+ Requires-Dist: torch>=2.6.0
16
20
  Requires-Dist: transformers>=4.40.0
17
21
  Requires-Dist: datasets>=2.18.0
18
22
  Requires-Dist: safetensors>=0.4.0
19
23
  Requires-Dist: optuna>=3.6.0
20
24
  Requires-Dist: numpy>=1.24.0
21
25
  Requires-Dist: psutil>=5.9.0
26
+ Requires-Dist: tokenizers>=0.19.0
22
27
  Requires-Dist: tqdm>=4.66.0
23
- Requires-Dist: gradio>=4.0.0
28
+ Requires-Dist: gradio<6,>=5.0
24
29
  Provides-Extra: cluster
25
30
  Requires-Dist: python-louvain>=0.16; extra == "cluster"
26
31
  Requires-Dist: networkx>=3.0; extra == "cluster"
27
32
  Provides-Extra: mlx
28
- Requires-Dist: mlx>=0.12.0; extra == "mlx"
33
+ Requires-Dist: mlx>=0.32.4; extra == "mlx"
34
+ Provides-Extra: serve
35
+ Requires-Dist: fastapi==0.115.9; extra == "serve"
36
+ Requires-Dist: uvicorn==0.34.3; extra == "serve"
37
+ Provides-Extra: translate
38
+ Requires-Dist: sacrebleu==2.6.0; extra == "translate"
39
+ Requires-Dist: sacremoses==0.2.0; extra == "translate"
29
40
  Provides-Extra: dev
30
41
  Requires-Dist: pytest>=7.0; extra == "dev"
31
42
  Requires-Dist: black>=24.0; extra == "dev"
32
43
  Requires-Dist: ruff>=0.4.0; extra == "dev"
44
+ Requires-Dist: httpx>=0.27; extra == "dev"
45
+ Requires-Dist: fastapi==0.115.9; extra == "dev"
46
+ Requires-Dist: uvicorn==0.34.3; extra == "dev"
33
47
  Dynamic: license-file
34
- Dynamic: requires-python
35
48
 
36
49
  # Project Chronos (Experimental)
37
50
 
@@ -95,6 +108,81 @@ Under a simulated 30 ms SSD delay, the new path keeps **35 ms+ per token** of pi
95
108
 
96
109
  ---
97
110
 
111
+ ## v3 kernel: recurrent-depth MoE (0.3.0)
112
+
113
+ v3 reuses a few physical layers many times. A prelude runs once, each shared recurrent group loops `recurrent_depth` times with a contractive update `h ← h + dt·(block(h + e_loop) − h)`, and a coda runs once. The 50M demo has 6 physical layers that execute as 18 virtual layers (prelude 1, 4 recurrent layers × depth 4, coda 1).
114
+
115
+ ```mermaid
116
+ flowchart LR
117
+ X["tokens"] --> P["Prelude<br/>runs once"]
118
+ P --> G["Recurrent group<br/>MLA / SWA + top-2 MoE"]
119
+ G -->|"loop d = 1..D<br/>contractive step, ACT halt"| G
120
+ G --> C["Coda<br/>runs once"]
121
+ C --> H["LM head"]
122
+ P -. "lookahead source" .-> LR["LookaheadRouter<br/>expert prefetch"]
123
+ ```
124
+
125
+ **What changed from v2**
126
+
127
+ | | v2 | v3 |
128
+ |---|---|---|
129
+ | Attention inside the loop | Iteration 0 only (`first_only`) | Every iteration |
130
+ | KV cache per recurrent layer | 1 slot; the every-iteration attention switch rewrote it each iteration (measured prefill+decode vs full-forward gap 0.94) | `shared_first`: Q recomputed each iteration, K/V from iteration 0, so KV slots = physical layers |
131
+ | Routing | top-1 (gate received no CE gradient) | top-2 + 1 shared expert |
132
+ | MoE dispatch | Python loop over experts with `.item()` syncs | Sorted grouped dispatch: `gather_mm` on MLX, `argsort` + `index_add_` on Torch |
133
+ | Early exit | Host sync every step | Tensor-only ACT, exact and batch-invariant; decode can exit per token without KV gaps |
134
+ | Decoding | Plain autoregressive | Recurrent-depth self-speculative decoding |
135
+
136
+ `per_iteration` (one KV slot per virtual layer) is kept as an ablation. Old v2 checkpoints load as `first_only`; their logits match a stored golden tensor within 1e-5.
137
+
138
+ **Self-speculative decoding (no extra parameters).** The same model drafts γ tokens at a shallow depth and verifies them with one full-depth batched forward pass. Greedy output is token-for-token identical to full-depth greedy. Sampling uses rejection sampling, which preserves the full-depth distribution. After a rejection, the cache is truncated: MLA slices `c_kv`, and the sliding-window cache keeps `window + γ_max` entries. Torch (`chronos/runtime/speculative.py`) and MLX (`chronos/mlx/speculative.py`, `ChronosMLXInferenceEngine.generate(speculative=True)`) share the algorithm. Tests cover greedy identity, the rejection distribution and rollback against a fresh prefill on both backends. The Web UI Inference tab has a switch for it, with draft depth and γ.
139
+
140
+ For the 50M demo it is exact but not faster on any runtime we measured (pretrain step-13,996 checkpoint, greedy, batch 1, FLORES+ dev en→zh, draft depth 1, γ 4; reports in `reports/speculative/`):
141
+
142
+ | Runtime | Plain tok/s | Speculative tok/s | Ratio | Acceptance |
143
+ |---|---|---|---|---|
144
+ | MLX GPU bf16, all experts in DRAM | 112.0 | 107.4 | 0.96× | 42 % |
145
+ | MLX GPU bf16, lazy experts (12 of 216 pages resident) | 43.7 | 32.0 | 0.73× | 42 % |
146
+ | Torch MPS fp32, all experts | 32.1 | 25.9 | 0.81× | 40 % |
147
+ | Torch MPS fp32, lazy experts | 17.0 | 14.7 | 0.86× | 40 % |
148
+
149
+ At this size a full-depth step costs about as much as a batched verify pass. With lazy experts, drafts and verify passes also route to different experts, so speculative decoding read 1.4–1.6× more expert pages from SSD. Greedy outputs were identical in CPU fp32 and Torch MPS fp32. In GPU bf16, near-tie tokens flipped in 2 of 24 sentences. The switch therefore stays off by default.
150
+
151
+ **Precision chain.** One compute dtype runs end to end. FP32 is used only where it pays: RMSNorm statistics, SDPA softmax, RoPE tables, router softmax, LM-head logits and optimizer master weights. The MLX↔Torch bf16 bridge is bit-exact. `auto` picks bf16 on MLX GPU and CUDA, and fp32 on CPU and MPS (MPS bf16 measured slower; see below).
152
+
153
+ **Tooling added in v3**
154
+
155
+ | Command | What it does |
156
+ |---|---|
157
+ | `chronos tokenizer` | Self-built byte-fallback BPE with script-aware pre-tokenization and language-balanced merges; writes an HF-compatible `tokenizer.json` + chat template |
158
+ | `chronos corpus download / build / shards` | Pinned downloads, cleaning, global dedup, eval-set leak removal, uint16 shards |
159
+ | `chronos longrun --spec recipe.json` (alias `run`) | Time-budgeted MLX run: warmup + cosine per phase wall-clock budget, NaN rollback, bit-exact resume, validation and translation probes |
160
+ | `chronos serve` | Ollama/OpenAI protocol server on the native runtime (see below) |
161
+ | `chronos monitor` | Read-only training monitor page + JSON API (see below) |
162
+
163
+ `chronos.model.factory.fit_config` searches for a configuration that matches total and active parameter targets.
164
+
165
+ **Status of the 50M en→zh demo (in progress).**
166
+ - Model: 49.69M total / 12.09M active parameters, 36 experts, MLA latent 128, SWA window 128, 16k self-built vocabulary.
167
+ - Run: a 72-hour MLX bf16 run (pretrain, then SFT) started on 2026-11-05.
168
+ - Interim measurement: valid CE 2.477 at pretrain step 13,996 of about 24.7k planned (it was 3.012 at step 1,656). That checkpoint is packaged as `chronos-enzh-50m-pretrain-s13996` (see Model bundle).
169
+ - BLEU/chrF on FLORES+ and WMT22, and the ablations (attention mode, depth, lazy-expert budget, speculative γ), will be published after the run finishes. No quality numbers are claimed before then.
170
+
171
+ **Inference and memory options (all off by default).** Each option is a config field and a `chronos serve` / Inference-tab override. Tests compare each one with its reference path on Torch and MLX.
172
+
173
+ | Field | Values (default first) | Effect |
174
+ |---|---|---|
175
+ | `kv_cache_dtype` | `auto`, `int8` | `int8` stores MLA `c_kv` and SWA k/v per token in groups of 32 with a scale; rollback and speculative decoding work on it |
176
+ | `mla_decode` | `expanded`, `absorbed`, `auto` | `absorbed` scores against `c_kv` without expanding K/V. `auto` absorbs only short cached chunks; it is opt-in because a bf16 prefill (expanded) followed by absorbed decode drifted from the full forward pass (max logit gap 0.06, measured) |
177
+ | `mla_cache_rope` | `false`, `true` | Also caches the roped key, trading memory for decode speed |
178
+ | `router_scope` | `per_iteration`, `shared` | `shared` reuses iteration 0's experts for the rest of the loop, so fewer experts are resident per token |
179
+ | `draft_exit_kl_coef`, `draft_exit_depth` | `0`, `1` | Training term: KL from the shallow exit to the detached full-depth logits, which raises speculative acceptance |
180
+ | `max_resident_experts`, `ram_budget_mb` | unset | Hard caps on the fast tier and the RAM tier. LRU eviction never evicts experts the lookahead router predicts. Prefetch covers every loop iteration of a virtual layer |
181
+
182
+ Web UI: the Tokenizer tab (extract → train → evaluate) and the Serve tab (start/stop `chronos serve`; the API key goes through the environment, never argv).
183
+
184
+ ---
185
+
98
186
  ## Three-tier storage (M1: cluster-aware safetensors)
99
187
 
100
188
  ```mermaid
@@ -224,7 +312,7 @@ flowchart LR
224
312
 
225
313
  Training dtype and resource policy:
226
314
 
227
- - `--dtype auto` is the default. MPS/MLX resolve to BF16-first for training stability, CUDA/XPU resolve to FP16, and CPU resolves to FP32 unless `--dtype float16` or `--dtype bfloat16` is set explicitly.
315
+ - `--dtype auto` is the default. One compute dtype covers weights, activations, KV cache and expert pages; FP32 is kept only inside fused kernels (SDPA softmax, RMSNorm statistics), for RoPE tables, router softmax, loss logits and the optimizer's FP32 masters/moments. `auto` resolves to BF16 on MLX GPU, BF16 on CUDA (FP16 if unsupported, with loss scaling), and FP32 on CPU and MPS. On MPS, native BF16 measured slower than FP32 (Chronos 50M on an M5 Max with torch 2.10: 0.749 vs 0.619 s per training step, 49.1 vs 37.3 ms per decoded token). Pass `--dtype bfloat16` explicitly to trade speed for half the weight and KV memory.
228
316
  - CPU training configures PyTorch to use physical cores by default. Override with `--cpu_threads` or `--cpu_budget_percent`.
229
317
  - On macOS, MPS/MLX training forces DataLoader workers to `0` by default to avoid Metal command-buffer crashes from multiprocessing. CPU/CUDA still use worker processes; advanced users can override the guard with `CHRONOS_ALLOW_METAL_DATALOADER_WORKERS=1`.
230
318
  - Native MLX training pushes UI logs, scalar readouts, and chart points every `log_interval` steps, and Web UI Stop is checked at each batch boundary.
@@ -235,7 +323,7 @@ The six-stage MLX trainer mirrors the PyTorch loss stack in `chronos.mlx.*`:
235
323
  masked CE, DPO/ORPO/GRPO/distillation losses, load balance, temporal locality,
236
324
  lookahead soft-target supervision, lookahead top-k hit loss, and router KL
237
325
  anchor. Numerically sensitive pieces run in FP32 even when model weights use
238
- BF16/FP16, which is why `auto` prefers BF16 on MLX/MPS: FP16 has too little
326
+ BF16/FP16, which is why `auto` prefers BF16 over FP16 on MLX GPU: FP16 has too little
239
327
  exponent range for router softmax, CE, and Adam moments on small unstable
240
328
  training runs.
241
329
 
@@ -406,6 +494,13 @@ pip install -e ".[dev]"
406
494
  pip install "Project_Chronos[mlx]"
407
495
  ```
408
496
 
497
+ **Optional extras** (versions pinned):
498
+
499
+ ```bash
500
+ pip install "Project_Chronos[serve]" # chronos serve / chronos monitor (fastapi, uvicorn)
501
+ pip install "Project_Chronos[translate]" # corpus detokenization + BLEU/chrF probes (sacremoses, sacrebleu)
502
+ ```
503
+
409
504
  **vLLM serving (optional, Linux + CUDA only):**
410
505
 
411
506
  ```bash
@@ -413,16 +508,17 @@ pip install vllm
413
508
  ```
414
509
 
415
510
  > **minimind dependency**: Project Chronos uses [minimind](https://github.com/jingyaogong/minimind) as its MoE kernel.
416
- > If it is not found locally, Chronos clones it automatically into `~/.cache/chronos/minimind-master/` on first import.
511
+ > If it is not found locally, Chronos clones it automatically into `~/.cache/chronos/minimind-master/` on first import (this needs `git` and network access).
512
+ > Set `CHRONOS_MINIMIND_DIR=/path/to/minimind` to use a local copy instead; model bundles ship one under `third_party/minimind` and their launcher sets the variable.
417
513
  > minimind is licensed under **Apache-2.0**. See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for attribution details.
418
514
 
419
- **Requirements**: Python 3.10+, PyTorch 2.4+
515
+ **Requirements**: Python 3.10+, PyTorch 2.6+
420
516
 
421
517
  ---
422
518
 
423
519
  ## Quick start
424
520
 
425
- ### Web UI (M6: 8 tabs, 4 languages)
521
+ ### Web UI (12 tabs, 4 languages)
426
522
 
427
523
  ```bash
428
524
  chronos-ui
@@ -432,17 +528,127 @@ python chronos_app.py
432
528
 
433
529
  Tabs included:
434
530
 
435
- - `Config` with a live parameter / memory estimator merged in from the old Designer
436
- - `Train` with its own `data_path`
531
+ - `Config`: v3 presets, the auto planner (below) and a live parameter / memory estimator
532
+ - `Data` for dataset scanning and conversion
533
+ - `Tokenizer`: extract text from datasets, train the Chronos BPE, evaluate and save
534
+ - `Train` with its own `data_path`; applies the selected stage's overrides
535
+ - `Training Monitor` (read-only view of `runs/`; see below)
437
536
  - `6-Stage Pipeline` with per-stage dataset paths
438
537
  - `Inference`
439
538
  - `Export` for FP16/Q8_0 safetensors and GGUF deployment artifacts
539
+ - `Serve`: start and stop `chronos serve` and view its log
440
540
  - `Benchmark` with Markdown table + comparison plots
441
541
  - `Auto-Tune` with persistent logs and one-click `Apply Best -> Config`
442
542
  - `IO Monitor`
443
543
 
544
+ At a 1280 px wide window, Gradio moves the last tabs (Auto-Tune, IO Monitor) into its "…" overflow menu.
545
+
546
+ ### Presets and the auto planner
547
+
548
+ The Config tab ships five v3 presets. Each one is generated by the planner and stored in `ui/presets_v3.json`; regenerate the file with `python -m ui.presets`. Parameter counts are measured with a meta-device model; peak memory is an estimate.
549
+
550
+ | Preset | Total / active params (measured) | Shape | Memory level | Est. training peak |
551
+ |---|---|---|---|---|
552
+ | Chronos-v3 Tiny (smoke / CI) | 1.51M / 1.29M | E4 top-2, vocab 6400, seq 128, depth 2 | none | 2.13 GB |
553
+ | Chronos-v3 50M (en→zh recipe) | 49.69M / 12.09M | h384, L6, E36 top-2, vocab 16384, seq 512 | none | 16.4 GB (the live run measures 8.72 GB peak) |
554
+ | Chronos-v3 200M (32 GB) — default | 200.72M / 28.20M | h576, E32 top-2 | balanced | 10.14 GB |
555
+ | Chronos-v3 500M (32 GB) | 499.53M / 61.59M | E48 top-3 | aggressive | 9.26 GB |
556
+ | Chronos-v3 1B (64 GB) | 1002.17M / 99.74M | E64 top-4, seq 2048 | aggressive | 18.92 GB |
557
+
558
+ The old preset names (Recommended-CN, Tiny/Small/Medium/Large) still load; they map to the closest v3 tier.
559
+
560
+ **Auto planner** (Config tab → "Auto plan"). Inputs:
561
+ - target total parameters, and whether to use MoE;
562
+ - the expert count, plus either the number of active experts or an active-parameter target;
563
+ - a memory-saving level: `none`, `balanced`, `aggressive` or `extreme`;
564
+ - optional dataset paths, RAM, token budget, vocabulary size and sequence length.
565
+
566
+ `chronos.model.planner.plan_training` then does the following:
567
+ 1. **Profiles the datasets.** It reads the shard manifest or samples the files, classifies records as pretrain, SFT, preference or RL, and reads the tokenizer report. The vocabulary size, sequence length (p95 / cap), token count and tokenizer path come from the data when available.
568
+ 2. **Searches the architecture.** It looks for the hidden size, layer count, expert width and GQA heads whose meta-device count is closest to the target.
569
+ 3. **Sets LR and batch size** from the DeepSeek LLM compute-optimal fits (η = 0.3118·C^−0.125, B = 0.2920·C^0.3271), capped for wide models.
570
+ 4. **Fits memory.** It picks micro-batch, accumulation, int8 KV, router scope, activation checkpointing, optimizer paging and an expert RAM budget for the memory level.
571
+ 5. **Writes per-stage values.** Pretrain, SFT, DPO, ORPO, GRPO and distill each get their own learning rate, batch, epochs, save interval and stage-specific terms (β, temperature, α).
572
+
573
+ The stage table is editable; the Train tab merges the selected stage's row over the shared values, and the pretrain row stays in sync with the shared widgets. "Save plan" writes the config, stage values and report to JSON. Every number in the report is labelled measured or estimated.
574
+
444
575
  Built-in i18n: `zh-Hans`, `zh-Hant`, `en`, `ja`
445
576
 
577
+ ### Training monitor (console tab + standalone page/API)
578
+
579
+ A `chronos longrun` run directory holds `run_spec.json`, `metrics.jsonl`,
580
+ `status.json` (heartbeat), `runtime.json` (precision policy, device, versions,
581
+ code hash), `parameters.jsonl` (per-tensor weight/grad/update statistics and
582
+ per-virtual-layer routing), `samples.jsonl`, `inspections/` and checkpoints.
583
+ The console's **Training Monitor** tab and a standalone page both read these
584
+ files and never touch the training device. Runs started before telemetry
585
+ existed still show progress; their status is derived from `metrics.jsonl` and
586
+ the process table.
587
+
588
+ ```bash
589
+ chronos monitor --runs-dir runs # http://127.0.0.1:7870/
590
+ chronos serve --models-dir exports --monitor-runs-dir runs # same page at /monitor/
591
+ ```
592
+
593
+ JSON API (read-only): `GET /api/state?run=&history=1`, `/api/metrics?run=&phase=&since=`,
594
+ `/api/parameters`, `/api/tensors`, `/api/tensor?name=`, `/api/log?bytes=`, `/api/runs`.
595
+
596
+ Security: the default bind is 127.0.0.1 with no authentication. Any other
597
+ address requires `--allow-remote` and `--api-key` (or `CHRONOS_MONITOR_KEY`).
598
+ Browsers sign in once and get an HttpOnly, SameSite=Strict session cookie;
599
+ scripts send `Authorization: Bearer <key>`. Failed logins are rate-limited.
600
+ Off loopback, add `--ssl-certfile/--ssl-keyfile` or a TLS reverse proxy,
601
+ otherwise the key crosses the network in clear text.
602
+
603
+ ### Ollama / OpenAI protocol server
604
+
605
+ `chronos serve` runs the native Chronos runtime behind the Ollama and OpenAI HTTP APIs. The kernel is not converted to another architecture, so recurrent depth, SSD-lazy experts with lookahead prefetch, compressed KV and self-speculative decoding stay active.
606
+
607
+ ```bash
608
+ pip install "Project_Chronos[serve]"
609
+ chronos serve --models-dir ./exports --port 11435 # 11434 would collide with a running Ollama
610
+ OLLAMA_HOST=127.0.0.1:11435 ollama list
611
+ OLLAMA_HOST=127.0.0.1:11435 ollama run <model-name> "Hello"
612
+ ```
613
+
614
+ - Endpoints: `/api/version`, `/api/tags`, `/api/show`, `/api/ps`, `/api/pull`, `/api/generate` and `/api/chat` (streaming NDJSON), `/v1/models`, `/v1/chat/completions` (SSE).
615
+ - Models are `<name>.pth` + `<name>.config.json` pairs found under `--models-dir`.
616
+ - Chronos options go in the request `options`: `chronos_speculative`, `chronos_draft_depth`, `chronos_gamma`, `chronos_miss_policy`.
617
+ - Stock `ollama` / llama.cpp cannot execute Chronos GGUF files (MLA+SWA hybrid layers and the contractive recurrence have no stock equivalent); use this server instead.
618
+ - Security: binds 127.0.0.1 without authentication by default. Other addresses require `--allow-remote` and `--api-key`; clients then send `Authorization: Bearer <key>`.
619
+
620
+ ### Model bundle (ready-to-run pretrained model)
621
+
622
+ `chronos bundle build` packages one exported checkpoint of a `chronos longrun` run into a folder that works right after unpacking. Building only reads the run directory.
623
+
624
+ ```bash
625
+ chronos bundle build --run-dir runs/enzh_50m_v1 --which best --wheel dist/project_chronos-0.3.0-py3-none-any.whl --pack
626
+ ```
627
+
628
+ | Bundle path | Content |
629
+ |---|---|
630
+ | `model/` | weights + `.config.json` sidecar, tokenizer (`model/tokenizer/`) |
631
+ | `eval/` | FLORES+ dev/devtest (CC BY-SA 4.0) for `bundle eval` / `probe` |
632
+ | `data/sft_valid/` | the run's SFT validation shards |
633
+ | `third_party/minimind/` | vendored minimind (Apache-2.0), so no git clone is needed |
634
+ | `wheels/`, `bin/setup.sh`, `bin/chronos` | offline install into `.venv`, launcher that sets `CHRONOS_BUNDLE` / `CHRONOS_MINIMIND_DIR` |
635
+ | `recipes/source_run_spec.json`, `recommended.json` | the recipe that produced the weights; fine-tune tiers `smoke` / `quick` / `standard` / `full` |
636
+ | `bundle.json` | provenance (step, tokens, valid CE), measured quality probe, SHA-256 of every file |
637
+
638
+ On the recipient side:
639
+
640
+ ```bash
641
+ bin/setup.sh # venv + wheel + `bundle check`
642
+ bin/chronos bundle translate "The weather is very nice today."
643
+ bin/chronos bundle translate --backend mlx --speculative --file examples/translate_en.txt
644
+ bin/chronos bundle eval --split devtest -n 200
645
+ bin/chronos bundle prepare-data my_pairs.jsonl --out work/data # FLORES+ is removed from your data
646
+ bin/chronos bundle finetune --data work/data --run-dir work/ft --tier quick --mode sft
647
+ bin/chronos bundle serve -- --port 11435
648
+ ```
649
+
650
+ `--speculative` needs `--repetition-penalty 1.0` (its default), because the penalty changes the target distribution at every position. `finetune` writes a `chronos longrun` spec with `init_checkpoint` set to the bundle weights and refuses a run directory that already holds a run. Bundles built from data with unknown licences (WMT19, OPUS-100) say in `NOTICE.md` that the weights are for research only.
651
+
446
652
  ### Deployment export
447
653
 
448
654
  ```bash
@@ -575,7 +781,10 @@ Project_Chronos/
575
781
  │ ├── deps.py # Auto-download minimind if missing
576
782
  │ ├── __init__.py # AutoConfig / AutoModelForCausalLM registration
577
783
  │ ├── model/
578
- │ │ ├── config.py # ChronosConfig
784
+ │ │ ├── config.py # ChronosConfig (v3 fields, v2 migration)
785
+ │ │ ├── recurrent.py # Loop/group embeddings, contractive step, tensor-only ACT
786
+ │ │ ├── precision_ops.py # RMSNorm/SDPA/RoPE with one compute dtype
787
+ │ │ ├── factory.py # Parameter-budget config search
579
788
  │ │ ├── hybrid_attention.py # MLAAttention + SlidingWindowAttention
580
789
  │ │ ├── lookahead_router.py # Per-token lookahead predictor
581
790
  │ │ ├── moe_chronos.py # ChronosMOEFeedForward + shared experts + soft gating
@@ -594,7 +803,11 @@ Project_Chronos/
594
803
  │ │ └── prefill_scheduler.py # Prefill-time expert preloader
595
804
  │ ├── mlx/
596
805
  │ │ ├── attention.py / moe.py / model.py / expert_store.py / inference.py
806
+ │ │ ├── moe_kernels.py # Sorted gather_mm dispatch (mlx >= 0.32.4)
807
+ │ │ ├── speculative.py # MLX self-speculative decoding (Torch parity)
808
+ │ │ └── training/ # longrun.py, telemetry.py, recipes/
597
809
  │ ├── runtime/
810
+ │ │ ├── speculative.py # Recurrent-depth self-speculative decoding
598
811
  │ │ ├── cache_manager.py # prefetch_for_next_step / ensure_resident
599
812
  │ │ ├── inference_engine.py # End-to-end inference engine
600
813
  │ │ └── metrics.py # MetricsBus for the IO Monitor
@@ -613,14 +826,19 @@ Project_Chronos/
613
826
  │ │ ├── io_profiler.py # Lookahead validation
614
827
  │ │ └── benchmark.py # End-to-end benchmarking
615
828
  │ ├── data/
616
- │ │ └── flexible_dataset.py # Flexible JSONL dataset loader
829
+ │ │ ├── flexible_dataset.py # Flexible JSONL dataset loader
830
+ │ │ └── corpus/ # download / clean / dedup / leak filter / shards
831
+ │ ├── tokenizer/ # Chronos BPE builder (extract, normalize, train, evaluate)
832
+ │ ├── monitor/ # Read-only run monitor: snapshot, API server, static page
617
833
  │ ├── backend/
618
834
  │ │ ├── __init__.py # BackendDispatcher (cpu/mps/cuda/mlx)
619
835
  │ │ ├── dispatcher.py # Capability probing + priority logic
620
836
  │ │ └── ext/opencl.py # Third-party OpenCL extension hook
621
837
  │ ├── _backend_legacy.py # Backward-compatible older APIs
838
+ │ ├── bundle/ # chronos bundle: build/check/translate/finetune
622
839
  │ ├── serving/
623
- │ │ ├── __init__.py
840
+ │ │ ├── ollama_server.py # chronos serve: Ollama/OpenAI protocol layer
841
+ │ │ ├── runtime.py # Model discovery, lazy experts, speculative generation
624
842
  │ │ └── vllm_adapter.py # Optional vLLM registration
625
843
  │ └── cli.py # Unified CLI
626
844
  ├── ui/ # Gradio Web UI (zh-Hans / zh-Hant / en / ja)
@@ -628,7 +846,9 @@ Project_Chronos/
628
846
  │ ├── estimator.py # Live parameter / memory estimator
629
847
  │ └── tabs/
630
848
  │ ├── config_tab.py # Config + Designer merged together
849
+ │ ├── data_tab.py
631
850
  │ ├── train_tab.py # Owns data_path
851
+ │ ├── monitor_tab.py # Training Monitor (shares chronos.monitor)
632
852
  │ ├── pipeline_tab.py # Per-stage datasets across all 6 stages
633
853
  │ ├── inference_tab.py
634
854
  │ ├── benchmark_tab.py # Markdown table + gr.BarPlot
@@ -646,8 +866,9 @@ Project_Chronos/
646
866
  │ ├── compare_minimind_chronos_v2.py
647
867
  │ └── compare_minimind_chronos_v3.py
648
868
  ├── tests/
649
- │ ├── test_smoke.py
650
- │ ├── test_smoke_cuda.py
869
+ │ ├── test_smoke.py / test_smoke_cuda.py
870
+ │ ├── test_v3_kernel.py / test_speculative.py / test_moe_dispatch.py / test_precision_chain.py
871
+ │ ├── test_tokenizer_builder.py / test_longrun.py / test_monitor.py
651
872
  │ └── fixtures/
652
873
  ├── docs/
653
874
  │ └── vllm_integration.md
@@ -689,7 +910,19 @@ timeline
689
910
  : HF IO, vLLM adapter, multi-backend dispatch
690
911
  : Stage 6 distillation and pluggable rewards
691
912
  : Web UI v2, benchmark plots, IO Monitor
913
+ v3 (0.3.0)
914
+ : Recurrent-depth kernel with shared_first KV
915
+ : top-2 + shared expert, grouped MoE dispatch
916
+ : Self-speculative decoding (Torch and MLX)
917
+ : Ollama/OpenAI protocol server
918
+ : Ready-to-run model bundles (chronos bundle)
919
+ : Chronos tokenizer, corpus pipeline, long-run trainer
920
+ : Training monitor page, API and console tab
921
+ : int8 KV, MLA absorbed decode, shared router scope (opt-in)
922
+ : Auto planner, v3 presets, tokenizer and serve tabs
692
923
  Next
924
+ : 50M en-zh results and ablations
925
+ : Speculative decoding: a draft path that pays off on larger models and lazy experts
693
926
  : Train IntentClassifier on large activation corpora
694
927
  : Benchmark 7B+ checkpoints
695
928
  : Inject masks on the vLLM worker path