Search code examples
c#c++arrayfire

Convert af::array to af_array and back


I would like to use the ArrayFire library to run multiple artificial neural networks on the GPU in parallel.

Since I am mainly a C# developer I tried to realize it via SiaNet. But I encountered the problem that SiaNet can only run one neural network at a time.

This is because SiaNet and the C# API of ArrayFire do not implement the batchFunc function.

I wanted to make up for this and built my own little library. There I call the batchFunc function and want to build an API which can be called from C# with PInvokes.

The problem is that I can only use af_array from C#, but the batchFunc function can only process af::array. Therefore I need to convert one into the other.

My MatrixMultiply function, to have a function that I can pass batchFunc:

af::array MatrixMultiply(const af::array &lhs, const af::array &rhs) {
    return matmul(lhs, rhs);
}

My PInvoke friendly function:

af_err BatchMatmul(af_array *out, const af::array lhs, const af::array rhs) {
    try
    {
    *out = &(af::batchFunc(lhs, rhs, MatrixMultiply));

    return AF_SUCCESS;
    }
    catch (af::exception& e) {
    fprintf(stderr, "%s\n", e.what());
    return AF_ERR_BATCH;
    }
}

As I call it on C# side:

[DllImport("BatchOpsWrapperLib.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
public static extern af_err BatchMatmul(out IntPtr array_out, IntPtr array_lhs, IntPtr array_rhs);

I have hardly or not at all worked with C/C++ so far and would like to ask you for help here.

Edit: This is my reworked new function:

af_err BatchMatmul(af_array *out, const af_array lhs, const af_array rhs)
{
    try
    {
        af_array retainedLhs = 0;
        af_array retainedRhs = 0;

        af_retain_array(&retainedLhs, lhs);
        af_retain_array(&retainedRhs, rhs);

        af_array resultHandle = 0;

        af_retain_array(&resultHandle, af::batchFunc(af::array(retainedLhs),
                                                     af::array(retainedRhs),
                                                     MatrixMultiply).get());

        *out = resultHandle;

        return AF_SUCCESS;
    }
    catch (af::exception& e) {
        fprintf(stderr, "%s\n", e.what());
        return AF_ERR_BATCH;
    }
}

Solution

  • An af::array instance has a method .get(), from which you can retrieve an af_array instance.

    af::array some_array = ...;
    af_array c_array = some_array.get();
    

    You can also construct an af::array from an af_array using af::array(some_af_array).

    af::array another_array = af::array(c_array);`