// ivector/logistic-regression-test.cc // Copyright 2014 David Snyder // See ../../COPYING for clarification regarding multiple authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, // MERCHANTABLITY OR NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing permissions and // limitations under the License. #include #include "ivector/logistic-regression.h" namespace kaldi { void UnitTestPosteriors() { int32 n_features = Rand() % 600 + 10, n_xs = Rand() % 200 + 100, n_labels = Rand() % 20 + 10; LogisticRegressionConfig conf; conf.max_steps = 20; conf.normalizer = 0.001; Matrix xs(n_xs, n_features); xs.SetRandn(); Matrix weights(n_labels, n_features + 1); weights.SetRandn(); LogisticRegression classifier = LogisticRegression(); std::vector classes; for (int32 i = 0; i < weights.NumRows(); i++) { classes.push_back(i); } classifier.SetWeights(weights, classes); // Get posteriors for the xs using batch and serial methods. Matrix batch_log_posteriors; classifier.GetLogPosteriors(xs, &batch_log_posteriors); Matrix log_posteriors(n_xs, n_labels); for (int32 i = 0; i < n_xs; i++) { Vector x(n_features); x.CopyRowFromMat(xs, i); Vector log_post; classifier.GetLogPosteriors(x, &log_post); // Verify that sum_y p(y|x) = 1.0. Vector post(log_post); post.ApplyExp(); KALDI_ASSERT(ApproxEqual(post.Sum(), 1.0)); log_posteriors.Row(i).CopyFromVec(log_post); } // Verify equivalence of batch and serial methods. float tolerance = 0.01; KALDI_ASSERT(log_posteriors.ApproxEqual(batch_log_posteriors, tolerance)); } void UnitTestTrain() { int32 n_features = Rand() % 600 + 10, n_xs = Rand() % 200 + 100, n_labels = Rand() % 20 + 10; double normalizer = 0.01; Matrix xs(n_xs, n_features); xs.SetRandn(); std::vector ys; for (int32 i = 0; i < n_xs; i++) { ys.push_back(Rand() % n_labels); } LogisticRegressionConfig conf; conf.max_steps = 20; conf.normalizer = normalizer; // Train the classifier LogisticRegression classifier = LogisticRegression(); classifier.Train(xs, ys, conf); // Internally in LogisticRegression we add an additional element to // the x vectors: a 1.0 which handles the prior. Matrix xs_with_prior(n_xs, n_features + 1); for (int32 i = 0; i < n_xs; i++) { xs_with_prior(i, n_features) = 1.0; } SubMatrix sub_xs(xs_with_prior, 0, n_xs, 0, n_features); sub_xs.CopyFromMat(xs); Matrix xw(n_xs, n_labels); xw.AddMatMat(1.0, xs_with_prior, kNoTrans, classifier.weights_, kTrans, 0.0); Matrix grad(classifier.weights_.NumRows(), classifier.weights_.NumCols()); double objf_trained = classifier.GetObjfAndGrad(xs_with_prior, ys, xw, &grad, normalizer); // Calculate objective function using a random weight matrix. Matrix xw_rand(n_xs, n_labels); Matrix weights_rand(classifier.weights_); weights_rand.SetRandn(); xw.AddMatMat(1.0, xs_with_prior, kNoTrans, weights_rand, kTrans, 0.0); // Verify that the objective function after training is better // than the objective function with a random weight matrix. double objf_rand_w = classifier.GetObjfAndGrad(xs_with_prior, ys, xw_rand, &grad, normalizer); KALDI_ASSERT(objf_trained > objf_rand_w); KALDI_ASSERT(objf_trained > Log(1.0 / n_xs)); } } int main() { using namespace kaldi; srand (time(NULL)); UnitTestTrain(); UnitTestPosteriors(); return 0; }