Changelog¶
All notable changes to micm-nlp will be documented here. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
[Unreleased]¶
[0.3.0] - 2026-09-03¶
Changed (breaking)¶
The
tokenizerssubpackage is flat. Two module paths moved:micm_nlp.tokenizers.bert_byt5.BertByT5Tokenizerandmicm_nlp.tokenizers.xlm_roberta.CustomXlmRobertaare now both inmicm_nlp.tokenizers.architectures, mirroringmicm_nlp.models.architectures. Each module held one wrapper class and nothing else; the split bought no isolation.micm_nlp.tokenizers.lib.sent.ka_sen_tok.KaSenTokis nowmicm_nlp.tokenizers.ka_sen_tok.KaSenTok, and its two data files moved fromlib/sent/data/totokenizers/data/. Thelibandlib.sentpackages held a docstring each and no code — three levels of nesting around one module.
No shims: the old paths are gone. Nothing in this repo or in
xpe-expimported either class outside of tests and one lazy import, both updated. Updatetokenizer.clsvalues in any consumer config that names them.
Added¶
Docstrings for every published class and function. 220 objects had none, so each API page opened with a module description and then listed bare signatures; the generated reference now documents the whole public surface.
Fixed¶
utils.print_traceback()importedmicm_nlp.setup, a module that stopped existing in 0.2.0 when it was merged intobootstrap, so every call raisedModuleNotFoundError.TokenizerTrainer.train()returned silently for amodel.typeit cannot train.TokTypeSEhas six members and only three have a trainer, so a valid config could finish a run reporting nothing wrong and leaving no tokenizer behind. It now raisesValueError.CrossPromptEncoder’s class docstring used a Markdown code fence, which reStructuredText cannot parse, and its example importedmicm_nlp.models.cross_prompt_encoder— a path that no longer exists.CrossPromptEncoderConfig.encoder_embedding_normalizedefaulted to'unit'(max_norm1.0). Because_filtered_kwargsstripsNone-valued kwargs at the factory boundary, a YAMLencoder_embedding_normalize: nullnever reached the dataclass — so every savedadapter_config.jsonrecorded"unit"regardless of what the run actually did. The defaults are nowNone/None, so a saved adapter config records what happened. Behaviour is unchanged: normalisation is driven by the callback, whose registration reads the top-levelpeftblock. Adapter configs written before this change misreport the field — do not read a normalisation claim out of them.CrossPromptEncoder.__init__now validates the normalisation settings: an unknown mode raises, and'clip'without amax_normraises rather than silently doing nothing (Tensor.clamp(max=None)is a no-op, which the newNonedefault would otherwise have turned into a silent non-normalising clip).
Documentation¶
The site’s API reference now mirrors
src/micm_nlp/rather than a hand-written taxonomy, and its prose comes fromREADME.mdthrough MyST{include}, so README is the single copy of every passage the two share.
[0.2.1] - 2026-08-11¶
Fixed¶
NormalizePromptEncoderEmbeddingswas never registered: the trainer read its settings fromtask.peft, butpeftis a top-level config block, so the lookup always returnedNone. Registration is now additionally gated onpeft.encoder_embedding_normalizebeing set — without itnormalize_embeddings()is a no-op that would still log a0.0norm to W&B on every step of every XPE run. Consequence for existing results: any run that setencoder_embedding_normalizedid not in fact normalise, and measured the unnormalised model.DataCollatorTaskIDDecorator.__call__opened with a leftoverprint()/exit()debug pair, which made the rest of the method dead code.tokenize_sentences()defaulted toSentTokTypeSE.KA, whose branch was commented out, so calling it without an explicit method raisedValueError. The default is nowSentTokTypeSE.NLTK, and theKAbranch works again.micm_nlp.tokenizers.lib.sent.ka_sen_tokcould not be imported at all: it read its abbreviation lists frommicm_nlp.datasets.storage.collections.abbreviations, a package that does not exist here. The two data files (885 Georgian abbreviations, 379 abbreviation endings) now ship inside the package attokenizers/lib/sent/data/and are loaded throughimportlib.resources, so they survive installation from a wheel.nltk.download('punkt')no longer runs at import time — the models are checked first and only fetched when genuinely missing.
Changed¶
Every module now carries a module-level docstring, so the generated API reference explains what each module is for instead of listing bare symbols. Three known defects are now documented where they live: the unregistered
NormalizePromptEncoderEmbeddingscallback, the leftover debug body inDataCollatorTaskIDDecorator.__call__, andka_sen_tok’s missing abbreviation data (it cannot be imported as shipped).
[0.2.0] - 2026-08-10¶
Added¶
Token-budget batching:
TokenBudgetBatchSamplerbuilds batches to a target token count instead of a fixed sample count, with acalibrate_token_budgetprobe that binary-searches the largest budget that fits in memory.eval_max_tokens_per_batch/test_max_tokens_per_batchconfig keys (validated), wiring token-budget batching into the eval and test dataloaders. When unset, the previous fixed-batch path is used unchanged.early_stopping_metriconCustomTrainingArgsConfig, decoupling early stopping from best-checkpoint selection:'metric_for_best_model'delegates totraining_args, any literal key (e.g.'eval_loss') is monitored directly with its direction inferred. Defaults to'eval_loss', preserving prior behaviour.A seed configured in
training_argsis now honoured without enablingfull_determinism; the seed is randomised only when none is configured. Lets callers share fixed seeds across methods for paired comparison at no determinism overhead.Label-restricted likelihood for
mcqa_ftpviapreproc_rules.label_restricted_likelihood(opt-in, lm-eval-harnessmultiple_choicestyle): restricts the answer-slot argmax to the candidate label tokens inds.label.namesrather than the full vocabulary.Documentation site (Sphinx + Furo, API reference generated from source), published on Read the Docs.
Changed¶
BREAKING
LossEarlyStoppingCallbackis nowCustomEarlyStoppingCallback. The callback monitors any metric, not only loss, so the old name was misleading.BREAKING
env.pyandsetup.pyhave been consolidated intobootstrap.py; both were small and conceptually overlapping, andsetup.pycollided with packaging tooling.PROJECT_ROOT_PATHis relaxed toPath | NonesoEnv()can be imported beforeinit()runs.get_preprocess_logits_for_metricsmoved fromtraining/callbacks.pytoevals/eval.py, next toget_compute_metrics— the two share the prediction-shape contract, and the hook was never aTrainerCallback.Token-budget calibration merged into the
training/batchingmodule.Sequence lengths now fall back to
input_idsin the HuggingFace style instead of requiring an explicit length-column override.Token-budget
HEADROOMlowered from 0.85 to 0.80; the 15% margin was consumed by cumulative memory fragmentation during long evaluation sweeps.calibrate_token_budget’stoleranceparameter is deprecated and ignored — the search now always runs to convergence.
Fixed¶
calibrate_token_budgetended its binary search once the window shrank belowtoleranceand then probed only the window’s top edge, so any true fitting batch size in the coarse-halving dead zone was skipped and the budget collapsed to a single sequence. Every heavily-tokenised language was silently batched at ~1, and those whose shortest sequence fell below the floor were skipped entirely.Predictions were zipped against
ds_splitin dataset order whileTokenBudgetBatchSampleryields globally length-sorted samples, so undereval_per_taskgrouping every per-task metric was attributed to the wrong task. Batch samplers now expose anorderpermutation and alignment is applied sampler-agnostically; theSequentialSamplerpath is unaffected.Calibration probe correctness: binary-search over sorted lengths for a deterministic, shape-correct probe; post-loop
hiprobe so datasets smaller than the tolerance get the right budget; probe withlabels=so the cross-entropy logits cost is included; probehard_capdirectly and guard misconfiguredstart/hard_cap.NormalizePromptEncoderEmbeddingshookedon_optimizer_step, which does not receivemodelunder transformers 4.48, making the callback a no-op.The length column was stripped by
_remove_unused_columnsbefore the token-budget and length-grouped samplers could read it.Boolean values were accepted where a token budget was expected.
Single-process runs on multi-GPU partitions inherited SLURM environment variables that pushed accelerate into
MULTI_GPUmode and aborted during NCCL init;init()now strips them whenWORLD_SIZE=1.pad_to_multiple_ofis sourced from the data collator instead of a duplicated parameter.micm_nlp.evals.metricshad no__init__.py, making it an implicit namespace package unlike every other subpackage. It is now a regular package.
[0.1.0] - 2026-04-30¶
Added¶
Initial public release of the micm-nlp toolkit.
Config-driven pipeline (tokenization → preprocessing → training → evaluation).
Example: HuggingFace Hub dataset loading + decoder-only tokenization (
examples/preprocess_dataset.py+examples/configs/xsc_preprocess.yml).Example: PEFT fine-tuning + evaluation using Cross-Prompt Encoder (XPE) on a decoder-only LM (
examples/run_model.py+examples/configs/xsc_finetune.yml).WandB experiment tracking integration.