From 2447428ec7efff7ea0dec65f0282d76886e74248 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Thu, 21 Nov 2024 15:18:02 +0000 Subject: [PATCH 1/4] Fixed issue with converting inferred states --- .../Observations/GaussianObservationsStatistics.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs b/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs index ffeb6c00..86b84959 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs +++ b/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs @@ -49,7 +49,7 @@ public class GaussianObservationsStatistics /// [Description("The sequence of inferred most probable states.")] [XmlIgnore] - public int[] InferredMostProbableStates { get; set; } + public long[] InferredMostProbableStates { get; set; } /// /// Transforms an observable sequence of into an observable sequence @@ -64,7 +64,7 @@ public IObservable Process(IObservable var covarianceMatricesPyObj = (double[,,])observationsPyObj.GetArrayAttr("Sigmas"); var stdDevsPyObj = DiagonalSqrt(covarianceMatricesPyObj); var batchObservationsPyObj = (double[,])pyObject.GetArrayAttr("batch_observations"); - var inferredMostProbableStatesPyObj = (int[])pyObject.GetArrayAttr("inferred_most_probable_states"); + var inferredMostProbableStatesPyObj = (long[])pyObject.GetArrayAttr("inferred_most_probable_states"); return new GaussianObservationsStatistics { From cbf464049f3bb0bc7bf08f065bdbe00d1218ea7d Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Thu, 21 Nov 2024 15:43:59 +0000 Subject: [PATCH 2/4] Update name to predicted states --- .../Observations/GaussianObservationsStatistics.cs | 10 +++++----- src/Bonsai.ML.HiddenMarkovModels/main.py | 7 +++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs b/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs index 86b84959..a1deec68 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs +++ b/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs @@ -45,11 +45,11 @@ public class GaussianObservationsStatistics public double[,] BatchObservations { get; set; } /// - /// The sequence of inferred most probable states. + /// The predicted state for each observation in the batch of observations. /// - [Description("The sequence of inferred most probable states.")] + [Description("The predicted state for each observation in the batch of observations.")] [XmlIgnore] - public long[] InferredMostProbableStates { get; set; } + public long[] PredictedStates { get; set; } /// /// Transforms an observable sequence of into an observable sequence @@ -64,7 +64,7 @@ public IObservable Process(IObservable var covarianceMatricesPyObj = (double[,,])observationsPyObj.GetArrayAttr("Sigmas"); var stdDevsPyObj = DiagonalSqrt(covarianceMatricesPyObj); var batchObservationsPyObj = (double[,])pyObject.GetArrayAttr("batch_observations"); - var inferredMostProbableStatesPyObj = (long[])pyObject.GetArrayAttr("inferred_most_probable_states"); + var predictedStatesPyObj = (long[])pyObject.GetArrayAttr("predicted_states"); return new GaussianObservationsStatistics { @@ -72,7 +72,7 @@ public IObservable Process(IObservable StdDevs = stdDevsPyObj, CovarianceMatrices = covarianceMatricesPyObj, BatchObservations = batchObservationsPyObj, - InferredMostProbableStates = inferredMostProbableStatesPyObj + PredictedStates = PredictedStates }; }); } diff --git a/src/Bonsai.ML.HiddenMarkovModels/main.py b/src/Bonsai.ML.HiddenMarkovModels/main.py index aad1386e..3f83b932 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/main.py +++ b/src/Bonsai.ML.HiddenMarkovModels/main.py @@ -85,7 +85,7 @@ def get_nonlinearity_type(func): self.thread = None self.curr_batch_size = 0 self.flush_data_between_batches = True - self.inferred_most_probable_states = np.array([], dtype=int) + self.predicted_states = np.array([], dtype=int) def update_params(self, initial_state_distribution, transitions_params, observations_params): hmm_params = self.params @@ -122,6 +122,9 @@ def update_params(self, initial_state_distribution, transitions_params, observat else: self.observations_params = (hmm_params[2],) + def get_predicted_states(self): + self.predicted_states = np.array([self.infer_state(obs) for obs in self.batch_observations]).astype(int) + def infer_state(self, observation: list[float]): self.log_alpha = self.compute_log_alpha( @@ -221,7 +224,7 @@ def on_completion(future): if self.flush_data_between_batches: self.batch = None - self.inferred_most_probable_states = np.array([self.infer_state(obs) for obs in self.batch_observations]).astype(int) + self.get_predicted_states() self.is_running = True From 6c981fbb7c5e4b4c9a71b955677ceeff7cdcbebb Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Sat, 23 Nov 2024 12:49:24 +0000 Subject: [PATCH 3/4] Updated main script for maintaining batch data through observations --- .../InferState.bonsai | 2 +- src/Bonsai.ML.HiddenMarkovModels/main.py | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Bonsai.ML.HiddenMarkovModels/InferState.bonsai b/src/Bonsai.ML.HiddenMarkovModels/InferState.bonsai index 67cad75f..3cad8001 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/InferState.bonsai +++ b/src/Bonsai.ML.HiddenMarkovModels/InferState.bonsai @@ -52,7 +52,7 @@ - hmm.most_likely_states([59.7382107943162,3.99285183724331]) + hmm.infer_state([59.7382107943162,3.99285183724331]) diff --git a/src/Bonsai.ML.HiddenMarkovModels/main.py b/src/Bonsai.ML.HiddenMarkovModels/main.py index 3f83b932..f9d7d6b8 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/main.py +++ b/src/Bonsai.ML.HiddenMarkovModels/main.py @@ -122,15 +122,15 @@ def update_params(self, initial_state_distribution, transitions_params, observat else: self.observations_params = (hmm_params[2],) - def get_predicted_states(self): - self.predicted_states = np.array([self.infer_state(obs) for obs in self.batch_observations]).astype(int) - def infer_state(self, observation: list[float]): - self.log_alpha = self.compute_log_alpha( - np.expand_dims(np.array(observation), 0), self.log_alpha) + observation = np.expand_dims(np.array(observation), 0) + self.log_alpha = self.compute_log_alpha(observation, self.log_alpha) self.state_probabilities = np.exp(self.log_alpha).astype(np.double) - return self.state_probabilities.argmax() + prediction = self.state_probabilities.argmax() + self.predicted_states = np.append(self.predicted_states, prediction) + self.batch_observations = np.vstack([self.batch_observations, observation]) + return prediction def compute_log_alpha(self, obs, log_alpha=None): @@ -174,8 +174,6 @@ def fit_async(self, self.batch = np.vstack( [self.batch[1:], np.expand_dims(np.array(observation), 0)]) - self.batch_observations = self.batch - if not self.is_running and self.loop is None and self.thread is None: if self.curr_batch_size >= batch_size: @@ -224,8 +222,6 @@ def on_completion(future): if self.flush_data_between_batches: self.batch = None - self.get_predicted_states() - self.is_running = True if self.loop is None or self.loop.is_closed(): From b58cbd2326ad5390a14342a096a2d1c6a69da71d Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Tue, 7 Jan 2025 17:47:51 +0000 Subject: [PATCH 4/4] Corrected use of predicted states attribute --- .../GaussianObservationsStatisticsClustersVisualizer.cs | 7 ++++--- .../Observations/GaussianObservationsStatistics.cs | 2 +- src/Bonsai.ML.HiddenMarkovModels/main.py | 7 ++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs b/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs index d5400317..bdd54973 100644 --- a/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs +++ b/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs @@ -149,7 +149,6 @@ public override void Show(object value) { if (value is Observations.GaussianObservationsStatistics gaussianObservationsStatistics) { - var statesCount = gaussianObservationsStatistics.Means.GetLength(0); var observationDimensions = gaussianObservationsStatistics.Means.GetLength(1); @@ -227,12 +226,14 @@ public override void Show(object value) var batchObservationsCount = gaussianObservationsStatistics.BatchObservations.GetLength(0); var offset = BufferData && batchObservationsCount > BufferCount ? batchObservationsCount - BufferCount : 0; + var predictedStatesCount = gaussianObservationsStatistics.PredictedStates.Length; + for (int i = offset; i < batchObservationsCount; i++) { var dim1 = gaussianObservationsStatistics.BatchObservations[i, dimension1SelectedIndex]; var dim2 = gaussianObservationsStatistics.BatchObservations[i, dimension2SelectedIndex]; - var state = gaussianObservationsStatistics.InferredMostProbableStates[i]; - allScatterSeries[(int)state].Points.Add(new ScatterPoint(dim1, dim2, value: state, tag: state)); + var state = gaussianObservationsStatistics.PredictedStates[i]; + allScatterSeries[Convert.ToInt32(state)].Points.Add(new ScatterPoint(dim1, dim2, value: state, tag: state)); } for (int i = 0; i < statesCount; i++) diff --git a/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs b/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs index a1deec68..991b7cca 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs +++ b/src/Bonsai.ML.HiddenMarkovModels/Observations/GaussianObservationsStatistics.cs @@ -72,7 +72,7 @@ public IObservable Process(IObservable StdDevs = stdDevsPyObj, CovarianceMatrices = covarianceMatricesPyObj, BatchObservations = batchObservationsPyObj, - PredictedStates = PredictedStates + PredictedStates = predictedStatesPyObj }; }); } diff --git a/src/Bonsai.ML.HiddenMarkovModels/main.py b/src/Bonsai.ML.HiddenMarkovModels/main.py index f9d7d6b8..acafea6a 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/main.py +++ b/src/Bonsai.ML.HiddenMarkovModels/main.py @@ -78,7 +78,7 @@ def get_nonlinearity_type(func): self.state_probabilities = None self.batch = None - self.batch_observations = np.array([[]], dtype=float) + self.batch_observations = np.array([[]], dtype=float).reshape((0, dimensions)) self.is_running = False self._fit_finished = False self.loop = None @@ -86,6 +86,7 @@ def get_nonlinearity_type(func): self.curr_batch_size = 0 self.flush_data_between_batches = True self.predicted_states = np.array([], dtype=int) + self.buffer_count = 250 def update_params(self, initial_state_distribution, transitions_params, observations_params): hmm_params = self.params @@ -129,7 +130,11 @@ def infer_state(self, observation: list[float]): self.state_probabilities = np.exp(self.log_alpha).astype(np.double) prediction = self.state_probabilities.argmax() self.predicted_states = np.append(self.predicted_states, prediction) + if self.predicted_states.shape[0] > self.buffer_count: + self.predicted_states = self.predicted_states[1:] self.batch_observations = np.vstack([self.batch_observations, observation]) + if self.batch_observations.shape[0] == self.buffer_count: + self.batch_observations = self.batch_observations[1:] return prediction def compute_log_alpha(self, obs, log_alpha=None):