Skip to content

Superseded by #85: Investigate HMM backend surface - #79

Closed
AKuederle wants to merge 29 commits into
masterfrom
investigate/hmm-backend-surface
Closed

Superseded by #85: Investigate HMM backend surface#79
AKuederle wants to merge 29 commits into
masterfrom
investigate/hmm-backend-surface

Conversation

@AKuederle

Copy link
Copy Markdown
Member

No description provided.

"""Configuration of a single trainable HMM submodule."""

name: str
role: Literal["transition", "stride", "other"]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why "other" should be Literal["transition", "stride"] | str


def __init__(
self,
modules: dict[str, HmmSubModelConfig] = cf(_default_modules()),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dicts are bad for tpcp. Check the docs list of tuples is better

To rephrase it again: We want to create a fully labeled dataset with already optimal hidden-state labels, but as
these lables are hidden, we need to predict them with our already trained models...
"""
"""Create fully labeled gait sequences from typed regions and trained submodels."""

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expand doccstring with more info again.

Sequence of gaitmap stride lists.
The number of stride lists must match the number of sensordata objects (i.e. they must belong together).
region_list_sequence
Sequence of typed region lists.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain the expected format

architecture="left-right-strict",
name="stride_model",
@classmethod
def _from_json_dict(cls, json_dict: dict) -> Self:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done for backwards compatibility right? Add a todo note that we should remove this again and rather convert the old model to the correct format

return sum(module.n_states for module in self.model_config.modules.values())

@property
def module_offsets(self) -> dict[str, int]:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not relevant for user facing -> _module_offsets


# predict hidden state labels for complete walking bouts
module_offsets = self.module_offsets
labels_train_sequence = create_fully_labeled_gait_sequences(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename create_fully_labeled_gait_sequences?

return normalized_region_list


def convert_region_list_to_transition_list(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we find a more performant version for this? I think we have a couple of helper funcs in utisl that can help here.


def _stride_list_to_region_list(stride_list: pd.DataFrame, region_type: str = "stride") -> pd.DataFrame:
region_list = stride_list[["start", "end"]].copy()
region_list.insert(0, "roi_id", np.arange(len(region_list)))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just rename stride_id (the index to roi id)

return log_emissions


def _viterbi_decode(model: HMMState, log_emissions: np.ndarray) -> np.ndarray:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use numba to speed this and other funcs up here?

return np.argmax(posterior, axis=1)


class ScipyHmmInferenceBackend(BaseHmmBackend):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the scipy backend in its own file, so that we can import it even when pomegrante isnot installed

region_list_sequence = []
for sensor in ["left_sensor", "right_sensor"]:
region_list = stride_list[sensor][["start", "end"]].copy()
region_list.insert(0, "roi_id", np.arange(len(region_list)))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use assign and reuse the stride index/stride id

return tuple(transitions)


class PomegranateHmmBackend(BaseHmmBackend):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to dedicated file to allow imports of base and scipy backend when pomegrante not installed

model = fix_model_names(model)
model.bake()
model.freeze_distributions()
return _clone_model(model, assert_correct=False)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to clone, given that we just created the model here?

return tuple(module.name for module in self.modules if module.role == "stride")

@property
def custom_model_names(self) -> tuple[str, ...]:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above

model_config: CompositeHmmConfig = cf(CompositeHmmConfig()),
feature_transform: RothHmmFeatureTransformer = cf(RothHmmFeatureTransformer()),
*,
algo_predict: Literal["viterbi", "map"] = "viterbi",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense to have the training params on teh composite config instead of here?



class RothHmmConfig(_BaseSerializable):
"""Serializable configuration bundle for `RothSegmentationHmm`."""

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring should explain all parameters (Same for all other classes in teh config module)

self.backend = backend

@property
def model_config(self) -> CompositeHmmConfig:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove all the roperty mappings. user should just access everything through hmm_config

return model


def pomegranate_model_to_hmm_state(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to pomegrante_legacy_backend file

@codecov-commenter

codecov-commenter commented Mar 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.95%. Comparing base (3c6e508) to head (ae62c36).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #79      +/-   ##
==========================================
+ Coverage   89.93%   89.95%   +0.01%     
==========================================
  Files          61       61              
  Lines        3438     3424      -14     
==========================================
- Hits         3092     3080      -12     
+ Misses        346      344       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Member Author

Superseded by #85, which implements the backend-neutral HMM model, swappable inference/training backends, reusable topology composition, and legacy JSON loading. Closing this earlier approach in favor of the completed replacement.

@AKuederle AKuederle changed the title Investigate/hmm backend surface Superseded by #85: Investigate HMM backend surface Jul 17, 2026
@AKuederle AKuederle closed this Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants