Skip to content

Commit

Permalink
Merge pull request kaldi-asr#25 from david-ryan-snyder/xvector2
Browse files Browse the repository at this point in the history
xvector: printing eigenvalues of output s
  • Loading branch information
danpovey committed Mar 2, 2016
2 parents 1476f84 + 56d2b1b commit 67961a6
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 8 deletions.
93 changes: 93 additions & 0 deletions src/nnet3/nnet-utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// Copyright 2015 Johns Hopkins University (author: Daniel Povey)
// 2016 Daniel Galvez
// David Snyder
//
// See ../../COPYING for clarification regarding multiple authors
//
Expand All @@ -20,6 +21,10 @@

#include "nnet3/nnet-utils.h"
#include "nnet3/nnet-simple-component.h"
#include "nnet3/nnet-compute.h"
#include "nnet3/nnet-optimize.h"
#include "nnet3/nnet-example.h"


namespace kaldi {
namespace nnet3 {
Expand Down Expand Up @@ -421,6 +426,94 @@ std::string NnetInfo(const Nnet &nnet) {
return ostr.str();
}

std::string SpMatrixOutputInfo(const Nnet &nnet) {
std::ostringstream os;
// The output 's' is vectorized SpMatrix.
std::string output_name = "s";
int32 node_index = nnet.GetNodeIndex(output_name);
if (node_index != -1 && nnet.IsOutputNode(node_index)) {
// Check that the output dim is of the form
// (1/2)*(d+1)*d.
int32 output_dim = nnet.OutputDim(output_name);
int32 d = (0.5) * (1 + sqrt(1 + 8 * output_dim)) - 1;
if (((d + 1) * d) / 2 == output_dim) {
SpMatrix<BaseFloat> S(d);
Vector<BaseFloat> s_vec(output_dim);
GetConstantOutput(nnet, output_name, &s_vec);
S.CopyFromVec(s_vec);
Vector<BaseFloat> s(d);
Matrix<BaseFloat> P(d, d);
S.Eig(&s, &P);
SortSvd(&s, &P);
os << "Eigenvalues of output 's': " << s;
}
}
return os.str();
}

void GetConstantOutput(const Nnet &nnet_const, const std::string &output_name,
Vector<BaseFloat> *output) {
Nnet nnet(nnet_const);
std::string input_name = "input";
int32 left_context,
right_context,
input_node_index = nnet.GetNodeIndex(input_name),
output_node_index = nnet.GetNodeIndex(output_name);
if (output_node_index == -1 && !nnet.IsOutputNode(output_node_index))
KALDI_ERR << "No output node called '" << output_name
<< "' in the network.";
if (input_node_index == -1 && nnet.IsInputNode(input_node_index))
KALDI_ERR << "No input node called '" << input_name
<< "' in the network.";
KALDI_ASSERT(output->Dim() == nnet.OutputDim(output_name));
ComputeSimpleNnetContext(nnet, &left_context, &right_context);

// It's difficult to get the output of the node
// directly. Instead, we can create some fake input,
// propagate it through the network, and read out the
// output.
CuMatrix<BaseFloat> cu_feats(left_context + right_context,
nnet.InputDim(input_name));
Matrix<BaseFloat> feats(cu_feats);

ComputationRequest request;
NnetIo nnet_io = NnetIo(input_name, 0, feats);
request.inputs.clear();
request.outputs.clear();
request.inputs.resize(1);
request.outputs.resize(1);
request.need_model_derivative = false;
request.store_component_stats = false;

std::vector<Index> output_indexes;
request.inputs[0].name = input_name;
request.inputs[0].indexes = nnet_io.indexes;
request.inputs[0].has_deriv = false;
output_indexes.resize(1);
output_indexes[0].n = 0;
output_indexes[0].t = 0;
request.outputs[0].name = output_name;
request.outputs[0].indexes = output_indexes;
request.outputs[0].has_deriv = false;

CachingOptimizingCompiler compiler(nnet, NnetOptimizeOptions());
const NnetComputation *computation = compiler.Compile(request);
NnetComputer computer(NnetComputeOptions(), *computation,
nnet, &nnet);

// check to see if something went wrong.
if (request.inputs.empty())
KALDI_ERR << "No input in computation request.";
if (request.outputs.empty())
KALDI_ERR << "No output in computation request.";

computer.AcceptInput("input", &cu_feats);
computer.Forward();
const CuMatrixBase<BaseFloat> &output_mat = computer.GetOutput(output_name);
CuSubVector<BaseFloat> output_vec(output_mat, 0);
output->CopyFromVec(output_vec);
}


} // namespace nnet3
} // namespace kaldi
12 changes: 11 additions & 1 deletion src/nnet3/nnet-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,22 @@ int32 NumUpdatableComponents(const Nnet &dest);
void ConvertRepeatedToBlockAffine(Nnet *nnet);

/// This function returns various info about the neural net.
/// If the nnet satisfied IsSimpleNnet(nnet), the info includes "left-context=5\nright-context=3\n...". The info includes
/// If the nnet satisfied IsSimpleNnet(nnet), the info includes
/// "left-context=5\nright-context=3\n...". The info includes
/// the output of nnet.Info().
/// This is modeled after the info that AmNnetSimple returns in its
/// Info() function (we need this in the CTC code).
std::string NnetInfo(const Nnet &nnet);

/// Returns a string containing info on an output node called 's' if
/// it can be interpreted as a symmetric matrix.
std::string SpMatrixOutputInfo(const Nnet &nnet);

/// This function assumes that the node named in 'output_node' is a constant
/// function of the input features (e.g, a ConstantFunctionComponent is
/// its input) and returns it in 'out'.
void GetConstantOutput(const Nnet &nnet, const std::string &output_name,
Vector<BaseFloat> *out);

} // namespace nnet3
} // namespace kaldi
Expand Down
12 changes: 7 additions & 5 deletions src/nnet3bin/nnet3-info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "base/kaldi-common.h"
#include "util/common-utils.h"
#include "nnet3/nnet-nnet.h"
#include "nnet3/nnet-utils.h"

int main(int argc, char *argv[]) {
try {
Expand All @@ -35,22 +36,23 @@ int main(int argc, char *argv[]) {
"e.g.:\n"
" nnet3-info 0.raw\n"
"See also: nnet3-am-info\n";

ParseOptions po(usage);

po.Read(argc, argv);

if (po.NumArgs() != 1) {
po.PrintUsage();
exit(1);
}

std::string raw_nnet_rxfilename = po.GetArg(1);

Nnet nnet;
ReadKaldiObject(raw_nnet_rxfilename, &nnet);

std::cout << nnet.Info();
std::cout << SpMatrixOutputInfo(nnet);

return 0;
} catch(const std::exception &e) {
Expand All @@ -72,6 +74,6 @@ component-node name=affine1_node component=affine1 input=Append(Offset(input, -4
component-node name=nonlin1 component=relu1 input=affine1_node
component-node name=final_affine component=final_affine input=nonlin1
component-node name=output_nonlin component=logsoftmax input=final_affine
output-node name=output input=output_nonlin
output-node name=output input=output_nonlin
EOF
*/
6 changes: 4 additions & 2 deletions src/xvectorbin/nnet3-xvector-compute.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,16 +179,18 @@ int main(int argc, char *argv[]) {
for (int32 i = out_offset;
i < std::min(out_offset + xvector_period, num_rows); i++)
xvector_mat.Row(i).CopyFromVec(xvector);
} else
} else {
xvector_mat.Row(chunk_indx).CopyFromVec(xvector);
}
}

// If output is a vector, scale it by the total weight.
if (output_as_vector) {
xvector_avg.Scale(1.0 / total_chunk_weight);
vector_writer.Write(utt, xvector_avg);
} else
} else {
matrix_writer.Write(utt, xvector_mat);
}

frame_count += feats.NumRows();
num_success++;
Expand Down

0 comments on commit 67961a6

Please sign in to comment.