tracebloc 1.2.87__tar.gz → 1.2.89__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 (190) hide show
  1. {tracebloc-1.2.87 → tracebloc-1.2.89}/PKG-INFO +1 -1
  2. {tracebloc-1.2.87 → tracebloc-1.2.89}/pyproject.toml +1 -1
  3. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_link_regeneration.py +5 -2
  4. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_linking.py +14 -1
  5. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/hf/__init__.py +4 -0
  6. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/heads.py +1 -0
  7. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/interfaces.py +4 -0
  8. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/head.py +3 -1
  9. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/remote.py +1 -0
  10. tracebloc-1.2.89/tracebloc/datasets/__init__.py +6 -0
  11. tracebloc-1.2.89/tracebloc/datasets/base.py +55 -0
  12. tracebloc-1.2.89/tracebloc/datasets/detection.py +51 -0
  13. tracebloc-1.2.87/tracebloc/utils/key_point_detection_utils.py → tracebloc-1.2.89/tracebloc/datasets/keypoint_detection.py +9 -9
  14. tracebloc-1.2.87/tracebloc/utils/semantic_segmentation_utils.py → tracebloc-1.2.89/tracebloc/datasets/semantic_segmentation.py +14 -13
  15. tracebloc-1.2.89/tracebloc/datasets/tabular.py +34 -0
  16. tracebloc-1.2.89/tracebloc/datasets/text.py +189 -0
  17. tracebloc-1.2.87/tracebloc/utils/time_series_utils.py → tracebloc-1.2.89/tracebloc/datasets/time_series.py +30 -91
  18. tracebloc-1.2.89/tracebloc/datasets/time_to_event.py +32 -0
  19. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/link_model_dataset.py +1 -1
  20. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/__init__.py +1 -0
  21. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/lora.py +2 -0
  22. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/lora_validation.py +4 -1
  23. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/loss.py +4 -0
  24. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/plan.py +2 -0
  25. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/shape.py +3 -0
  26. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_multi_label_text_classifier.py +0 -4
  27. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_nlp_base.py +5 -0
  28. tracebloc-1.2.89/tracebloc/upload/torch_text_regressor.py +103 -0
  29. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/user.py +3 -0
  30. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/constants.py +4 -1
  31. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/detection_utils.py +4 -48
  32. tracebloc-1.2.89/tracebloc/utils/key_point_detection_utils.py +7 -0
  33. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/registry.py +5 -0
  34. tracebloc-1.2.89/tracebloc/utils/semantic_segmentation_utils.py +7 -0
  35. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/tabular_classification_utils.py +3 -13
  36. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/tabular_regression_utils.py +4 -13
  37. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/text_classification_utils.py +19 -225
  38. tracebloc-1.2.89/tracebloc/utils/time_series_utils.py +73 -0
  39. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/time_to_event_utils.py +4 -26
  40. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/header_rules.py +6 -0
  41. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc.egg-info/PKG-INFO +1 -1
  42. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc.egg-info/SOURCES.txt +10 -0
  43. {tracebloc-1.2.87 → tracebloc-1.2.89}/MANIFEST.in +0 -0
  44. {tracebloc-1.2.87 → tracebloc-1.2.89}/README.md +0 -0
  45. {tracebloc-1.2.87 → tracebloc-1.2.89}/license.txt +0 -0
  46. {tracebloc-1.2.87 → tracebloc-1.2.89}/setup.cfg +0 -0
  47. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/__init__.py +0 -0
  48. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_deprecation.py +0 -0
  49. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_framework_utils.py +0 -0
  50. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_http_utils.py +0 -0
  51. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_link_answer.py +0 -0
  52. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_raw_width_note.py +0 -0
  53. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_stored_link.py +0 -0
  54. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/_upload_conversion.py +0 -0
  55. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/checks.py +0 -0
  56. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/client.py +0 -0
  57. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/config.py +0 -0
  58. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/contracts/stage_urls.v1.json +0 -0
  59. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/contracts/stage_urls.v1.source.json +0 -0
  60. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/contracts/survival_payload.py +0 -0
  61. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/contracts/training_requirements.source.json +0 -0
  62. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/contracts/training_requirements.txt +0 -0
  63. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/__init__.py +0 -0
  64. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/acceptance.py +0 -0
  65. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/__init__.py +0 -0
  66. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/hf/_build.py +0 -0
  67. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/hf/_model_type.py +0 -0
  68. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/tabular.py +0 -0
  69. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/vision/__init__.py +0 -0
  70. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/families/vision/_matching.py +0 -0
  71. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/gate.py +0 -0
  72. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/licence/__init__.py +0 -0
  73. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/licence/spdx.py +0 -0
  74. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/outputs.py +0 -0
  75. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/__init__.py +0 -0
  76. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/arguments.py +0 -0
  77. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/assemble.py +0 -0
  78. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/checkpoint.py +0 -0
  79. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/gate_rules.py +0 -0
  80. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/generate.py +0 -0
  81. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/import_check.py +0 -0
  82. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/layer0.py +0 -0
  83. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/live.py +0 -0
  84. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/model_class.py +0 -0
  85. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/repo.py +0 -0
  86. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/shake.py +0 -0
  87. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/owncode/source_tree.py +0 -0
  88. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/package.py +0 -0
  89. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/report.py +0 -0
  90. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/tokenizers.py +0 -0
  91. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/convert/training_versions.py +0 -0
  92. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/env_login.py +0 -0
  93. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/exceptions.py +0 -0
  94. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/fetch.py +0 -0
  95. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/inference.py +0 -0
  96. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/library_fetch.py +0 -0
  97. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/lifelines_weights.py +0 -0
  98. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/_partials.tpl +0 -0
  99. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/embeddings.tpl +0 -0
  100. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/nlp_finetune.tpl +0 -0
  101. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/nlp_generative.tpl +0 -0
  102. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/survival.tpl +0 -0
  103. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/tabular_timeseries.tpl +0 -0
  104. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/notebook/templates/vision_from_scratch.tpl +0 -0
  105. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/__init__.py +0 -0
  106. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/classes.py +0 -0
  107. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/declaration.py +0 -0
  108. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/fitted_model.py +0 -0
  109. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/frame_recording.py +0 -0
  110. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/link_check.py +0 -0
  111. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/pairs.py +0 -0
  112. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/schema.py +0 -0
  113. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/seed_prefixes.py +0 -0
  114. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/sklearn_check.py +0 -0
  115. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/survival.py +0 -0
  116. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode/torch_checks.py +0 -0
  117. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode_frame.py +0 -0
  118. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode_seed.py +0 -0
  119. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode_survival.py +0 -0
  120. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/raw_mode_torch.py +0 -0
  121. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/seed_weights.py +0 -0
  122. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/__init__.py +0 -0
  123. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/augmentation.py +0 -0
  124. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/callbacks.py +0 -0
  125. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/converted.py +0 -0
  126. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/features.py +0 -0
  127. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/image_channels.py +0 -0
  128. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/image_size.py +0 -0
  129. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/memory_estimate.py +0 -0
  130. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/preprocessing.py +0 -0
  131. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/subdataset.py +0 -0
  132. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/submitter.py +0 -0
  133. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/training/summary.py +0 -0
  134. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/__init__.py +0 -0
  135. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/lifelines_time_to_event.py +0 -0
  136. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/model_upload.py +0 -0
  137. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/scikit_survival_time_to_event.py +0 -0
  138. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/sequence_length.py +0 -0
  139. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/skl_tabular_base.py +0 -0
  140. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/skl_tabular_classifier.py +0 -0
  141. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/skl_tabular_regression.py +0 -0
  142. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/statistical_base.py +0 -0
  143. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/survival_base.py +0 -0
  144. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_causal_language_modeler.py +0 -0
  145. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_embeddings.py +0 -0
  146. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_handler.py +0 -0
  147. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_image_classifier.py +0 -0
  148. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_key_point_detector.py +0 -0
  149. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_masked_language_modeler.py +0 -0
  150. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_object_detector.py +0 -0
  151. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_semantic_segmentation.py +0 -0
  152. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_sentence_pair_classifier.py +0 -0
  153. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_seq2seq_modeler.py +0 -0
  154. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_tabular_classifier.py +0 -0
  155. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_tabular_regression.py +0 -0
  156. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_text_classifier.py +0 -0
  157. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_time_series_classifier.py +0 -0
  158. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_time_series_forecaster.py +0 -0
  159. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_time_to_event.py +0 -0
  160. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/torch_token_classifier.py +0 -0
  161. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/weight_loaders.py +0 -0
  162. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/upload/weights_parts.py +0 -0
  163. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/__init__.py +0 -0
  164. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/class_order.py +0 -0
  165. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/custom_loss_probe.py +0 -0
  166. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/data_probes.py +0 -0
  167. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/declared_classes.py +0 -0
  168. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/device.py +0 -0
  169. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/entry_point.py +0 -0
  170. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/errors.py +0 -0
  171. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/feature_dict.py +0 -0
  172. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/general_utils.py +0 -0
  173. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/model_loading.py +0 -0
  174. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/model_params.py +0 -0
  175. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/resources.py +0 -0
  176. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/safetensors_io.py +0 -0
  177. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/tabular_custom_loss_utils.py +0 -0
  178. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/utils/warnings_once.py +0 -0
  179. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/__init__.py +0 -0
  180. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/checker.py +0 -0
  181. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/estimator_checks.py +0 -0
  182. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/lifelines_checks.py +0 -0
  183. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/pytorch_checks.py +0 -0
  184. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/rewriter.py +0 -0
  185. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/scikit_survival_checks.py +0 -0
  186. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc/validation/sklearn_checks.py +0 -0
  187. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc.egg-info/dependency_links.txt +0 -0
  188. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc.egg-info/requires.txt +0 -0
  189. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc.egg-info/top_level.txt +0 -0
  190. {tracebloc-1.2.87 → tracebloc-1.2.89}/tracebloc_package/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tracebloc
3
- Version: 1.2.87
3
+ Version: 1.2.89
4
4
  Summary: Build AI with anyone. On data that can't move. SDK for the tracebloc collaborative AI workspace.
5
5
  Author-email: tracebloc <lukas@tracebloc.io>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tracebloc"
7
- version = "1.2.87"
7
+ version = "1.2.89"
8
8
  description = "Build AI with anyone. On data that can't move. SDK for the tracebloc collaborative AI workspace."
9
9
  license = "MIT"
10
10
  license-files = ["license.txt"]
@@ -35,7 +35,7 @@ from tracebloc.convert.heads import NAMED_AT_LINK
35
35
  from tracebloc.convert.package import SEED_EXCLUDED_PREFIXES, write_package
36
36
  from tracebloc.convert.report import report_document, write_report
37
37
  from tracebloc.utils.constants import TaskCategory
38
- from tracebloc.validation.header_rules import NO_OUTPUT_CLASSES
38
+ from tracebloc.validation.header_rules import NO_OUTPUT_CLASSES, SINGLE_OUTPUT
39
39
 
40
40
  #: The package values naming, once a head is aligned, the order its rows follow
41
41
  #: and the prefixes it was declared under before it stopped starting fresh.
@@ -57,7 +57,10 @@ def _positive_int(value: Any) -> int | None:
57
57
 
58
58
 
59
59
  def _class_count(category: str, content: Mapping[str, Any]) -> int | None:
60
- """The head width the dataset needs: distinct BIO tags for token classification."""
60
+ """The head width the dataset needs: one for a single-output task, distinct
61
+ BIO tags for token classification."""
62
+ if category in SINGLE_OUTPUT:
63
+ return 1
61
64
  if category == TaskCategory.TOKEN_CLASSIFICATION:
62
65
  names = content.get("class_names") or ()
63
66
  tags = {tag for sequence in names for tag in str(sequence).split()}
@@ -44,7 +44,7 @@ from .validation.scikit_survival_checks import (
44
44
  from .validation.lifelines_checks import (
45
45
  non_averageable_lifelines_estimator_reason,
46
46
  )
47
- from .validation.header_rules import NO_OUTPUT_CLASSES
47
+ from .validation.header_rules import NO_OUTPUT_CLASSES, SINGLE_OUTPUT
48
48
  from tracebloc.utils.constants import (
49
49
  SKLEARN_FRAMEWORK,
50
50
  SCIKIT_SURVIVAL_FRAMEWORK,
@@ -446,6 +446,19 @@ def _apply_link_success(
446
446
  f"model file."
447
447
  )
448
448
 
449
+ # Hard-fail: a one-output head (text regression) has no class names to count.
450
+ if category in SINGLE_OUTPUT:
451
+ try:
452
+ declared_outputs = int(classes)
453
+ except (TypeError, ValueError):
454
+ declared_outputs = None
455
+ if declared_outputs is not None and declared_outputs != 1:
456
+ raise DatasetLinkingError(
457
+ f"Model declares output_classes={declared_outputs} but a "
458
+ f"text regression model predicts one number per text. Set "
459
+ f"output_classes = 1 and give the model a 1-wide head."
460
+ )
461
+
449
462
  # OPTIONAL soft check: warn (do NOT block) if the model likely
450
463
  # won't fit the compute the backend assigned to this dataset.
451
464
  # No-op until the backend returns a "resources" object in the
@@ -83,6 +83,10 @@ TASK_CLASSES: dict[TaskCategory, tuple[str, str]] = {
83
83
  "AutoModelForSequenceClassification",
84
84
  "MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING_NAMES",
85
85
  ),
86
+ TaskCategory.TEXT_REGRESSION: (
87
+ "AutoModelForSequenceClassification",
88
+ "MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING_NAMES",
89
+ ),
86
90
  TaskCategory.TOKEN_CLASSIFICATION: (
87
91
  "AutoModelForTokenClassification",
88
92
  "MODEL_FOR_TOKEN_CLASSIFICATION_MAPPING_NAMES",
@@ -15,6 +15,7 @@ from tracebloc.utils.constants import TaskCategory
15
15
  #: from the checkpoint.
16
16
  PROBLEM_TYPES: Mapping[TaskCategory, str] = {
17
17
  TaskCategory.MULTI_LABEL_TEXT_CLASSIFICATION: "multi_label_classification",
18
+ TaskCategory.TEXT_REGRESSION: "regression",
18
19
  }
19
20
  #: Tasks whose Hugging Face head is named for the use case's classes once the
20
21
  #: link gives them; until then transformers' ``LABEL_<n>``.
@@ -24,6 +24,7 @@ from typing import Any, Callable, Mapping, Protocol
24
24
 
25
25
  from tracebloc.exceptions import ModelValidationError, TraceblocError
26
26
  from tracebloc.utils.constants import Framework, TaskCategory, _StringEnum
27
+ from tracebloc.validation.header_rules import SINGLE_OUTPUT
27
28
 
28
29
  #: The package whose modules are the shipped families.
29
30
  FAMILIES_PACKAGE = "tracebloc.convert.families"
@@ -135,6 +136,7 @@ class UseCaseTask:
135
136
  where ``category`` is the checkpoint's declared head and the package is
136
137
  regenerated at link. ``counts`` are keyed by :data:`COUNT_NAMES`;
137
138
  ``class_names`` are the dataset's, which the head's rows are aligned to.
139
+ A :data:`SINGLE_OUTPUT` task's ``output_classes`` is 1, whatever is counted.
138
140
  """
139
141
 
140
142
  category: TaskCategory
@@ -149,6 +151,8 @@ class UseCaseTask:
149
151
  for name, count in self.counts.items():
150
152
  if isinstance(count, bool) or not isinstance(count, int) or count < 1:
151
153
  raise ValueError(f"count {name} must be a positive int, got {count!r}")
154
+ if self.category in SINGLE_OUTPUT:
155
+ object.__setattr__(self, "counts", {**self.counts, "output_classes": 1})
152
156
  object.__setattr__(self, "counts", _frozen(self.counts))
153
157
  object.__setattr__(self, "class_names", tuple(self.class_names))
154
158
 
@@ -20,12 +20,14 @@ from tracebloc.convert.interfaces import (
20
20
  )
21
21
  from tracebloc.utils.constants import TaskCategory
22
22
 
23
- #: Tasks whose class head is one linear layer with a row per class.
23
+ #: Tasks whose head is one linear layer with a row per class (one row: a
24
+ #: regression's predicted number).
24
25
  CLASSIFICATION_HEADS = (
25
26
  TaskCategory.IMAGE_CLASSIFICATION,
26
27
  TaskCategory.TEXT_CLASSIFICATION,
27
28
  TaskCategory.SENTENCE_PAIR_CLASSIFICATION,
28
29
  TaskCategory.MULTI_LABEL_TEXT_CLASSIFICATION,
30
+ TaskCategory.TEXT_REGRESSION,
29
31
  TaskCategory.TOKEN_CLASSIFICATION,
30
32
  TaskCategory.TABULAR_CLASSIFICATION,
31
33
  TaskCategory.TIME_SERIES_CLASSIFICATION,
@@ -44,6 +44,7 @@ AUTO_CLASS = {
44
44
  TaskCategory.TEXT_CLASSIFICATION: "AutoModelForSequenceClassification",
45
45
  TaskCategory.SENTENCE_PAIR_CLASSIFICATION: "AutoModelForSequenceClassification",
46
46
  TaskCategory.MULTI_LABEL_TEXT_CLASSIFICATION: "AutoModelForSequenceClassification",
47
+ TaskCategory.TEXT_REGRESSION: "AutoModelForSequenceClassification",
47
48
  TaskCategory.TOKEN_CLASSIFICATION: "AutoModelForTokenClassification",
48
49
  TaskCategory.MASKED_LANGUAGE_MODELING: "AutoModelForMaskedLM",
49
50
  TaskCategory.CAUSAL_LANGUAGE_MODELING: "AutoModelForCausalLM",
@@ -0,0 +1,6 @@
1
+ """Synthetic datasets used by the SDK's upload-time functional checks.
2
+
3
+ RFC-0348 A.2 moved these classes here from ``tracebloc/utils/*_utils.py``;
4
+ the old import paths keep working through re-exports. Submodules import
5
+ torch, so this package stays import-light and does not import them eagerly.
6
+ """
@@ -0,0 +1,55 @@
1
+ """Shared bases for the synthetic datasets (RFC-0348 A.2)."""
2
+
3
+ import torch
4
+ from torch.utils.data import Dataset
5
+
6
+
7
+ class SyntheticDataset(Dataset):
8
+ """Dataset whose length comes from one attribute.
9
+
10
+ ``_size_attr`` names the attribute. When ``_size_is_count`` is true the
11
+ attribute already holds the count (e.g. ``num_samples``); otherwise the
12
+ length of the attribute is used, indexing ``_size_key`` first when set
13
+ (e.g. ``encodings["input_ids"]``).
14
+ """
15
+
16
+ _size_attr = "num_samples"
17
+ _size_is_count = True
18
+ _size_key = None
19
+
20
+ def __len__(self):
21
+ size = getattr(self, self._size_attr)
22
+ if self._size_is_count:
23
+ return size
24
+ if self._size_key is not None:
25
+ size = size[self._size_key]
26
+ return len(size)
27
+
28
+
29
+ class EncodedDataset(SyntheticDataset):
30
+ """Dataset over tokenizer ``encodings``; length is the number of input_ids rows."""
31
+
32
+ _size_attr = "encodings"
33
+ _size_is_count = False
34
+ _size_key = "input_ids"
35
+
36
+
37
+ class UnshiftedLabelsDataset(EncodedDataset):
38
+ """Encoded dataset whose labels are the unshifted input_ids, padding -> -100."""
39
+
40
+ def __init__(self, encodings, pad_token_id):
41
+ self.encodings = encodings
42
+ self.pad_token_id = pad_token_id
43
+
44
+ def __getitem__(self, idx):
45
+ input_ids = list(self.encodings["input_ids"][idx])
46
+ attention_mask = list(self.encodings["attention_mask"][idx])
47
+ labels = [
48
+ -100 if token_id == self.pad_token_id else token_id
49
+ for token_id in input_ids
50
+ ]
51
+ return {
52
+ "input_ids": torch.tensor(input_ids, dtype=torch.long),
53
+ "attention_mask": torch.tensor(attention_mask, dtype=torch.long),
54
+ "labels": torch.tensor(labels, dtype=torch.long),
55
+ }
@@ -0,0 +1,51 @@
1
+ """Synthetic object-detection data for the upload check (RFC-0348 A.2)."""
2
+
3
+ import random
4
+
5
+ import torch
6
+
7
+ from tracebloc.datasets.base import SyntheticDataset
8
+ from tracebloc.utils.declared_classes import declared_classes
9
+
10
+
11
+ class FakeObjectDetectionDataset(SyntheticDataset):
12
+ def __init__(
13
+ self, num_samples, num_classes=None, data_shape=(256, 256), num_channels=3
14
+ ):
15
+ self.num_samples = num_samples
16
+ self.num_classes = num_classes if num_classes else random.randint(1, 10)
17
+ self.classes = [self._generate_class_name() for _ in range(self.num_classes)]
18
+ self.data_shape = data_shape
19
+ self.num_channels = num_channels
20
+ self.data = self._generate_fake_data()
21
+
22
+ def _generate_class_name(self):
23
+ # Generate a random class name
24
+ return "".join(random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") for _ in range(5))
25
+
26
+ def _generate_fake_data(self):
27
+ data = []
28
+ for _ in range(self.num_samples):
29
+ # Match the model's native input-channel count (1 for grayscale,
30
+ # 3 for RGB) so grayscale detectors aren't false-rejected by
31
+ # hardcoded 3-channel dummy data.
32
+ image = torch.rand((self.num_channels, *self.data_shape)) # Fake image
33
+ num_objects = random.randint(1, 5)
34
+ labels = [
35
+ random.randint(0, self.num_classes - 1) for _ in range(num_objects)
36
+ ]
37
+ boxes = [
38
+ (random.random(), random.random(), random.random(), random.random())
39
+ for _ in range(num_objects)
40
+ ]
41
+ target = {"boxes": boxes, "labels": labels}
42
+ data.append((image, target))
43
+ return data
44
+
45
+ def __getitem__(self, idx):
46
+ return self.data[idx]
47
+
48
+ def __iter__(self):
49
+ return iter(self.data)
50
+
51
+ get_classes = declared_classes
@@ -1,10 +1,15 @@
1
+ """Synthetic keypoint-detection data for the upload check (RFC-0348 A.2)."""
2
+
3
+ import numpy as np
1
4
  import torch
2
- from torch.utils.data import Dataset
3
5
  from PIL import Image
4
- import numpy as np
6
+
7
+ from tracebloc.datasets.base import SyntheticDataset
5
8
 
6
9
 
7
- class FakeKeypointDetectionDataset(Dataset):
10
+ class FakeKeypointDetectionDataset(SyntheticDataset):
11
+ _size_attr = "num_images"
12
+
8
13
  def __init__(
9
14
  self,
10
15
  num_images,
@@ -21,9 +26,6 @@ class FakeKeypointDetectionDataset(Dataset):
21
26
  self.transform = transform
22
27
  self.num_channels = num_channels
23
28
 
24
- def __len__(self):
25
- return self.num_images
26
-
27
29
  def __getitem__(self, idx):
28
30
  # Create a blank image with the model's native channel count
29
31
  # ("L" => 1-channel grayscale, "RGB" => 3-channel). ToTensor in
@@ -79,8 +81,6 @@ class FakeKeypointDetectionDataset(Dataset):
79
81
  xx, yy = np.meshgrid(
80
82
  np.arange(self.data_shape[1]), np.arange(self.data_shape[0])
81
83
  )
82
- heatmaps[i] = np.exp(
83
- -((xx - x) ** 2 + (yy - y) ** 2) / (2 * sigma**2)
84
- )
84
+ heatmaps[i] = np.exp(-((xx - x) ** 2 + (yy - y) ** 2) / (2 * sigma**2))
85
85
 
86
86
  return torch.tensor(heatmaps, dtype=torch.float32)
@@ -1,15 +1,19 @@
1
- import torch
2
- import torchvision.transforms as transforms
3
- from torch.utils.data import Dataset
1
+ """Synthetic semantic-segmentation data for the upload check (RFC-0348 A.2)."""
2
+
4
3
  import numpy as np
4
+ import torch
5
+
6
+ from tracebloc.datasets.base import SyntheticDataset
5
7
 
6
8
 
7
- class FakeSemanticSegmentationDataset(Dataset):
9
+ class FakeSemanticSegmentationDataset(SyntheticDataset):
8
10
  """
9
11
  A fake dataset for semantic segmentation testing.
10
12
  Creates random images and corresponding segmentation masks.
11
13
  """
12
14
 
15
+ _size_attr = "num_images"
16
+
13
17
  def __init__(
14
18
  self, data_shape, num_images=10, num_classes=2, transform=None, num_channels=3
15
19
  ):
@@ -28,13 +32,13 @@ class FakeSemanticSegmentationDataset(Dataset):
28
32
  # (1 for grayscale models, 3 for RGB). Channels-last HWC here;
29
33
  # __getitem__ / ToTensor moves it to CHW.
30
34
  if isinstance(data_shape, int):
31
- img = np.random.rand(
32
- data_shape, data_shape, num_channels
33
- ).astype(np.float32)
35
+ img = np.random.rand(data_shape, data_shape, num_channels).astype(
36
+ np.float32
37
+ )
34
38
  else:
35
- img = np.random.rand(
36
- data_shape[0], data_shape[1], num_channels
37
- ).astype(np.float32)
39
+ img = np.random.rand(data_shape[0], data_shape[1], num_channels).astype(
40
+ np.float32
41
+ )
38
42
 
39
43
  # Create random segmentation mask
40
44
  if isinstance(data_shape, int):
@@ -49,9 +53,6 @@ class FakeSemanticSegmentationDataset(Dataset):
49
53
  self.images.append(img)
50
54
  self.masks.append(mask)
51
55
 
52
- def __len__(self):
53
- return self.num_images
54
-
55
56
  def __getitem__(self, idx):
56
57
  image = self.images[idx]
57
58
  mask = self.masks[idx]
@@ -0,0 +1,34 @@
1
+ """Tabular datasets for the upload check (RFC-0348 A.2)."""
2
+
3
+ import numpy as np
4
+ import torch
5
+
6
+ from tracebloc.datasets.base import SyntheticDataset
7
+
8
+
9
+ # Custom dataset for regression
10
+ class TabularRegressionDataset(SyntheticDataset):
11
+ _size_attr = "targets"
12
+ _size_is_count = False
13
+
14
+ def __init__(self, features, targets):
15
+ self.features = features.astype(np.float32)
16
+ self.targets = targets.astype(np.float32) # Continuous values, not classes
17
+
18
+ def __getitem__(self, idx):
19
+ return torch.tensor(self.features[idx]), torch.tensor(self.targets[idx])
20
+
21
+
22
+ class TabularClassificationDataset(SyntheticDataset):
23
+ """Tabular classification rows; was the nested ``TabularDataset`` in
24
+ ``tabular_classification_utils.get_dataloader``."""
25
+
26
+ _size_attr = "labels"
27
+ _size_is_count = False
28
+
29
+ def __init__(self, features, labels):
30
+ self.features = features.astype(np.float32)
31
+ self.labels = labels.astype(np.float32)
32
+
33
+ def __getitem__(self, idx):
34
+ return torch.tensor(self.features[idx]), torch.tensor(self.labels[idx])
@@ -0,0 +1,189 @@
1
+ """Synthetic NLP datasets for the upload check (RFC-0348 A.2).
2
+
3
+ The builders that tokenize text and return these stay in
4
+ tracebloc.utils.text_classification_utils.
5
+ """
6
+
7
+ import torch
8
+
9
+ from tracebloc.datasets.base import (
10
+ EncodedDataset,
11
+ SyntheticDataset,
12
+ UnshiftedLabelsDataset,
13
+ )
14
+
15
+
16
+ # Dataset
17
+ class TextDataset(SyntheticDataset):
18
+ _size_attr = "labels"
19
+ _size_is_count = False
20
+
21
+ def __init__(self, encodings, labels):
22
+ self.encodings = encodings
23
+ self.labels = labels
24
+
25
+ def __getitem__(self, idx):
26
+ item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
27
+ item["labels"] = torch.tensor(self.labels[idx])
28
+ return item
29
+
30
+
31
+ class MaskedLanguageModelingDataset(EncodedDataset):
32
+ """Synthetic MLM dataset: applies 80/10/10 masking on-the-fly.
33
+
34
+ Used only for the SDK-side functional check (small training loop) so
35
+ the upload pipeline can validate that the user's model accepts MLM
36
+ inputs and produces a per-token logits tensor.
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ encodings,
42
+ mask_token_id,
43
+ pad_token_id,
44
+ vocab_size,
45
+ mask_prob=0.15,
46
+ seed=42,
47
+ ):
48
+ import numpy as np
49
+
50
+ self.encodings = encodings
51
+ self.mask_token_id = mask_token_id
52
+ self.pad_token_id = pad_token_id
53
+ self.vocab_size = vocab_size
54
+ self.mask_prob = mask_prob
55
+ self._rng = np.random.default_rng(seed)
56
+
57
+ def __getitem__(self, idx):
58
+ input_ids = list(self.encodings["input_ids"][idx])
59
+ attention_mask = list(self.encodings["attention_mask"][idx])
60
+ labels = [-100] * len(input_ids)
61
+
62
+ for i, token_id in enumerate(input_ids):
63
+ # Don't mask padding tokens.
64
+ if token_id == self.pad_token_id:
65
+ continue
66
+ if self._rng.random() < self.mask_prob:
67
+ labels[i] = token_id
68
+ rand = self._rng.random()
69
+ if rand < 0.8:
70
+ input_ids[i] = self.mask_token_id
71
+ elif rand < 0.9:
72
+ input_ids[i] = int(self._rng.integers(0, self.vocab_size))
73
+ # else: keep original — model still predicts it.
74
+
75
+ return {
76
+ "input_ids": torch.tensor(input_ids, dtype=torch.long),
77
+ "attention_mask": torch.tensor(attention_mask, dtype=torch.long),
78
+ "labels": torch.tensor(labels, dtype=torch.long),
79
+ }
80
+
81
+
82
+ class TokenClassificationDummyDataset(EncodedDataset):
83
+ """Synthetic token-classification dataset: random per-token tag ids.
84
+
85
+ Used only for the SDK-side functional check (small training loop) so
86
+ the upload pipeline can validate that the user's model accepts token
87
+ inputs and produces ``(batch, seq_len, num_classes)`` logits.
88
+ """
89
+
90
+ def __init__(self, encodings, num_classes, pad_token_id, seed=42):
91
+ import numpy as np
92
+
93
+ self.encodings = encodings
94
+ self.num_classes = num_classes
95
+ self.pad_token_id = pad_token_id
96
+ self._rng = np.random.default_rng(seed)
97
+
98
+ def __getitem__(self, idx):
99
+ # Return EVERY tokenizer output key (e.g. token_type_ids for
100
+ # BERT-family tokenizers), not just input_ids/attention_mask: the
101
+ # client's dataset does the same and its HF path forwards
102
+ # ``model(**batch)``, so the upload-time validation batch must
103
+ # carry the same keys the model will see at training time.
104
+ item = {
105
+ key: torch.tensor(values[idx], dtype=torch.long)
106
+ for key, values in self.encodings.items()
107
+ }
108
+ input_ids = list(self.encodings["input_ids"][idx])
109
+ labels = [
110
+ (
111
+ -100
112
+ if token_id == self.pad_token_id
113
+ else int(self._rng.integers(0, self.num_classes))
114
+ )
115
+ for token_id in input_ids
116
+ ]
117
+ item["labels"] = torch.tensor(labels, dtype=torch.long)
118
+ return item
119
+
120
+
121
+ class CausalLanguageModelingDataset(UnshiftedLabelsDataset):
122
+ """Synthetic causal-LM dataset: labels are the (unshifted) input_ids.
123
+
124
+ Used only for the SDK-side functional check (small training loop) so the
125
+ upload pipeline can validate that the user's decoder-only model accepts
126
+ causal-LM inputs and produces ``(batch, seq_len, vocab_size)`` logits.
127
+
128
+ Following the Hugging Face convention (and the client's
129
+ ``CausalLanguageModelingDataset``), ``labels[i] == input_ids[i]`` on real
130
+ tokens — NOT pre-shifted. The one-position next-token shift is applied
131
+ exactly once downstream (HF models shift internally when given ``labels``;
132
+ the non-HF training branch shifts explicitly). Padding positions carry
133
+ ``-100`` so they are ignored by the loss.
134
+ """
135
+
136
+
137
+ class EmbeddingsDummyDataset(SyntheticDataset):
138
+ """Synthetic contrastive-embeddings dataset: anchor / positive text pairs.
139
+
140
+ Used only for the SDK-side functional check (small training loop) so the
141
+ upload pipeline can validate that the user's text encoder accepts a
142
+ tokenized batch, exposes ``last_hidden_state``, mean-pools to one embedding
143
+ per example, and trains under the in-batch contrastive (InfoNCE) objective.
144
+
145
+ Each item carries the anchor / positive ``input_ids`` and ``attention_mask``
146
+ (the keys the backend ``EmbeddingsDataset`` produces). There are no labels —
147
+ embeddings is self-supervised; the target for anchor ``i`` is positive ``i``,
148
+ derived from the pairing at loss time.
149
+ """
150
+
151
+ _size_attr = "anchor_encodings"
152
+ _size_is_count = False
153
+ _size_key = "input_ids"
154
+
155
+ def __init__(self, anchor_encodings, positive_encodings):
156
+ self.anchor_encodings = anchor_encodings
157
+ self.positive_encodings = positive_encodings
158
+
159
+ def __getitem__(self, idx):
160
+ return {
161
+ "anchor_input_ids": torch.tensor(
162
+ self.anchor_encodings["input_ids"][idx], dtype=torch.long
163
+ ),
164
+ "anchor_attention_mask": torch.tensor(
165
+ self.anchor_encodings["attention_mask"][idx], dtype=torch.long
166
+ ),
167
+ "positive_input_ids": torch.tensor(
168
+ self.positive_encodings["input_ids"][idx], dtype=torch.long
169
+ ),
170
+ "positive_attention_mask": torch.tensor(
171
+ self.positive_encodings["attention_mask"][idx], dtype=torch.long
172
+ ),
173
+ }
174
+
175
+
176
+ class Seq2SeqDummyDataset(UnshiftedLabelsDataset):
177
+ """Synthetic seq2seq dataset: labels are the (unshifted) input_ids.
178
+
179
+ Used only for the SDK-side functional check (small training loop) so the
180
+ upload pipeline can validate that the user's encoder-decoder model accepts
181
+ seq2seq inputs and produces ``(batch, target_seq_len, vocab_size)`` logits.
182
+
183
+ The target sequence equals the source (a copy/denoise smoke objective), so
184
+ ``labels[i] == input_ids[i]`` on real tokens — NOT pre-shifted. HF seq2seq
185
+ models build ``decoder_input_ids`` from ``labels`` internally; the non-HF
186
+ training branch teacher-forces on the source and compares logits to labels
187
+ directly (no external shift). Padding positions carry ``-100`` so they are
188
+ ignored by the loss.
189
+ """