Integration of muRISCV-NN kernel library in TVM

Our team at the TU Munich (@r.stahl @fabian) has recently open-sourced our work on porting the ARM CMSIS-NN library to RISC-V targets: https://github.com/tum-ei-eda/muriscv-nn

Let me shortly summarize the features:

  • Support for 3 Modes: Default (Portable C-Code), Packed (P-Extension, sub-word SIMD, v0.9.2), Vector (V-Extension, super-word SIMD, v1.0)
  • CMSIS-NN Compatibility layer: You can simply use libmuriscv-nn.a instead of lib libcmsis-nn.a and you should be good to go without changing any code.
  • This allows using the library not only using the TFLite micro framework but also in TVM using the CMSIS-NN BYOC integration.

The main reason for this post is discussing if this library would be a good contribution to TVM bringing the RISC-V support in (Micro)TVM one step further. If there is interest I would be happy to formulate an RFC for this.

However these are my current concerns:

  • The library is already usable using the existing CMSISNN BYOC implementation. Thus it wouldn’t make sense to copy and paste all the available code for adding muRiscvNN support as well.
  • The only thing I would like to get rid of if the fake-mapping of the mcpu PassConfig used by the BYOC code to decide which extensions should be enabled. Currently for enabling the P/V-Extension we use --target-cmsis-nn-mcpu=cortex-m33/55 which is quite unintuitive.

I am looking forward to any feedback.

4 Likes

Here are some Metrics generated for the MLPerf Tiny Benchmark. The Instruction Counts are obtained using the Spike Simulator/ISS and therefore not cycle-accurate as RVV1.0 compatible chips are not yet available.

@PhilippvK this looks like great work! is there a demo script that shows how to integrate muRISCV-NN with TVM? perhaps we could look at the mcpu issue in that context.

@PhilippvK this looks like great work! is there a demo script that shows how to integrate muRISCV-NN with TVM? perhaps we could look at the mcpu issue in that context.

I recently added some integration tests which can be found here: https://github.com/tum-ei-eda/muriscv-nn/blob/integration-tests/Integration/TVM/tvm_integration_tests.sh

If only considering the V-Extension the complete flow can be broken down to:

# clone muriscvnn
git clone https://github.com/tum-ei-eda/muriscv-nn.git
cd muriscv-nn
git checkout integration-tests

# download toolchain
cd Toolchain && ./download_rv32gcv.sh && cd -
export TOOLCHAIN_DIR=$(pwd)/Toolchain/rv32gcv

# install tvm
virtualenv -p python3.8 .venv # optional
source .venv/bin/activate # optional
pip install "tlcpack-nightly" -f https://tlcpack.ai/wheels
pip install tflite

# install muriscvnn
cmake . -B./build -DUSE_VEXT=ON -DUSE_PEXT=OFF -DTOOLCHAIN=GCC -DRISCV_GCC_PREFIX=$TOOLCHAIN_DIR -DENABLE_TESTS=OFF
cmake --build ./build

# download model
wget -q https://raw.githubusercontent.com/tum-ei-eda/mlonmcu-models/main/resnet/resnet.tflite

# generate mlf
tvmc compile resnet.tflite --runtime crt --executor aot --pass-config "tir.disable_vectorize=1" --pass-config "tir.usmp.enable=1" --pass-config "tir.usmp.algorithm=hill_climb" --opt-level 3 -f mlf --runtime-crt-system-lib 0 --target-c-constants-byte-alignment 4 --target-c-workspace-byte-alignment 4 --target-c-executor aot --target-c-unpacked-api 1 --target-c-interface-api c --output mlf.tar --target cmsis-nn,c --target-cmsis-nn-mcpu=cortex-m55
mkdir -p mlf
tar xf mlf.tar -C mlf/

# build runtime
export PREFIX=$TOOLCHAIN_DIR/bin/riscv32-unknown-elf
cd mlf/runtime
cp template/crt_config-template.h crt_config.h
make common -j`nproc` \
        CRT_CONFIG=crt_config.h \
        CC=$PREFIX-gcc \
        CXX=$PREFIX-g++ \
        RANLIB=$PREFIX-ranlib \
        EXTRA_CFLAGS="-Wno-error=incompatible-pointer-types"
cd -

# build target sw
KERNEL_SRCS=($(find ./mlf/codegen/host/src -name "*.c"))
# The following should be transformed into a makefile
$PREFIX-gcc -o main.elf Integration/TVM/sw/main.c ${KERNEL_SRCS} \
       -I./mlf/runtime/include/ \
       -I./mlf/codegen/host/include \
       -I./Include/CMSIS/NN/Include/ \
       -I./Include/ \
       -L./build/Source/ \
       -L./mlf/runtime/build/ \
       -lmuriscv_nn \
       -lcommon \
       -Wno-implicit-function-declaration \
       -Wno-incompatible-pointer-types \
       -Wno-attributes

# install spike
cd ./Sim/Spike/bin && ./download.sh && cd -

# run simulation
./Sim/Spike/bin/spike --isa=rv32gcv --varch=vlen:1024,elen:32 ./Sim/Spike/bin/pk main.elf

Ideally we whole flow would be based on MicroTVM, which is currently lacking support for Spike Simulation.


For the main discussion of the mcpu mapping only the --target-cmsis-nn-mcpu=cortex-m55 part is relevant. For riscv targets the existing extensions can be obtained either from the -march=rv32gcv string (GCC) or from the -mattr=+v features (LLVM). I think hardcoding mcpu -> MVEI/DSP mappings for RISC-V targets in the cmsis-nn BYOC backend does not sound like a good idea to me. In addition if muRISCV-NN would be a good addition to the TVM ecosystem, we should also consider adding the following:

  • Add documentation/tutorials
  • Add Tests
  • CI Integration (RISC-V Toolchain (GCC/LLVM), Spike Simulator)
  • MircoTVM Template capable of running Spike