nnet-limit-rank.cc
Go to the documentation of this file.
1 // nnet2/nnet-limit-rank.cc
2 
3 // Copyright 2012 Johns Hopkins University (author: Daniel Povey)
4 
5 // See ../../COPYING for clarification regarding multiple authors
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
15 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
16 // MERCHANTABLITY OR NON-INFRINGEMENT.
17 // See the Apache 2 License for the specific language governing permissions and
18 // limitations under the License.
19 
20 #include "nnet2/nnet-limit-rank.h"
21 #include "util/kaldi-thread.h"
22 
23 namespace kaldi {
24 namespace nnet2 {
25 
27  public:
29  int32 c,
30  Nnet *nnet): opts_(opts), c_(c), nnet_(nnet) { }
31  void operator () () {
32  AffineComponent *ac = dynamic_cast<AffineComponent*>(
33  &(nnet_->GetComponent(c_)));
34  KALDI_ASSERT(ac != NULL);
35 
36  // We'll limit the rank of just the linear part, keeping the bias vector full.
38  int32 rows = M.NumRows(), cols = M.NumCols(), rc_min = std::min(rows, cols);
39  Vector<BaseFloat> s(rc_min);
40  Matrix<BaseFloat> U(rows, rc_min), Vt(rc_min, cols);
41  // Do the destructive svd M = U diag(s) V^T. It actually outputs the transpose of V.
42  M.DestructiveSvd(&s, &U, &Vt);
43  SortSvd(&s, &U, &Vt); // Sort the singular values from largest to smallest.
44 
45  int32 d = GetRetainedDim(rows, cols);
46  BaseFloat old_svd_sum = s.Sum();
47  U.Resize(rows, d, kCopyData);
48  s.Resize(d, kCopyData);
49  Vt.Resize(d, cols, kCopyData);
50  BaseFloat new_svd_sum = s.Sum();
51  KALDI_LOG << "For component " << c_ << " of dimension " << rows
52  << " x " << cols << ", reduced rank from "
53  << rc_min << " to " << d << ", SVD sum reduced from "
54  << old_svd_sum << " to " << new_svd_sum;
55  Vt.MulRowsVec(s); // Vt <-- diag(s) Vt.
56  M.AddMatMat(1.0, U, kNoTrans, Vt, kNoTrans, 0.0); // Reconstruct with reduced
57  // rank.
58  Vector<BaseFloat> bias_params(ac->BiasParams());
59  ac->SetParams(bias_params, M);
60  }
61 
64  KALDI_ERR << "bad --parameter-proportion " << opts_.parameter_proportion;
65  // If we do SVD to dimension d, so that it's U diag(s) V^T where
66  // U is rows * d, s is d, and V is cols * d, then the #params is as follows...
67  // the first column of U has free parameters (#rows - 1) [the -1 is due to
68  // the length constraint]; the second has (#rows - 2) [subtract 1 for the
69  // length constraint and one for orthogonality with the previous row], etc.
70  // Total is params(U) = (rows * d) - ((d(d+1))/2),
71  // params(s) = d,
72  // params(V) = (cols * d) - ((d(d+1))/2),
73  // So total is (rows + cols) * d - d * d .
74  // For example, if d = #rows, this equals (#rows * #cols)
75  // We are solving for:
76  // (rows * cols) * parameter_proportion = (rows + cols) * d - d * d, or
77  // d^2 - d * (rows + cols) + (rows*cols)*parameter_proportion
78  // In quadratic equation
79  // a = 1.0,
80  // b = -(rows + cols)
81  // c = rows * cols * parameter_proportion.
82  // Take smaller solution.
83  BaseFloat a = 1.0, b = -(rows + cols),
84  c = rows * cols * opts_.parameter_proportion;
85  BaseFloat x = (-b - sqrt(b * b - 4 * a * c)) / (2.0 * a);
86  int32 ans = static_cast<int32>(x);
87  KALDI_ASSERT(ans > 0 && ans <= std::min(rows, cols));
88  return ans;
89  }
90 
92  private:
96 };
97 
98 
100  Nnet *nnet) {
101  TaskSequencerConfig task_config;
102  task_config.num_threads = opts.num_threads;
103  TaskSequencer<LimitRankClass> tc(task_config);
104  for (int32 c = 0; c < nnet->NumComponents(); c++) {
105  if (dynamic_cast<AffineComponent*>(&(nnet->GetComponent(c))) != NULL)
106  tc.Run(new LimitRankClass(opts, c, nnet));
107  }
108 }
109 
110 
111 } // namespace nnet2
112 } // namespace kaldi
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
const Component & GetComponent(int32 c) const
Definition: nnet-nnet.cc:141
virtual void SetParams(const VectorBase< BaseFloat > &bias, const MatrixBase< BaseFloat > &linear)
void Run(C *c)
This function takes ownership of the pointer "c", and will delete it in the same sequence as Run was ...
Definition: kaldi-thread.h:190
void LimitRankParallel(const NnetLimitRankOpts &opts, Nnet *nnet)
This function limits the rank of each affine transform in the neural net, by zeroing out the smallest...
LimitRankClass(const NnetLimitRankOpts &opts, int32 c, Nnet *nnet)
const CuVector< BaseFloat > & BiasParams()
kaldi::int32 int32
void Resize(MatrixIndexT length, MatrixResizeType resize_type=kSetZero)
Set vector to a specified size (can be zero).
const NnetLimitRankOpts & opts_
int32 NumComponents() const
Returns number of components– think of this as similar to # of layers, but e.g.
Definition: nnet-nnet.h:69
int32 GetRetainedDim(int32 rows, int32 cols)
#define KALDI_ERR
Definition: kaldi-error.h:147
Real Sum() const
Returns sum of the elements.
void MulRowsVec(const VectorBase< Real > &scale)
Equivalent to (*this) = diag(scale) * (*this).
A class representing a vector.
Definition: kaldi-vector.h:406
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
MatrixIndexT NumRows() const
Returns number of rows (or zero for empty matrix).
Definition: kaldi-matrix.h:64
void Resize(const MatrixIndexT r, const MatrixIndexT c, MatrixResizeType resize_type=kSetZero, MatrixStrideType stride_type=kDefaultStride)
Sets matrix to a specified size (zero is OK as long as both r and c are zero).
const CuMatrix< BaseFloat > & LinearParams()
#define KALDI_LOG
Definition: kaldi-error.h:153
void SortSvd(VectorBase< Real > *s, MatrixBase< Real > *U, MatrixBase< Real > *Vt, bool sort_on_absolute_value)
Function to ensure that SVD is sorted.