Repository navigation
Conversation
Test CoverageTotal: 75.27% (21568 / 28656 lines)
|
Logiquo
force-pushed
the
feat/metric-2
branch
2 times, most recently
from
November 2, 2026 00:48
8fca165 to
01f45dd
Compare
Label processors now say what kind of label they are and how to train on it; BaseModel delegates instead of switching on a mode string. - LabelProcessor mixin: mode, is_timeseries, supports_pos_weight, activation() and loss(). Binary, MultiClass, MultiLabel and Regression implement them; the time-series labels apply their static counterpart per label record (formerly _label_record_loss) and skip SequenceProcessorV2's pass over the samples in fit(). - BaseModel.get_loss_function() and prepare_y_prob() use the label processor; _resolve_mode reads LabelProcessor.mode instead of walking the registry; set_pos_weight checks supports_pos_weight. - MultiClassLabelProcessor and MultiLabelProcessor take an optional labels (the label set, or its size) that fixes the vocabulary; fit then only checks the labels. Omitted, the label set is learned as before.
TimeseriesLabelProcessor and its binary and regression subclasses are labels built on SequenceProcessorV2; they now live in timeseries_label_processor.py instead of next to the legacy TimeseriesProcessor feature processor. They have not been released, so no import path or pickled cache depends on the old location.
Logiquo
force-pushed
the
feat/metric-2
branch
from
November 2, 2026 00:56
01f45dd to
0c28e2f
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1361.
Summary
BaseModeldecided how to train on a label from a mode string: it found the mode by walking each processor class's MRO against registry names, then switched on it inget_loss_functionandprepare_y_prob. Label semantics lived in the model rather than in the processor that defines the label.This PR moves those semantics onto the label processors:
LabelProcessormixin (pyhealth.processors.LabelProcessor):mode,is_timeseries,supports_pos_weight,activation(logits)andloss(logits, y_true, pos_weight=None).modeactivationlosspos_weightBinaryLabelProcessorbinaryMultiClassLabelProcessormulticlassMultiLabelProcessormultilabelRegressionLabelProcessorregressionTimeseriesBinaryLabelProcessortimeseries_binaryTimeseriesRegressionLabelProcessortimeseries_regressionThe time-series labels delegate to their static counterpart (
base_cls) and keep the per-record shape check and the zero loss for a batch without label records (formerly_label_record_loss). TheirfitisFeatureProcessor's no-op:SequenceProcessorV2.fitread every sample and found no tokens or statistics to learn.BaseModeldelegates.get_loss_function()returns the label processor'slosswith the model'spos_weight, andprepare_y_prob()itsactivation. The results are unchanged._resolve_modereadsLabelProcessor.modeinstead of walking the registry.set_pos_weightcheckssupports_pos_weight. Without a fitted label processor (e.g. a dataset whose processors are not fitted), the processor registered under the mode is used.Optional
labelsonMultiClassLabelProcessorandMultiLabelProcessor: the label set in index order, or its sizeKfor labels already0..K-1. When given, the vocabulary (andsize()) is fixed, andfitonly checks that every label is in it. A class missing from the training split still gets its output. When omitted, the label set is learned as before, which code-prediction tasks such as drug recommendation and medical coding rely on. Pass it as("multiclass", {"labels": [...]}).autoimproveresolves the label mode fromLabelProcessor.modetoo.Own module. The time-series label processors move from
timeseries_processor.py(the legacyTimeseriesProcessorinput processor) totimeseries_label_processor.py. They are unreleased, so no import path or pickled cache depends on the old location;from pyhealth.processors import ...is unchanged.Breaking changes
get_loss_function()returns afunctools.partialof the processor's loss, so it has no__name__. The loss values are unchanged.Tests
tests/core/test_label_processor.pycovers:pos_weight, its rejection where unsupported, the per-record shape check, the zero loss on an empty batch, and the time-seriesfitnot reading the samples;MultiHotProcessoris not);labels: fixed indices and size,Kmeaningrange(K), unknown and invalid labels, omitted labels learned as before, pickling (including an instance pickled beforelabelsexisted), andlabelspassed through a task schema;BaseModeldelegation.test_legacy_mode_resolutioncompares loss values rather than function names.test_survival_mdnimports pytest, which is not installed, andtest_transformers_model.TestChunking.test_windows_need_a_fast_tokenizeralso fails onmasterhere.