LicheeRV Nanoでncnnをクロスコンパイルしてbenckmarkを実行する手順


## 目的
PC(Ubuntu)にクロスコンパイル環境を構築して、ディープラーニングフレームワークのncnnとベンチマークソフトウェアのbenchmarkビルドし、LicheeRV Nano
でncnn benchmarkを実行します。

https://github.com/nnn112358/ncnn_benchmark_test

また、こちらのリポジトリで、これまでにCoreMP135、Raspberry Pi Zero 2 W、M5Stack_UnitV2、LicheeNano RV、Luckfox Pico Maxでのncnn benchmarkを比較した結果を公開しています。



## PC環境
まず以下のバージョンのUbuntuをインストールしたPC環境で、クロスコンパイル環境を構築します。

```
Ubuntu 22.04.3 LTS(x64)
```

## コンパイルに必要なライブラリのインストール

 コンパイルに必要なライブラリを含むパッケージをaptからインストールします
 
```
$ sudo apt install pkg-config build-essential ninja-build automake autoconf libtool wget curl git gcc libssl-dev bc slib squashfs-tools android-sdk-libsparse-utils android-sdk-ext4-utils jq cmake python3-distutils tclsh scons parallel ssh-client tree python3-dev python3-pip device-tree-compiler libssl-dev ssh cpio squashfs-tools fakeroot libncurses5 flex bison
```

ツールチェインをダウンロードして、解凍します。

```
$ cd /opt/
$ sudo wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/03/07/16/host-tools.tar.gz
$ sudo tar xvf host-tools.tar.gz
$ sudo chmod +r /opt/host-tools/
```

ツールチェインへのパスを通します。

```
$ export RISCV_ROOT_PATH="/opt/host-tools/gcc/riscv64-linux-musl-x86_64/"
```


以下のコマンドを実行して、コンパイラのバージョン情報が出てれくれば、ツールチェインのインストールが完了です。

```
$ ${RISCV_ROOT_PATH}bin/riscv64-unknown-linux-musl-g++ -v
Using built-in specs.
COLLECT_GCC=/opt/host-tools/gcc/riscv64-linux-musl-x86_64//bin/riscv64-unknown-linux-musl-g++
COLLECT_LTO_WRAPPER=/opt/host-tools/gcc/riscv64-linux-musl-x86_64/bin/../libexec/gcc/riscv64-unknown-linux-musl/10.2.0/lto-wrapper
Target: riscv64-unknown-linux-musl
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (Xuantie-900 linux-5.10.4 musl gcc Toolchain V2.6.1 B-20220906)
```


## ncnnのインストール
ncnnは、Tencentが開発しているモバイルプラットフォーム向けに最適化された高性能なニューラルネットワーク推論コンピューティングフレームワークです。

このシェルスクリプトで、ARMプロセッサ向けにncnnライブラリをgitからクローン、ビルド、そしてインストールします。

```
$ git clone https://github.com/Tencent/ncnn.git -b 20240410 --depth 1 
$ cd ncnn/
```

LicheeRV Nanoのc906用のビルド設定ファイルを作成します。

```
$ gedit ./toolchains/c906-v240.toolchain.cmake
```

```c906-v240.toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR riscv64)
set(C906 True)

if(DEFINED ENV{RISCV_ROOT_PATH})
    file(TO_CMAKE_PATH $ENV{RISCV_ROOT_PATH} RISCV_ROOT_PATH)
else()
    message(FATAL_ERROR "RISCV_ROOT_PATH env must be defined")
endif()

set(RISCV_ROOT_PATH ${RISCV_ROOT_PATH} CACHE STRING "root path to riscv toolchain")

set(CMAKE_C_COMPILER "${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-musl-gcc")
set(CMAKE_CXX_COMPILER "${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-musl-g++")

set(CMAKE_FIND_ROOT_PATH "${RISCV_ROOT_PATH}/riscv64-unknown-linux-gnu")

set(CMAKE_SYSROOT "${RISCV_ROOT_PATH}/sysroot")

if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM)
    set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
endif()
if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
    set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
endif()
if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
    set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
    set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
endif()

set(CMAKE_C_FLAGS "-march=rv64gcv0p7_zfh_xtheadc -mabi=lp64d -mtune=c906 -DC906=1 -static")
set(CMAKE_CXX_FLAGS "-march=rv64gcv0p7_zfh_xtheadc -mabi=lp64d -mtune=c906 -DC906=1 -static")

# cache flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags")
```

```
$ cmake -B build/c906 -DCMAKE_TOOLCHAIN_FILE=../toolchains/c906-v240.toolchain.cmake -DCMAKE_BUILD_TYPE=release -DNCNN_BUILD_TESTS=ON -DNCNN_OPENMP=OFF -DNCNN_THREADS=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_RVV=ON -DNCNN_SIMPLEOCV=ON -DNCNN_BUILD_EXAMPLES=OFF . 
$ cmake --build build/c906 
$ cmake --install build/c906 --prefix install/c906
```

## ncnn benckmarkのインストール

ncnnディレクトリ内でbenckmarkのファイルを整理し、それをzip圧縮します。

```
$ cd ncnn
$ mkdir install/c906/benchmark
$ cp ./build/c906/benchmark/benchncnn ./install/c906/benchmark
$ cp ./benchmark/*.param ./install/c906/benchmark
$ zip -r ./install/c906/riscv_c906_ncnn_benchmark.zip ./install/c906/benchmark

```

## LicheeRV Nanoでのベンチマークの実行

zipファイルをLicheeRV Nanoにscpでコピー、LicheeRV Nanoでncnn benchmarkを実行します。


```
# unzip riscv_c906_ncnn_benchmark.zip 
# cd benchmark
# ./benchncnn 4 1 0 -1 1
loop_count = 4
num_threads = 1
powersave = 0
gpu_device = -1
cooling_down = 1
          squeezenet  min =  258.75  max =  265.83  avg =  260.87
     squeezenet_int8  min = 9659.92  max = 9667.19  avg = 9665.30
           mobilenet  min =  398.63  max =  401.00  avg =  399.75
      mobilenet_int8  min = 14793.44  max = 14806.26  avg = 14798.42
        mobilenet_v2  min =  297.37  max =  299.08  avg =  298.39
        mobilenet_v3  min =  243.94  max =  244.84  avg =  244.30
          shufflenet  min =  441.43  max =  444.05  avg =  442.29
       shufflenet_v2  min =  281.79  max =  282.26  avg =  281.99
             mnasnet  min =  298.63  max =  299.22  avg =  298.87
     proxylessnasnet  min =  349.01  max =  356.01  avg =  350.96
     efficientnet_b0  min =  423.65  max =  431.97  avg =  426.17
   efficientnetv2_b0  min =  587.97  max =  588.66  avg =  588.39
        regnety_400m  min =  416.59  max =  418.47  avg =  417.32
           blazeface  min =  133.46  max =  133.72  avg =  133.57
           googlenet  min =  995.92  max =  996.87  avg =  996.34
      googlenet_int8  min = 21981.34  max = 22006.10  avg = 21994.08
            resnet18  min =  709.38  max =  710.55  avg =  709.81
       resnet18_int8  min = 22158.76  max = 22167.79  avg = 22161.85
Killed
```

LicheeRV Nanoでncnnをクロスコンパイルしてbenckmarkを実行することができました。


## 参考資料

https://github.com/nnn112358/ncnn_benchmark_test

https://qiita.com/nnn112358/items/5b978464b005e7209fd8

https://qiita.com/nnn112358/items/5cfc32fd6cd1c8f4fe47

https://qiita.com/nnn112358/items/a4e262efd91641684402

https://qiita.com/nnn112358/items/67847f6779a3deadd5d4

https://qiita.com/nnn112358/items/25f2e08b00d3ca360e97