This provides the Theano Op SprintErrorSigOp to get a loss and error signal which is calculated via Sprint. And there are helper classes to communicate with the Sprint subprocess to transfer the posteriors and get back the loss and error signal. It uses the SprintControl Sprint interface for the communication.

class SprintErrorSignals.SeqTrainParallelControlDevHost(output_layer, output_target, sprint_opts, forward_seq_delay=5)[source]

Counterpart to Engine.SeqTrainParallelControl. This does all the handling on the Device proc side.

class CalcLossState(forward_data, sprint_instance)[source]
class SeqTrainParallelControlDevHost.ForwardData(seq_idx, seq_tag, posteriors)[source]
class SeqTrainParallelControlDevHost.LossData(calc_loss_state)[source]

Called via Engine.SeqTrainParallelControl. We expect that assign_dev_data was called before to set the right data. :param EngineUtil.Batch batch: the current batch, containing one or more seqs

SeqTrainParallelControlDevHost.have_seqs_loss_data(start_seq, end_seq)[source]

Called via Engine.SeqTrainParallelControl.


Called via Engine.SeqTrainParallelControl. :returns whether we added something to self.calc_loss_states.


Called via Engine.SeqTrainParallelControl.

Returns:True iff we can start training for the current batches.

Called via Engine.SeqTrainParallelControl.


Called via Engine.SeqTrainParallelControl.


Called via Engine.SeqTrainParallelControl.


Called via Engine.SeqTrainParallelControl.

class SprintErrorSignals.SprintAlignmentAutomataOp(sprint_opts)[source]

Op: maps segment names (tags) to fsa automata (using sprint) that can be used to compute a BW-alignment

perform(node, inputs, output_storage, params=None)[source]
class SprintErrorSignals.SprintErrorSigOp(sprint_opts)[source]

Op: log_posteriors, seq_lengths -> loss, error_signal (grad w.r.t. z, i.e. before softmax is applied)

make_node(log_posteriors, seq_lengths)[source]
perform(node, inputs, output_storage, params=None)[source]
class SprintErrorSignals.SprintInstancePool(sprint_opts)[source]

This is a pool of Sprint instances. First, for each unique sprint_opts, there is a singleton

which can be accessed via get_global_instance.
Then, this can be used in multiple ways.
  1. get_batch_loss_and_error_signal.
  2. ...
Parameters:tags (list[str]|numpy.ndarray) – sequence names, used for Sprint (ndarray of shape (batch, max_str_len))
Returns:(edges, weights, start_end_states). all together in one automaton. edges are of shape (4, num_edges), each (from, to, emission-idx, seq-idx), of dtype uint32. weights are of shape (num_edges,), of dtype float32. start_end_states are of shape (2, batch), each (start,stop) state idx, batch = len(tags), of dtype uint32.
Return type:(numpy.ndarray, numpy.ndarray, numpy.ndarray)
get_batch_loss_and_error_signal(log_posteriors, seq_lengths, tags=None)[source]
  • log_posteriors (numpy.ndarray) – 3d (time,batch,label)
  • seq_lengths (numpy.ndarray) – 1d (batch)
  • tags (list[str]) – seq names, length = batch

:rtype (numpy.ndarray, numpy.ndarray) :returns (loss, error_signal). error_signal has the same shape as posteriors. loss is a 1d-array (batch).

Note that this accesses some global references, like global current seg info, via the current Device instance. Thus this is expected to be run from the Device host proc,

inside from SprintErrorSigOp.perform.

This also expects that we don’t have chunked seqs.

classmethod get_global_instance(sprint_opts)[source]
global_instances = {}[source]
class SprintErrorSignals.SprintSubprocessInstance(sprintExecPath, minPythonControlVersion=2, sprintConfigStr='', sprintControlConfig=None, usePythonSegmentOrder=True)[source]

The Sprint instance which is used to calculate the error signal. Communication is over a pipe. We pass the fds via cmd-line to the child proc. Basic protocol with the subprocess (encoded via pickle):

P2C: tuple (cmd, *cmd_args). cmd is any str. C2P: tuple (status, *res_args). status == “ok” if no error.

“init”, name, version -> “ok”, child_name, version “exit” -> (exit) “get_loss_and_error_signal”, seg_name, seg_len, posteriors -> “ok”, loss, error_signal

Numpy arrays encoded via TaskSystem.Pickler (which is optimized for Numpy).

On the Sprint side, we handle this via the SprintControl Sprint interface.

  • sprintExecPath (str) – this executable will be called for the sub proc.
  • minPythonControlVersion (int) – will be checked in the subprocess. via Sprint PythonControl
  • sprintConfigStr (str) – passed to Sprint as command line args. can have “config:” prefix - in that case, looked up in config. handled via eval_shell_str(), can thus have lazy content (if it is callable, will be called).
  • sprintControlConfig (dict[str]|None) – passed to SprintControl.init().
Version = 1[source]

:rtype (str, float, numpy.ndarray) :returns (seg_name, loss, error_signal). error_signal has the same shape as posteriors.

get_loss_and_error_signal__send(seg_name, seg_len, log_posteriors)[source]
  • seg_name (str) – the segment name (seq_tag)
  • seg_len (int) – the segment length in frames
  • log_posteriors (numpy.ndarray) – 2d (time,label) float array, log probs
SprintErrorSignals.sprint_loss_and_error_signal(output_layer, target, sprint_opts, log_posteriors, seq_lengths)[source]
  • output_layer (NetworkOutputLayer.SequenceOutputLayer) – output layer
  • target (str) – e.g. “classes”
  • sprint_opts (dict[str]) – for SprintInstancePool
  • log_posteriors – 3d ndarray (time,batch,dim)
  • seq_lengths – 1d ndarray (batch,) -> seq len

loss, error_signal. loss is a 2d ndarray (batch,) -> loss. error_signal has the same shape as log_posteriors. error_signal is the grad w.r.t. z, i.e. before softmax is applied.