Saver Tutorial: Save execution sequence with Saver and replay on a backend

This tutorial describes how to use the QNN Saver backend to capture the execution sequence of QNN APIs. The captured output can then be compiled and replayed on any QNN backend.

Linux

Generating saver_output.c

saver_output.c is an artifact produced by running a model on the Saver backend. A model in a source framework can be converted into a model.cpp and model.bin using the QNN Converters. Sample model.cpp and model.bin files are located in ${QNN_SDK_ROOT}/examples/QNN/converter/models/.

model.cpp and model.bin are used to create a model.so via qnn-model-lib-generator.

$ ${QNN_SDK_ROOT}/bin/x86_64-linux-clang/qnn-model-lib-generator \
              -c ${QNN_SDK_ROOT}/examples/QNN/converter/models/qnn_model_float.cpp \
              -b ${QNN_SDK_ROOT}/examples/QNN/converter/models/qnn_model_float.bin \
              -o ${QNN_SDK_ROOT}/examples/QNN/converter/model_libs # This can be any path

This will produce the following artifacts:

  • ${QNN_SDK_ROOT}/examples/QNN/converter/model_libs/aarch64-android/libqnn_model_float.so

  • ${QNN_SDK_ROOT}/examples/QNN/converter/model_libs/x86_64-linux-clang/libqnn_model_float.so

The resulting model.so can be run on the Saver backend using qnn-net-run:

$ cd ${QNN_SDK_ROOT}/examples/QNN/converter/models/
$ ${QNN_SDK_ROOT}/bin/x86_64-linux-clang/qnn-net-run \
              --backend ${QNN_SDK_ROOT}/lib/x86_64-linux-clang/libQnnSaver.so \
              --model ${QNN_SDK_ROOT}/examples/QNN/converter/model_libs/x86_64-linux-clang/libqnn_model_float.so \
              --input_list input_list_float.txt

This will produce the following artifacts:

  • ./saver_output/saver_output.c

  • ./saver_output/params.bin

See Tutorial: Converting and executing a CNN model with QNN for more information on converting a model from a source framework into the QNN shared library format.

Alternatively, the following script performs the steps described above and can be used for convenience.

$ cd ${QNN_SDK_ROOT}/examples/QNN/NetRun/linux-x86_64
$ ./linux-qnn-net-run.sh -b saver

This will produce a quantized saver_output.c and params.bin in ${QNN_SDK_ROOT}/examples/QNN/NetRun/linux-x86_64/saver_output/quantized/ for replay on DSP or HTP backends, and a non-quantized saver_output.c and params.bin in ${QNN_SDK_ROOT}/examples/QNN/NetRun/linux-x86_64/saver_output/non_quantized/ for replay on CPU or GPU backends.

Compiling saver_output.c

To compile saver_output.c for replay on a backend, use the Makefile located in ${QNN_SDK_ROOT}/examples/QNN/Saver. This makefile can be used to compile saver_output.c for the specified QNN backend on a compatible platform.

Note

  • Compiling for x86 targets requires clang.

  • Compiling for Android targets requires Android NDK.

  • Compiling for DSP/HTP backends on Android targets requires Hexagon SDK.

Refer to Setup to set the appropriate environment variables.

With saver_output.c located in the same directory as Makefile, run make all to compile for all QNN backends on supported targets.

$ cp ./saver_output/saver_output.c ${QNN_SDK_ROOT}/examples/QNN/Saver
$ cp ./saver_output/params.bin ${QNN_SDK_ROOT}/examples/QNN/Saver
$ cd ${QNN_SDK_ROOT}/examples/QNN/Saver
$ make x86 android

This will produce a folder for each target:

  • ./x86_64-linux-clang

  • ./aarch64-android

These folders will contain one executable for each backend available on the target named saver_output_<backend>.

To create executables for all backends on a specific target, run make <target>. Valid options for <target> are x86 or aarch64.

To create an executable for a specific backend on a specific target, run make <backend>_<target>. Valid options for <backend> are cpu or htp for <target>=x86, and cpu, gpu, dsp, hta, or htp for <target>=aarch64.

Replaying saver_output.c on x86

To replay on x86 backends, set LD_LIBRARY_PATH to point to the desired QNN backend library and run the executable. Ensure params.bin is in the current working directory.

$ cd ${QNN_SDK_ROOT}/examples/QNN/Saver
$ export QNN_BACKEND=<backend> # where <backend> is QnnCpu or QnnHtp
$ export LD_LIBRARY_PATH=${QNN_SDK_ROOT}/lib/x86_64-linux-clang:$LD_LIBRARY_PATH
$ ./x86_64-linux-clang/saver_output_${QNN_BACKEND} [--logging <verbose,debug,info,warn,error>] # optionally enable logging

Replaying saver_output.c on Android

Replay on QNN CPU, QNN HTA, or QNN GPU Backend

Make a directory on device, push QNN backend library, saver_output.c executable, and params.bin:

$ export QNN_BACKEND=<backend> # where <backend> is QnnCpu, QnnHta, or QnnGpu
$ adb shell "mkdir /data/local/tmp/saver"
$ adb push ${QNN_SDK_ROOT}/lib/aarch64-android/lib${QNN_BACKEND}.so /data/local/tmp/saver
$ adb push ${QNN_SDK_ROOT}/examples/QNN/Saver/aarch64-android/saver_output_${QNN_BACKEND} /data/local/tmp/saver
$ adb push ./saver_output/params.bin /data/local/tmp/saver

Set LD_LIBRARY_PATH on device and execute

$ adb shell
$ cd /data/local/tmp/saver
$ export LD_LIBRARY_PATH=/data/local/tmp/saver:$LD_LIBRARY_PATH
$ ./saver_output_${QNN_BACKEND} [-l <verbose,debug,info,warn,error>] # optionally enable logging

Replay on QNN DSP or QNN HTP Backend

Make a directory on device, push QNN backend stub/skel, saver_output.c executable, and params.bin:

$ export QNN_BACKEND=<backend>  # where <backend> is QnnDsp or QnnHtp
$ export HEXAGON_ARCH=<v65,v66,v68,v69,v73,v75>  # based on device
$ adb shell "mkdir data/local/tmp/saver"
$ adb push ${QNN_SDK_ROOT}/lib/aarch64-android/lib${QNN_BACKEND}.so /data/local/tmp/saver
$ adb push ${QNN_SDK_ROOT}/lib/aarch64-android/lib${QNN_BACKEND}${HEXAGON_ARCH^}Stub.so /data/local/tmp/saver
$ adb push ${QNN_SDK_ROOT}/lib/hexagon-${HEXAGON_ARCH}/unsigned/lib${QNN_BACKEND}${HEXAGON_ARCH^}Skel.so /data/local/tmp/saver
$ adb push ${QNN_SDK_ROOT}/lib/aarch64-android/libQnnHtpPrepare.so /data/local/tmp/saver  # if QNN_BACKEND=QnnHtp
$ adb push ${QNN_SDK_ROOT}/examples/QNN/Saver/aarch64-android/saver_output_${QNN_BACKEND} /data/local/tmp/saver
$ adb push ${QNN_SDK_ROOT}/examples/QNN/Saver/params.bin /data/local/tmp/saver

Set LD_LIBRARY_PATH and ADSP_LIBRARY_PATH on device and execute:

$ adb shell
$ cd /data/local/tmp/saver
$ export LD_LIBRARY_PATH=/data/local/tmp/saver:$LD_LIBRARY_PATH
$ export ADSP_LIBRARY_PATH=/data/local/tmp/saver:$ADSP_LIBRARY_PATH
$ ./saver_output_${QNN_BACKEND} [-l <verbose,debug,info,warn,error>] # optionally enable logging

Windows

Setup

The tutorial assumes general setup instructions have been followed at Setup.

Please use “x86_x64 Cross Tools Command Prompt for VS 2022” to set QNN_SDK_ROOT:

$ set QNN_SDK_ROOT=\path\to\QNN_SDK_ROOT

Build

Please use “x86_x64 Cross Tools Command Prompt for VS 2022” in this step.

Generate Model

For CPU, generate a non-quantized model:

For Windows native/x86_x64 PC developers

$ cd "%QNN_SDK_ROOT%\examples\QNN\Saver"
$ mkdir model && cd model
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_float.cpp" .
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_float.bin" .
$ py -3 "%QNN_SDK_ROOT%\bin\x86_64-windows-msvc\qnn-model-lib-generator" ^
           -c .\qnn_model_float.cpp ^
           -b .\qnn_model_float.bin ^
           -o .\model_libs ^
           -t windows-x86_64

After executing commands from above, you should be able to see:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\model\model_libs\x64\qnn_model_float.dll

For Windows on Snapdragon developers

$ cd "%QNN_SDK_ROOT%\examples\QNN\Saver"
$ mkdir model && cd model
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_float.cpp" .
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_float.bin" .
$ py -3 "%QNN_SDK_ROOT%\bin\aarch64-windows-msvc\qnn-model-lib-generator" ^
           -c .\qnn_model_float.cpp ^
           -b .\qnn_model_float.bin ^
           -o .\model_libs ^
           -t windows-aarch64

After executing commands from above, you should be able to see:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\model\model_libs\ARM64\qnn_model_float.dll

For DSP and HTP, generate a quantized model:

For Windows native/x86_x64 PC developers

$ cd "%QNN_SDK_ROOT%\examples\QNN\Saver"
$ mkdir model && cd model
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_8bit_quantized.cpp" .
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_8bit_quantized.bin" .
$ py -3 "%QNN_SDK_ROOT%\bin\x86_64-windows-msvc\qnn-model-lib-generator" ^
           -c .\qnn_model_8bit_quantized.cpp ^
           -b .\qnn_model_8bit_quantized.bin ^
           -o .\model_libs ^
           -t windows-x86_64

After executing commands from above, you should be able to see:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\model\model_libs\x64\qnn_model_8bit_quantized.dll

For Windows on Snapdragon developers

$ cd "%QNN_SDK_ROOT%\examples\QNN\Saver"
$ mkdir model && cd model
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_8bit_quantized.cpp" .
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\qnn_model_8bit_quantized.bin" .
$ py -3 "%QNN_SDK_ROOT%\bin\aarch64-windows-msvc\qnn-model-lib-generator" ^
           -c .\qnn_model_8bit_quantized.cpp ^
           -b .\qnn_model_8bit_quantized.bin ^
           -o .\model_libs ^
           -t windows-aarch64

After executing commands from above, you should be able to see:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\model\model_libs\ARM64\qnn_model_8bit_quantized.dll

Generate saver_output.c and params.bin

Please check the path of <model>.dll and replace in the below commands:

$ cd "%QNN_SDK_ROOT%\examples\QNN\Saver"
$ mkdir source && cd source
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\input_data_float" .\input_data_float /i
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\converter\models\input_list_float.txt" .
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\Saver\model\model_libs\x64\<model>.dll" .
$ "%QNN_SDK_ROOT%\bin\x86_64-windows-msvc\qnn-net-run.exe" ^
           --backend "%QNN_SDK_ROOT%\lib\x86_64-windows-msvc\QnnSaver.dll" ^
           --model <model>.dll ^
           --input_list .\input_list_float.txt

After executing commands from above, you should be able to see:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\saver_output.c

  • %QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\params.bin

Build saver_output.c

Please choose one target between [x64, ARM64] as the parameter of “-A” config. Executables for all backends on the target named saver_output_<backend> will be generated.

$ cd "%QNN_SDK_ROOT%\examples\QNN\Saver"
$ xcopy "%QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\saver_output.c" .
$ mkdir build && cd build
$ cmake -S ../ -B ./ -T ClangCL -A [x64, ARM64]
$ cmake --build ./ --config Release

To generate an executable for a specific backend, please use below command to build. Valid options for <backend> are cpu for <target>=x64, and cpu, dsp, or htp for <target>=ARM64.

$ cmake --build ./ --config Release --target [cpu, dsp, htp]

After executing commands from above, you should be able to see:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\build\Release\saver_output_<backend>.exe

Run

Please use “Command Prompt” to execute, and ensure the params.bin is the same file generated in build.

For CPU

Run on x86.

Please push below files to a folder:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\build\Release\saver_output_QnnCpu.exe

  • %QNN_SDK_ROOT%\lib\x86_64-windows-msvc\QnnCpu.dll

  • %QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\params.bin

To execute:

$ .\saver_output_QnnCpu.exe [--logging <verbose,debug,info,warn,error>] # optionally enable logging

Run on aarch64.

Please push below files to device:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\build\Release\saver_output_QnnCpu.exe

  • %QNN_SDK_ROOT%\lib\aarch64-windows-msvc\QnnCpu.dll

  • %QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\params.bin

To execute:

$ .\saver_output_QnnCpu.exe [--logging <verbose,debug,info,warn,error>] # optionally enable logging

For DSP

Run on aarch64.

Please push below files to device:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\build\Release\saver_output_QnnDsp.exe

  • %QNN_SDK_ROOT%\lib\aarch64-windows-msvc\QnnDsp.dll

  • %QNN_SDK_ROOT%\lib\aarch64-windows-msvc\QnnDspV66Stub.dll

  • %QNN_SDK_ROOT%\lib\hexagon-v66\unsigned\libQnnDspV66Skel.so

  • %QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\params.bin

To execute:

$ .\saver_output_QnnDsp.exe [--logging <verbose,debug,info,warn,error>] # optionally enable logging

For HTP

Run on aarch64.

Please push below files to device:

  • %QNN_SDK_ROOT%\examples\QNN\Saver\build\Release\saver_output_QnnHtp.exe

  • %QNN_SDK_ROOT%\lib\aarch64-windows-msvc\QnnHtp.dll

  • %QNN_SDK_ROOT%\lib\aarch64-windows-msvc\QnnHtpPrepare.dll

  • %QNN_SDK_ROOT%\lib\aarch64-windows-msvc\QnnHtp<Hexagon Architecture>Stub.dll

  • %QNN_SDK_ROOT%\lib\hexagon-v68\unsigned\libQnnHtp<Hexagon Architecture>Skel.so

  • %QNN_SDK_ROOT%\examples\QNN\Saver\source\saver_output\params.bin

To execute:

$ .\saver_output_QnnHtp.exe [--logging <verbose,debug,info,warn,error>] # optionally enable logging