Onyx logo

Previous topic

onyx.dataflow.command – A dataflow processing element for executing command line subprocesses

Next topic

Graph

This Page

onyx.dataflow.framesynchronous – Pedagogical outline of frame synchronous decoding

class onyx.dataflow.framesynchronous.Epsilon(num_virtual_states, user_data=None)

Bases: object

A network epsilon. Just passes its activations to its outputs. Never has any likelihoods scores, just propagation outputs.

activate(scores, act_ids_notused)
apply_likelihoods(observation, normalization)
has_output

True if the output is active, that is if it has any probability mass.

num_virtual_states
output

The output scores; suitable for activation of successors.

output_tokens

The output scores; suitable for activation of successors. The tokens part of the output will always be None.

pass_tokens()
class onyx.dataflow.framesynchronous.FrameSynchronousProcessor(model, thresholds, sendee=None, sending=True, bypass_types=())

Bases: onyx.dataflow.streamprocess.ProcessorBase

Pedagogical example of a frame-synchronous decoder, written as a dataflow Processor.

Events coming into this processor must be of type np.ndarray.

dc

A debug context for this processor. This attribute is an object returned by dcheck() in the onyx.util.debugprint module, and may be used for debug output. The tag for turning on such output is available as debug_tag

debug_tag

Activate this tag to get debugging information, see onyx.util.debugprint.DebugPrint

graph

Return a graph for this processor. By default this is just a single node whose label is the label of processor; derived classes may wish to override this property.

label

Return a label for this processor. By default this is just the name of the class; derived classes may wish to override this property by providing a different label to __init__().

process(event)
send(result)

Internal function that pushes result into the sendee. Implementations of process() must call this to push results. To set up the sendee, (the target of the push), clients of the processor must either initialize the object with a sendee, or call set_sendee(). Processors created with a sendee of False will never send, but will not error if send is called.

sendee

The callable this processor will use to send events; see set_sendee()

sending

Whether this processor will currently send events at all; see set_sending()

set_sendee(sendee)

Clients call this to set up the callable where the processor will send its results.

set_sending(sending)

Clients call this to turn sending from a processor on or off.

static std_process_prologue(process_function)

Subclasses may use this decorater on their process function to implement the usual bypass and process semantics and to set up the debug context returned by dc().

class onyx.dataflow.framesynchronous.Sink

Bases: object

A network sink for probability mass. Accumulates (and correctly normalizes) all the mass with which it gets activated. Handles any dimensionality of activation. Never has any output. Always has scores of length one.

activate(activation, act_ids_notused)
apply_likelihoods(observation, normalization)
has_output
internal_scores
pass_tokens()
scores
class onyx.dataflow.framesynchronous.decode_context(model, parameter)

Bases: object

A synthetic implementation of a context that activates a sequence of Hmms, dynamically creating new Hmm(s) each time the current end of a sequence first activates its output. After a certain number of Hmms have been created it merges everything into a sink that just accumulates mass. Never prunes.

Used in _synthetic_example() to show that probability mass is preserved. Does splitting and merging to explore a network with a lozenge shape with a tail. Also does normalization so as to keep the best score near 1. And it uses some epsilon sequences; one at the start of the lattice.

XXX there’s not a clean split between the decode_context and the synthetic_model... most functionality belongs in decode_context

apply_likelihoods(elements)
finish_observation()
get_initial_elements()
get_result()
mass
propagate_hypotheses(elements)
prune_inactive(elements)
set_observation(elements, observation)
sink
successor_ids(id)
update_result(elements)
onyx.dataflow.framesynchronous.forward_sequence_builder(scorer, state_iter, probs, user_data=None)

This function serves as a plug-in replacement for the ForwardSequence c’tor under the assumption that the scoring function will always return 1.0. It uses Hmms (from onyx.am.hmm) as the underlying model.

onyx.dataflow.framesynchronous.frame_synchronous_decode(model, parameter, observation_stream, callback=None)

A somewhat abstract pedagogical overview of frame-synchronous processing steps.

The Arguments

The model contains everything that’s static from the point-of-view of doing decoding. This includes the acoustic and language models, the lexicon, the grammar, etc.

The parameter includes all the parametric settings for this particular decode. These would include things like algorithm selection, pruning thresholds, resource limits, etc. You might have several different parameter values to select from based on e.g. application state, speed requirements, etc. You’d hand one of them into this function. The parameter needs to be compatible with the model.

The observation_stream is an iterable of the (single) stream of observations to be decoded.

The callback is an optional callable that will be called with the observation, the map of active elements, and the intermediate results at the end of the processing of each observation.

Internal to the Function

There is a decoding context that the model produces using the parameter:

context = model.make_decode_context(parameter)

This context has the dynamic state for the decode. It has methods for the few top-level operations that are performed during a decode. Unrealistically, the pedagogical version of contexts used here gives the client full control over the list of active elements.

There is a map of active_elements keyed off of some unique identifier. These active_elements are abstract. Each one is active in that it holds one or more active hypotheses and their histories. Each one is an element in that it represents some part of the decomposition of an entire decode into smaller pieces. An active_element could be as small as a single Hmm state, or as large as the network for decoding an entire utterance, or larger....

The use of an identifier to key the map of active elements supports possibility of having joins during the decode, i.e. so that histories with provably shared futures can be merged and only one such future actually activated for decoding. This is such an important optimization that it’s visible in this abstract overview. Again, unrealistically, the context manages the ids without explicitly owning the active list....

Each of the active elements has some basic features:

  • it has one or more inputs, each of which accepts a history
  • it has one or more outputs, each of which can generate a history
  • it knows how to update its hypotheses and histories given an observation

The function loops over the sequence of observations. In the loop it does a few things:

  • setup the context for the observation
  • find each active element that has active outputs, activate its successors
  • apply observation likelihoods to the scores
  • prune inactive elements
  • update the result based on active elements with active outputs
  • clean up the observation-specific context
  • yield the intermediate results

See _synthetic_example_1() for a synthetic example that uses this function rather trvially. See _synthetic_example_2() for a synthetic example that uses this function more realistically (as far as building a complex network is concerned, and normalization).

onyx.dataflow.framesynchronous.get_acoustic_observations(audio_filename)
onyx.dataflow.framesynchronous.htk_mmf_from_filename(model_filename)

Read models from an HTK MMF-file at model_filename.

Returns the tuple: (model_dict, hmm_mgr, gmm_mgr, model_filename)

onyx.dataflow.framesynchronous.lozenge_ids(growth, steady, id, verbose=False)

Generate successor id sets to support a lozenge shape network.

>>> for id in xrange(12):
...   ids = lozenge_ids(2, 2, id, True)
...   print id, ids
growth width steady: 2 2 2
grow_upper width_upper shrink_upper: 2 6 9
0 (1,)
1 (2, 3)
2 (4,)
3 (5,)
4 (6,)
5 (7,)
6 (8,)
7 (8,)
8 (9,)
9 (10,)
10 (11,)
11 (12,)
>>> for id in xrange(17):
...   ids = lozenge_ids(3, 1, id, True)
...   print id, ids
growth width steady: 3 4 1
grow_upper width_upper shrink_upper: 4 8 15
0 (1,)
1 (2, 3)
2 (4, 5)
3 (6, 7)
4 (8,)
5 (9,)
6 (10,)
7 (11,)
8 (12,)
9 (12,)
10 (13,)
11 (13,)
12 (14,)
13 (14,)
14 (15,)
15 (16,)
16 (17,)
class onyx.dataflow.framesynchronous.real_decode_context(model, (grammar_spec, thresholds))

Bases: object

A real decoder!

A ‘dictation grammar’ with the option of epsilons for merging

In addition to model having a make_decode_context() method, it needs to have a new_epsilon_element() that will return an epsilon hmm element.

apply_likelihoods(elements)
finish_observation()
get_initial_elements()
get_result()
propagate_hypotheses(elements)
prune_inactive(elements)
set_observation(elements, observation)
sink
successor_ids(id)
update_result(elements)
class onyx.dataflow.framesynchronous.real_model(model_dict, hmm_mgr, gmm_mgr, model_filename='<unknown>')

Bases: object

A model object that uses HmmMgr and GmmMgr

The model_dict is a map from HMM acoustic class name to HMM-id in the hmm_mgr. The hmm_mgr is a HmmMgr instance of the HMM templates to use for decoding. gmm_mgr is a GmmMgr instance holding the Gaussian models. Optional model_filename is the name of the file from which the models were loaded.

epsilon_hmm_id
make_decode_context(parameter)
new_epsilon_element(user_data=None)
onyx.dataflow.framesynchronous.result_to_string(result)

Silly little helper for collapsing runs of the first item in result elements

>>> result_to_string([(1, 2), (2, 2), (3, 3), (3, 4)])
'1 2 3'
class onyx.dataflow.framesynchronous.synthetic_model(hmm_factory, out_transitions)

Bases: object

hmm_factory
make_decode_context(parameter)
new_element(num_states, user_data=None)
new_epsilon_element(user_data=None)
out_transitions
scorer(model_id, observation)
onyx.dataflow.framesynchronous.synthetic_probs(count)

Create a synthetic distribution of out-arc weights for count out arcs.

Element 0 is self loop, element 1 is is forward-one, etc. Make forward-one arc get the most weight according to the following, where n is count:

  • 1/4 to self loop
  • eps = 1/(2^n)
  • (1/2 + eps) to forward one
  • 1/8 to forward two
  • 1/16 to forward three
  • etc
  • 1/(2^n) to forward n-1
>>> synthetic_probs(5)
(0.25, 0.53125, 0.125, 0.0625, 0.03125)
>>> synthetic_probs(1)
(1.0,)
onyx.dataflow.framesynchronous.uniform_probs(count)

Create a uniform distribution of count elements.