nnet-convolutional-component.h
Go to the documentation of this file.
1 // nnet/nnet-convolutional-component.h
2 
3 // Copyright 2014 Brno University of Technology (author: Karel Vesely)
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 
21 #ifndef KALDI_NNET_NNET_CONVOLUTIONAL_COMPONENT_H_
22 #define KALDI_NNET_NNET_CONVOLUTIONAL_COMPONENT_H_
23 
24 #include <string>
25 #include <vector>
26 
27 #include "nnet/nnet-component.h"
28 #include "nnet/nnet-utils.h"
29 #include "cudamatrix/cu-math.h"
30 
31 namespace kaldi {
32 namespace nnet1 {
33 
67  public:
69  UpdatableComponent(dim_in, dim_out),
70  patch_dim_(0),
71  patch_step_(0),
72  patch_stride_(0),
73  max_norm_(0.0)
74  { }
75 
77  { }
78 
79  Component* Copy() const { return new ConvolutionalComponent(*this); }
81 
82  void InitData(std::istream &is) {
83  // define options
84  BaseFloat bias_mean = -2.0, bias_range = 2.0, param_stddev = 0.1;
85  // parse config
86  std::string token;
87  while (is >> std::ws, !is.eof()) {
88  ReadToken(is, false, &token);
89  if (token == "<ParamStddev>") ReadBasicType(is, false, &param_stddev);
90  else if (token == "<BiasMean>") ReadBasicType(is, false, &bias_mean);
91  else if (token == "<BiasRange>") ReadBasicType(is, false, &bias_range);
92  else if (token == "<PatchDim>") ReadBasicType(is, false, &patch_dim_);
93  else if (token == "<PatchStep>") ReadBasicType(is, false, &patch_step_);
94  else if (token == "<PatchStride>") ReadBasicType(is, false, &patch_stride_);
95  else if (token == "<LearnRateCoef>") ReadBasicType(is, false, &learn_rate_coef_);
96  else if (token == "<BiasLearnRateCoef>") ReadBasicType(is, false, &bias_learn_rate_coef_);
97  else if (token == "<MaxNorm>") ReadBasicType(is, false, &max_norm_);
98  else KALDI_ERR << "Unknown token " << token << ", a typo in config?"
99  << " (ParamStddev|BiasMean|BiasRange|PatchDim|PatchStep|PatchStride)";
100  }
101 
102  //
103  // Sanity checks:
104  //
105  // splice (input are spliced frames):
107  int32 num_splice = input_dim_ / patch_stride_;
108  KALDI_LOG << "num_splice " << num_splice;
109  // number of patches:
111  int32 num_patches = 1 + (patch_stride_ - patch_dim_) / patch_step_;
112  KALDI_LOG << "num_patches " << num_patches;
113  // filter dim:
114  int32 filter_dim = num_splice * patch_dim_;
115  KALDI_LOG << "filter_dim " << filter_dim;
116  // num filters:
117  KALDI_ASSERT(output_dim_ % num_patches == 0);
118  int32 num_filters = output_dim_ / num_patches;
119  KALDI_LOG << "num_filters " << num_filters;
120  //
121 
122  //
123  // Initialize trainable parameters,
124  //
125  // Gaussian with given std_dev (mean = 0),
126  filters_.Resize(num_filters, filter_dim);
127  RandGauss(0.0, param_stddev, &filters_);
128  // Uniform,
129  bias_.Resize(num_filters);
130  RandUniform(bias_mean, bias_range, &bias_);
131  }
132 
133  void ReadData(std::istream &is, bool binary) {
134  // convolution hyperparameters,
135  ExpectToken(is, binary, "<PatchDim>");
136  ReadBasicType(is, binary, &patch_dim_);
137  ExpectToken(is, binary, "<PatchStep>");
138  ReadBasicType(is, binary, &patch_step_);
139  ExpectToken(is, binary, "<PatchStride>");
140  ReadBasicType(is, binary, &patch_stride_);
141 
142  // variant-length list of parameters,
143  bool end_loop = false;
144  while (!end_loop) {
145  int first_char = PeekToken(is, binary);
146  switch (first_char) {
147  case 'L': ExpectToken(is, binary, "<LearnRateCoef>");
148  ReadBasicType(is, binary, &learn_rate_coef_);
149  break;
150  case 'B': ExpectToken(is, binary, "<BiasLearnRateCoef>");
151  ReadBasicType(is, binary, &bias_learn_rate_coef_);
152  break;
153  case 'M': ExpectToken(is, binary, "<MaxNorm>");
154  ReadBasicType(is, binary, &max_norm_);
155  break;
156  case '!': ExpectToken(is, binary, "<!EndOfComponent>");
157  default: end_loop = true;
158  }
159  }
160 
161  // trainable parameters
162  ExpectToken(is, binary, "<Filters>");
163  filters_.Read(is, binary);
164  ExpectToken(is, binary, "<Bias>");
165  bias_.Read(is, binary);
166 
167  //
168  // Sanity checks:
169  //
170  // splice (input are spliced frames):
172  int32 num_splice = input_dim_ / patch_stride_;
173  // number of patches:
175  int32 num_patches = 1 + (patch_stride_ - patch_dim_) / patch_step_;
176  // filter dim:
177  int32 filter_dim = num_splice * patch_dim_;
178  // num filters:
179  KALDI_ASSERT(output_dim_ % num_patches == 0);
180  int32 num_filters = output_dim_ / num_patches;
181  // check parameter dims:
182  KALDI_ASSERT(num_filters == filters_.NumRows());
183  KALDI_ASSERT(num_filters == bias_.Dim());
184  KALDI_ASSERT(filter_dim == filters_.NumCols());
185  //
186  }
187 
188  void WriteData(std::ostream &os, bool binary) const {
189  // convolution hyperparameters
190  WriteToken(os, binary, "<PatchDim>");
191  WriteBasicType(os, binary, patch_dim_);
192  WriteToken(os, binary, "<PatchStep>");
193  WriteBasicType(os, binary, patch_step_);
194  WriteToken(os, binary, "<PatchStride>");
195  WriteBasicType(os, binary, patch_stride_);
196  if (!binary) os << "\n";
197 
198  // re-scale learn rate
199  WriteToken(os, binary, "<LearnRateCoef>");
200  WriteBasicType(os, binary, learn_rate_coef_);
201  WriteToken(os, binary, "<BiasLearnRateCoef>");
203  // max-norm regularization
204  WriteToken(os, binary, "<MaxNorm>");
205  WriteBasicType(os, binary, max_norm_);
206  if (!binary) os << "\n";
207 
208  // trainable parameters
209  WriteToken(os, binary, "<Filters>");
210  if (!binary) os << "\n";
211  filters_.Write(os, binary);
212  WriteToken(os, binary, "<Bias>");
213  if (!binary) os << "\n";
214  bias_.Write(os, binary);
215  }
216 
217  int32 NumParams() const {
218  return filters_.NumRows()*filters_.NumCols() + bias_.Dim();
219  }
220 
221  void GetGradient(VectorBase<BaseFloat>* gradient) const {
222  KALDI_ASSERT(gradient->Dim() == NumParams());
223  int32 filters_num_elem = filters_.NumRows() * filters_.NumCols();
224  gradient->Range(0, filters_num_elem).CopyRowsFromMat(filters_);
225  gradient->Range(filters_num_elem, bias_.Dim()).CopyFromVec(bias_);
226  }
227 
228  void GetParams(VectorBase<BaseFloat>* params) const {
229  KALDI_ASSERT(params->Dim() == NumParams());
230  int32 filters_num_elem = filters_.NumRows() * filters_.NumCols();
231  params->Range(0, filters_num_elem).CopyRowsFromMat(filters_);
232  params->Range(filters_num_elem, bias_.Dim()).CopyFromVec(bias_);
233  }
234 
235  void SetParams(const VectorBase<BaseFloat>& params) {
236  KALDI_ASSERT(params.Dim() == NumParams());
237  int32 filters_num_elem = filters_.NumRows() * filters_.NumCols();
238  filters_.CopyRowsFromVec(params.Range(0, filters_num_elem));
239  bias_.CopyFromVec(params.Range(filters_num_elem, bias_.Dim()));
240  }
241 
242  std::string Info() const {
243  return std::string("\n filters") + MomentStatistics(filters_) +
244  ", lr-coef " + ToString(learn_rate_coef_) +
245  ", max-norm " + ToString(max_norm_) +
246  "\n bias" + MomentStatistics(bias_) +
247  ", lr-coef " + ToString(bias_learn_rate_coef_);
248  }
249 
250  std::string InfoGradient() const {
251  return std::string("\n filters_grad") + MomentStatistics(filters_grad_) +
252  ", lr-coef " + ToString(learn_rate_coef_) +
253  ", max-norm " + ToString(max_norm_) +
254  "\n bias_grad" + MomentStatistics(bias_grad_) +
255  ", lr-coef " + ToString(bias_learn_rate_coef_);
256  }
257 
260  // useful dims
261  int32 num_splice = input_dim_ / patch_stride_;
262  int32 num_patches = 1 + (patch_stride_ - patch_dim_) / patch_step_;
263  int32 num_filters = filters_.NumRows();
264  int32 num_frames = in.NumRows();
265  int32 filter_dim = filters_.NumCols();
266 
267  // we will need the buffers
268  if (vectorized_feature_patches_.NumRows() != num_frames) {
269  vectorized_feature_patches_.Resize(num_frames, filter_dim * num_patches, kUndefined);
270  feature_patch_diffs_.Resize(num_frames, filter_dim * num_patches, kSetZero);
271  }
272 
273  /* Prepare feature patches, the layout is:
274  * |----------|----------|----------|---------| (in = spliced frames)
275  * xxx xxx xxx xxx (x = selected elements)
276  *
277  * xxx : patch dim
278  * xxx
279  * ^---: patch step
280  * |----------| : patch stride
281  *
282  * xxx-xxx-xxx-xxx : filter dim
283  *
284  */
285  // build-up a column selection map:
286  int32 index = 0;
287  column_map_.resize(filter_dim * num_patches);
288  for (int32 p = 0; p < num_patches; p++) {
289  for (int32 s = 0; s < num_splice; s++) {
290  for (int32 d = 0; d < patch_dim_; d++) {
291  column_map_[index] = p * patch_step_ + s * patch_stride_ + d;
292  index++;
293  }
294  }
295  }
296  // select the columns
297  CuArray<int32> cu_column_map(column_map_);
298  vectorized_feature_patches_.CopyCols(in, cu_column_map);
299 
300  // compute filter activations
301  for (int32 p = 0; p < num_patches; p++) {
302  CuSubMatrix<BaseFloat> tgt(out->ColRange(p * num_filters, num_filters));
304  p * filter_dim, filter_dim));
305  tgt.AddVecToRows(1.0, bias_, 0.0); // add bias
306  // apply all filters
307  tgt.AddMatMat(1.0, patch, kNoTrans, filters_, kTrans, 1.0);
308  }
309  }
310 
311  /*
312  This function does an operation similar to reversing a map,
313  except it handles maps that are not one-to-one by outputting
314  the reversed map as a vector of lists.
315  @param[in] forward_indexes is a vector of int32, each of whose
316  elements is between 0 and input_dim - 1.
317  @param[in] input_dim. See definitions of forward_indexes and
318  backward_indexes.
319  @param[out] backward_indexes is a vector of dimension input_dim
320  of lists, The list at (backward_indexes[i]) is a list
321  of all indexes j such that forward_indexes[j] = i.
322  */
323  void ReverseIndexes(const std::vector<int32> &forward_indexes,
324  std::vector<std::vector<int32> > *backward_indexes) {
325  int32 i;
326  int32 size = forward_indexes.size();
327  backward_indexes->resize(input_dim_);
328  int32 reserve_size = 2+ forward_indexes.size() / input_dim_;
329  std::vector<std::vector<int32> >::iterator iter = backward_indexes->begin(),
330  end = backward_indexes->end();
331  for (; iter != end; ++iter)
332  iter->reserve(reserve_size);
333  for (int32 j = 0; j < size; j++) {
334  i = forward_indexes[j];
336  (*backward_indexes)[i].push_back(j);
337  }
338  }
339 
340  /*
341  This function transforms a vector of lists into a list of vectors,
342  padded with -1.
343  @param[in] The input vector of lists. Let in.size() be D, and let
344  the longest list length (i.e. the max of in[i].size()) be L.
345  @param[out] The output list of vectors. The length of the list will
346  be L, each vector-dimension will be D (i.e. out[i].size() == D),
347  and if in[i] == j, then for some k we will have that
348  out[k][j] = i. The output vectors are padded with -1
349  where necessary if not all the input lists have the same side.
350  */
351  void RearrangeIndexes(const std::vector<std::vector<int32> > &in,
352  std::vector<std::vector<int32> > *out) {
353  int32 D = in.size();
354  int32 L = 0;
355  for (int32 i = 0; i < D; i++)
356  if (in[i].size() > L)
357  L = in[i].size();
358  out->resize(L);
359  for (int32 i = 0; i < L; i++)
360  (*out)[i].resize(D, -1);
361  for (int32 i = 0; i < D; i++) {
362  for (int32 j = 0; j < in[i].size(); j++) {
363  (*out)[j][i] = in[i][j];
364  }
365  }
366  }
367 
369  const CuMatrixBase<BaseFloat> &out,
370  const CuMatrixBase<BaseFloat> &out_diff,
371  CuMatrixBase<BaseFloat> *in_diff) {
372  // useful dims
373  int32 num_patches = 1 + (patch_stride_ - patch_dim_) / patch_step_;
374  int32 num_filters = filters_.NumRows();
375  int32 filter_dim = filters_.NumCols();
376 
377  // backpropagate to vector of matrices
378  // (corresponding to position of a filter)
379  for (int32 p = 0; p < num_patches; p++) {
380  CuSubMatrix<BaseFloat> patch_diff(feature_patch_diffs_.ColRange(
381  p * filter_dim, filter_dim));
382  CuSubMatrix<BaseFloat> out_diff_patch(out_diff.ColRange(
383  p * num_filters, num_filters));
384  patch_diff.AddMatMat(1.0, out_diff_patch, kNoTrans,
385  filters_, kNoTrans, 0.0);
386  }
387 
388  // sum the derivatives into in_diff, we will compensate #summands
389  std::vector<std::vector<int32> > reversed_column_map;
390  ReverseIndexes(column_map_, &reversed_column_map);
391  std::vector<std::vector<int32> > rearranged_column_map;
392  RearrangeIndexes(reversed_column_map, &rearranged_column_map);
393  for (int32 p = 0; p < rearranged_column_map.size(); p++) {
394  CuArray<int32> cu_cols(rearranged_column_map[p]);
395  in_diff->AddCols(feature_patch_diffs_, cu_cols);
396  }
397  }
398 
399 
400  void Update(const CuMatrixBase<BaseFloat> &input,
401  const CuMatrixBase<BaseFloat> &diff) {
402  // useful dims
403  int32 num_patches = 1 + (patch_stride_ - patch_dim_) / patch_step_;
404  int32 num_filters = filters_.NumRows();
405  int32 filter_dim = filters_.NumCols();
406 
407  // we use following hyperparameters from the option class
408  const BaseFloat lr = opts_.learn_rate;
409 
410  //
411  // calculate the gradient
412  //
413  filters_grad_.Resize(num_filters, filter_dim, kSetZero); // reset
414  bias_grad_.Resize(num_filters, kSetZero); // reset
415  // use all the patches
416  for (int32 p = 0; p < num_patches; p++) { // sum
417  CuSubMatrix<BaseFloat> diff_patch(diff.ColRange(p * num_filters,
418  num_filters));
420  p * filter_dim, filter_dim));
421  filters_grad_.AddMatMat(1.0, diff_patch, kTrans, patch, kNoTrans, 1.0);
422  bias_grad_.AddRowSumMat(1.0, diff_patch, 1.0);
423  }
424 
425  //
426  // update
427  //
430  //
431 
432  // max-norm
433  if (max_norm_ > 0.0) {
434  CuMatrix<BaseFloat> lin_sqr(filters_);
435  lin_sqr.MulElements(filters_);
436  CuVector<BaseFloat> l2(filters_.NumRows());
437  l2.AddColSumMat(1.0, lin_sqr, 0.0);
438  l2.ApplyPow(0.5); // we have per-neuron L2 norms
439  CuVector<BaseFloat> scl(l2);
440  scl.Scale(1.0/max_norm_);
441  scl.ApplyFloor(1.0);
442  scl.InvertElements();
443  filters_.MulRowsVec(scl); // shink to sphere!
444  }
445  }
446 
447  private:
449  patch_step_,
450  patch_stride_;
452 
456 
459 
461 
469  std::vector<int32> column_map_;
470 
477 };
478 
479 } // namespace nnet1
480 } // namespace kaldi
481 
482 #endif // KALDI_NNET_NNET_CONVOLUTIONAL_COMPONENT_H_
std::string ToString(const T &t)
Convert basic type to a string (please don&#39;t overuse),.
Definition: nnet-utils.h:52
This code computes Goodness of Pronunciation (GOP) and extracts phone-level pronunciation feature for...
Definition: chain.dox:20
std::string Info() const
Print some additional info (after <ComponentName> and the dims),.
int32 patch_step_
step of the convolution (i.e.
void SetParams(const VectorBase< BaseFloat > &params)
Set the trainable parameters from, reshaped as a vector,.
void ReverseIndexes(const std::vector< int32 > &forward_indexes, std::vector< std::vector< int32 > > *backward_indexes)
ConvolutionalComponent implements convolution over single axis (i.e.
void WriteData(std::ostream &os, bool binary) const
Writes the component content.
ComponentType GetType() const
Get Type Identification of the component,.
void GetGradient(VectorBase< BaseFloat > *gradient) const
Get gradient reshaped as a vector,.
NnetTrainOptions opts_
Option-class with training hyper-parameters,.
std::string MomentStatistics(const VectorBase< Real > &vec)
Get a string with statistics of the data in a vector, so we can print them easily.
Definition: nnet-utils.h:63
int32 input_dim_
Data members,.
void ReadBasicType(std::istream &is, bool binary, T *t)
ReadBasicType is the name of the read function for bool, integer types, and floating-point types...
Definition: io-funcs-inl.h:55
BaseFloat bias_learn_rate_coef_
Scalar applied to learning rate for bias (to be used in ::Update method),.
void ReadData(std::istream &is, bool binary)
Reads the component content.
BaseFloat learn_rate_coef_
Scalar applied to learning rate for weight matrices (to be used in ::Update method),.
Class UpdatableComponent is a Component which has trainable parameters, it contains SGD training hype...
CuMatrix< BaseFloat > filters_grad_
gradient of filters
void RandUniform(BaseFloat mu, BaseFloat range, CuMatrixBase< Real > *mat, struct RandomState *state=NULL)
Fill CuMatrix with random numbers (Uniform distribution): mu = the mean value, range = the &#39;width&#39; of...
Definition: nnet-utils.h:188
kaldi::int32 int32
void ReadToken(std::istream &is, bool binary, std::string *str)
ReadToken gets the next token and puts it in str (exception on failure).
Definition: io-funcs.cc:154
This class represents a matrix that&#39;s stored on the GPU if we have one, and in memory if not...
Definition: matrix-common.h:71
void RearrangeIndexes(const std::vector< std::vector< int32 > > &in, std::vector< std::vector< int32 > > *out)
void ApplyFloor(Real floor_val, MatrixIndexT *floored_count=NULL)
Definition: cu-vector.h:139
ComponentType
Component type identification mechanism,.
void AddCols(const CuMatrixBase< Real > &src, const CuArrayBase< MatrixIndexT > &indices)
Add column indices[r] of src to column r.
Definition: cu-matrix.cc:2701
void BackpropagateFnc(const CuMatrixBase< BaseFloat > &in, const CuMatrixBase< BaseFloat > &out, const CuMatrixBase< BaseFloat > &out_diff, CuMatrixBase< BaseFloat > *in_diff)
Backward pass transformation (to be implemented by descending class...)
std::string InfoGradient() const
Print some additional info about gradient (after <...> and dims),.
void InitData(std::istream &is)
Initialize the content of the component by the &#39;line&#39; from the prototype,.
int32 patch_stride_
shift for 2nd dim of a patch
CuMatrix< BaseFloat > filters_
(i.e. frame length before splicing)
BaseFloat max_norm_
limit L2 norm of a neuron weights to positive value
int32 NumParams() const
Number of trainable parameters,.
void AddVecToRows(Real alpha, const CuVectorBase< Real > &row, Real beta=1.0)
(for each row r of *this), r = alpha * row + beta * r
Definition: cu-matrix.cc:1261
void AddColSumMat(Real alpha, const CuMatrixBase< Real > &mat, Real beta=1.0)
Sum the columns of the matrix, add to vector.
Definition: cu-vector.cc:1298
void ExpectToken(std::istream &is, bool binary, const char *token)
ExpectToken tries to read in the given token, and throws an exception on failure. ...
Definition: io-funcs.cc:191
void MulElements(const CuMatrixBase< Real > &A)
Multiply two matrices elementwise: C = C .* A.
Definition: cu-matrix.cc:667
CuMatrix< BaseFloat > feature_patch_diffs_
Buffer for backpropagation: derivatives in the domain of &#39;vectorized_feature_patches_&#39;, 1row = vectorized rectangular feature patches, 1col = dim over speech frames,.
CuMatrix< BaseFloat > vectorized_feature_patches_
Buffer of reshaped inputs: 1row = vectorized rectangular feature patches, 1col = dim over speech fram...
#define KALDI_ERR
Definition: kaldi-error.h:147
void RandGauss(BaseFloat mu, BaseFloat sigma, CuMatrixBase< Real > *mat, struct RandomState *state=NULL)
Fill CuMatrix with random numbers (Gaussian distribution): mu = the mean value, sigma = standard devi...
Definition: nnet-utils.h:164
void AddMatMat(Real alpha, const CuMatrixBase< Real > &A, MatrixTransposeType transA, const CuMatrixBase< Real > &B, MatrixTransposeType transB, Real beta)
C = alpha * A(^T)*B(^T) + beta * C.
Definition: cu-matrix.cc:1291
This class is used for a piece of a CuMatrix.
Definition: matrix-common.h:70
void WriteToken(std::ostream &os, bool binary, const char *token)
The WriteToken functions are for writing nonempty sequences of non-space characters.
Definition: io-funcs.cc:134
MatrixIndexT Dim() const
Returns the dimension of the vector.
Definition: kaldi-vector.h:64
int PeekToken(std::istream &is, bool binary)
PeekToken will return the first character of the next token, or -1 if end of file.
Definition: io-funcs.cc:170
CuVector< BaseFloat > bias_
bias for each filter
int32 output_dim_
Dimension of the output of the Component,.
CuSubMatrix< Real > ColRange(const MatrixIndexT col_offset, const MatrixIndexT num_cols) const
Definition: cu-matrix.h:665
Matrix for CUDA computing.
Definition: matrix-common.h:69
void PropagateFnc(const CuMatrixBase< BaseFloat > &in, CuMatrixBase< BaseFloat > *out)
Abstract interface for propagation/backpropagation.
#define KALDI_ASSERT(cond)
Definition: kaldi-error.h:185
void Scale(Real value)
Definition: cu-vector.cc:1216
void WriteBasicType(std::ostream &os, bool binary, T t)
WriteBasicType is the name of the write function for bool, integer types, and floating-point types...
Definition: io-funcs-inl.h:34
Abstract class, building block of the network.
void GetParams(VectorBase< BaseFloat > *params) const
Get the trainable parameters reshaped as a vector,.
MatrixIndexT NumRows() const
Dimensions.
Definition: cu-matrix.h:215
Provides a vector abstraction class.
Definition: kaldi-vector.h:41
CuVector< BaseFloat > bias_grad_
gradient of biases
Component * Copy() const
Copy component (deep copy),.
#define KALDI_LOG
Definition: kaldi-error.h:153
ConvolutionalComponent(int32 dim_in, int32 dim_out)
void Update(const CuMatrixBase< BaseFloat > &input, const CuMatrixBase< BaseFloat > &diff)
Compute gradient and update parameters,.
int32 patch_dim_
number of consecutive inputs, 1st dim of patch
SubVector< Real > Range(const MatrixIndexT o, const MatrixIndexT l)
Returns a sub-vector of a vector (a range of elements).
Definition: kaldi-vector.h:94