Package jazzparser :: Package taggers :: Package segmidi :: Package chordclass :: Module hmm :: Class ChordClassHmm
[hide private]
[frames] | no frames]

Class ChordClassHmm

source code

                       object --+    
                                |    
utils.nltk.ngram.model.NgramModel --+
                                    |
                                   ChordClassHmm

Hidden Markov Model based on the model described in the paper. The structure of this model was descibed in my 2nd year review.

States are in the form of a tuple (schema,root) where schema is the name of a lexical schema from the jazz grammar and root is a pitch class root.

Emissions are in the form of a list of pairs (pc,r), where pc is a pitch class (like root above) and r is an onset time abstraction. The metrical model (the r part) can be disabled.

An additional distribution is stored over the number of notes emitted. This needs to be included in the computation of the emission probability for a set of notes for it to form a valid probability distribution. For simplicity, we don't condition this on the chord class. We also need a maximum number of possible notes that can be emitted max_notes so that this is a finite distribution.

Unlike with NgramModel, the emission domain is the domain of values from which each element of an emission is selected. In other words, the actual domain of emissions is the infinite set of combinations of the values in emission_dom (in fact finite because of max_notes)

As for prior distributions (start state distribution), we ignore the root of the first state - it doesn't make any sense to look at it since the model is pitch-invariant throughout.


Note: mutable distributions: if you use mutable distributions for transition or emission distributions, make sure you invalidate the cache by calling clear_cache after updating the distributions. Various caches are used to speed up retreival of probabilities. If you fail to do this, you'll end up getting some values unpredictably from the old distributions

To Do: Make this inherit from jazzparser.utils.nltk.ngram.DictionaryHmmModel so that we can use a specialization of the jazzparser.utils.nltk.ngram.baumwelch.BaumWelchTrainer with it.

Instance Methods [hide private]
 
__init__(self, schema_transition_dist, root_transition_dist, emission_dist, emission_number_dist, initial_state_dist, schemata, chord_class_mapping, chord_classes, history='', description='', metric=False, illegal_transitions=[], fixed_root_transitions={})
x.__init__(...) initializes x; see help(type(x)) for signature
source code
 
clear_cache(self)
Initializes or empties probability distribution caches.
source code
 
add_history(self, string)
Adds a line to the end of this model's history string.
source code
 
sequence_to_ngram(self, seq)
Needed for the generic Ngram stuff.
source code
 
ngram_to_sequence(self, ngram)
Needed for the generic Ngram stuff.
source code
 
last_label_in_ngram(self, ngram)
Needed for the generic Ngram stuff.
source code
 
backoff_ngram(self, ngram)
Needed for the generic Ngram stuff.
source code
 
train_transition_distribution(self, inputs, grammar, contprob=0.3)
Train the transition distribution parameters in a supervised manner, using chord corpus input.
source code
 
train_emission_number_distribution(self, inputs)
Trains the distribution over the number of notes emitted from a chord class.
source code
 
transition_log_probability(self, state, previous_state)
Gives the probability P(label_i | label_(i-1), ..., label_(i-n)), where the previous labels are given in the sequence label_context.
source code
 
emission_log_probability(self, emission, state)
Gives the probability P(emission | label).
source code
 
chord_class_emission_log_probability(self, emission, chord_class, root)
The standard emission probability is P(emission | state).
source code
 
forward_log_probabilities(self, sequence, normalize=True, array=False)
We override this to provide a faster implementation.
source code
 
backward_log_probabilities(self, sequence, normalize=True, array=False)
We override this to provide a faster implementation.
source code
 
normal_forward_probabilities(self, sequence, array=False)
If you want the normalized matrix of forward probabilities, it's ok to use normal (non-log) probabilities and these can be computed more quickly, since you don't need to sum logs (which is time consuming).
source code
 
normal_backward_probabilities(self, sequence, array=False)
Return the backward probability matrices a Numpy array.
source code
 
compute_gamma(self, sequence, forward=None, backward=None)
Computes the gamma matrix used in Baum-Welch.
source code
 
compute_xi(self, sequence, forward=None, backward=None)
Computes the xi matrix used by Baum-Welch.
source code
 
to_picklable_dict(self)
Produces a picklable representation of model as a dict.
source code

Inherited from utils.nltk.ngram.model.NgramModel: __repr__, backward_probabilities, decode_forward, decode_gamma, emission_probability, forward_backward_log_probabilities, forward_backward_probabilities, forward_probabilities, gamma_probabilities, generalized_viterbi, generate, get_all_ngrams, get_backoff_models, get_emission_matrix, get_transition_matrix, labeled_sequence_log_probability, normal_forward_backward_probabilities, precompute, transition_log_probability_debug, transition_probability, transition_probability_debug, viterbi_decode, viterbi_selector_probabilities

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __sizeof__, __str__, __subclasshook__

Class Methods [hide private]
 
initialize_chord_classes(cls, tetrad_prob, max_notes, grammar, illegal_transitions=[], fixed_root_transitions={}, metric=False)
Creates a new model with the distributions initialized naively to favour simple chord-types, in a similar way to what R&S do in the paper.
source code
 
from_picklable_dict(cls, data)
Reproduces an n-gram model that was converted to a picklable form using to_picklable_dict.
source code
Static Methods [hide private]
 
train(*args, **kwargs)
We don't train these HMMs using the train method, since our training procedure is not the same as the superclass, so this would be confusing, as this method would require completely different input.
source code
Properties [hide private]

Inherited from utils.nltk.ngram.model.NgramModel: model_type

Inherited from object: __class__

Method Details [hide private]

__init__(self, schema_transition_dist, root_transition_dist, emission_dist, emission_number_dist, initial_state_dist, schemata, chord_class_mapping, chord_classes, history='', description='', metric=False, illegal_transitions=[], fixed_root_transitions={})
(Constructor)

source code 

x.__init__(...) initializes x; see help(type(x)) for signature

Overrides: object.__init__
(inherited documentation)

clear_cache(self)

source code 

Initializes or empties probability distribution caches.

Make sure to call this if you change or update the distributions.

Overrides: utils.nltk.ngram.model.NgramModel.clear_cache

train(*args, **kwargs)
Static Method

source code 

We don't train these HMMs using the train method, since our training procedure is not the same as the superclass, so this would be confusing, as this method would require completely different input.

We train our models by initializing in some way (usually hand-setting of parameters), then using Baum-Welch on unlabelled data.

This method will just raise an error.

Overrides: utils.nltk.ngram.model.NgramModel.train

initialize_chord_classes(cls, tetrad_prob, max_notes, grammar, illegal_transitions=[], fixed_root_transitions={}, metric=False)
Class Method

source code 

Creates a new model with the distributions initialized naively to favour simple chord-types, in a similar way to what R&S do in the paper.

The transition distribution is initialized so that everything is equiprobable.

Parameters:
  • tetrad_prob (float) - prob of a note in the tetrad. This prob is distributed over the notes of the tetrad. The remaining prob mass is distributed over the remaining notes. You'll want this to be >0.33, so that tetrad notes are more probable than others.
  • max_notes (int) - maximum number of notes that can be generated in each emission. Usually best to set to something high, like 100 - it's just to make the distribution finite.
  • grammar (jazzparser.grammar.Grammar) - grammar from which to take the chord class definitions
  • metric (bool) - if True, creates a model with a metrical component (dependence on metrical position). Default False

train_transition_distribution(self, inputs, grammar, contprob=0.3)

source code 

Train the transition distribution parameters in a supervised manner, using chord corpus input.

This is used as an initialization step to set transition parameters before running EM on unannotated data.

Parameters:
  • inputs (jazzparser.data.input.AnnotatedDbBulkInput) - annotated chord training data
  • contprob (float or string) - probability mass to reserve for staying on the same state (self transitions). Use special value 'learn' to learn the probabilities from the durations

train_emission_number_distribution(self, inputs)

source code 

Trains the distribution over the number of notes emitted from a chord class. It's not conditioned on the chord class, so the only training data needed is a segmented MIDI corpus.

Parameters:

transition_log_probability(self, state, previous_state)

source code 

Gives the probability P(label_i | label_(i-1), ..., label_(i-n)), where the previous labels are given in the sequence label_context. The context should be in reverse order, i.e. with the most recent label at the start.

Note that this is the probability of a label given the previous n-1 labels, which is the same as the probability of the n-gram [label_i, ..., label_(i-n+1)] given the ngram [label_(i-1), ..., label_(i-n)], since all but the last element of the ngram overlaps with the condition, so has probability 1.

Caches all computed transition probabilities. This is particularly important for backoff models. Many n-grams will back off to the same (n-1)-gram and we don't want to recompute the transition probability for that each time.

Overrides: utils.nltk.ngram.model.NgramModel.transition_log_probability
(inherited documentation)

emission_log_probability(self, emission, state)

source code 

Gives the probability P(emission | label). Returned as a base 2 log.

The emission should be a list of emitted notes.

Each note should be given as a tuple (pc,beat), where pc is the pitch class of the note and beat is the beat specifier for the metrical model. If the model is non-metric, you may set to beat always to 0, as it will be ignored and assumed to be 0.

Overrides: utils.nltk.ngram.model.NgramModel.emission_log_probability

chord_class_emission_log_probability(self, emission, chord_class, root)

source code 

The standard emission probability is P(emission | state). This instead returns P(emission | chord class). The emission is given in the same way as to emission_log_probability.

The root number is also required. For emission_log_probability, this is included in the state label.

forward_log_probabilities(self, sequence, normalize=True, array=False)

source code 

We override this to provide a faster implementation.

It might also be possible to speed up the superclass' implementation using numpy, but it's easier here because we know we're using an HMM, not a higher-order ngram.

This is based on the fwd prob calculation in NLTK's HMM implementation.

Parameters:
  • array (bool) - if True, returns a numpy 2d array instead of a list of dicts.
Overrides: utils.nltk.ngram.model.NgramModel.forward_log_probabilities

backward_log_probabilities(self, sequence, normalize=True, array=False)

source code 

We override this to provide a faster implementation.

Parameters:
  • array (bool) - if True, returns a numpy 2d array instead of a list of dicts.
Overrides: utils.nltk.ngram.model.NgramModel.backward_log_probabilities

See Also: forward_log_probability

normal_forward_probabilities(self, sequence, array=False)

source code 

If you want the normalized matrix of forward probabilities, it's ok to use normal (non-log) probabilities and these can be computed more quickly, since you don't need to sum logs (which is time consuming).

Returns the matrix, and also the vector of values that each timestep was divided by to normalize (i.e. total probability of each timestep over all states). Also returns the total log probability of the sequence.

Parameters:
  • array (bool) - if True, returns a numpy 2d array instead of a list of dicts.
Returns:
(matrix,normalizing vector,log prob)
Overrides: utils.nltk.ngram.model.NgramModel.normal_forward_probabilities

normal_backward_probabilities(self, sequence, array=False)

source code 

Return the backward probability matrices a Numpy array. This is faster than backward_log_probabilities because it uses Numpy arrays with non-log probabilities and normalizes each timestep.

Parameters:
  • array (bool) - if True, returns a numpy 2d array instead of a list of dicts.
Returns:
matrix over timesteps and all labels, with a dimension for each state in each (n-1)-gram: for time steps i and labels k, P(word^(i+1), ..., word^T | label_k^i)
Overrides: utils.nltk.ngram.model.NgramModel.normal_backward_probabilities

See Also: normal_forward_probabilities

(except that this doesn't return the logprob)

compute_gamma(self, sequence, forward=None, backward=None)

source code 

Computes the gamma matrix used in Baum-Welch. This is the matrix of state occupation probabilities for each timestep. It is computed from the forward and backward matrices.

These can be passed in as arguments to avoid recomputing if you need to reuse them, but will be computed from the model if not given. They are assumed to be the matrices computed by normal_forward_probabilities and normal_backward_probabilities (i.e. normalized, non-log probabilities).

compute_xi(self, sequence, forward=None, backward=None)

source code 

Computes the xi matrix used by Baum-Welch. It is the matrix of joint probabilities of occupation of pairs of conecutive states: P(i_t, j_{t+1} | O).

As with compute_gamma forward and backward matrices can optionally be passed in to avoid recomputing.

to_picklable_dict(self)

source code 

Produces a picklable representation of model as a dict. You can't just pickle the object directly because some of the NLTK classes can't be pickled. You can pickle this dict and reconstruct the model using NgramModel.from_picklable_dict(dict).

Overrides: utils.nltk.ngram.model.NgramModel.to_picklable_dict

from_picklable_dict(cls, data)
Class Method

source code 

Reproduces an n-gram model that was converted to a picklable form using to_picklable_dict.

Overrides: utils.nltk.ngram.model.NgramModel.from_picklable_dict