// cudamatrix/cu-vector.h // Copyright 2009-2012 Karel Vesely // Johns Hopkins University (author: Daniel Povey) // Lucas Ondel // 2013 Xiaohui Zhang // 2015 Guoguo Chen // 2017 Daniel Galvez // 2019 Yiwen Shao // 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. #ifndef KALDI_CUDAMATRIX_CU_VECTOR_H_ #define KALDI_CUDAMATRIX_CU_VECTOR_H_ #include "matrix/kaldi-vector.h" #include "cudamatrix/cu-common.h" #include "cudamatrix/cu-value.h" #include "cudamatrix/cu-math.h" namespace kaldi { template class CuMatrixBase; template Real VecVec(const CuVectorBase &v1, const CuVectorBase &v2); template Real VecVec(const CuVectorBase &v1, const CuVectorBase &v2); /** * Vector for CUDA computing */ template class CuVectorBase { public: friend class CuVectorBase; friend class CuVectorBase; friend class CuMatrixBase; friend class MatrixBase; friend class CuPackedMatrix; friend class CuSpMatrix; friend class CuTpMatrix; template friend OtherReal VecVec(const CuVectorBase &v1, const CuVectorBase &v2); friend void cu::Splice(const CuMatrixBase &src, const CuArray &frame_offsets, CuMatrixBase *tgt); friend class CuRand; /// Dimensions MatrixIndexT Dim() const { return dim_; } /// Returns a pointer to the start of the vector's data. inline Real* Data() { return data_; } /// Returns a pointer to the start of the vector's data (const). inline const Real* Data() const { return data_; } /// Copy functions; these will crash if the dimension /// do not match. The operator = in class CuVector will /// also change the sizes for you. void CopyFromVec(const CuVectorBase &src); template void CopyFromVec(const CuVectorBase &M); template void CopyFromVec(const VectorBase &src); template void CopyToVec(VectorBase *dst) const; void CopyRowsFromMat(const CuMatrixBase &M); void CopyRowsFromMat(const MatrixBase &M); /// Math operations void SetZero(); void Set(Real value); void Add(Real value); void Scale(Real value); void AddVec(Real alpha, const CuVectorBase &vec, Real beta = 1.0); template void AddVec(Real alpha, const CuVectorBase &vec, Real beta = 1.0); /// Sum the rows of the matrix, add to vector void AddRowSumMat(Real alpha, const CuMatrixBase &mat, Real beta = 1.0); /// Sum the columns of the matrix, add to vector void AddColSumMat(Real alpha, const CuMatrixBase &mat, Real beta = 1.0); /// Add triangular matrix times vector: this <-- beta*this + alpha*M*v. /// Works even if rv == *this. void AddTpVec(const Real alpha, const CuTpMatrix&M, const MatrixTransposeType trans, const CuVectorBase &v, const Real beta); // **beta previously defaulted to 0.0** /// Multiplies this vector by lower-triangular marix: *this <-- *this *M void MulTp(const CuTpMatrix &M, const MatrixTransposeType trans); bool ApproxEqual(const CuVectorBase &other, float tol = 0.01) const; void InvertElements(); /// Copies selected elements from 'mat' to *this. Expects this->Dim() /// to equal elements.Dim(). If trans == kNoTrans, /// expects mat.NumRows() to equal this.Dim(), and for each i, /// copies mat(i, elements[i]) to (*this)(i). /// If trans == kTrans, /// expects mat.NumCols() to equal this.Dim(), and for each i, /// copies mat(elements[i], i) to (*this)(i). void CopyElements(const CuMatrixBase &mat, const MatrixTransposeType trans, const CuArrayBase &elements); void Floor(const CuVectorBase &src, Real floor_val, MatrixIndexT *floored_count = NULL); void Ceiling(const CuVectorBase &src, Real ceiling_val, MatrixIndexT *ceiled_count = NULL); void Pow(const CuVectorBase &src, Real power); inline void ApplyFloor(Real floor_val, MatrixIndexT *floored_count = NULL) { this -> Floor(*this, floor_val, floored_count); }; inline void ApplyCeiling(Real ceiling_val, MatrixIndexT *ceiled_count = NULL) { this -> Ceiling(*this, ceiling_val, ceiled_count); }; inline void ApplyPow(Real power) { this -> Pow(*this, power); }; void ApplySoftMax(); void ApplyLogSoftMax(); void ApplyExp(); void ApplyLog(); Real Sum() const; void SetRandn(); void SetRandUniform(); CuSubVector Range(const MatrixIndexT o, const MatrixIndexT l) { return CuSubVector(*this, o, l); } const CuSubVector Range(const MatrixIndexT o, const MatrixIndexT l) const { return CuSubVector(*this, o, l); } void CopyColFromMat(const CuMatrixBase &mat, MatrixIndexT col); template void CopyColFromMat(const CuMatrixBase &mat, MatrixIndexT col); void AddMatVec(const Real alpha, const CuMatrixBase &M, MatrixTransposeType trans, const CuVectorBase &v, const Real beta); void AddVecVec(Real alpha, const CuVectorBase &v, const CuVectorBase &r, Real beta); void AddSpVec(const Real alpha, const CuSpMatrix &S, const CuVectorBase &v, const Real beta); /// Add the diagonal of a matrix times itself: /// *this = diag(M M^T) + beta * *this (if trans == kNoTrans), or /// *this = diag(M^T M) + beta * *this (if trans == kTrans). void AddDiagMat2(Real alpha, const CuMatrixBase &M, MatrixTransposeType trans, Real beta); /// Add the diagonal of a matrix product: *this = diag(M N), assuming the /// "trans" arguments are both kNoTrans; for transpose arguments, it behaves /// as you would expect. void AddDiagMatMat(Real alpha, const CuMatrixBase &M, MatrixTransposeType transM, const CuMatrixBase &N, MatrixTransposeType transN, Real beta = 1.0); inline CuValue operator() (MatrixIndexT i) { KALDI_PARANOID_ASSERT(static_cast(i) < static_cast(dim_)); return CuValue(data_ + i); } Real Norm(Real p); // Only works for p = 1 and p = 2. inline Real operator() (MatrixIndexT i) const { KALDI_PARANOID_ASSERT(static_cast(i) < static_cast(dim_)); return CuValue(data_ + i); // will be casted to Real. } /// Extracts the diagonal of a packed matrix M; works for Sp or Tp. void CopyDiagFromPacked(const CuPackedMatrix &M); /// Extracts the diagonal of a matrix. void CopyDiagFromMat(const CuMatrix &M); /// Returns the maximum value of any element, or -infinity for the empty vector. Real Max() const; /// Returns the minimum value of any element, or +infinity for the empty vector. Real Min() const; // Set each element to y = (x == orig ? changed : x). void ReplaceValue(Real orig, Real changed); // Multiplies (*this) by v elementwise: (*this)[i] *= v void MulElements(const CuVectorBase &v); // Divides (*this) by v elementwise: (*this)[i] /= v void DivElements(const CuVectorBase &v); // The following two functions should only be called if we did not compile // with CUDA or could not get a CUDA card; in that case the contents are // interpreted the same as a regular vector. // Do not use the following functions unless you know what you are doing! inline const VectorBase &Vec() const { return *(reinterpret_cast* >(this)); } inline VectorBase &Vec() { return *(reinterpret_cast* >(this)); } protected: /// Default constructor: make it protected so the user cannot /// instantiate this class. CuVectorBase(): data_(NULL), dim_(0) { } Real *data_; ///< GPU data pointer (or regular data pointer ///< if CUDA is not compiled in or we have no GPU). MatrixIndexT dim_; ///< dimension of the vector private: KALDI_DISALLOW_COPY_AND_ASSIGN(CuVectorBase); }; template class CuVector: public CuVectorBase { friend class CuVectorBase; friend class CuVectorBase; friend class CuMatrixBase; friend class CuPackedMatrix; friend class CuSpMatrix; friend class CuTpMatrix; public: CuVector() { } CuVector(MatrixIndexT dim, MatrixResizeType t = kSetZero) { Resize(dim, t); } CuVector(const CuVectorBase &v); CuVector(const VectorBase &v); explicit CuVector(const CuVector &v) : CuVectorBase() { Resize(v.Dim(), kUndefined); this->CopyFromVec(v); } template explicit CuVector(const CuVectorBase &v) : CuVectorBase() { Resize(v.Dim(), kUndefined); this->CopyFromVec(v); } template explicit CuVector(const VectorBase &v) : CuVectorBase() { Resize(v.Dim(), kUndefined); this->CopyFromVec(Vector(v)); } /// Allocate the memory void Resize(MatrixIndexT dim, MatrixResizeType t = kSetZero); ~CuVector() { Destroy(); } CuVector &operator = (const CuVectorBase &other) { Resize(other.Dim(), kUndefined); this->CopyFromVec(other); return *this; } CuVector &operator = (const CuVector &other) { Resize(other.Dim(), kUndefined); this->CopyFromVec(other); return *this; } CuVector &operator = (const VectorBase &other) { Resize(other.Dim()); this->CopyFromVec(other); return *this; } void Swap(CuVector *vec); void Swap(Vector *vec); /// I/O void Read(std::istream &is, bool binary); void Write(std::ostream &is, bool binary) const; private: void Destroy(); }; // We'll fill out the following class if it's needed. template class CuSubVector: public CuVectorBase { public: CuSubVector(const CuVectorBase &t, const MatrixIndexT origin, const MatrixIndexT length) : CuVectorBase() { KALDI_ASSERT(static_cast(origin)+ static_cast(length) <= static_cast(t.Dim())); CuVectorBase::data_ = const_cast(t.Data()+origin); CuVectorBase::dim_ = length; } /// Copy constructor /// this constructor needed for Range() to work in base class. CuSubVector(const CuSubVector &other) : CuVectorBase () { CuVectorBase::data_ = other.data_; CuVectorBase::dim_ = other.dim_; } CuSubVector(const Real* data, MatrixIndexT length) : CuVectorBase () { // Yes, we're evading C's restrictions on const here, and yes, it can be used // to do wrong stuff; unfortunately the workaround would be very difficult. CuVectorBase::data_ = const_cast(data); CuVectorBase::dim_ = length; } /// This operation does not preserve const-ness, so be careful. CuSubVector(const CuMatrixBase &matrix, MatrixIndexT row) { CuVectorBase::data_ = const_cast(matrix.RowData(row)); CuVectorBase::dim_ = matrix.NumCols(); } }; /// I/O template std::ostream &operator << (std::ostream &out, const CuVectorBase &vec); template bool ApproxEqual(const CuVectorBase &a, const CuVectorBase &b, Real tol = 0.01) { return a.ApproxEqual(b, tol); } template inline void AssertEqual(const CuVectorBase &a, const CuVectorBase &b, Real tol = 0.01) { KALDI_ASSERT(a.ApproxEqual(b, tol)); } template template void CuVectorBase::CopyFromVec(const CuVectorBase &v) { v.CopyToVec(&this); } template template void VectorBase::CopyFromVec(const CuVectorBase &cu) { cu.CopyToVec(this); } // declare template specializations. template <> template <> void CuVectorBase::CopyFromVec(const CuVectorBase &src); template<> template <> void CuVectorBase::CopyFromVec(const CuVectorBase &src); template template Vector::Vector(const CuVectorBase &cu) { Init(cu.Dim()); cu.CopyToVec(this); } /// Returns \f$ v_1^T M v_2 \f$ . template Real VecMatVec(const CuVectorBase &v1, const CuMatrixBase &M, const CuVectorBase &v2); } // namespace #endif