No project description provided
Project description
A Hidden Markov Model package for python
Installation
To install this package simply run the command:
pip install hidden-py
Table of Contents
Overview
This package contains logic for inferring, simulating, and fitting Hidden Markov Models with discrete states and obserfvations. In contrast to more common HMM packages that deal primarily with mixture models, output symbols are continuous, and drawn from a distriubtion of values that is somehow conditional on the hidden state.
Here, we have thusfar considered primarily scenarios where the observation value is an integer, and one of the possible hidden states. There are three major use-cases for this codebase: dynamics/simulation, system identification/parameter fitting, and signal processing. In all cases, these functionalities are outlined in several tutorial notebooks in the notebooks/tutorials
location of the github repository
Hidden Markov Models
Markov Models are a class of stochastic models for characterizing the behaviour of systems that transition between states randomly, with a probability that depends only on the curent state of the system (i.e. they are memoryless). Because if this simplification, the dynamics on a set of discrete states can be captured entirely by a single matrix, known as the transition matrix, $A$, with elements $A_{ij} = p(x_t=i | x_{t-1} = j)$ quantifying the probability that during timestep $t-1 \to t$, the system will transition from state $j\to i$.
Because of the normalization of probability, the columns of $A$ are constrained to be qual to unity.
A hidden Markov model (HMM), on the other hand, is a probabilistic function of a Markov model. This means that the output of an HMM is an observation $y$, that is correlated with the underlying (hidden/unobserved) state of the Markov model, but only probabilitsically so. For a set of discrete possible observations (as we capture in this package), the observation process can also be modelled by a matrix (the observation matrix) $B$ with elemetnts $B_{ij} = p(y_t = i | x_{t} = j)$ quantifying the probability that our measurement/observation $y_t$ at time $t$ is equal to $i$ given the hidden system is in state $j$. Here, the diagonal elements represent our probability of observing the correct state, while off-diagonals represent the probability of error.
The goal of simulation is simply to generate trajectories of both the hidden state and observation time-series that is conistent with these probabilities.
The goal for system identification/parameter fitting is to fit the most likely parameters (elements of the $A$ and $B$) matrices, given only a time series of observations.
Finally, the goal if signal processing is to make use of the observation sequence to infer what the hidden state is at a particular point in time.
Dynamics/Simulation
The hidden.dynamics
submodule contains the code necessary to simulate the hidden state and observation dynamics as specified by a state transition matrix $A$ (with elements that quantify the rate of transitions between states) and an observation matrix $B$, with elements that quantify the probability of observing a given output symbol, given the current hidden state.
For instance, the code necessary to initialize a hidden Markov model, run the dyanamics, and extract the observation and state time-series
from hidden_py import dynamics
# 2 hidden states, 2 possible observation values
hmm = dynamics.HMM(2, 2)
# Helper routine to initialize A and B matrices
hmm.init_uniform_cycle()
# Run dynamics for 100 time steps
hmm.run_dynamics(100)
# Pull out the observations, and true (simulated) hidden state values
observations = hmm.get_obs_ts()
hidden_states = hmm.get_state_ts()
System Identification
The infer
submodule contains the code that wraps lower-level functionality (primarily in the filters/bayesian.py
and optimize/optimization.py
files) for both signal processing and system identification/parameter fitting.
There are two separate means of performing system identification: Local/Global partial likelihood optimization, and complete-data likelihood optimization. While more comprehensive details are contained in the github notebooks, broadly speaking partial data likelihood optimization performs relatively standard optimizations on the likelihood function $\mathcal{L}(\theta | Y)$ which considers only the observations as the data. Effectively, these optimizers wrap the scipy.opt.minimize
functions by encoding and decoding the $A$ and $B$ matrices into a parameter vector (ensuring that their column-normalization is preserved) and calculating the negative log-likelihood of a particular parameter vector. In practice, given a set of observations, we can initialize an analyzer
and run either local (using, by default, the scipy.opt.minimize
function with the L-BFGS-B
algorithm) or global (using the scipy
SHGO algorithm) as:
from hidden_py import infer
# Input the dimensions of the HMM and observations
analyzer = infer.MarkovInfer(2, 2)
# Initial estimates of the A and B matrices
A_est = np.array([
[0.8, 0.1],
[0.2, 0.9]
])
B_est = np.array([
[0.9, 0.05],
[0.1, 0.95]
])
# Run local partial-data likelihood optimization (default behaviour), the symmetric keyword can be used to specify whether or not the A and B matrices are assumed to be symmetric
opt_local = analyzer.optimize(observations, A_est, B_est, symmetric=False)
# And the partial-data global likelihood optimization, the A and B initial matrices are not used in the optimizer, aside from providing a way of specifying the dimension of the parameter vectors
opt_global = analyzer.optimize(observations, A_est, B_est, symmetric=False, opt_type=OptClass.Global)
Now, for the complete-data likeihood optimization, the interface is very similar, but behind the scenes the code will implement an implementation of the Baum-Welch reparameterization algorithm (an instance of an Expectation-Maximization algorithm) to find the optimal parameter values. In practice, this can be done as:
from hidden_py import infer
from hidden_py.optimize.base import OptClass
analyzer = infer.MarkovInfer(2, 2)
res_bw = analyzer.optimize(observations, A_est, B_est, opt_type=OptClass.ExpMax)
In all cases, there is also an option to add algorithm options to customize the specifics of the optinization. Most relevant is for the expectation-maximization where you can specify a maximum number of iterations for the algorithm, as well as a threshold on the size of parameter changes (quantified by the matrix norm of pre- and post-update $A$ and $B$ matrices). This can be accessed through the algo_opts
dictionary. For instance, if we wanted to change the maximum iterations in the BW algorithm to 1000 and set the termination threshold at 1e-10
, we would perform the previous call as
options = {
'maxiter': 1000,
"threshold": 1e-10
}
res_bw = analyzer.optimize(observations, A_est, B_est, opt_type=OptClass.ExpMax, algo_opts=options)
In essence, this set of tools allows you to infer the best model given a set of observed data. Under the hood, many of the tools from the signal processing module are used, but the analyzer.optimize(...)
function calls largely hide that complexity.
Signal Processing
The infer
submodule can also be used for the purposes of signal processing: given a valid estimate of the model parameters, how can we best estimate the hidden state value, given the observations. There are two distinct domains of application, first would be prediction in real time, where only observations in the past are available for inferring the current hidden state (this would use the so-called forward-filtered estiamte). There is also an ex post approach, which uses the entirety of observations from a given period of time to estimate the hidden state at a particular point within that time period. This is the so-called Bayesian smoothec estiamte of the hidden state.
Quantitatively the forward filter and Bayesian smoothed estimates of a given HMM sequence of observations can be calculated in the following way:
from hidden_py import infer
analyzer = infer.MarkovInfer(2, 2)
# Gets the forward algorithm results
analyzer.forward_algo(observations, A, B)
# Gets the Bayesian-smoothed estimate of the hidden state
analyzer.bayesian_smooth(observations, A, B)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for hidden_py-1.0.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 264f4ea9331d17583f5197552e6e25b6df4be3f3598739b369da3b8aff45f904 |
|
MD5 | dfc21c9ae82b559feef549b026c6ff9b |
|
BLAKE2b-256 | 972795270bbcd7ecc504320f415e480175405e52019154c0ebec9e5897f6227f |