I've been using Edge Impulse for the past couple of years for creating machine learning algorithms for my projects like my robotic Lego Land Rover Defender. I've successfully installed the Edge Impulse runner on the Ubuntu image for AMD FPGAs such as the Kria SOMs. However, to take full advantage of the Kria's processing power, figuring out how to implement Edge Impulse with hardware acceleration using Vitis is a must.
While I'm still working out the kinks in the accelerated kernel code, I decided the install process of a C++ library of an impulse exported from Edge Impulse Studio into a Vitis workspace deserved its own write-up.
This project assumes that Vivado, Vitis, and XRT (Xilinx Runtime) are already installed on the host PC. I'm using 2022.1 in this project with OpenCV 4.4.0, the following should work with 2022.2 as well, but I have not yet verified this with 2023.1 and later or 2021.2 and earlier (I probably won't bother with 2021.2 and earlier to be honest - if you're following this workflow, you should be using 2022.1 or later).
Install OpenCVFirst, if not already done, the OpenCV libraries for the Vitis Vision library needs to be compiled and installed.
Start by installing a few dependencies:
~$ sudo apt-get install ocl-icd-libopencl1
~$ sudo apt-get install opencl-headers
~$ sudo apt-get install ocl-icd-opencl-dev
This is where I found my first stumbling block. The version of cmake Vitis uses under the hood (and therefore is the version that your Linux machine switches to when you source the Vitis tools to the environment) is too old for OpenCV 4.4.0. So I have to modify the settings script for Vitis to add (ADD, not replace) the newer version:
~$ sudo gedit /tools/Xilinx/Vitis/2022.1/.settings64-Vitis.sh
Then update the script to the following (I aded the newlines for read-ability here, but you don't need them):
/tools/Xilinx/Vitis_HLS/2022.1/bin:
/tools/Xilinx/Model_Composer/2022.1/bin:
/tools/Xilinx/Vitis/2022.1/bin:
/tools/Xilinx/Vitis/2022.1/gnu/microblaze/lin/bin:
/tools/Xilinx/Vitis/2022.1/gnu/arm/lin/bin:
/tools/Xilinx/Vitis/2022.1/gnu/microblaze/linux_toolchain/lin64_le/bin:
/tools/Xilinx/Vitis/2022.1/gnu/aarch32/lin/gcc-arm-linux-gnueabi/bin:
/tools/Xilinx/Vitis/2022.1/gnu/aarch32/lin/gcc-arm-none-eabi/bin:
/tools/Xilinx/Vitis/2022.1/gnu/aarch64/lin/aarch64-linux/bin:
/tools/Xilinx/Vitis/2022.1/gnu/aarch64/lin/aarch64-none/bin:
/tools/Xilinx/Vitis/2022.1/gnu/armr5/lin/gcc-arm-none-eabi/bin:
/tools/Xilinx/Vitis/2022.1/tps/lnx64/cmake-3.24.2/bin: *** make sure cmake 3.24 is before cmake 3.3
/tools/Xilinx/Vitis/2022.1/tps/lnx64/cmake-3.3.2/bin:
/tools/Xilinx/Vitis/2022.1/aietools/bin:
/tools/Xilinx/Vivado/2022.1/bin:
/tools/Xilinx/DocNav:
/home/whitney/.local/bin:
/usr/local/sbin:/usr/local/bin:
/usr/sbin:
/usr/bin:
/sbin:
/bin:
/usr/games:
/usr/local/games:
/snap/bin:
/snap/bin
Next create a new directory to compile the OpenCV source in and clone it:
~$ mkdir -p opencv-4-4-0
~$ cd ./opencv-4-4-0/
~/opencv-4-4-0$ git clone https://github.com/opencv/opencv --branch 4.4.0 source
~/opencv-4-4-0$ git clone https://github.com/opencv/opencv_contrib --branch 4.4.0 source_contrib
Change directories into the source
folder, create a directory called build
, then setup the environment by sourcing the Vitis tools and exporting the appropriate variables:
~/opencv-4-4-0$ cd ./source
~/opencv-4-4-0/source$ mkdir -p build
~/opencv-4-4-0/source$ cd ./build/
~/opencv-4-4-0/source/build$ source /tools/Xilinx/Vitis/2022.1/settings64.sh
~/opencv-4-4-0/source/build$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib64 sudo ldconfig
~/opencv-4-4-0/source/build$ export LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:$LIBRARY_PATH
Then use cmake
to compile OpenCV:
~/opencv-4-4-0/source/build$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=~/opencv-4-4-0/install -D WITH_V4L=ON -D OPENCV_EXTRA_MODULES_PATH=~/opencv-4-4-0/source_contrib/modules/ -DBUILD_TESTS=OFF -DBUILD_ZLIB=ON -DBUILD_JPEG=ON -DWITH_JPEG=ON -DWITH_PNG=ON -DBUILD_EXAMPLES=OFF -DINSTALL_C_EXAMPLES=OFF -DINSTALL_PYTHON_EXAMPLES=OFF -DWITH_OPENEXR=OFF -DBUILD_OPENEXR=OFF -D CMAKE_CXX_COMPILER=/tools/Xilinx/Vitis_HLS/2022.1/tps/lnx64/gcc-6.2.0/bin/g++ ../
And finally, install using make
:
~/opencv-4-4-0/source/build$ make all -j8
~/opencv-4-4-0/source/build$ make install
Once OpenCV has been compiled and installed, you can go back and remove the later cmake version from the Vitis settings script. I never did and I haven't had any issues so far, but just remember this is Vitis does something funky to you in the future...
Export C++ Library from Edge Impulse StudioNow that everything is installed and ready, download your impulse from Edge Impulse Studio as a C++ Library.
Assuming you've already designed your impulse and trained it, go to the deployment tab and search for C++ in deployment options. Then select C++ library:
Select Quantized (int8) then click build. The DSP48E2 slices in the Kria SOMs and other AMD FPGAs are optimized for INT8 computations, so selecting the unoptimized float32 option would make this whole exercise pointless.
Upon completion, the C++ library will automatically be downloaded to your PC as a ZIP file:
Now that the impulse C++ library is downloaded, we can create the accelerated application project in Vitis. I've covered the basics of accelerated application development on the Kria in Vitis 2022.1 in detail here, so I'm starting with that Vitis workspace here to save some time. I'm just adding a new application project to it using the same platform project I created already (this is one of my big timesaver tips for AMD FPGA boards when reusing them for multiple projects).
From the Vitis workspace, select New > Application Project...
Select the KR260 custom platform to build the application on, then give the application the desired name:
Then provide the application project the path to the sysroot, root filesystem, and kernel image for the KR260 generated from PetaLinux:
Finally, select the Simple Vector Addition template. This will make some of the naming weird with "vadd" everywhere, but it's easier than creating the file structure from scratch and linking everything.
Once the new application project is generated, the next step is to import the C++ library of your impulse as source files.
Under the new application name, right-click on the src folder and select Import Sources...
Then navigate to wherever you extracted the downloaded ZIP file from EI Studio and import it as a whole, being sure to keep the full file structure within it intact (I had pre-generated a new main.cpp
I was also importing, so you can ignore that if you haven't already):
While having the impulse's C++ library imported into the application project is half the battle, the compiler within Vitis doesn't understand that it's a library it needs to call and will simply try to compile it as source code. Which needless to say will cause all sorts of heartburn and accomplish nothing. So we need to tell Vitis that the impulse's C++ library is indeed a library in the application project's C/C++ Build Settings.
Right-click on the application project name from the Explorer window and select C/C++ Build Settings.
In the Settings window, navigate to C/C++ Build > Settings. Then under GCC Host Linker (ARMv8-A for A53/A72 - 64 bit) > Libraries, you'll see the option for Libraries and Library search path.
Add the math library in Libraries since we'll be doing quite a bit of mathing (can you tell I write these projects late at night???)... Click the little plus icon and just type the m flag. Then add the lib directory of the OpenCV installation to Library search path (/<OpenCV install path>/install/lib/
):
Then in Include Paths under GCC Host Compiler (ARMv8-A for A53/A72 - 64 bit) > Includes, add the paths to the OpenCV include directory and the C++ library of the impulse as imported into the application project (./<application name>/src/
). So for me, those paths were:
~/opencv-4-4-0/install/include/opencv4
~/Kria_KR260/kr260_custom_platform/edge_impulse_v0/src/
Click Apply and Close to save the settings.
Create New Main.cFinally, create a new main function to call the impulse. Right-click on the src
folder and select create new file.
I just used the template from Edge Impulse docs and added the include path for the OpenCV library (which is necessary for the code to pull from the video source like the USB webcam) as a quick sanity check that the application would compile with the C++ library before I dove into moving elements into the accelerated kernel. I've attached it below for reference.
I did find that I had to fix one pointer in the way is was initializing memory in ./tensorflow/lite/c/common.c
:
Otherwise, everything compiled cleanly and proved to be a good starting point for accelerated development. Stay tuned for the next post!
Comments