VariableMergingOptimizer Class Reference

This class is responsible for merging matrices, although you probably want to access it via the the function VariableMergingOptimization(). More...

#include <nnet-optimize-utils.h>

Collaboration diagram for VariableMergingOptimizer:

Public Member Functions

 VariableMergingOptimizer (const NnetOptimizeOptions &config, const Nnet &nnet, NnetComputation *computation)
 
bool MergeVariables ()
 

Private Member Functions

std::pair< bool, boolMayBeMerged (int32 command, int32 s1, int32 s2) const
 This function returns a pair of bools saying whether we can do a (left and/or right) merge respectively, based on the conditions defined in the header. More...
 
void DoMerge (int32 command_index, int32 s_to_keep, int32 m_to_discard)
 
void MarkAsDirty (int32 s)
 Marks the variables underlying submatrix 's' as dirty. More...
 
void Initialize ()
 

Private Attributes

const NnetOptimizeOptionsconfig_
 
const Nnetnnet_
 
NnetComputationcomputation_
 
Analyzer analyzer_
 
std::vector< std::vector< int32 > > matrix_to_submatrix_
 
std::vector< boolvariable_dirty_
 
bool already_called_merge_variables_
 

Detailed Description

This class is responsible for merging matrices, although you probably want to access it via the the function VariableMergingOptimization().

We identify pairs of submatrices which can potentially be merged into a single submatrix.

Suppose there are two different submatrices s1 != s2 that are submatrices of different respective matrices m1 != m2, and somewhere in the computation we have a command C, which is one of: (a) the assignment command "s2 = s1", or (b) a propagate command with s1 as input and s2 as output, with a component that supports propagate in place, or (c) a backprop command with s1 as output-deriv and s2 as input-deriv, with a component that supports backprop in place.

Then the triple (C, s1, s2) is a candidate for merging. We support two types of merging: 'right merging', in which we delete s1 and use s2 instead; and 'left merging' in which we delete s2 and use s1 instead. The two types of merging may seem to be essentially equivalent, but they they are not because in general s1 and s2 may be sub-matrices of larger matrices.

Note the following definitions:

  • Define last-access(submatrix) as the last command that accesses that submatrix for either read or write. [note: deallocation does not count as a read or write operation].
  • Define first-nontrivial-access(submatrix) as the first command other than zeroing (kSetConst with 0.0) that accessed that submatrix for either read or write.
  • Define last-write-access(submatrix) as the last command-index that accessed the submatrix in a write operation, or -1 if there is no such command (this could happen for inputs).
  • Define data-invalidated-command(c, submatrix) as the first command-index after 'c' that 'submatrix' is written to; or if there is no such command, then the command index of the deallocation command for 'submatrix'; or if this does not exist, then num-commands.

The conditions that must be satisfied for merges are as follows:

  • Condition c1: it cannot be the case that m1 and m2 are both inputs, or that they are both outputs.
  • Condition c2: If either m1 or m2 is an input or an output, then s1 must be the entirety of m1 and s2 must be the entirety of m2 (this is because inputs and outputs must be whole matrices).
  • Condition c3: if we are left-merging (deleting s2,m2), then s2 must be the entirety of m2.
  • Condition c4: If we are right-merging (deleting s1,m1), then s1 must be the entirety of m1.
  • Condition c5: None of the the variables underlying s1 and s2 may be marked as 'dirty' (implying that they were the subjects of a previous merge during the lifetime of this class).
  • Condition c6: if we are left-merging (deleting s2, m2) and m2 has stride_type == kStrideEqualNumCols, then s1 must be the entirety of m1. [note: because of condition c3, we can assume that s2 is the entirety of m2.]
  • Condition c7: if we are right-merging (deleting s1, m1) and m1 has stride_type == kStrideEqualNumCols, then s2 must be the entirety of m2. [note: because of condition c4, we can assume that s1 is the entirety of m1.]

If the command C is case (a), i.e. an assignment operation, then the following conditions must apply:

  • first-nontrivial-access(s2) == C
  • last-write-access(s1) < C
  • last-access(s1) < data-invalidated-command(C, s2) Otherwise (cases (b) and (c), in-place propagate or backprop), we insist that:
  • first-nontrivial-access(s2) == C
  • last-access(s1) == C Note: in either case, these conditions imply that m2/s2 is not an input and m1/s1 is not an output. [i.e. s1 *may* be an input and s2 *may* be an output].

We can explain the procedure for both left-merge and right-merge in one, because it's the same. Define s_to_keep and m_to_keep as s1 and m1 if we're left-merging and s2 and m2 if we're right-merging, and s_to_discard and m_to_discard the opposite way.

The procedure to merge in general is as follows:

  • All submatrices that reference m1, make them reference m2 instead. [later we'll renumber so that there are no duplicates.] This automatically takes care of making the input and output and allocation/deallocation commands refer to the right matrix, in most cases.
  • We need to get rid of duplicate or unnecessary allocation commands: If m_to_discard is an input then get rid of the allocation command for m_to_keep; otherwise get rid of the allocation command of m_to_discard.
  • We need to get rid of duplicate or unnecessary deallocation commands: If m_to_discard is an output then get rid of the deallocation command for m_to_keep; otherwise get rid of the deallocation command for m_to_discard.

At the end when we call RemoveOrphanMatrices(), the renumbering code will automatically detect that there are duplicate submatrices, and will merge them, as well as removing the now-unused matrix indexes. After merging, we will mark the variables (i.e. row-ranges) underlying s1 and s2 as being "dirty" so they can no longer be merged during the lifetime of this class– this is so we don't have to think to hard; we apply this optimization multiple times until it makes no change (see nnet-optimize.cc:VariableMerginOptimization()).

Definition at line 133 of file nnet-optimize-utils.h.

Constructor & Destructor Documentation

◆ VariableMergingOptimizer()

VariableMergingOptimizer ( const NnetOptimizeOptions config,
const Nnet nnet,
NnetComputation computation 
)

Definition at line 711 of file nnet-optimize-utils.cc.

References VariableMergingOptimizer::analyzer_, VariableMergingOptimizer::computation_, kaldi::nnet3::ComputeMatrixToSubmatrix(), Analyzer::Init(), VariableMergingOptimizer::matrix_to_submatrix_, ComputationVariables::NumVariables(), VariableMergingOptimizer::variable_dirty_, and Analyzer::variables.

714  :
715  config_(config), nnet_(nnet),
716  computation_(computation),
718  analyzer_.Init(nnet, *computation);
721 }
void Init(const Nnet &nnet, const NnetComputation &computation)
std::vector< std::vector< int32 > > matrix_to_submatrix_
void ComputeMatrixToSubmatrix(const NnetComputation &computation, std::vector< std::vector< int32 > > *mat_to_submat)
This function computes a vector &#39;mat_to_submat&#39;, indexed by matrix index, such that (*mat_to_submat)[...
ComputationVariables variables
Definition: nnet-analyze.h:295

Member Function Documentation

◆ DoMerge()

void DoMerge ( int32  command_index,
int32  s_to_keep,
int32  m_to_discard 
)
private

Definition at line 819 of file nnet-optimize-utils.cc.

References NnetComputation::Command::alpha, VariableMergingOptimizer::analyzer_, NnetComputation::Command::arg1, NnetComputation::Command::arg2, NnetComputation::Command::command_type, NnetComputation::commands, VariableMergingOptimizer::computation_, ComputationAnalysis::FirstNontrivialMatrixAccess(), kaldi::nnet3::GetSubMatrixOfSubMatrix(), kaldi::nnet3::kAcceptInput, KALDI_ASSERT, kaldi::nnet3::kMatrixCopy, kaldi::nnet3::kNoOperation, kaldi::nnet3::kSetConst, kaldi::kStrideEqualNumCols, VariableMergingOptimizer::MarkAsDirty(), NnetComputation::matrices, Analyzer::matrix_accesses, VariableMergingOptimizer::matrix_to_submatrix_, and NnetComputation::submatrices.

Referenced by VariableMergingOptimizer::MergeVariables().

821  {
822  // Prevent further optimizations touching either submatrix (we can try again
823  // in a later round of optimization, with a new instance of this class).
824  MarkAsDirty(s_to_keep);
825  MarkAsDirty(s_to_discard);
826 
827  int32 m_to_keep = computation_->submatrices[s_to_keep].matrix_index,
828  m_to_discard = computation_->submatrices[s_to_discard].matrix_index;
829  KALDI_ASSERT(m_to_keep != m_to_discard && m_to_keep > 0 && m_to_discard > 0);
830 
831  { // modify submatrices of m_to_discard to effectively be sub-matrices of
832  // s_to_keep instead (they will refer to m_to_keep as the matrix_index).
833  std::vector<int32>::const_iterator iter =
834  matrix_to_submatrix_[m_to_discard].begin(),
835  end = matrix_to_submatrix_[m_to_discard].end();
836  for (; iter != end; ++iter) {
837  int32 submatrix_index = *iter;
838  KALDI_ASSERT(computation_->submatrices[submatrix_index].matrix_index
839  == m_to_discard);
840  computation_->submatrices[submatrix_index] =
841  GetSubMatrixOfSubMatrix(*computation_, submatrix_index,
842  s_to_keep);
843  }
844  }
845 
846  ComputationAnalysis analysis(*computation_, analyzer_);
847  NnetComputation::Command &c = computation_->commands[command_index];
848  const std::vector<MatrixAccesses> &matrix_accesses =
850 
851  // - If it was a matrix-copy (assignment) with scale 1.0, replace the
852  // assignment command with a no-op.
853  // If it was matrix-copy with a scale, leave the command there;
854  // it will have the effect of scaling the matrix (it will be
855  // mapped so that arg1 == arg2, but that is OK).
856  if (c.command_type == kMatrixCopy && c.alpha == 1.0) {
857  // remove the command.
858  c.command_type = kNoOperation;
859  c.arg1 = -1;
860  c.arg2 = -1;
861  }
862 
863  // We want to ensure that there is only one deallocation command.
864  // If neither matrix is an output, then there will be 2 deallocation
865  // commands and we keep the one for m_to_keep (which, if the sizes
866  // differ, will be the larger of the two, so it's the one whose
867  // submatrix index refers to the entirety of the matrix).
868  // If one of them is an output, then remove the deallocation command
869  // of whichever one is not an output.
870  // As a simplification to the logic above: if the 'discard' matrix
871  // has a deallocation command (i.e. if that matrix was not an output)
872  // then remove it; otherwise remove the deallocation command of
873  // the 'keep' matrix.
874 
875  int32 dealloc_keep = matrix_accesses[m_to_keep].deallocate_command,
876  dealloc_discard = matrix_accesses[m_to_discard].deallocate_command;
877  if (dealloc_discard != -1) {
878  computation_->commands[dealloc_discard].command_type = kNoOperation;
879  } else {
880  KALDI_ASSERT(dealloc_keep != -1);
881  computation_->commands[dealloc_keep].command_type = kNoOperation;
882  }
883 
884  {
885  // - Both m_to_keep and m_to_discard will have commands that allocate
886  // them, as all matrices do (note, kAcceptInput counts as an allocation
887  // command). If one of them is kAcceptInput, then delete the other one,
888  // because the position of the kAcceptInput commands is important.
889  // Otherwise delete the "discard" one. As a simplification of the logic
890  // of the previous sentence: if the "discard" allocate command is
891  // kAcceptInput then delete the "keep" allocate command, else delete
892  // the "discard" allocate command.
893  // Note: after we renumber the submatrices, they both refer to the
894  // same underlying matrix, but we need to refer to them using a
895  // submatrix that refers to the entire matrix. The one we keep will
896  // always refer to the entire matrix. (In the case where one of
897  // them is an input, both submatrices are guaranteed to refer to the
898  // entire matrix, this is guaranteed by the logic we use to decide
899  // which matrices we can merge).
900  int32 alloc_keep = matrix_accesses[m_to_keep].allocate_command,
901  alloc_discard = matrix_accesses[m_to_discard].allocate_command;
902 
903  KALDI_ASSERT(alloc_keep != -1 && alloc_discard != -1);
904  KALDI_ASSERT(analysis.FirstNontrivialMatrixAccess(m_to_discard) >
905  alloc_keep);
906 
907  NnetComputation::Command
908  &keep_alloc_command = computation_->commands[alloc_keep],
909  &discard_alloc_command = computation_->commands[alloc_discard];
910  int32 matrix_whose_zeroing_to_discard;
911  if (discard_alloc_command.command_type == kAcceptInput) {
912  keep_alloc_command.command_type = kNoOperation;
913  matrix_whose_zeroing_to_discard = m_to_keep;
914  } else {
915  discard_alloc_command.command_type = kNoOperation;
916  matrix_whose_zeroing_to_discard = m_to_discard;
917  }
918  // Now remove the command that zeroed one of the matrices
919  // (the one whose allocation command we just discarded).
920  int32 zeroing_command_to_discard =
921  matrix_accesses[matrix_whose_zeroing_to_discard].accesses[0].command_index;
922  NnetComputation::Command &zeroing_command =
923  computation_->commands[zeroing_command_to_discard];
924  if (zeroing_command.command_type == kSetConst &&
925  zeroing_command.alpha == 0.0) {
926  // if 'zeroing_command' actually *was* a zeroing command, then remove it.
927  zeroing_command.command_type = kNoOperation;
928  }
929  }
930 
931  // If the matrix to discard had stride_type == kStrideEqualNumCols, set the
932  // stride type of the matrix we're keeping to kStrideEqualNumCols.
933  if (computation_->matrices[m_to_discard].stride_type == kStrideEqualNumCols) {
934  computation_->matrices[m_to_keep].stride_type = kStrideEqualNumCols;
935  // ... and perform an additional check.
936  KALDI_ASSERT(computation_->matrices[m_to_discard].num_rows ==
937  computation_->matrices[m_to_keep].num_rows &&
938  computation_->matrices[m_to_discard].num_cols ==
939  computation_->matrices[m_to_keep].num_cols);
940  }
941 }
kaldi::int32 int32
std::vector< MatrixInfo > matrices
std::vector< Command > commands
static NnetComputation::SubMatrixInfo GetSubMatrixOfSubMatrix(const NnetComputation &computation, int32 submat_a, int32 submat_b)
This static function returns a SubMatrixInfo corresponding to replacing the matrix-index in a&#39;s "matr...
std::vector< std::vector< int32 > > matrix_to_submatrix_
std::vector< SubMatrixInfo > submatrices
std::vector< MatrixAccesses > matrix_accesses
Definition: nnet-analyze.h:298
void MarkAsDirty(int32 s)
Marks the variables underlying submatrix &#39;s&#39; as dirty.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185

◆ Initialize()

void Initialize ( )
private

◆ MarkAsDirty()

void MarkAsDirty ( int32  s)
private

Marks the variables underlying submatrix 's' as dirty.

Definition at line 807 of file nnet-optimize-utils.cc.

References VariableMergingOptimizer::analyzer_, ComputationVariables::AppendVariablesForSubmatrix(), KALDI_ASSERT, VariableMergingOptimizer::variable_dirty_, and Analyzer::variables.

Referenced by VariableMergingOptimizer::DoMerge().

807  {
808  std::vector<int32> variable_indexes;
809  analyzer_.variables.AppendVariablesForSubmatrix(s, &variable_indexes);
810  std::vector<int32>::const_iterator iter = variable_indexes.begin(),
811  end = variable_indexes.end();
812  for (; iter != end; ++iter) {
813  int32 v = *iter;
814  KALDI_ASSERT(static_cast<size_t>(v) < variable_dirty_.size());
815  variable_dirty_[v] = true;
816  }
817 }
kaldi::int32 int32
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void AppendVariablesForSubmatrix(int32 submatrix_index, std::vector< int32 > *variable_indexes) const
ComputationVariables variables
Definition: nnet-analyze.h:295

◆ MayBeMerged()

std::pair< bool, bool > MayBeMerged ( int32  command,
int32  s1,
int32  s2 
) const
private

This function returns a pair of bools saying whether we can do a (left and/or right) merge respectively, based on the conditions defined in the header.

Note: if one of the variables underlying s1 or s2 is marked as 'dirty' due to a previous merge, this function will return (false,false). The terms left-merge and right-merge are defined in the extended comment above this class. Note: left_merge will always be false if config.allow_left_merge == false, and the same respectively for right_merge.

Parameters
command[in] The command-index that assigns s2 := s1 or does a forward or backprop with s1 as the input and s2 as the output
s1[in] A submatrix-index s1 > 0.
s2[in] A submatrix-index s2 > 0

Definition at line 945 of file nnet-optimize-utils.cc.

References NnetOptimizeOptions::allow_left_merge, NnetOptimizeOptions::allow_right_merge, VariableMergingOptimizer::analyzer_, ComputationVariables::AppendVariablesForSubmatrix(), NnetComputation::commands, VariableMergingOptimizer::computation_, VariableMergingOptimizer::config_, ComputationAnalysis::DataInvalidatedCommand(), ComputationAnalysis::FirstNontrivialAccess(), MatrixAccesses::is_input, MatrixAccesses::is_output, NnetComputation::IsWholeMatrix(), KALDI_ASSERT, kaldi::nnet3::kMatrixCopy, kaldi::kStrideEqualNumCols, ComputationAnalysis::LastAccess(), ComputationAnalysis::LastWriteAccess(), NnetComputation::matrices, Analyzer::matrix_accesses, NnetComputation::submatrices, VariableMergingOptimizer::variable_dirty_, and Analyzer::variables.

Referenced by VariableMergingOptimizer::MergeVariables().

946  {
947  KALDI_ASSERT(s1 > 0 && s2 > 0 && static_cast<size_t>(command_index) <
948  computation_->commands.size());
950  return std::pair<bool,bool>(false,false);
951  int32 m1 = computation_->submatrices[s1].matrix_index,
952  m2 = computation_->submatrices[s2].matrix_index;
953  // we can't merge two different submatrices of the same matrix.
954  if (m1 == m2) return std::pair<bool,bool>(false,false);
955  std::vector<int32> variable_indexes;
956  analyzer_.variables.AppendVariablesForSubmatrix(s1, &variable_indexes);
957  analyzer_.variables.AppendVariablesForSubmatrix(s2, &variable_indexes);
958  std::vector<int32>::iterator iter = variable_indexes.begin(),
959  end = variable_indexes.end();
960  // condition c5:
961  for (; iter != end; ++iter)
962  if (variable_dirty_[*iter])
963  return std::pair<bool,bool>(false,false);
964  const std::vector<MatrixAccesses> &matrix_accesses = analyzer_.matrix_accesses;
965  const MatrixAccesses &m1_access = matrix_accesses[m1],
966  &m2_access = matrix_accesses[m2];
967  // condition c1:
968  if ((m1_access.is_input && m2_access.is_input) ||
969  (m1_access.is_output && m2_access.is_output))
970  return std::pair<bool,bool>(false,false);
971  // condition c2:
972  if ((m1_access.is_input || m1_access.is_output ||
973  m2_access.is_input || m2_access.is_output) &&
974  (!computation_->IsWholeMatrix(s1) ||
976  return std::pair<bool,bool>(false,false);
977  bool left = config_.allow_left_merge,
978  right = config_.allow_right_merge;
979  // condition c3:
980  if (!computation_->IsWholeMatrix(s2)) left = false;
981  // condition c4:
982  if (!computation_->IsWholeMatrix(s1)) right = false;
983  // condition c6:
984  if (computation_->matrices[m2].stride_type == kStrideEqualNumCols &&
985  !computation_->IsWholeMatrix(s1)) left = false;
986  // condition c7:
987  if (computation_->matrices[m1].stride_type == kStrideEqualNumCols &&
988  !computation_->IsWholeMatrix(s2)) right = false;
989 
990 
991  if (!left && !right) // save some time.
992  return std::pair<bool,bool>(false,false);
993  bool is_assignment = (computation_->commands[command_index].command_type ==
994  kMatrixCopy &&
995  computation_->commands[command_index].alpha == 1.0);
996  ComputationAnalysis analysis(*computation_, analyzer_);
997  if (is_assignment) {
998  if (analysis.FirstNontrivialAccess(s2) == command_index &&
999  analysis.LastWriteAccess(s1) < command_index &&
1000  analysis.LastAccess(s1) <
1001  analysis.DataInvalidatedCommand(command_index, s2)) {
1002  return std::pair<bool,bool>(left, right); // possible success.
1003  }
1004  } else {
1005  if (analysis.FirstNontrivialAccess(s2) == command_index &&
1006  analysis.LastAccess(s1) == command_index) {
1007  return std::pair<bool,bool>(left, right); // possible success.
1008  }
1009  }
1010  // failure.
1011  return std::pair<bool,bool>(false,false);
1012 }
kaldi::int32 int32
std::vector< MatrixInfo > matrices
std::vector< Command > commands
std::vector< SubMatrixInfo > submatrices
std::vector< MatrixAccesses > matrix_accesses
Definition: nnet-analyze.h:298
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void AppendVariablesForSubmatrix(int32 submatrix_index, std::vector< int32 > *variable_indexes) const
ComputationVariables variables
Definition: nnet-analyze.h:295
bool IsWholeMatrix(int32 submatrix_index) const

◆ MergeVariables()

bool MergeVariables ( )

Definition at line 723 of file nnet-optimize-utils.cc.

References VariableMergingOptimizer::already_called_merge_variables_, NnetComputation::Command::arg1, NnetComputation::Command::arg2, NnetComputation::Command::arg3, NnetComputation::Command::arg4, NnetComputation::Command::arg5, NnetComputation::Command::arg6, NnetOptimizeOptions::backprop_in_place, NnetComputation::Command::command_type, NnetComputation::commands, VariableMergingOptimizer::computation_, VariableMergingOptimizer::config_, VariableMergingOptimizer::DoMerge(), Nnet::GetComponent(), KALDI_ASSERT, kaldi::nnet3::kBackprop, kaldi::nnet3::kBackpropInPlace, kaldi::nnet3::kBackpropNoModelUpdate, kaldi::nnet3::kMatrixCopy, kaldi::nnet3::kPropagate, kaldi::nnet3::kPropagateInPlace, VariableMergingOptimizer::MayBeMerged(), VariableMergingOptimizer::nnet_, NnetOptimizeOptions::optimize, NnetOptimizeOptions::propagate_in_place, Component::Properties(), NnetOptimizeOptions::remove_assignments, kaldi::nnet3::RemoveNoOps(), and kaldi::nnet3::RenumberComputation().

Referenced by kaldi::nnet3::VariableMergingOptimization().

723  {
726  if (!config_.optimize)
727  return false;
728  bool merged = false;
729  int32 num_commands = computation_->commands.size();
730  for (int32 command_index = 0; command_index < num_commands;
731  command_index++) {
732  // This loop looks for pairs of sub-matrix indexes s1,s2 that we could
733  // potentially merge into a single variable.
734  const NnetComputation::Command &c = computation_->commands[command_index];
735  int32 s1 = -1, s2 = -1;
736  if (c.command_type == kMatrixCopy &&
738  s2 = c.arg1; // s2 is the written-to matrix.
739  s1 = c.arg2;
740  } else if (c.command_type == kPropagate &&
742  const Component *component = nnet_.GetComponent(c.arg1);
743  if (component->Properties() & kPropagateInPlace) {
744  s1 = c.arg3;
745  s2 = c.arg4; // s2 is the written-to matrix.
746  }
747  } else if ((c.command_type == kBackprop ||
748  c.command_type == kBackpropNoModelUpdate) &&
750  const Component *component = nnet_.GetComponent(c.arg1);
751  if (component->Properties() & kBackpropInPlace) {
752  s1 = c.arg5;
753  s2 = c.arg6; // s2 is the written-to matrix.
754  if (s1 == c.arg3 || s2 == c.arg3 || s1 == c.arg4 || s2 == c.arg4) {
755  // we don't think this should ever happen, but just out of an
756  // abundance of caution: if either of these submatrix indexes are the
757  // input-value or output-value args to Backprop, don't do the optimization.
758  s1 = -1;
759  s2 = -1;
760  }
761  }
762  }
763  if (s1 > 0 && s2 > 0) {
764  std::pair<bool,bool> p = MayBeMerged(command_index, s1, s2);
765  if (p.first) {
766  DoMerge(command_index, s1, s2);
767  merged = true;
768  } else if (p.second) {
769  DoMerge(command_index, s2, s1);
770  merged = true;
771  }
772  }
773  }
774  if (merged) {
777  }
778  return merged;
779 }
void RenumberComputation(NnetComputation *computation)
This function detects submatrices and matrices that are never used (e.g.
kaldi::int32 int32
std::vector< Command > commands
void DoMerge(int32 command_index, int32 s_to_keep, int32 m_to_discard)
Component * GetComponent(int32 c)
Return component indexed c. Not a copy; not owned by caller.
Definition: nnet-nnet.cc:150
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void RemoveNoOps(NnetComputation *computation)
Removes commands of type kNoOperation in the computation.
std::pair< bool, bool > MayBeMerged(int32 command, int32 s1, int32 s2) const
This function returns a pair of bools saying whether we can do a (left and/or right) merge respective...

Member Data Documentation

◆ already_called_merge_variables_

bool already_called_merge_variables_
private

Definition at line 184 of file nnet-optimize-utils.h.

Referenced by VariableMergingOptimizer::MergeVariables().

◆ analyzer_

◆ computation_

◆ config_

◆ matrix_to_submatrix_

std::vector<std::vector<int32> > matrix_to_submatrix_
private

◆ nnet_

const Nnet& nnet_
private

Definition at line 172 of file nnet-optimize-utils.h.

Referenced by VariableMergingOptimizer::MergeVariables().

◆ variable_dirty_


The documentation for this class was generated from the following files: