The Nerv Matrix Package
Part of the Nerv toolkit.
Description
Underlying structure
In the begining is could be useful to know something about the underlying structure of a Nerv matrix. Please keep in mind that matrice in Nerv is row-major.
Every matrix object is a encapsulation of a C struct that describes the attributes of this matrix.
typedef struct Matrix {
size_t stride; /* size of a row */
long ncol, nrow, nmax; /* dimension of the matrix, nmax is simply nrow * ncol */
union {
float *f;
double *d;
long *i;
} data; /* pointer to actual storage */
long *data_ref;
} Matrix;
It is worth mentioning that that data_ref
is a counter which counts the number of references to its memory space, mind that it will also be increased when a row of the matrix is referenced(col = m[2]
). A Nerv matrix will deallocate its space when this counter is decreased to zero.
Also note that all assigning operation in Nerv is reference copy, you can use copy_tod
or copy_toh
method to copy value. Also, row assigning operations like m1[2]=m2[3]
is forbidden in Nerv.
Class hierarchy
The class hierarchy of the matrix classes can be clearly observed in matrix/init.c
.
First there is a abstract base class Nerv.Matrix, which is inherited by Nerv.CuMatrix and Nerv.MMatrix(also abstract).
Finally, there is Nerv.CuMatrixFloat, Nerv.CuMatrixDouble, inheriting Nerv.CuMatrix, and Nerv.MMatrixFloat, Nerv.MMatrixDouble, Nerv.MMatrixInt , inheriting Nerv.MMatrix.
Methods
Mind that usually a matrix object can only do calculation with matrix of its own type(a Nerv.CuMatrixFloat matrix can only do add operation with a Nerv.CuMatrixFloat).
In the methods description below, Matrix could be Nerv.CuMatrixFloat, Nerv.CuMatrixDouble, Nerv.MMatrixFloat or Nerv.MMatrixDouble. Element_type could be float
or double
, respectively.
* Matrix = Matrix(int nrow, int ncol)
Returns a Matrix object of nrow
rows and ncol
columns.
* Element_type = Matrix.get_elem(Matrix self, int index)
Returns the element value at the specific index(treating the matrix as a vector). The index should be less than nmax
of the matrix.
* void Matrix.set_elem(Matrix self, int index, Element_type value)
Set the value at index
to be value
.
* int Matrix.ncol(Matrix self)
Get ncol
, the number of columns.
* int Matrix.nrow(Matrix self)
Get nrow
, the number of rows.
* int Matrix.get_dataref_value(Matrix self)
Returns the value(not a pointer) of space the data_ref
pointer pointed to. This function is mainly for debugging.
* Matrix/Element_type, boolean Matrix.__index__(Matrix self, int index)
If the matrix has more than one row, will return the row at index
as a Matrix . Otherwise it will return the value at index
.
* void Matrix.__newindex__(Matrix self, int index, Element_type value)
Set the element at index
to be value
.
- Matrix Matrix.create(Matrix a)
Return a new Matrix ofa
's size(of the same number of rows and columns). - Matrix Matrix.colsum(Matrix self)
Return a new Matrix of size (1,self.ncol
), which stores the sum of all columns of Matrixself
. - Matrix Matrix.rowsum(Matrix self)
Return a new Matrix of size (self.nrow
,1), which stores the sum of all rows of Matrixself
. - Matrix Matrix.rowmax(Matrix self)
Return a new Matrix of size (self.nrow
,1), which stores the max value of all rows of Matrixself
. - Matrix Matrix.rowmax_idx(Matrix self)
Return two new Matrix of size (self.nrow
,1), which stores the max value of all rows of Matrixself
, and its corresponding column indices(start from zero). - Matrix Matrix.trans(Matrix self)
Return a new Matrix of size (self.ncol
,self.nrow
), which stores the transpose of Matrixself
. - void Matrix.copy_fromh(Matrix self, MMatrix a)
Copy the content of a MMatrixa
to Matrixself
, they should be of the same size. - void Matrix.copy_fromd(Matrix self, CuMatrix a)
Copy the content of a CuMatrixa
to Matrixself
, they should be of the same size. - void Matrix.copy_toh(Matrix self, MMatrix a)
Copy the content of the Matrixself
to a MMatrixa
. - void Matrix.copy_tod(Matrix self, CuMatrix a)
Copy the content of the Matrixself
to a CuMatrixa
. - void Matrix.copy_rows_fromh_by_idx(Matrix self, MMatrix ma, MMatrixInt idx, int idx_begin)
idx
should be a row vector. This function copy the rows ofma
toself
according toidx
, in other words, it assignsma[idx[i+idx_begin]]
toself[i]
. - void Matrix.copy_rows_fromd_by_idx(Matrix self, Matrix b, Matrix idx, int idx_begin)
idx
needs to a row vector matrix, it stacks the rows of indexidx
of the CuMatrixb
and copies toself
.idx_begin
is used as an offset in theidx
index array. - void Matrix.update_select_rows(Matrix self, Matrix err, Matrix idx, double alpha, double beta)
Update selected rows ofself
, i.e.self[idx[i]] = self[idx[i]] * (1 - beta * alpha) + alpha * err[i]
. - void Matrix.add(Matrix self, Matrix ma, Matrix mb, Element_type alpha, Element_type beta)
It sets the content of Matrixself
to bealpha * ma + beta * mb
.Matrixma,mb,self
should be of the same size. - void Matrix.mul(Matrix self, Matrix ma, Matrix mb, Element_type alpha, Element_type beta, [string ta, string tb])
It sets the content of Matrixself
to bebeta * self + alpha * ma * mb
.ta
andtb
is optional, ifta
is 'T', thenma
will be transposed, also iftb
is 'T',mb
will be transposed. - void Matrix.add_row(Matrix self, Matrix va, Element_type beta)
Addbeta * va
to every row of Matrixself
. - void Matrix.fill(Matrix self, Element_type value)
Fill the content of Matrixself
to bevalue
. - void Matrix.sigmoid(Matrix self, Matrix ma)
Set the element of Matrixself
to be elementwise-sigmoid ofma
. - void Matrix.sigmoid_grad(Matrix self, Matrix err, Matrix output)
Set the element of Matrixself
, to beself[i][j]=err[i][j]*output[i][j]*(1-output[i][j])
. This function is used to propagate sigmoid layer error. - Matrix Matrix.softmax(Matrix self, Matrix a)
Calculate a row-by-row softmax of Matrixa
and save the result inself
. Returns a newself.nrow*1
index matrix that stores the index of the maximum value of each row. - void Matrix.mul_elem(Matrix self, Matrix ma, Matrix mb)
Calculate element-wise multiplication of Matrixma
andmb
, store the result inself
. - void Matrix.log_elem(Matrix self, Matrix ma)
Calculate element-wise log of Matrixma
, store the result inself
. - void Matrix.expand_frm(Matrix self, Matrix a, int context)
Treating each row ofa
as speech feature, and do a feature expansion. Theself
should of size(a.nrow, a.ncol * (context * 2 + 1))
.self[i]
will be(a[i-context] a[i-context+1] ... a[i] a[i+1] a[i+context])
.a[0]
anda[nrow]
will be copied to extend the index range. - void Matrix.rearrange_frm(Matrix self, Matrix a, int step)
Rearrangea
according to its feature dimension. Thestep
is the length of context. So,self[i][j]
will be assigneda[i][j / step + (j % step) * (a.ncol / step)]
.a
andself
should be of the same size andstep
should be divisible bya.ncol
. - void Matrix.scale_row(Matrix self, Matrix scale)
Scale each column ofself
according to a vectorscale
.scale
should be of size1 * self.ncol
. - Matrix Matrix.__add__(Matrix ma, Matrix mb)
Returns a new Matrix which stores the result ofma+mb
. - Matrix Matrix.__sub__(Matrix ma, Matrix mb)
Returns a new Matrix which stores the result ofma-mb
. - Matrix Matrix.__mul__(Matrix ma, Matrix mb)
Returns a new Matrix which stores the result ofma*mb
. - CuMatrix CuMatrix.new_from_host(MMatrix m)
Return a new CuMatrix which is a copy ofm
. - MMatrix CuMatrix.new_to_host(CuMatrix self)
Return a new MMatrix which is a copy ofself
. - string Matrix.__tostring__(Matrix self)
Returns a string containing values of Matrixself
.
- MMatrix MMatrix.load(ChunkData chunk)
Return a new MMatrix loaded from the file position inchunk
. - void MMatrix.save(MMatrix self, ChunkFileHandle chunk)
Writeself
to the file position inchunk
. - void MMatrix.copy_from(MMatrix ma, MMatrix mb,[int b_bgein, int b_end, int a_begin])
Copy a part ofmb
(rows of index[b_begin..b_end)
) toma
beginning at row indexa_begin
. If not specified,b_begin
will be0
,b_end
will beb.nrow
,a_begin
will be0
.
Examples
- Use
get_dataref_value
to test Nerv's matrix space allocation.
m = 10
n = 10
fm = nerv.MMatrixFloat(m, n)
dm = nerv.MMatrixDouble(m, n)
for i = 0, m - 1 do
for j = 0, n - 1 do
t = i / (j + 1)
fm[i][j] = t
dm[i][j] = t
end
end
print("test fm:get_dataref_value:", fm:get_dataref_value())
print("forced a garbade collect")
collectgarbage("collect")
print("test fm:get_dataref_value:", fm:get_dataref_value())
print(fm)
print(dm)
- Test some Matrix calculations.
m = 4
n = 4
fm = nerv.CuMatrixFloat(m, n)
dm = nerv.CuMatrixDouble(m, n)
for i = 0, m - 1 do
for j = 0, n - 1 do
-- local t = math.random(10)
t = i / (j + 1)
fm[i][j] = t
dm[i][j] = t
end
end
print(fm)
fs = fm:create()
fs:softmax(fm)
-- print(fs)
print(dm)
ds = dm:create()
ds:softmax(dm)
-- print(ds)
print(fs)
print(fs + fs)
print(ds + ds)
print(fs - fs)
print(ds - ds)
a = fs:create()
a:mul_elem(fs, fs)
print(a)
a:log_elem(fs)
print(a)