Intel® Movidius™ Neural Compute SDK C API v2
The Intel® Movidius™ Neural Compute SDK (Intel® Movidius™ NCSDK) comes with a C language API (API) that enables developers to create applications in C or C++ that utilize hardware-accelerated Deep Neural Networks via neural compute devices like the Intel® Movidius™ Neural Compute Stick.
The C API is provided as a header file (mvnc.h) and an associated library file (libmvnc.so), both of which are placed on the development computer when the NCSDK is installed.
Documentation
Enumerations | |
---|---|
ncDeviceHwVersion_t | Contains neural compute device hardware versions. |
ncDeviceOption_t | Contains neural compute device options. |
ncDeviceState_t | Contains neural compute device NCAPI states. |
ncFifoDataType_t | Contains FIFO queue element data types. |
ncFifoOption_t | Contains FIFO queue options. |
ncFifoState_t | Contains FIFO queue NCAPI states. |
ncFifoType_t | Contains FIFO queue access types. |
ncGlobalOption_t | Contains global (application-level) options. |
ncGraphOption_t | Contains network graph options. |
ncGraphState_t | Contains network graph NCAPI states. |
ncLogLevel_t | Contains application logging levels. |
ncStatus_t | Contains status code return values for NCAPI functions. |
Structs | |
---|---|
struct ncDeviceHandle_t | Holds data and resources corresponding to a neural compute device. |
struct ncFifoHandle_t | Holds data and resources corresponding to a FIFO queue. |
struct ncGraphHandle_t | Holds data and resources corresponding to network graph. |
struct ncTensorDescriptor_t | Holds information that describes the shape of a tensor. |
Global Functions | |
---|---|
ncGlobalGetOption | Gets the value of a global option for the application. |
ncGlobalSetOption | Sets the value of a global option for the application. |
Device Functions | |
---|---|
ncDeviceClose | Closes communication with a previously opened neural compute device. |
ncDeviceCreate | Initializes a ncDeviceHandle_t struct for use with the NCAPI. |
ncDeviceDestroy | Destroys a device handle and frees associated resources. |
ncDeviceGetOption | Gets the value of an option for a neural compute device. |
ncDeviceOpen | Boots and initializes a neural compute device and opens communication. |
ncDeviceSetOption | Sets the value of an option for a neural compute device. |
FIFO Functions | |
---|---|
ncFifoAllocate | Allocates a FIFO buffer for graph input or output. |
ncFifoCreate | Initializes a ncFifoHandle_t struct for use with the NCAPI. |
ncFifoDestroy | Destroys a FIFO handle and frees associated resources. |
ncFifoGetOption | Gets the value of an option for a FIFO. |
ncFifoReadElem | Reads an element from a FIFO. |
ncFifoRemoveElem | Not yet implemented. |
ncFifoSetOption | Sets the value of an option for a FIFO. |
ncFifoWriteElem | Writes an element to a FIFO. |
Graph Functions | |
---|---|
ncGraphAllocate | Allocates a graph to a neural compute device. |
ncGraphCreate | Initializes a ncGraphHandle_t struct for use with the NCAPI. |
ncGraphDestroy | Destroys a graph handle and frees associated resources. |
ncGraphQueueInference | Queues an inference from a network graph. |
ncGraphGetOption | Gets the value of an option for a graph. |
ncGraphSetOption | Sets the value of an option for a graph. |
Convenience Functions | |
---|---|
ncGraphAllocateWithFifos | Allocates a network graph and creates and allocates associated FIFOs with default options. |
ncGraphAllocateWithFifosEx | Allocates a network graph and creates and allocates associated FIFOs with explicit options. |
ncGraphQueueInferenceWithFifoElem | Writes an input tensor to a FIFO and queues an inference from a network graph. |
C API Overview
1. Import the NCAPI
Import the mvnc.h
header and anything else that you need.
#include <stdio.h>
#include <stdlib.h>
#include <mvnc.h>
int main(void) {
// Every NCAPI function will return a status code that should normally be NC_OK
ncStatus_t retCode;
...
You can get and set application-level information and options with ncGlobalGetOption() and ncGlobalSetOption().
2. Set up a neural compute device
The ncDeviceHandle_t struct is used to represent a neural compute device throughout the NCAPI. The NCAPI provides functions to communicate with the device.
Initialize a device handle with ncDeviceCreate().
// Create a device handle for the first device found (index 0)
struct ncDeviceHandle_t* deviceHandle;
retCode = ncDeviceCreate(0, &deviceHandle);
if (retCode != NC_OK) {
printf("Error [%d]: Could not create a neural compute device handle.\n", retCode);
exit(-1);
}
Boot and initialize the neural compute device and open communication with ncDeviceOpen().
// Boot the device and open communication
retCode = ncDeviceOpen(deviceHandle);
if (retCode != NC_OK) {
printf("Error [%d]: Could not open the neural compute device.\n", retCode);
exit(-1);
}
You can get information about the device using ncDeviceGetOption() for options in the ncDeviceOption_t enumeration.
*Note: If you are using more than one neural compute device, you must create and open a separate device handle for each.
3. Set up a network graph and associated FIFO queues for the device
The NCSDK requires a neural network graph file compiled with the mvNCCompile NCSDK tool. Many network models from TensorFlow* and Caffe are supported. See Configuring Your Network for the Intel® Movidius™ Neural Compute SDK for more information about preparing your network model for use with the NCSDK.
When you have a compiled graph, load the graph file data to a buffer.
// Load the graph file into a buffer
// void* graphFileBuffer = ...
// unsigned int graphFileLength = ...
The ncGraphHandle_t struct is used to represent a neural network graph throughout the NCAPI. The NCAPI provides functions to perform inferences using the graph.
Initialize the graph handle with a name string. The name string can be anything you like up to NC_MAX_NAME_SIZE characters, or just an empty string. You can read this name later with ncGraphGetOption().
// Initialize a graph handle
struct ncGraphHandle_t* graphHandle;
retCode = ncGraphCreate("graph1", &graphHandle);
if (retCode != NC_OK) {
printf("Error [%d]: Could not create a graph handle.\n", retCode);
// Do clean up...
exit(-1);
}
Graph input and output is done with FIFO (first-in, first-out) queues. The ncFifoHandle_t struct is used to represent a FIFO throughout the NCAPI. The NCAPI provides functions for managing FIFO queues.
Create input and output FIFO queues for the graph using default FIFO options and allocate the graph to the device with ncGraphAllocateWithFifos().
// Allocate the graph to the device and create input and output FIFOs with default options
struct ncFifoHandle_t* inFifoHandle;
struct ncFifoHandle_t* outFifoHandle;
retCode = ncGraphAllocateWithFifos(deviceHandle, graphHandle, graphFileBuffer,
graphFileLength, &inFifoHandle, &outFifoHandle);
if (retCode != NC_OK) {
printf("Error [%d]: Could not allocate graph with FIFOs.\n", retCode);
// Do clean up...
exit(-1);
}
free(graphFileBuffer);
You can also use ncGraphAllocateWithFifosEx() to explicitly set FIFO options for type, data type, and size. See the ncFifoHandle_t documentation for more information on creating and allocating FIFOs.
You can get information about a graph using ncGraphGetOption() for options in the ncGraphOption_t enumeration. You can get information about a FIFO using ncFifoGetOption() for options in the ncFifoOption_t enumeration.
*Note: You must create and allocate a graph handle for each network graph file that you wish to use. A neural compute device can have more than one graph allocated to it, but each graph can only be allocated to a single device.
4. Get an input tensor
The way that you obtain and pre-process your input tensor will depend on your individual application. OpenCV and GStreamer are popular libraries for loading and manipulating images from file or a camera stream.
Input tensor data must be the data type specified by the NC_RW_FIFO_DATA_TYPE option for the input FIFO. The default is 32-bit floating point, but FIFOs can also be configured to store 16-bit floating point data. See the ncFifoDataType_t.html enumeration.
// Load an input tensor and do pre-processing...
// float* imageBuffer = ...
// unsigned int imageBufferLength = ...
The NCSDK includes example applications that demonstrate image tensor pre-processing for several networks.
5. Perform an inference
Use ncGraphQueueInferenceWithFifoElem() to write the input tensor to your input FIFO and queue it for inference. When the inference is complete the input tensor will be removed from the input FIFO and the result tensor will be placed in the output FIFO. The third parameter is the size of the input tensor in bytes. This must match the expected size for the network. The fourth parameter can be any data that you wish to have associated with this particular tensor when you read the inference result, such as the original tensor or a window handle, or NULL.
// Write the tensor to the input FIFO and queue an inference
retCode = ncGraphQueueInferenceWithFifoElem(
graphHandle, inFifoHandle, outFifoHandle, imageBuffer, &imageBufferLength, NULL);
if (retCode != NC_OK) {
printf("Error [%d]: Could not write to the input FIFO and queue an inference.\n", retCode);
// Do clean up...
exit(-1);
}
If the input FIFO is full, this function call will block until there is room to write to the FIFO. You can check how many elements are in the input and output FIFOs with ncFifoGetOption() for NC_RO_FIFO_WRITE_FILL_LEVEL and NC_RO_FIFO_READ_FILL_LEVEL, respectively. Note that the inference will take some amount of time to complete, depending on network model speed and device communication latency, so you may need to wait to see updated levels.
After the inference is complete, you can get the inference result with ncFifoReadElem(). The size of the output tensor will depend on the network definition as well as the output FIFO’s data type. You can calculate the size of the output tensor yourself or use ncFifoGetOption() for NC_RO_FIFO_ELEMENT_DATA_SIZE to get the correct size.
// Get the size of the output tensor
unsigned int outFifoElemSize = 0;
unsigned int optionSize = sizeof(outFifoElemSize);
retCode = ncFifoGetOption(outFifoHandle, NC_RO_FIFO_ELEMENT_DATA_SIZE,
&outFifoElemSize, &optionSize);
if (retCode != NC_OK) {
printf("Error [%d]: Could not get the output FIFO element data size.\n", retCode);
// Do clean up...
exit(-1);
}
// Get the output tensor
float* resultData = (float*) malloc(outFifoElemSize);
void* userParam; // this will be set to point to the user-defined data that you passed into ncGraphQueueInferenceWithFifoElem() with this tensor
retCode = ncFifoReadElem(outFifoHandle, (void*)resultData, &outFifoElemSize, &userParam);
if (retCode != NC_OK) {
printf("Error [%d]: Could not read the result from the ouput FIFO.\n", retCode);
// Do clean up...
exit(-1);
}
You can then use the output result as intended for your particular network model.
6. Clean up
Before closing communication with the device, use ncGraphDestroy() and ncFifoDestroy() to set graph and FIFO handles to NULL and clean up associated memory. The FIFOs must be empty before being destroyed. Then use ncDeviceClose() to close the device and ncDeviceDestroy() to set the device handle to NULL and clean up associated memory.
// Clean up the FIFOs
ncFifoDestroy(&inFifoHandle);
ncFifoDestroy(&outFifoHandle);
// Clean up the graph
ncGraphDestroy(&graphHandle);
// Close and clean up the device
ncDeviceClose(deviceHandle);
ncDeviceDestroy(&deviceHandle);
}