This file contains information about the general use of Flint in its C compatibility mode. Remember to set the CMake flag, s.t. no Exceptions are thrown.
Instead the function will return NULL, and set the errno (see the error related functions of flint for
more context).
In general all operations that take two parameters of equal shape (like e.g.
addition, division, minimum, equal etc.) allow normal and inverse broadcasting.
Broadcasting is implemented without repeating the data, but by directly accessing it.
- normal broadcasting: a node with shape [4, 6, 8] can be broadcasted to a node with shape [2, 4, 6, 8] by repeating the first node 2 times in the first dimension.
- inverse broadcasting: a node with shape [2, 4, 6] can be broadcasted to a node with shape [2, 4, 6, 8] by repeating the first node 8 times in the last dimension.
float data_a[] = {0, 1, 2, 3, 4, 5}; double shape_a[] = {2, 3}; float data_b[] = {2, 4, 6}; double shape_b = 3; FGraphNode* a = fCreateGraph((void*)data_a, 6, F_FLOAT32, shape_a, 2); FGraphNode* b = fCreateGraph((void*)data_b, 3, F_FLOAT32, &shape_b, 1); FGraphNode* c = fmul(a, b); // {{2, 5, 8}, {5, 8, 11}}
Broadcasting is implemented without repeating the data, but by directly accessing it.
Overview
Types and Functions • enum FErrorType
• FErrorType flintInit(int backends)
• FErrorType flintInit_cpu()
• FErrorType flintInit_gpu()
• int flintInitializedBackends()
• FErrorType flintCleanup()
• FErrorType flintCleanup_cpu()
• FErrorType flintCleanup_gpu()
• enum FLogType
• void fSetLoggingLevel(enum FLogType type)
• enum FImageFormat
• void flogging(enum FLogType type, const char *msg)
• FErrorType fErrorType()
• const char *fErrorMessage()
• void fEnableEagerExecution()
• void fDisableEagerExecution()
• int fIsEagerExecution()
• enum FType
• struct FOperation
• struct FResultData
• struct FGraphNode
• struct FStore
• FGraphNode *fCreateGraph(const void *data, const int num_entries, const enum FType data_type, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_i(const int value, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_l(const long value, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_f(const float value, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_d(const double value, const size_t *shape, const int dimensions)
• FGraphNode *frandom(const size_t *shape, const int dimensions)
• FGraphNode *farange(const size_t *shape, const int dimensions, const int ax)
• void fFreeGraph(FGraphNode *graph)
• FGraphNode *fExecuteGraph(FGraphNode *node)
• FGraphNode *fExecuteGraph_cpu(FGraphNode *node)
• FGraphNode *fExecuteGraph_gpu(FGraphNode *node)
• FGraphNode *fExecuteGraph_cpu_eagerly(FGraphNode *node)
• FGraphNode *fExecuteGraph_gpu_eagerly(FGraphNode *node)
• FResultData *fSyncMemory(FGraphNode *data)
• FGraphNode *fCalculateResult(FGraphNode *node)
• FGraphNode *fCalculateGradient(FGraphNode *outputfct, FGraphNode *dx)
• FErrorType fCalculateGradients(FGraphNode *outputfct, FGraphNode **dx, const unsigned int num_gradients, FGraphNode **gradients)
• void fStartGradientContext()
• void fStopGradientContext()
• bool fIsGradientContext()
• void fMarkGradientVariable(FGraphNode *node)
• void fUnmarkGradientVariable(FGraphNode *node)
• FGraphNode *fOptimizeMemory(FGraphNode *node)
• void fEnforceInverseBroadcasting(FGraphNode *node)
• void fUnenforceInverseBroadcasting(FGraphNode *node)
• char *fserialize(FGraphNode *node, size_t *bytes_written)
• FGraphNode *fdeserialize(char *data, size_t *bytes_read)
• FGraphNode *fload_image(const char *path)
• FGraphNode *fadd_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fsub_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fdiv_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fmul_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fpow_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fadd_ci(FGraphNode *a, const int b)
• FGraphNode *fadd_cl(FGraphNode *a, const long b)
• FGraphNode *fadd_cf(FGraphNode *a, const float b)
• FGraphNode *fadd_cd(FGraphNode *a, const double b)
• FGraphNode *fsub_ci(FGraphNode *a, const int b)
• FGraphNode *fsub_cl(FGraphNode *a, const long b)
• FGraphNode *fsub_cf(FGraphNode *a, const float b)
• FGraphNode *fsub_cd(FGraphNode *a, const double b)
• FGraphNode *fsub_ici(const int a, FGraphNode *b)
• FGraphNode *fsub_icl(const long a, FGraphNode *b)
• FGraphNode *fsub_icf(const float a, FGraphNode *b)
• FGraphNode *fsub_icd(const double a, FGraphNode *b)
• FGraphNode *fdiv_ci(FGraphNode *a, const int b)
• FGraphNode *fdiv_cl(FGraphNode *a, const long b)
• FGraphNode *fdiv_cf(FGraphNode *a, const float b)
• FGraphNode *fdiv_cd(FGraphNode *a, const double b)
• FGraphNode *fdiv_ici(const int a, FGraphNode *b)
• FGraphNode *fdiv_icl(const long a, FGraphNode *b)
• FGraphNode *fdiv_icf(const float a, FGraphNode *b)
• FGraphNode *fdiv_icd(const double a, FGraphNode *b)
• FGraphNode *fmul_ci(FGraphNode *a, const int b)
• FGraphNode *fmul_cl(FGraphNode *a, const long b)
• FGraphNode *fmul_cf(FGraphNode *a, const float b)
• FGraphNode *fmul_cd(FGraphNode *a, const double b)
• FGraphNode *fpow_ci(FGraphNode *a, const int b)
• FGraphNode *fpow_cl(FGraphNode *a, const long b)
• FGraphNode *fpow_cf(FGraphNode *a, const float b)
• FGraphNode *fpow_cd(FGraphNode *a, const double b)
• FGraphNode *flog(FGraphNode *a)
• FGraphNode *flog2(FGraphNode *a)
• FGraphNode *flog10(FGraphNode *a)
• FGraphNode *fsin(FGraphNode *a)
• FGraphNode *fsqrt_g(FGraphNode *a)
• FGraphNode *fexp(FGraphNode *a)
• FGraphNode *fcos(FGraphNode *a)
• FGraphNode *ftan(FGraphNode *a)
• FGraphNode *fasin(FGraphNode *a)
• FGraphNode *facos(FGraphNode *a)
• FGraphNode *fatan(FGraphNode *a)
• FGraphNode *fneg(FGraphNode *a)
• FGraphNode *fsign(FGraphNode *a)
• FGraphNode *feven(FGraphNode *a)
• FGraphNode *fless_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fgreater_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fequal_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fless_ci(FGraphNode *a, const int b)
• FGraphNode *fless_cl(FGraphNode *a, const long b)
• FGraphNode *fless_cf(FGraphNode *a, const float b)
• FGraphNode *fless_cd(FGraphNode *a, const double b)
• FGraphNode *fgreater_ci(FGraphNode *a, const int b)
• FGraphNode *fgreater_cl(FGraphNode *a, const long b)
• FGraphNode *fgreater_cf(FGraphNode *a, const float b)
• FGraphNode *fgreater_cd(FGraphNode *a, const double b)
• FGraphNode *fequal_ci(FGraphNode *a, const int b)
• FGraphNode *fequal_cl(FGraphNode *a, const long b)
• FGraphNode *fequal_cf(FGraphNode *a, const float b)
• FGraphNode *fequal_cd(FGraphNode *a, const double b)
• FGraphNode *fmatmul(FGraphNode *a, FGraphNode *b)
• FGraphNode *fflatten(FGraphNode *a)
• FGraphNode *fflatten_dimension(FGraphNode *a, int dimension)
• FGraphNode *fconvert(FGraphNode *a, enum FType newtype)
• FGraphNode *freshape(FGraphNode *a, const size_t *newshape, const int dimensions)
• FGraphNode *fmin_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fmin_ci(FGraphNode *a, const int b)
• FGraphNode *fmin_cl(FGraphNode *a, const long b)
• FGraphNode *fmin_cf(FGraphNode *a, const float b)
• FGraphNode *fmin_cd(FGraphNode *a, const double b)
• FGraphNode *fmax_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fmax_ci(FGraphNode *a, const int b)
• FGraphNode *fmax_cl(FGraphNode *a, const long b)
• FGraphNode *fmax_cf(FGraphNode *a, const float b)
• FGraphNode *fmax_cd(FGraphNode *a, const double b)
• FGraphNode *freduce_sum(FGraphNode *a, const int dimension)
• FGraphNode *freduce_mul(FGraphNode *a, const int dimension)
• FGraphNode *freduce_min(FGraphNode *a, const int dimension)
• FGraphNode *freduce_max(FGraphNode *a, const int dimension)
• FGraphNode *fslice(FGraphNode *a, const long *start, const long *end)
• FGraphNode *fslice_step(FGraphNode *a, const long *start, const long *end, const long *step)
• FGraphNode *fextend(FGraphNode *a, const size_t *new_shape, const size_t *insert_at)
• FGraphNode *fextend_step(FGraphNode *a, const size_t *new_shape, const size_t *insert_at, const long *step_size)
• FGraphNode *fconcat(FGraphNode *a, FGraphNode *b, const unsigned int axis)
• FGraphNode *fexpand(FGraphNode *a, const unsigned int axis, const unsigned int size)
• FGraphNode *fabs_g(FGraphNode *a)
• FGraphNode *frepeat(FGraphNode *a, int *repititions)
• FGraphNode *ftranspose(FGraphNode *a, int *transpositions)
• FGraphNode *fconvolve(FGraphNode *a, FGraphNode *kernel, const unsigned int *steps)
• FGraphNode *findex(FGraphNode *a, FGraphNode *indices)
• FGraphNode *findex_set(FGraphNode *a, FGraphNode *b, FGraphNode *indices)
• FGraphNode *fsliding_window(FGraphNode *a, const size_t *size, const unsigned int *steps)
• FGraphNode *funslide_window(FGraphNode *a, const size_t *shape, const unsigned int *steps)
• FGraphNode *fpermutate(FGraphNode *a, unsigned int ax)
• FGraphNode *fpooling_sum(FGraphNode *a, const size_t *window_size, const unsigned int *step_size)
• FGraphNode *fpooling_max(FGraphNode *a, const size_t *window_size, const unsigned int *step_size)
• FGraphNode *fdropout(FGraphNode *g, const double p)
• FErrorType flintInit(int backends)
• FErrorType flintInit_cpu()
• FErrorType flintInit_gpu()
• int flintInitializedBackends()
• FErrorType flintCleanup()
• FErrorType flintCleanup_cpu()
• FErrorType flintCleanup_gpu()
• enum FLogType
• void fSetLoggingLevel(enum FLogType type)
• enum FImageFormat
• void flogging(enum FLogType type, const char *msg)
• FErrorType fErrorType()
• const char *fErrorMessage()
• void fEnableEagerExecution()
• void fDisableEagerExecution()
• int fIsEagerExecution()
• enum FType
• struct FOperation
• struct FResultData
• struct FGraphNode
• struct FStore
• FGraphNode *fCreateGraph(const void *data, const int num_entries, const enum FType data_type, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_i(const int value, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_l(const long value, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_f(const float value, const size_t *shape, const int dimensions)
• FGraphNode *fconstant_d(const double value, const size_t *shape, const int dimensions)
• FGraphNode *frandom(const size_t *shape, const int dimensions)
• FGraphNode *farange(const size_t *shape, const int dimensions, const int ax)
• void fFreeGraph(FGraphNode *graph)
• FGraphNode *fExecuteGraph(FGraphNode *node)
• FGraphNode *fExecuteGraph_cpu(FGraphNode *node)
• FGraphNode *fExecuteGraph_gpu(FGraphNode *node)
• FGraphNode *fExecuteGraph_cpu_eagerly(FGraphNode *node)
• FGraphNode *fExecuteGraph_gpu_eagerly(FGraphNode *node)
• FResultData *fSyncMemory(FGraphNode *data)
• FGraphNode *fCalculateResult(FGraphNode *node)
• FGraphNode *fCalculateGradient(FGraphNode *outputfct, FGraphNode *dx)
• FErrorType fCalculateGradients(FGraphNode *outputfct, FGraphNode **dx, const unsigned int num_gradients, FGraphNode **gradients)
• void fStartGradientContext()
• void fStopGradientContext()
• bool fIsGradientContext()
• void fMarkGradientVariable(FGraphNode *node)
• void fUnmarkGradientVariable(FGraphNode *node)
• FGraphNode *fOptimizeMemory(FGraphNode *node)
• void fEnforceInverseBroadcasting(FGraphNode *node)
• void fUnenforceInverseBroadcasting(FGraphNode *node)
• char *fserialize(FGraphNode *node, size_t *bytes_written)
• FGraphNode *fdeserialize(char *data, size_t *bytes_read)
• FGraphNode *fload_image(const char *path)
• FGraphNode *fadd_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fsub_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fdiv_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fmul_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fpow_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fadd_ci(FGraphNode *a, const int b)
• FGraphNode *fadd_cl(FGraphNode *a, const long b)
• FGraphNode *fadd_cf(FGraphNode *a, const float b)
• FGraphNode *fadd_cd(FGraphNode *a, const double b)
• FGraphNode *fsub_ci(FGraphNode *a, const int b)
• FGraphNode *fsub_cl(FGraphNode *a, const long b)
• FGraphNode *fsub_cf(FGraphNode *a, const float b)
• FGraphNode *fsub_cd(FGraphNode *a, const double b)
• FGraphNode *fsub_ici(const int a, FGraphNode *b)
• FGraphNode *fsub_icl(const long a, FGraphNode *b)
• FGraphNode *fsub_icf(const float a, FGraphNode *b)
• FGraphNode *fsub_icd(const double a, FGraphNode *b)
• FGraphNode *fdiv_ci(FGraphNode *a, const int b)
• FGraphNode *fdiv_cl(FGraphNode *a, const long b)
• FGraphNode *fdiv_cf(FGraphNode *a, const float b)
• FGraphNode *fdiv_cd(FGraphNode *a, const double b)
• FGraphNode *fdiv_ici(const int a, FGraphNode *b)
• FGraphNode *fdiv_icl(const long a, FGraphNode *b)
• FGraphNode *fdiv_icf(const float a, FGraphNode *b)
• FGraphNode *fdiv_icd(const double a, FGraphNode *b)
• FGraphNode *fmul_ci(FGraphNode *a, const int b)
• FGraphNode *fmul_cl(FGraphNode *a, const long b)
• FGraphNode *fmul_cf(FGraphNode *a, const float b)
• FGraphNode *fmul_cd(FGraphNode *a, const double b)
• FGraphNode *fpow_ci(FGraphNode *a, const int b)
• FGraphNode *fpow_cl(FGraphNode *a, const long b)
• FGraphNode *fpow_cf(FGraphNode *a, const float b)
• FGraphNode *fpow_cd(FGraphNode *a, const double b)
• FGraphNode *flog(FGraphNode *a)
• FGraphNode *flog2(FGraphNode *a)
• FGraphNode *flog10(FGraphNode *a)
• FGraphNode *fsin(FGraphNode *a)
• FGraphNode *fsqrt_g(FGraphNode *a)
• FGraphNode *fexp(FGraphNode *a)
• FGraphNode *fcos(FGraphNode *a)
• FGraphNode *ftan(FGraphNode *a)
• FGraphNode *fasin(FGraphNode *a)
• FGraphNode *facos(FGraphNode *a)
• FGraphNode *fatan(FGraphNode *a)
• FGraphNode *fneg(FGraphNode *a)
• FGraphNode *fsign(FGraphNode *a)
• FGraphNode *feven(FGraphNode *a)
• FGraphNode *fless_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fgreater_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fequal_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fless_ci(FGraphNode *a, const int b)
• FGraphNode *fless_cl(FGraphNode *a, const long b)
• FGraphNode *fless_cf(FGraphNode *a, const float b)
• FGraphNode *fless_cd(FGraphNode *a, const double b)
• FGraphNode *fgreater_ci(FGraphNode *a, const int b)
• FGraphNode *fgreater_cl(FGraphNode *a, const long b)
• FGraphNode *fgreater_cf(FGraphNode *a, const float b)
• FGraphNode *fgreater_cd(FGraphNode *a, const double b)
• FGraphNode *fequal_ci(FGraphNode *a, const int b)
• FGraphNode *fequal_cl(FGraphNode *a, const long b)
• FGraphNode *fequal_cf(FGraphNode *a, const float b)
• FGraphNode *fequal_cd(FGraphNode *a, const double b)
• FGraphNode *fmatmul(FGraphNode *a, FGraphNode *b)
• FGraphNode *fflatten(FGraphNode *a)
• FGraphNode *fflatten_dimension(FGraphNode *a, int dimension)
• FGraphNode *fconvert(FGraphNode *a, enum FType newtype)
• FGraphNode *freshape(FGraphNode *a, const size_t *newshape, const int dimensions)
• FGraphNode *fmin_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fmin_ci(FGraphNode *a, const int b)
• FGraphNode *fmin_cl(FGraphNode *a, const long b)
• FGraphNode *fmin_cf(FGraphNode *a, const float b)
• FGraphNode *fmin_cd(FGraphNode *a, const double b)
• FGraphNode *fmax_g(FGraphNode *a, FGraphNode *b)
• FGraphNode *fmax_ci(FGraphNode *a, const int b)
• FGraphNode *fmax_cl(FGraphNode *a, const long b)
• FGraphNode *fmax_cf(FGraphNode *a, const float b)
• FGraphNode *fmax_cd(FGraphNode *a, const double b)
• FGraphNode *freduce_sum(FGraphNode *a, const int dimension)
• FGraphNode *freduce_mul(FGraphNode *a, const int dimension)
• FGraphNode *freduce_min(FGraphNode *a, const int dimension)
• FGraphNode *freduce_max(FGraphNode *a, const int dimension)
• FGraphNode *fslice(FGraphNode *a, const long *start, const long *end)
• FGraphNode *fslice_step(FGraphNode *a, const long *start, const long *end, const long *step)
• FGraphNode *fextend(FGraphNode *a, const size_t *new_shape, const size_t *insert_at)
• FGraphNode *fextend_step(FGraphNode *a, const size_t *new_shape, const size_t *insert_at, const long *step_size)
• FGraphNode *fconcat(FGraphNode *a, FGraphNode *b, const unsigned int axis)
• FGraphNode *fexpand(FGraphNode *a, const unsigned int axis, const unsigned int size)
• FGraphNode *fabs_g(FGraphNode *a)
• FGraphNode *frepeat(FGraphNode *a, int *repititions)
• FGraphNode *ftranspose(FGraphNode *a, int *transpositions)
• FGraphNode *fconvolve(FGraphNode *a, FGraphNode *kernel, const unsigned int *steps)
• FGraphNode *findex(FGraphNode *a, FGraphNode *indices)
• FGraphNode *findex_set(FGraphNode *a, FGraphNode *b, FGraphNode *indices)
• FGraphNode *fsliding_window(FGraphNode *a, const size_t *size, const unsigned int *steps)
• FGraphNode *funslide_window(FGraphNode *a, const size_t *shape, const unsigned int *steps)
• FGraphNode *fpermutate(FGraphNode *a, unsigned int ax)
• FGraphNode *fpooling_sum(FGraphNode *a, const size_t *window_size, const unsigned int *step_size)
• FGraphNode *fpooling_max(FGraphNode *a, const size_t *window_size, const unsigned int *step_size)
• FGraphNode *fdropout(FGraphNode *g, const double p)
The C-Backend has a memory management system optimized for easy usage in C++, which makes it a little bit weird in C.
It uses reference counting for all nodes, but the initial counter is set to 0 and increased when connected to another node.
The reason for that is that a call toFGraphNode *gn1 = fCreateGraph(...); // counter is 0 FGraphNode *gn2 = fCreateGraph(...); // counter is 0 FGraphNode *gn3 = fadd(gn1, gn2); // counter of gn3 is 0, of gn1 is 1 and of gn2 is 1
fFreeGraphdoes not decrease the reference counter but frees the node when it is already 0. If a node is freed the method can be recursively called for all its parents, in the example if one calls
fFreeGraph(gn3),
gn1and
gn2are freed too. This is important when calling
fOptimizeMemoryfor e.g.
gn3, which is allowed to free parental informations when no longer needed. Since in that case
gn1and
gn2have a reference counter of 1 depending on
gn3they could no longer be used after a call to
fOptimizeMemory(gn3), to prevent that you have to artifically manipulate the reference counter for nodes in such a context by calling
gn1->reference_counter++.
enum FErrorType
Types of erros that can occur in the framework (also see
fErrorMessage) Error Types:
NO_ERROR
: no error occured up until nowWRONG_TYPE
: Tensor has wrong data type, e.g. a floating point tensor infeven
ILLEGAL_DIMENSION
: the dimension parameter is not inside the legal range of the function, e.g. flattening the first dimension of a tensor.ILLEGAL_DIMENSIONALITY
: the dimensionality of a parameter does not work with the function, usually because it is too low (e.g. matrix multiplication with 1 dimensional tensors).INCOMPATIBLE_SHAPES
: the shapes of the parameters dont fit togetherINVALID_SELECT
: a index or slicing operation received parameters which are semantically impossible or outside of the shape of the tensor.OCL_ERROR
: OpenCL ErrorINTERNAL_ERROR
: illegal state of flint, should not happenOUT_OF_MEMORY
: no more cpu or gpu memory availableILLEGAL_DERIVE
: derivation of graph to a variable is not possibleIO_ERROR
: file writing or reading problem
FErrorType flintInit(int backends)
Initializes the cpu and the gpu backends. These functions are already
implicitly called by the execution functions if necessary. The method allows
disabling of the gpu backend (by passing
FLINT_BACKEND_ONLY_CPU), disabling of the cpu backend (by passing
FLINT_BACKEND_BOTH), initializing both backends explicitly (by passing
FLINT_BACKEND_BOTH, which is recommended, since Flint is then allowed to choose the framework with heuristics). Only use those functions if you...
- ...want to explicitly decide where and when the initialization should take place
- ...want to only start one backend
NO_ERRORon success or the error type
FErrorType flintInit_cpu()
Don't call this function explicitly if you intent to use Flint normally. Use
flintInit. Returns
NO_ERRORon success or the error type
FErrorType flintInit_gpu()
Don't call this function explicitly if you intent to use Flint normally. Use
flintInit. Returns
NO_ERRORon success or the error type
int flintInitializedBackends()
Returns an integer containing the Backend information bitwise.
See constants
FLINT_BACKEND_ONLY_CPU,
FLINT_BACKEND_ONLY_GPUand
FLINT_BACKEND_BOTH.
FErrorType flintCleanup()
Deallocates any resourced allocated by the corresponding backends.
This method calls the other two (following) which are only executed if the
framework was initialized, else they do nothing. Returns
NO_ERRORon success or the error type
FErrorType flintCleanup_cpu()
Deallocates any resourced allocated by the cpu backend, if it was
initialized, else it does nothing. Returns
NO_ERRORon success or the error type
FErrorType flintCleanup_gpu()
Deallocates any resourced allocated by the gpu backend, if it was
initialized, else it does nothing. Returns
NO_ERRORon success or the error type
enum FLogType
See also:
flogging,
FLogType
F_DEBUG
(only internal debugging informations of the framework),F_VERBOSE
(verbose information, may be helpful to users of the library),F_INFO
(informational data of the framework, e.g. which graphics card has been chosen),F_ERROR
(unrecoverable errors, generated by function calls to the framework, raises a exception everytime),F_WARNING
(probably unwanted behaviour or undefined behaviour caused by missuse of functions).
void fSetLoggingLevel(enum FLogType type)
Sets the logging level of the framework. Adjust this for debugging purposes,
or if you release software in which Flint is contained.
See also:
flogging,
FLogTypeLevels:
- 0: No logging
- 1: Only
F_ERROR
- 2: Logging level
F_WARNING
(should be used for production) - 3: Logging level
F_INFO
(for developement) - 4: Logging level
F_VERBOSE
(for library developement) - 5: Logging level
F_DEBUG
(when a bug in the library has been found)
enum FImageFormat
Supported Image formats for fstore_image
void flogging(enum FLogType type, const char *msg)
Logs a NULL terminated string with the given logging level.
See also:
fSetLoggingLevel
FErrorType fErrorType()
Queries the type of the last error that occured in this framework.
Errors cause an exception or if C-compatibility is enabled the function in
which the error occurs returns NULL. Then this function yields the type of
error.
const char *fErrorMessage()
Queries the message of the last error that occured in this framework.
Errors cause an exception or if C-compatibility is enabled the function in
which the error occurs returns NULL. Then this function yields the message
of the error. If no error occured returns an empty string.
void fEnableEagerExecution()
All graph nodes that represent actual operations are after this call
executed eagerly, i.e. they are executed during graph construction.
This may improve performance when only using the CPU backend, in any other
case disabling eager execution should be preferred.
void fDisableEagerExecution()
Disable eager execution, i.e. the graph is constructed without execution of
the nodes until an operation makes the execution of a parent graph necessary
or the user calls
fExecuteGraph.
int fIsEagerExecution()
Returns 1 if eager execution has been enabled, else 0
enum FType
The 4 allowed data types:
F_INT32
(integer, 32bit)F_INT64
(integer, 64bit)F_FLOAT32
(floating point, 32bit)F_FLOAT64
(floating point, 64bit)
struct FOperation
Describes one operation. An operation always has a shape, described by
FOperation.shapewhich is an array of size
FOperation.dimensionswith each entry denoting the size of the corresponding dimension.
FOperation.op_typedenotes the type of operation,
FOperation.data_typethe type of the underlying data,
FOperation.additional_datais operation specific.
struct FResultData
Stores the resulting data after an execution of
fExecuteGraph(or implicit execution). The data can be found in
FResultData.data, the datatype in
FOperation.data_typeof the corresponding
FGraphNode. The number of entries (not number of bytes) is stored in
FResultData.num_entries. The data may be consistently modified if...
- ...the data size is changed, num_entries is equivalently updated and
realloc
is used and ... - ...the data was not already loaded to the gpu (i.e. the result must be the
return value of
fExecuteGraph_cpu
)
struct FGraphNode
Describes one node in the Graph. Stores the corresponding operation in
FGraphNode.operation, an array of predecessors (the arguments of the operation) in
FGraphNode.predecessors, its size in
FGraphNode.num_predecessorand the reference counter in
FGraphNode.reference_counter. Do not modify any parameter by yourself, since the framework manages them, but you can read the data and structure from them. The nodes are allocated by the operation functions, they and their members should neither be manually created, edited or freed except by the corresponding flint methods.
struct FStore
Result of an call to
fCreateGraph, see
FResultData. Data of this Operation may not be changed manually when using a GPU Backend.
FGraphNode *fCreateGraph(const void *data, const int num_entries, const enum FType data_type, const size_t *shape, const int dimensions)
data
: pointer to the flattened data array that should be loaded into the nodenum_entries
: the number of elements (NOT BYTES!) that should be loadeddata_type
: the datatype ofdata
shape
: an array of sizedimensions
, each entry describing the size of the corresponding dimension. Make sure,data
is at least as large as the product of all entries inshape
dimensions
: the number of dimensions
dataand
shapemay be deleted.
FGraphNode *fconstant_i(const int value, const size_t *shape, const int dimensions)
Creates a tensor that contains the single given values in all entries
value
: the value this tensor should consist ofshape
: an array of sizedimensions
, each entry describing the size of the corresponding dimension.dimensions
: the number of dimensions
FGraphNode *fconstant_l(const long value, const size_t *shape, const int dimensions)
Creates a tensor that contains the single given values in all entries
value
: the value this tensor should consist ofshape
: an array of sizedimensions
, each entry describing the size of the corresponding dimension.dimensions
: the number of dimensions
FGraphNode *fconstant_f(const float value, const size_t *shape, const int dimensions)
Creates a tensor that contains the single given values in all entries
value
: the value this tensor should consist ofshape
: an array of sizedimensions
, each entry describing the size of the corresponding dimension.dimensions
: the number of dimensions
FGraphNode *fconstant_d(const double value, const size_t *shape, const int dimensions)
Creates a tensor that contains the single given values in all entries
value
: the value this tensor should consist ofshape
: an array of sizedimensions
, each entry describing the size of the corresponding dimension.dimensions
: the number of dimensions
FGraphNode *frandom(const size_t *shape, const int dimensions)
Creates a tensor that contains randomly distributed values in the range of
[0, 1)
shape
: an array of sizedimensions
, each entry describing the size of the corresponding dimension.dimensions
: the number of dimensions
FGraphNode *farange(const size_t *shape, const int dimensions, const int ax)
Creates a int64 tensor that contains the indices relative to a given
dimension
axfor each element, i.e. each entry is its index in that corresponding dimension. If you need to index more than one dimension, create multiple such tensors with
arange.
void fFreeGraph(FGraphNode *graph)
Decrements
FGraphNode.reference_counterof
graph(for reference counting) and deallocates the node and its corresponding data, if the counter reaches 0. If the node is deallocated, the same process is repeated with its predecessors. So you can safely connect nodes multiple times and have only to free the leaf nodes (i.e. the results), without caring about cross-reference, since those are handled by the reference counting system.
FGraphNode *fExecuteGraph(FGraphNode *node)
Executes the graph node operations from all yet to be executed predecessors
to
nodeand returns a node with a
FResultDataoperation in which the resulting data is stored. If the graph is executed by the GPU backend, a opencl kernel containing all selected operations (the nodes operation and those indirect parent operations which were not yet executed) are compiled and executed. The kernels are cached, so it improves the performance of a program if the same graph-structures are reused (not necessary the same nodes, but the same combination of nodes), since then the backend can reuse already compiled kernels. The GPU backend is allowed to keep the Result data on the GPU without synchronizing it (so the generated
FResultDatamay not have a
datamember!). To force synchronization use
fSyncMemoryor replace the call with
fCalculateResult. If the CPU backend is chosen, it does not matter, since every operation is executed independently (here eager execution might be faster). The backend is selected by the framework if both are initialized, else the one that is initialized will be chosen. If both are uninitialized, both will be initialized prior to execution. If eager execution is enabled each node will be executed eagerly upon construction or with this method. Also see
fEnableEagerExecution,
fSyncMemory
FGraphNode *fExecuteGraph_cpu(FGraphNode *node)
Executes the graph node operations from all yet to be executed predecessors
to
nodeand returns a node with a
FResultDataoperation in which the resulting data is stored.
FGraphNode *fExecuteGraph_gpu(FGraphNode *node)
Executes the graph node operations from all yet to be executed predecessors
to
nodeand returns a node with a
FResultDataoperation in which the resulting data is stored. For the GPU backend, a opencl kernel containing all selected operations (the nodes operation and those indirect parent operations which were not yet executed) are compiled and executed. The kernels are cashed, so it improves the performance of a program if the same graph-structures are reused (not necessary the same nodes, but the same combination of nodes), since then the backend can reuse already compiled kernels.
FGraphNode *fExecuteGraph_cpu_eagerly(FGraphNode *node)
Executes the graph node directly and assumes that predecessor data has
already been computed. Uses the CPU backend. Mainly used by helper functions
of the framework, only use it if you now what you are doing.
Also see
fEnableEagerExecution,
fExecuteGraph_cpuand
fExecuteGraph
FGraphNode *fExecuteGraph_gpu_eagerly(FGraphNode *node)
Executes the graph node directly and assumes that predecessor data has
already been computed. Uses the GPU backend where for each operation and
parameter type combination one eager kernel will be computed. Mainly used by
helper functions of the framework, only use it if you now what you are doing.
Also see
fEnableEagerExecution,
fExecuteGraph_gpuand
fExecuteGraph
FResultData *fSyncMemory(FGraphNode *data)
fExecuteGraohdoes not guarantee that memory is present on the cpu (it may be kept on the GPU for performance reasons). This method enforces all GPU data to be flushed to the CPU (but never executes the node!). Also see
fCalculateResult
FGraphNode *fCalculateResult(FGraphNode *node)
Convenience Method that first execute
fExecuteGraphand then
fSyncMemoryon the node. It represents execution with one of both backends and additional memory synchronizing for the gpu framework.
FGraphNode *fCalculateGradient(FGraphNode *outputfct, FGraphNode *dx)
Calculates the overall gradient of an output node to a variable.
The variable must be marked as a gradient variable, see
fMarkGradientVariableand the output node
outputfctmust be constructed in an gradient context (to remember which variables are directly or indirectly present in which operation), which can be started with
fStartGradientContext. If you need to compute multiple gradients for one output use
fCalculateGradientssince it is far more efficient.
outputfct
: the Node which represents the chain of functions of which the gradient is to be computed.dx
: the variable for which outputfct is derived for
FErrorType fCalculateGradients(FGraphNode *outputfct, FGraphNode **dx, const unsigned int num_gradients, FGraphNode **gradients)
Calculates the overall gradient of an output node to multiple variables.
The variables must be marked as a gradient variable, see
fMarkGradientVariableand the output node
outputfctmust be constructed in an gradient context (to remember which variables are directly or indirectly present in which operation), which can be started with
fStartGradientContext. The gradients are of type
floatif
outputfctand
dxis of type
float, else of type
double.
outputfct
: the Node which represents the chain of functions of which the gradients are to be computed.dx
: array of variables for which outputfct is derived for.num_gradients
: the number of variables indx
.gradients
: an array of sizenum_gradients
in which the resulting gradients will be stored per variable.
void fStartGradientContext()
Starts a gradient context, gradient information will be inherited until the
next call to
fStopGradientContext. A history containing information about all watched nodes in the parent graph is kept up to date within a gradient context for each node created in it. The node does not have to be watched in that particular context (it just has to be marked as watched), but only for operations which are constructed inside such a gradient context a gradient to a variable may be computed. Since this context introduces overhead and limits
fOptimizeMemorysignificantly, it should be closed as soon as possible.
void fStopGradientContext()
Stops a gradient context, all inherited gradient information and watched
nodes will be kept, but no longer inherited to new ones.
bool fIsGradientContext()
Return true if the call to this function is placed within a gradient
context.
void fMarkGradientVariable(FGraphNode *node)
Marks this node as a node for which a gradient might be calculated later.
It is only possible to calculate the gradient for this node (as a derivative)
in operations that occur AFTER a call to this method (all subsequent
operations will have a remark that enlists this node as a possible gradient
variable, to enable less memory usage and faster gradient calculation).
void fUnmarkGradientVariable(FGraphNode *node)
Removes the gradient mark (and subsequent memory overhead) for this node.
After a call to this method no subsequent gradient calculations with this
node as a derivative will be possible.
FGraphNode *fOptimizeMemory(FGraphNode *node)
Optimizes memory by freeing all parental data (operand nodes of the
operation of this node) and transforming this node to a storage nodes
if no gradient variables are present in this node and result data is
present (i.e. it has been executed).
If you call this function manually please make sure to increase the
reference_counterof the parents if you want to keep their handles, since this function may decrease their counter and free them. The C++ framework does this automatically.
void fEnforceInverseBroadcasting(FGraphNode *node)
Sometimes there are combinations of nodes where both normal and inverse
broadcasting is possible, but yields different results, e.g. multiplication
for two nodes with shapes [3, 5, 3, 5] and [3, 5]. The framework chooses
normal broadcasting over inverse if both are possible, this function allows
you to alter this behaviour and mark a node to be inversely broadcasted.
After the call to this function the given node will from then on only
inversely broadcasted (in cases where only normal broadcasting is available
an error will occur!). It has no effect in operations that don't use
broadcasting. You can "unmark" the node with
fUnenforceInverseBroadcasting.
void fUnenforceInverseBroadcasting(FGraphNode *node)
Undos
fEnforceInverseBroadcastingfor a node.
char *fserialize(FGraphNode *node, size_t *bytes_written)
Serializes the data and shape of the node and returns an array of chars in
which the serialized data will be written (binary data, not a string). The
returned array is allocated on the systems heap with
malloc, so you have to free it after you are done with it. The number of bytes that the returned array has is written into the memory
bytes_writtenpoints to if it is not a nullptr. If the node doesn't have result data, it is executed first.
FGraphNode *fdeserialize(char *data, size_t *bytes_read)
Unserializes data generated by
fserialize. The size of the node is stored in the data and the complete node is read. The number of bytes read is stored in
bytes_read. Internally calls
fCreateGraph.
FGraphNode *fload_image(const char *path)
Loads an image from the given path.
The image will be stored in floating point data and the shape will be h, w, c
where w is the width, h is the height and c are the channels.
Supported formats include png, jpeg, bmp, gif, hdr ... essentially everything
stb_image supports
FGraphNode *fadd_g(FGraphNode *a, FGraphNode *b)
Elementwise addition of
aand
b, i.e.
a[i] + b[i].
FGraphNode *fsub_g(FGraphNode *a, FGraphNode *b)
Elementwise substraction of
aand
b, i.e.
a[i] - b[i].
FGraphNode *fdiv_g(FGraphNode *a, FGraphNode *b)
Elementwise division of
aand
b, i.e.
a[i] / b[i].
FGraphNode *fmul_g(FGraphNode *a, FGraphNode *b)
Elementwise multiplication of
aand
b, i.e.
a[i] * b[i].
FGraphNode *fpow_g(FGraphNode *a, FGraphNode *b)
Elementwise power of
aand
b, i.e.
pow(a[i], b[i]).
FGraphNode *fadd_ci(FGraphNode *a, const int b)
Elementwise addition of a and b, i.e.
a[i] + b.
FGraphNode *fadd_cl(FGraphNode *a, const long b)
Elementwise addition of a and b, i.e.
a[i] + b.
FGraphNode *fadd_cf(FGraphNode *a, const float b)
Elementwise addition of a and b, i.e.
a[i] + b.
FGraphNode *fadd_cd(FGraphNode *a, const double b)
Elementwise addition of a and b, i.e.
a[i] + b.
FGraphNode *fsub_ci(FGraphNode *a, const int b)
Elementwise subtraction of a and b, i.e.
a[i] - b.
FGraphNode *fsub_cl(FGraphNode *a, const long b)
Elementwise subtraction of a and b, i.e.
a[i] - b.
FGraphNode *fsub_cf(FGraphNode *a, const float b)
Elementwise subtraction of a and b, i.e.
a[i] - b.
FGraphNode *fsub_cd(FGraphNode *a, const double b)
Elementwise subtraction of a and b, i.e.
a[i] - b.
FGraphNode *fsub_ici(const int a, FGraphNode *b)
Elementwise subtraction of a and b, i.e.
a - b[i].
FGraphNode *fsub_icl(const long a, FGraphNode *b)
Elementwise subtraction of a and b, i.e.
a - b[i].
FGraphNode *fsub_icf(const float a, FGraphNode *b)
Elementwise subtraction of a and b, i.e.
a - b[i].
FGraphNode *fsub_icd(const double a, FGraphNode *b)
Elementwise subtraction of a and b, i.e.
a - b[i].
FGraphNode *fdiv_ci(FGraphNode *a, const int b)
Elementwise division of a and b, i.e.
a[i] / b.
FGraphNode *fdiv_cl(FGraphNode *a, const long b)
Elementwise division of a and b, i.e.
a[i] / b.
FGraphNode *fdiv_cf(FGraphNode *a, const float b)
Elementwise division of a and b, i.e.
a[i] / b.
FGraphNode *fdiv_cd(FGraphNode *a, const double b)
Elementwise division of a and b, i.e.
a[i] / b.
FGraphNode *fdiv_ici(const int a, FGraphNode *b)
Elementwise division of a and b, i.e.
a / b[i].
FGraphNode *fdiv_icl(const long a, FGraphNode *b)
Elementwise division of a and b, i.e.
a / b[i].
FGraphNode *fdiv_icf(const float a, FGraphNode *b)
Elementwise division of a and b, i.e.
a / b[i].
FGraphNode *fdiv_icd(const double a, FGraphNode *b)
Elementwise division of a and b, i.e.
a / b[i].
FGraphNode *fmul_ci(FGraphNode *a, const int b)
Elementwise multiplication of a and b, i.e.
a[i] * b.
FGraphNode *fmul_cl(FGraphNode *a, const long b)
Elementwise multiplication of a and b, i.e.
a[i] * b.
FGraphNode *fmul_cf(FGraphNode *a, const float b)
Elementwise multiplication of a and b, i.e.
a[i] * b.
FGraphNode *fmul_cd(FGraphNode *a, const double b)
Elementwise multiplication of a and b, i.e.
a[i] * b.
FGraphNode *fpow_ci(FGraphNode *a, const int b)
Takes the elementwise power of a to b, i.e.
pow(a[i], b).
FGraphNode *fpow_cl(FGraphNode *a, const long b)
Takes the elementwise power of a to b, i.e.
pow(a[i], b).
FGraphNode *fpow_cf(FGraphNode *a, const float b)
Takes the elementwise power of a to b, i.e.
pow(a[i], b).
FGraphNode *fpow_cd(FGraphNode *a, const double b)
Takes the elementwise power of a to b, i.e.
pow(a[i], b).
FGraphNode *flog(FGraphNode *a)
Takes the elementwise natural logarithm of
a
FGraphNode *flog2(FGraphNode *a)
Takes the elementwise logarithm of
ato the basis of 2
FGraphNode *flog10(FGraphNode *a)
Takes the elementwise logarithm of
ato the basis of 10
FGraphNode *fsin(FGraphNode *a)
Takes the elementwise sinus of
a
FGraphNode *fsqrt_g(FGraphNode *a)
Takes the elementwise square root of
a
FGraphNode *fexp(FGraphNode *a)
Takes the elementwise exponential of
a(power of the constant
eto
a)
FGraphNode *fcos(FGraphNode *a)
Takes the elementwise cosinus of
a
FGraphNode *ftan(FGraphNode *a)
Takes the elementwise tangents of
a
FGraphNode *fasin(FGraphNode *a)
Takes the elementwise inverse sinus of
a
FGraphNode *facos(FGraphNode *a)
Takes the elementwise inverse cosinus of
a
FGraphNode *fatan(FGraphNode *a)
Takes the elementwise inverse tangents of
a
FGraphNode *fneg(FGraphNode *a)
Negates the elements of
a, i.e.
-a[i]
FGraphNode *fsign(FGraphNode *a)
Returns a
F_INT32tensor x with the shape of a with
x[i] = 1if
a[i] >= 0else
x[i] = -1.
aneeds to have a integer data type.
FGraphNode *feven(FGraphNode *a)
Returns a
F_INT32tensor
xwith the shape of
awith
x[i] = 1if
a[i] % 2 = 0else
x[i] = 0.
FGraphNode *fless_g(FGraphNode *a, FGraphNode *b)
Compares two tensors elementwise by
a < band returns a 0,1
F_INT32Tensor.
0denotes that
a >= b,
1that
a < b.
FGraphNode *fgreater_g(FGraphNode *a, FGraphNode *b)
Compares two tensors elementwise by
a > band returns a 0,1
F_INT32Tensor.
FGraphNode *fequal_g(FGraphNode *a, FGraphNode *b)
Compares two tensors elementwise by
a = b
and returns a 0,1F_INT32
Tensor.0
denotes thata <= b
,1
thata > b
.
FGraphNode *fless_ci(FGraphNode *a, const int b)
FGraphNode *fless_cl(FGraphNode *a, const long b)
FGraphNode *fless_cf(FGraphNode *a, const float b)
FGraphNode *fless_cd(FGraphNode *a, const double b)
FGraphNode *fgreater_ci(FGraphNode *a, const int b)
Compares a tensor and a constant elementwise by
a > band returns a 0,1
INT32Tensor. See
fgreater_g.
FGraphNode *fgreater_cl(FGraphNode *a, const long b)
Compares a tensor and a constant elementwise by
a > band returns a 0,1
INT32Tensor. See
fgreater_g.
FGraphNode *fgreater_cf(FGraphNode *a, const float b)
Compares a tensor and a constant elementwise by
a > band returns a 0,1
INT32Tensor. See
fgreater_g.
FGraphNode *fgreater_cd(FGraphNode *a, const double b)
Compares a tensor and a constant elementwise by
a > band returns a 0,1
INT32Tensor. See
fgreater_g.
FGraphNode *fequal_ci(FGraphNode *a, const int b)
FGraphNode *fequal_cl(FGraphNode *a, const long b)
FGraphNode *fequal_cf(FGraphNode *a, const float b)
FGraphNode *fequal_cd(FGraphNode *a, const double b)
FGraphNode *fmatmul(FGraphNode *a, FGraphNode *b)
Carries out matrix multiplication on the last two dimensions of the tensors.
E.g. a matrix multiplication of two tensors with shapes
(64, 32, 16)and
(16, 24)will yield a tensor with shape
(64, 32, 24). Since for one entry of the tensor multiple other previous entries are needed, the operand tensors need to be executed first. Therefor the method will implicitly (or eagerly) execute the two parameter nodes
aand
bif their data is not already present.
FGraphNode *fflatten(FGraphNode *a)
Flattens the complete tensor to a tensor with one
dimension.
E.g.
flattened([[[3, 1, 4], [2, 1, 5]], [[0, 4, 2], [4, 7, 9]]]) = [3, 1, 4, 2, 1, 5, 0, 4, 2, 4, 7, 9].
FGraphNode *fflatten_dimension(FGraphNode *a, int dimension)
Flattens a tensor
awith
ndimensions along
dimension, resulting in a tensor with
n-1dimensions. Flattening a dimension will remove it from the shape of the tensor, therefor it's not possible to flatten the dimension 0. A Tensor
[[[3, 1, 4], [2, 1, 5]], [[0, 4, 2], [4, 7, 9]]]flattened along dimension 1 will result in
[[3,1,4], [2,1,5], [0,4,2], [4,7,9]].
FGraphNode *fconvert(FGraphNode *a, enum FType newtype)
Converts the data of
ato the type given by
newtype
FGraphNode *freshape(FGraphNode *a, const size_t *newshape, const int dimensions)
Reshapes the underlying data of the tensor to the new shape. The product of
each dimension of the new shape must be the same as the product of the
dimensions of the previous shape (i.e. it must describe the same number of
entries of the tensor).
FGraphNode *fmin_g(FGraphNode *a, FGraphNode *b)
Takes the minimum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] < b[i]else
b[i]
FGraphNode *fmin_ci(FGraphNode *a, const int b)
Takes the minimum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] < belse
b
FGraphNode *fmin_cl(FGraphNode *a, const long b)
Takes the minimum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] < belse
b
FGraphNode *fmin_cf(FGraphNode *a, const float b)
Takes the minimum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] < belse
b
FGraphNode *fmin_cd(FGraphNode *a, const double b)
Takes the minimum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] < belse
b
FGraphNode *fmax_g(FGraphNode *a, FGraphNode *b)
Takes the maximum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] > b[i]else
b[i]
FGraphNode *fmax_ci(FGraphNode *a, const int b)
Takes the maximum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] > belse
b
FGraphNode *fmax_cl(FGraphNode *a, const long b)
Takes the maximum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] > belse
b
FGraphNode *fmax_cf(FGraphNode *a, const float b)
Takes the maximum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] > belse
b
FGraphNode *fmax_cd(FGraphNode *a, const double b)
Takes the maximum of two tensors element wise along the last dimension of
each, i.e.
a[i]if
a[i] > belse
b
FGraphNode *freduce_sum(FGraphNode *a, const int dimension)
Reduces one dimension of the tensor by additive folding e.g.
freduce_sum([[1,2,3], [4,5,6]], 0) = [5,7,9],
freduce_sum([[1,2,3], [4,5,6]], 1) = [6,15]The results of the predecessor node must be available, to ensure that the method may execute the parameter node.
FGraphNode *freduce_mul(FGraphNode *a, const int dimension)
Reduces one dimension of the tensor by multiplicative folding e.g.
freduce_mul([[1,2,3], [4,5,6]], 0) = [4,10,18],
freduce_mul([[1,2,3], [4,5,6]], 1) = [6, 120]The results of the predecessor node must be available; to ensure that the method may execute the parameter node.
FGraphNode *freduce_min(FGraphNode *a, const int dimension)
Reduces one dimension of the tensor by keeping the minimum e.g.
freduce_min([[1,32,3], [4,5,3]], 0) = [1,5,3],
freduce_min([[9,2,3], [-1,5,6]], 1) = [2, -1]The results of the predecessor node must be available; to ensure that the method may execute the parameter node.
FGraphNode *freduce_max(FGraphNode *a, const int dimension)
Reduces one dimension of the tensor by keeping the maximum e.g.
freduce_max([[1,32,3], [4,5,3]], 0) = [4,32,3],
freduce_max([[9,2,3], [-1,5,6]], 1) = [9, 6]The results of the predecessor node must be available; to ensure that the method may execute the parameter node.
FGraphNode *fslice(FGraphNode *a, const long *start, const long *end)
Selects a slice of the tensor with a dimension wise start and end index.
startand
endare arrays with as many entries as the tensor has dimensions. They may contain negative values, which are then subtracted from the end of the tensor (e.g.
-1means the element before the last element).
startis inclusive and describes the start index of the selection per dimension and
enddescribes the end index per dimension and is exclusive.
FGraphNode *fslice_step(FGraphNode *a, const long *start, const long *end, const long *step)
Selects a slice of the tensor with a dimension wise start index, end index
and step size.
start,
endand
stepare arrays with as many entries as the tensor has dimensions.
startand
endmay contain negative values, which are then subtracted from the end of the tensor (e.g.
-1means the element before the last element).
startis inclusive and describes the start index of the selection per dimension and
enddescribes the end index per dimension and is exclusive.
stepcontains the per dimension step size (e.g.
2meaning every second element will be selected etc.) and may be negative as well, which reverses the traversal order (the first elements are selected as the last ones). For a negative step size,
start > endmust hold (for a positive of course
end > start) for each dimension.
FGraphNode *fextend(FGraphNode *a, const size_t *new_shape, const size_t *insert_at)
Creates a new tensor of zeroes with the requested shape. The original tensor
is embedded at the given indices.
a
original tensor which shape is to be extendednew_shape
array of new sizes per dimension. Hasdimension
number of entriesinsert_at
array with indices per dimension denoting wherea
is to be placed in the resulting tensor
FGraphNode *fextend_step(FGraphNode *a, const size_t *new_shape, const size_t *insert_at, const long *step_size)
Creates a new tensor of zeroes with the requested shape. The original tensor
is embedded at the given indices.
a
original tensor which shape is to be extended,new_shape
array of new sizes per dimension. Hasdimension
number of entries.insert_at
array with indices per dimension denoting wherea
is to be placed in the resulting tensor. Has a value per dimension.step_size
allows to pull aparta
, emplacingstep_size[i]
0 between each value ofa
. Has a value per dimension.
FGraphNode *fconcat(FGraphNode *a, FGraphNode *b, const unsigned int axis)
Concats two nodes with each other along an axis.
The nodes have to have the same type and dimensions.
e.g.
fconcat({[[0, 1], [2, 3]], [[4, 5], [6, 7]]}, 0) = [[0, 1], [2, 3], [4, 5], [6, 7]]
fconcat({[[0, 1], [2, 3]], [[4, 5], [6, 7]]}, 1) = [[0, 1, 4, 5], [2, 3, 6, 7]]
FGraphNode *fexpand(FGraphNode *a, const unsigned int axis, const unsigned int size)
Adds a new dimension at an arbitrary position to the tensor and repeats the
following dimensions to match a given shape.
ax
the dimension prior to which the new dimension will be inserted (0
means a new dimension in the front,n
means as a new last dimension).ax_size
the new size of that dimension (repeats the following dimensionsax_size - 1
times).
FGraphNode *fabs_g(FGraphNode *a)
Takes the elementwise absolute value of
a, i.e.
|a[i]|
FGraphNode *frepeat(FGraphNode *a, int *repititions)
Repeats dimensions of a tensor multiple times
a
: the node in which dimensions are to be repeatedrepititions
: array with the same number of entries as the tensor has dimensions
repeat([[0,1], [2,3]], [2, 3]) = [[0,1,0,1,0,1], [2,3,2,3,2,3], [0,1,0,1,0,1], [2,3,2,3,2,3]]
FGraphNode *ftranspose(FGraphNode *a, int *transpositions)
Transposes this tensor along multiple dimensions
a
: the node which should be transposedtranspositions
: an array with the same number of entries as the tensor has dimensions, which gives the perumtation of dimensions.
icorresponds to the former size in dimension
transpositions[i].
FGraphNode *fconvolve(FGraphNode *a, FGraphNode *kernel, const unsigned int *steps)
Convolves the
n-dimensional input tensor
awith a
nor
n+1-dimensional filter kernel
kerneland a per dimensional step size
stepswith size of
n-1. It is expected that
aand
kernelhave the same size in their last dimension (which will be completely reduced by the convolution). In all other dimensions the size of
ashould be larger or equal to the size of
kernelor - if kernel has a dimensionality of
n+1- every
ith dimension of
ashould be learger or equal to the dimension
i + 1of kernel, since the first dimension contains each filter. The
kernelwill be 'slid' over
ain each dimension, multiplying all values of
kernelwith the corresponding ones in
aand summing them up to a single value and moving the kernel further by the value given in
stepsin that corresponding dimension. If the filter is
n+1-dimensional the first dimension of
kernelis viewed as an array of filters in which for each a normal convolution is executed and each filter result is added to a new last dimension, meaning the result will instead have
n-dimensionality where the reduced last dimension is replaced by the result of each filter convolution (normal semantic for a convolution with
kfilters in machine learning. Here the semantic representation of the shape of
kernelwould be
(k, 1, kernel_size, ...)where
1is inserted for the batch dimension). The implementation does not include any padding, meaning only convolutions where the complete kernel still fits into the array will be executed (the shape will be calculated correspondingly). If you want to modify this behaviour (i.e. include padding) you can use
extend,
sliceor similar. The resulting Tensor will therefor have a shape with dimensionality
n - 1if kernel is also
ndimensional and size of
(shape[i] - kernel.get_shape()[i] - 1) / steps[i]if
(shape[i] - kernel.get_shape()[i]
- 1) is divisable by
steps[i]
else(shape[i] - kernel.get_shape()[i] - 1)
n+1dimensional the result has dimensionality of
nwith the same shape, except for the last dimension where it will have the numbers of filters (the first dimension of kernel) as its size.
FGraphNode *findex(FGraphNode *a, FGraphNode *indices)
Selects single elements with a index-tensor (integer tensor containing
indices for the selected dimension).
It indexes a dimension of the input tensor and the result has
the shape of the input tensor except for the indexed dimension.
It is assumed that except for the last entry its shape is a prefix of the
shape of the input tensor and the indexing will occur in the matched subsets
(the last dimension of the
indicesTensor is the one indexed in
a). E.g.
findex([[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]], [1, 0]) = [[[4, 5], [6, 7]], [[0, 1], [2, 3]]]
findex([[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]], [0, 0, 1]) = [[[0, 1], [0, 1], [1, 2]], [[3, 4], [3, 4], [5, 6]], [[7, 8], [7, 8], [9, 10]]]
findex([[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]], [[0], [1], [0]]) = [[[0], [2]], [[5], [7]], [[8], [10]]]
findex([[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]], [[0, 0], [1, 0], [0, 1]]) = [[[0, 0], [2, 2]], [[5, 4], [7, 6]], [[8, 9], [10, 11]]]
FGraphNode *findex_set(FGraphNode *a, FGraphNode *b, FGraphNode *indices)
Assigns to each element in
bone element in
awhere that element will be "send" to, i.e. the place in
athe index points to will be set to the corresponding element from
b. If multiple elements from
bare sent to the same place in
athey will be summed up. The shape of
indicesmust be a prefix of the shape of
b, meaning it can have as many dimensions as
bor less, but the sizes of the dimensions must be the same as the first of the shape of
b. E.g.
findex_set([[0, 1], [2, 3], [4, 5], [6, 7]], [[4, 5], [6, 7], [8, 9]], [0, 0, 2]) = [[10, 12], [2, 3], [8, 9], [6, 7]]
findex_set([[0, 1], [2, 3], [4, 5], [6, 7]], [[4, 5], [6, 7], [8, 9], [10, 11]], [[-1, 0], [1, 1], [1, 0], [1, -1]]) = [[5, 1], [2, 13], [9, 8], [6, 10]]
FGraphNode *fsliding_window(FGraphNode *a, const size_t *size, const unsigned int *steps)
Moves a window view with size
sizealong the original Tensor by starting with aligning the first element of the view with the first element of the tensor, copying the elements of the view and moving the window by the step size given for each dimension (the window is first moved in the innermost dimension and after each is iterated moves it in the outer dimensions). Each view becomes a new element in a new outer dimension.
fsliding_window([[0, 1], [2, 3], [4, 5], [6, 7]], [3, 2], [1, 1]) = [[[0, 1], [2, 3], [4, 5]], [[2, 3], [4, 5], [6, 7]]]
fsliding_window([[[0,1,2],[1,2,3],[2,3,4]], [[1,2,3],[2,3,4],[3,4,5]], [[2,3,4],[3,4,5],[4,5,6]], [[3,4,5],[4,5,6],[5,6,7]]], [2, 2, 2], [2, 1, 2]) = [[[[0, 1], [1, 2]], [[1, 2], [2, 3]]], [[[1, 2], [2, 3]], [[2, 3], [3, 4]]], [[[2, 3], [3, 4]], [[3, 4], [4, 5]]], [[[3, 4], [4, 5]], [[4, 5], [5, 6]]]]
FGraphNode *funslide_window(FGraphNode *a, const size_t *shape, const unsigned int *steps)
Reprojects the windows (first dimension of
a) to a common tensor, i.e. if
a = fsliding_window(x, window_size, steps)
shapeshould be the shape of
x, while steps remain the same and the resulting tensor will have the same shape of
xwith the elements in
areprojected to their original position in
x. Overlapping elements will be summed up. Meaning if e.g.
window_sizeand
stepswere the same, the result is exactly
x. If in a dimension
stepswas larger than
window_size, the resulting tensor will have
0elements were the "gaps" between the windows were. If in a dimension
stepswas smaller than
window_size(the windows were "overlapping") the overlapping elements are summed up in the result.
shapeand
stepstherefore have 1 entry less then
ahas dimensions.
FGraphNode *fpermutate(FGraphNode *a, unsigned int ax)
Randomly permutates (=swaps multiple elements with each other without
creating, copying or deleting new ones) one axis of the input tensor.
FGraphNode *fpooling_sum(FGraphNode *a, const size_t *window_size, const unsigned int *step_size)
Slides a window along the Tensor and reduces all elements inside that window
to their sum (just that one remains in the result tensor), and
then slides the window in each dimension by
step_sizeforward (like
fsliding_window). The last dimension is complety pooled, and the result is one dimension smaller then the original tensor
a
the tensor to poolwindow_size
array with one element less thena
has dimension, each describing the window size in that dimension for which for all elements inside each window the maximum should be taken.step_size
array of number of elements the window should be moved after each pooling for each dimension (one element less thena
has dimensions).
FGraphNode *fpooling_max(FGraphNode *a, const size_t *window_size, const unsigned int *step_size)
Slides a window along the Tensor and reduces all elements inside that window
to their maximum element (just that one remains in the result tensor), and
then slides the window in each dimension by
step_sizeforward (like
fsliding_window). The last dimension is complety pooled, and the result is one dimension smaller then the original tensor
a
the tensor to poolwindow_size
array with one element less thena
has dimension, each describing the window size in that dimension for which for all elements inside each window the maximum should be taken.step_size
array of number of elements the window should be moved after each pooling for each dimension (one element less thena
has dimensions).
FGraphNode *fdropout(FGraphNode *g, const double p)
Sets random selected elements in
gto 0 by the chance
p(i.e. if
pis 0.4. each element has a 40% probability of being set to 0).