kaldi中的Vector和Matrix

kaldi中的Vector和Matrix

    Vector和Matrix是kaldi中最常用的数据类型之一。语音数据,提取的特征,计算的结果,都保存在Vector或者Matrix之中。按照字面意思,Vector是“向量”,它只有一行数据,是一维的。Matrix是“矩阵”,它有行与列两个维度。kaldi中的Vector和Matrix,可以做许多数学上的操作。比如点加或点乘(每个元素都加上一个数,或者乘以一个数),比如矩阵之间的乘法和矩阵的奇异分解等。kaldi中Vector和Matrix还可以做一些特殊操作,比如对每个元素取对数,对所有元素做softmax等。

一、首先介绍下Vector。
    在matrix/kaldi-vector.h中,定义了三个类:VectorBase、Vector和SubVector。其中,VectorBase是基类(父类),Vector和SubVector是派生类(子类)。VectorBase中的成员函数已经可以完成一个向量类的所有操作了,Vector类只是做了封装,定义了多种形式的构造函数,增加了resize操作等。
    VectorBase类中的数据成员十分简单,就两个成员。一个指针data_指向存放数据的内存,一个整数dim_指示元素的个数。
VectorBase中的函数成员比较多,但基本可以分为两类。一类是基本的、简单的操作。例如SetZero函数,用以设置全部数据为0;例如max函数,返回向量中的最大值。另一类是偏应用的函数或操作。比如,ApplySoftMax函数,提供softmax操作;比如Norm函数,计算范数。

    下面的代码,有利于理解VectorBase的各种性质。注意,为了方面阅读和理解,对源代码做了修改。

template<typename Real>
class VectorBase {
  // *******数据成员,data_表示内存地址,dim_表示元素个数*******
  Real* data_;
  MatrixIndexT dim_;
  explicit VectorBase(): data_(NULL), dim_(0) { }
  
  // **************第一类,比较基础和简单的函数*******************
  // set类函数,设置全部值为0、特定值或者某种分布的随机值
  void SetZero();
  void Set(Real f);
  void SetRandn();
  void SetRandUniform();

  // 返回元素个数dim_,返回元素地址data_,返回占用内存大小,重载()操作等
  inline MatrixIndexT Dim() const { return dim_; }
  inline Real* Data() { return data_; }
  inline MatrixIndexT SizeInBytes() const { return (dim_*sizeof(Real)); }
  inline Real operator() (MatrixIndexT i) const { return *(data_ + i);  }
  inline Real & operator() (MatrixIndexT i) {   return *(data_ + i);  }
  Real Max() const;
  Real Min() const;
  Real Sum() const;
  Real SumLog() const;
  
  // 拷贝向量或者矩阵(全部或者局部,例如一行)的内容,来作为data_
  void CopyFromVec(const VectorBase<Real> &v);
  void CopyFromPacked(const PackedMatrix<Real> &M);
  void CopyRowsFromMat(const MatrixBase<Real> &M);
  void CopyColsFromMat(const MatrixBase<Real> &M);
  void CopyRowFromMat(const MatrixBase<Real> &M, MatrixIndexT row);
  void CopyDiagFromMat(const MatrixBase<Real> &M);
  
  // **************第二类,偏应用的操作和函数*******************
  void Add(Real c); 	 /// data_[i] += c;
  void Scale(Real c);	 /// data_[i] *= c; cblas_Xscal(dim_, c, data_, 1);
  void ApplyLog();  	 /// data_[i] = Log(data_[i])
  void ApplyExp();  	 /// data_[i] = Exp(data_[i])
  void ApplyAbs();  	 /// data_[i] = abs(data_[i])
  void InvertElements(); /// data_[i] = 1 / data_[i]
  void ApplyPow(Real power);  // 求指数
  Real Norm(Real p) const;    // 求p阶范数
  void MulElements(const VectorBase<Real> &v); //data_[i] *= v.data_[i];
  void DivElements(const VectorBase<Real> &v); //data_[i] /= v.data_[i];

  //各种形式的矩阵操作,一般调用BLAS,例如 AddVec: *this = *this + alpha * rv 
  void AddVec(const Real alpha, const VectorBase<Real> &v);
  void AddVec2(const Real alpha, const VectorBase<Real> &v); // rv^2
  void AddMatVec(...);	//  this <-- beta*this + alpha*M*v.
  void AddSpVec(...) 	//  this <-- beta*this + alpha*M*v.
  void AddTpVec(...) 	//  this <-- beta*this + alpha*M*v.
  void AddVecVec(...);	//  this <-- alpha * v .* r + beta*this .
  void AddVecDivVec(...);// this <---- alpha*v/r + beta*this
  void MulTp(...);		//  *this <-- *this *M
  
  //使用softmax: \f$ x(i) = exp(x(i)) / \sum_i exp(x(i)) \f$
  Real ApplySoftMax(){
    Real max = this->Max(), sum = 0.0;
    for (MatrixIndexT i = 0; i < dim_; i++)
      sum += (data_[i] = Exp(data_[i] - max));
    this->Scale(1.0 / sum);
    return max + Log(sum);
  }
  void Tanh(const VectorBase<Real> &src);
  void Sigmoid(const VectorBase<Real> &src);
}; // class VectorBase


template<typename Real>
class Vector: public VectorBase<Real> {
 public:
  // 各种构造函数和赋值操作。
  Vector(): VectorBase<Real>() {}
  explicit Vector(const MatrixIndexT s, MatrixResizeType resize_type)
      : VectorBase<Real>() {  Resize(s, resize_type);  }
  Vector(const Vector<Real> &v) : VectorBase<Real>()  { 
    Resize(v.Dim(), kUndefined);
    this->CopyFromVec(v);  }
  explicit Vector(const VectorBase<Real> &v) : VectorBase<Real>() {
    Resize(v.Dim(), kUndefined);
    this->CopyFromVec(v);  }
  Vector<Real> &operator = (const Vector<Real> &other) {
    Resize(other.Dim(), kUndefined);
    this->CopyFromVec(other);
    return *this; }

  // 新增的Swap、Resize和RemoveElement操作
  void Swap(Vector<Real> *other);
  void Resize(MatrixIndexT length, MatrixResizeType resize_type = kSetZero);
  void RemoveElement(MatrixIndexT i);

 private:
  void Init(const MatrixIndexT dim);
  void Destroy();
};

template<typename Real>
class SubVector : public VectorBase<Real> {
 public:
  //SubVector不分配内存,它使用其他VectorBase的数据,可以看作是“引用”。
  // 下面是各种版本的构造函数。
  SubVector(const VectorBase<Real> &t, const MatrixIndexT origin,
            const MatrixIndexT length) : VectorBase<Real>() {
     VectorBase<Real>::data_ = const_cast<Real*> (t.Data()+origin);
    VectorBase<Real>::dim_   = length;
  }
  SubVector(const PackedMatrix<Real> &M) {
    VectorBase<Real>::data_ = const_cast<Real*> (M.Data());
    VectorBase<Real>::dim_   = (M.NumRows()*(M.NumRows()+1))/2;
  }
  SubVector(const SubVector &other) : VectorBase<Real> () {// Copy constructor
    VectorBase<Real>::data_ = other.data_;
    VectorBase<Real>::dim_ = other.dim_;
  }
  SubVector(Real *data, MatrixIndexT length) : VectorBase<Real> () {
    VectorBase<Real>::data_ = data;
    VectorBase<Real>::dim_   = length;
  }
  SubVector(const MatrixBase<Real> &matrix, MatrixIndexT row) {
    VectorBase<Real>::data_ = const_cast<Real*>(matrix.RowData(row));
    VectorBase<Real>::dim_   = matrix.NumCols();
  }
  ~SubVector() {}  ///< Destructor (does nothing; no pointers are owned here).

 private:
  /// Disallow assignment operator.
  SubVector & operator = (const SubVector &other) {}
};

 通过上面的代码,我们可以看出,Vector对VectorBase并未做太多的扩展,它们的功能基本一样。SubVector可以看作一种“引用”,它自身并不分配内存保存数据,而是指向了其他的对象中的数据。


二、简单介绍下Matrix。
    跟Vector类似,在在matrix/kaldi-matrix.h中,定义了三个类:MatrixBase、Matrix和SubMatrix。MatrixBase是基类,另外两个是派生类。MatrixBase已经实现了非常多的方法。Matrix只是在基类的基础上,加了少数几个函数,比如Swap和RemoveRow等,这点跟Vector与VectorBase的关系一样。
    MatrixBase中,数据成员并不多,大部分也容易理解。比如,整数num_rows_和num_cols_表示矩阵的行数和列数,指针data_指向保存数据的内存地址。这里有另外一个整型变量stride_需要注意。stride_保存的是正真的一行的个数。这里的意思是,一个矩阵,一行可能可以存放许多数据(stride_个),但可以不放满,只放num_cols_个。这时,一部分空间是浪费的。当然,一般部分情况下,num_cols_和stride_是一致的。
    在矩阵上面的操作要比向量上的操作多,所以Matrix中的成员函数比Vector中的多很多。

template<typename Real>
class MatrixBase {
  //***************数据成员********************
  Real*   data_;             // data memory area
  MatrixIndexT  num_cols_;   // < Number of columns
  MatrixIndexT  num_rows_;   // < Number of rows
  MatrixIndexT  stride_;     // True number of columns 
  
  // 基本操作函数
  inline MatrixIndexT NumRows() const { return num_rows_; }
  inline MatrixIndexT NumCols() const { return num_cols_; }
  inline MatrixIndexT Stride() const {  return stride_; }
  inline Real* Data() const { return data_;  }
  inline Real* RowData(MatrixIndexT i) { return data_ + i * stride_;  }
  inline Real&  operator() ( r,  c) {return *(data_ + r * stride_ + c);  }
  size_t SizeInBytes() const {return num_rows_ * stride_ * sizeof(Real);}
  Real &Index (MatrixIndexT r, MatrixIndexT c) {  return (*this)(r, c); }

  // set、max、min等函数,省略若干
  void SetZero();
  void Set(Real);
  Real Sum() const;
  Real Max() const;
  Real Min() const;
  bool IsZero(Real cutoff = 1.0e-05) const;

  //Copy、SubVector、SubMatrix类函数,很多版本
  void CopyFromMat(const CompressedMatrix &M);
  void CopyRowsFromVec(const VectorBase<Real> &v);
  void CopyDiagFromVec(const VectorBase<Real> &v);
  inline SubVector<Real> Row(MatrixIndexT i);
  inline SubMatrix<Real> Range(...);

  // 一些加减乘除操作,其他应用操作
  void MulElements(const MatrixBase<Real> &A);
  void DivElements(const MatrixBase<Real> &A);
  void Scale(Real alpha);
  void Max(const MatrixBase<Real> &A);
  void Min(const MatrixBase<Real> &A);
  void MulColsVec(const VectorBase<Real> &scale);
  void MulRowsVec(const VectorBase<Real> &scale);
  void Add(const Real alpha);
  void ApplyFloor(Real floor_val);
  void ApplyCeiling(Real ceiling_val);
  void ApplyLog();
  void ApplyExp();
  Real ApplySoftMax();
  void Sigmoid(const MatrixBase<Real> &src);

  // 求正定矩阵、求逆;转置;特征分解;奇异值分解;矩阵运算
  Real LogDet(Real *det_sign = NULL) const;
  void Invert(Real *log_det = NULL, Real *det_sign = NULL,
              bool inverse_needed = true);
  void Transpose();
  void Eig(MatrixBase<Real> *P,
           VectorBase<Real> *eigs_real,
           VectorBase<Real> *eigs_imag) const;
  void Svd(VectorBase<Real> *s, MatrixBase<Real> *U,
           MatrixBase<Real> *Vt) const;
  void AddVecVec(...) //*this += alpha * a * b^T
  void AddMat(...) //*this += alpha * M
  void AddMatMatMat(...) //this <-- beta*this + alpha*A*B*C.
  void AddTpTp(...) //this <-- beta*this + alpha*A*B.
};



版权声明:本文为u013677156原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。