5. mannix functions - eliyahudev/mannix GitHub Wiki
This section will be focus on the main functions of mannix:
- convolution.
- maxpooling.
- Fully-connected (matrix multiplication).
- activation (reLU).
All the function used in this library are based on matrix operations. Even more complicated functions (tensor based) are still based on matrix (2D - see comment below) operation with inner loops. The follow part will show how to use each function.
Let's create a new main.c file. The matrix convolution function
Matrix_int32* matrixConvolution(Matrix_uint8* m1, Matrix_int8* m_filter, int bias, Matrix_int32* result_matrix);
obtains 4 parameters:
- input matrix (Matrix_uint8);
- feature matrix (Matrix_int8);
- bias (integer);
- output matrix (Matrix_int32);
first we declare the 4 parameters:
#include "../include/cnn_inc.h" int main() { #include "../include/tensor_allocation_setup.h" Matrix_uint8 input_mat[1]; Matrix_int8 conv_filter[1]; Matrix_int32 conv_bias[1]; Matrix_int32 result_mat[1];
Notice that we used different types of matrices, and for each we are using different C'tor-like and load functions.
// C'tor like functions creatMatrix_uint8(4, 4, &input_mat[0], (Allocator_uint8*) al); creatMatrix_int8(3, 3, &conv_filter[0], (Allocator_int8*) al); creatMatrix_int32(1, 1, &conv_bias[0], (Allocator_int32*) al); creatMatrix_int32(2, 2, &result_mat[0], (Allocator_int32*) al);
For this example we will read the data from csv. we will create 3 csv files for input, filter and bias matrices.
// load data from csv FILE* fd = fopen("../examples/matrix.csv","r"); FILE* fd_filter = fopen("../examples/filter.csv","r"); FILE* fd_bias = fopen("../examples/bias.csv","r"); int label[1]; label[0] = 0; // needed only for matrix with label getMatrix_uint8(input_mat, fd, label,-1, 1); getMatrix_int8(conv_filter, fd_filter, label,-1, 1); getMatrix_int32(conv_bias, fd_bias, label,-1, 1);
Now we are ready to use the convolution operation:
// Matrix convolution matrixConvolution(input_mat, conv_filter, conv_bias->data[0], result_mat);
And finally let's print the results:
// print results printf("printMatrix_int8(input_mat):\n"); printMatrix_uint8(input_mat); printf("\n\n"); printf("printMatrix_int8(conv_filter):\n"); printMatrix_int8(conv_filter); printf("\n\n"); printf("printMatrix_int32(conv_bias):\n"); printMatrix_int32(conv_bias); printf("\n\n"); printf("printMatrix_int32(result_mat):\n"); printMatrix_int32(result_mat); return 0; }
and the results are:
printMatrix_int8(input_mat): [1 2 3 4 ] [5 6 7 8 ] [9 10 11 12 ] [13 14 15 16 ]
printMatrix_int8(conv_filter): [1 0 0 ] [0 1 0 ] [0 0 1 ]
printMatrix_int32(conv_bias): [500 ]
printMatrix_int32(result_mat): [518 521 ] [530 533 ]
Max pool is easier to understand. The function:
Matrix_uint8* matrixMaxPool(Matrix_uint8* m1, Matrix_uint8* m2, int p_m, int p_n, int stride);
contains:
- input matrix (Matrix_uint8);
- output matrix (Matrix_int32);
- window sizes.
- stride.
As before we define and load data from csv file.
#include "../include/cnn_inc.h"
int main() {
#include "../include/tensor_allocation_setup.h" Matrix_uint8 input_mat[1]; Matrix_uint8 result_mat[1]; // C'tor like functions creatMatrix_uint8(4, 4, &input_mat[0], (Allocator_uint8*) al); creatMatrix_uint8(2, 2, &result_mat[0], (Allocator_uint8*) al); // load data from csv FILE* fd = fopen("../examples/matrix.csv","r"); int label[1]; label[0] = 0; // needed only for matrix with label getMatrix_uint8(input_mat, fd, label,-1, 1); // Matrix maxpolling // Matrix_uint8* matrixMaxPool(Matrix_uint8* m1, Matrix_uint8* m2, int p_m, int p_n, int stride){ matrixMaxPool(input_mat, result_mat, 2, 2, 2); // print results printf("printMatrix_uint8(input_mat):\n"); printMatrix_uint8(input_mat); printf("\n\n"); printf("printMatrix_uint8(result_mat):\n"); printMatrix_uint8(result_mat); return 0; }
The last function:
Matrix_uint8* matrixFCNActivate(Matrix_uint8* input_matrix, Matrix_int8* weight_matrix, Matrix_int32* bias_vector, Matrix_uint8* result_matrix, Allocator_int32* al, int sc);
and contains:
- input matrix (Matrix_uint8) - in a vector shape (after flattening);
- feature matrix (Matrix_int8) ;
- bias (integer) - in a vector shape ;
- output matrix (Matrix_int32);
- data allocator.
- scale factor - insted of signed int8 we can re scale the output (for example divided by 2^(7+scale_factor)).
The function is divided to 3 parts:
- matrix multiplication.
- matrix sum (for bias).
- activation.
Let's create again a new example:
#include "../include/cnn_inc.h"
int main() {
#include "../include/tensor_allocation_setup.h" Matrix_uint8 input_mat[1]; Matrix_int8 conv_filter[1]; Matrix_int32 conv_bias[1]; Matrix_uint8 result_mat[1]; // C'tor like functions creatMatrix_uint8(4, 1, &input_mat[0], (Allocator_uint8*) al); creatMatrix_int8(4, 4, &conv_filter[0], (Allocator_int8*) al); creatMatrix_int32(4, 1, &conv_bias[0], (Allocator_int32*) al);
notice that this function does not need memory allocation for the result matrix or dimention declaration. Actually, none of the function that we will use for a complete model need.
// load data from csv FILE* fd = fopen("../examples/input_vector.csv","r"); FILE* fd_filter = fopen("../examples/fc_weights.csv","r"); FILE* fd_bias = fopen("../examples/bias_vector.csv","r"); int label[1]; label[0] = 0; // needed only for matrix with label getMatrix_uint8(input_mat, fd, label,-1, 1); getMatrix_int8(conv_filter, fd_filter, label,-1, 1); getMatrix_int32(conv_bias, fd_bias, label,-1, 1);
now we can use the fully-connected function:
matrixFCNActivate(input_mat, conv_filter, conv_bias, result_mat, (Allocator_int32*) al, 1);
and finally let's print the results:
// print results printf("printMatrix_int8(input_mat):\n"); printMatrix_uint8(input_mat); printf("\n\n"); printf("printMatrix_int8(conv_filter):\n"); printMatrix_int8(conv_filter); printf("\n\n"); printf("printMatrix_int32(conv_bias):\n"); printMatrix_int32(conv_bias); printf("\n\n"); printf("printMatrix_int32(result_mat):\n"); printMatrix_uint8(result_mat); return 0;
}
We went through the main functions of mannix matrix, but when we move to complete model where tensors are involve, it can be much more complicated. The tensor functions are have three main goals:
- Allocate data, matrix and tensors.
- Calculate the tensors dimensions.
- Calculate complicated operations.
Create a dump file from csv can be rather exhaustive. To avoid complicated load function, we use the follow functions:
- void setFilter(Tensor4D_int8 *tens_4d, char *path, int layer) - get a 4 dimension tensor as an input, the path to the csv directory, and the layer number. it only get data with the format:
conv<layer_number>_w_<#_filter>_<#_matrix (in the filter)>.csv
for example the csv files for filter 0 (with a depth of 6) in the first convolution layer :
conv1_w_0_0.csv conv1_w_0_1.csv conv1_w_0_2.csv conv1_w_0_3.csv conv1_w_0_4.csv conv1_w_0_5.csv
- void setBias(Matrix_int32 *bias, char *file_path, char *type, int layer, char *w_b) - get a matrix as an input, the name of the operation, layer number. it get data with the format:
<operation_name><#_layer>_b.csv
for example:
fc1_b.csv
- void setWeight(Matrix_int8 *weight, char *file_path, char *type, int layer, char *w_b) - work the same as setBias.
- setImage(&image[0], imageFilePointer) - load input data to a 4D tensor. NOTICE! the input should be load ONLY after the weights and biases are loaded.
Now that we have all the information, we can build a complete model. This will be the purpose of the next section.