-
Notifications
You must be signed in to change notification settings - Fork 7
Nerlnet NIF Implementation
Erlang NIF and Nifpp are the building blocks of Nerlnet NIF implementation. Nerlnet NIF is based on nifpp wraper that wraps Erlang NIF.
This is a short explanation of important functions that form the core of Nerlnet NIF implementation:
Example:
static ErlNifFunc nif_funcs[] = {
// Structure of each cell:
{"<name of function in erlang>", Arity, <name of implemented function in C/Cpp>},
// Examples from Nerlnet code:
{"train_predict_create", 5, train_predict_create_nif},
{"create_module", 6, train_predict_create_nif},
{"get_weights", 1, get_weights_nif},
{"set_weights", 3, set_weights_nif}
};
Example of an implemented function:
static ERL_NIF_TERM train_predict_create_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
// Here implementing using NIF or nifpp API to get arguments from argv
// argc equals to arity
// Each argument of argv array has a corresponding argument in NIF API called from Erlang code.
}
static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
.
This function is not in use.
load_info is the second argument to erlang:load_nif/2.
*priv_data can be set to point to some private data if the library needs to keep a state between NIF calls.
enif_priv_data returns this pointer. *priv_data is initialized to NULL when load is called.
The library fails to load if load returns anything other than 0. load can be NULL if initialization is not needed.
int enif_thread_create(char *name, ErlNifTid *tid, void * (*func)(void *), void *args, ErlNifThreadOpts *opts)
Start a thread with func function.
name - A string (array of chars) that identifies the created thread.
It is used to identify the thread in planned future debug functionality.
tid - A pointer to a thread identifier variable.
func - A pointer to a function to execute in the created thread.
arg - A pointer to argument to the func function.
opts - A pointer to thread options to use or NULL.
Returns 0 on success, otherwise an errno value is returned to indicate the error.
The newly created thread begins executing in the function pointed to by func, and func is passed arg as argument.
When erl_drv_thread_create returns, the thread identifier of the newly created thread is available in *tid.
opts can be either a NULL pointer, or a pointer to an ErlDrvThreadOpts structure.
If opts is a NULL pointer (0), default options are used, otherwise the passed options are used.
NerlnetNIF uses this function to start a dirty thread that performs machine learning tasks, e.g., train or predict phases.
At the end of the task a message is sent back to the process that invoked the dirty thread.
ERL_NIF_INIT(erlModule, nif_funcs, load, NULL, NULL, NULL)
.
This is the magic macro to initialize a NIF library. It is to be evaluated in global file scope.
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, NULL, upgrade, unload)
MODULE - The first argument must be the name of the Erlang module as a C-identifier. It will be stringified by the macro.
ErlNifFunc - The second argument is the array of ErlNifFunc structures containing name, arity, and function pointer of each NIF.
load - is called when the NIF library is loaded and no previously loaded library exists for this module.
NULL - The fourth argument NULL is ignored. It was earlier used for the deprecated reload callback which is no longer supported since OTP 20.
The remaining arguments are pointers to callback functions that can be used to initialize the library.
They are not used in this simple example, hence they are all set to NULL.
The NerlLayer is a Component in NerlNif, it's to allow us abstraction in our libraries. NerlLayer represent Layer in NN It's not connected to opennn and have variables of NerlLayer, next_layer, prev_layer-previous and next layers in the NN layers_dims-dimensions layer_type-type of layer layer_functionality- functionality of layer there are also 2 classes who inherited from NerlLayer (NerlLayerCnn and NerlLayerPooling) in those layers, we add variables on NerlLayer. In NerlLayer we also define the size in vector, it's in vector to allow us to use layers with multiple dimensions in NerlLayerCnn we add kernel, padding, stride, type in NerlLayerPooling we add padding, stride.
The NerlWorker class, defines set of APIs between NIF and Erlang and between NIF and NN Cpp libraries. It represents an edge worker of Nerlnet. Arguments to generate a Nerlworker inherited class are: model_type, model_args, distributed_system_type, learning_rate, epochs, optimizer_type, loss_method.
NerlWorker also responsible for parsing the input strings and deal with complex layers of higher dimensions such as convolutional layers.
The NerlWorkerOpenNN class inherits from Nerlworker and implement the support of NN infra based on OpenNN. NerlWorkerOpenNN has translations methods that encode model parameters to OpenNN enums and convert nerltensor to Eigen tensor to represent dataset and other objects of OpenNN.
TODO
The script of NerlnetBuild.sh generates a shared library (.so) of Nerlnet NIF implementation. The shared library contains the infrastructure code (E.g., OpenNN), and the bridge that connects it with Nerlnet distributed ML application. The shared library is loaded in application and adds Nerlnet NIF functionality to Erlang VM.