Chapter 5 Hello_world 範例程式 - 推論

本章節對應到 TinyML TensorFLow Lite 機器學習中文版 的第六章. (原書第五章是說明 hello_world 原始程式及測試碼, 可以當作後續的研究分析, 列入 §附錄 B 的主題)

上一章, 我們已經建立了可以轉移到開發板上執行的模型, 模型只是機器學習應用 app 的一部分而已, TFLM 提供不同開發板的 hello_world app, 需要在筆電上將模型加入原始程式, 重新編譯成不同開發板可以執行的程式碼(不同 CPU 的程式碼無法跨平台執行), 也可以在 PC 或 Mac 上模擬結果.

本文介紹可以運作 hello_world 示範程式的有以下的前兩種 (網路上有更新, 可以支援更多設備):

5.1 在 STM32 DISCO_F746NG 上實現 hello_world

5.1.1 (無痛執行)在筆電上編譯程式, 並下載至 STM32 DISCO_F746NG

因為 TensorFlow Lite Micro 的開發持續在進行, 部份文件並沒有隨著開發進度而更新, 如果照著 github 上執行會產生一些錯誤, 而且, 在編譯 (make) 之前, 需要將 STM32 DISCO_F746NG 相關檔案複製到主程式目錄下, 因此, 我在 github 創建了一個 branch, 針對 DISCO_F746NG 的開發板做了檔案安排及設定調整, 可以直接編譯, 並下載到 DISCO_F746NG 開發板上執行.

參考我的 TFLM github - hello_world無痛執行

在下一節說明如果從 TFLM github 官網下載內容時, 需要做的修改.

5.1.2 (微痛執行)在筆電上編譯程式, 並下載至 STM32 DISCO_F746NG

此節乃針對已經熟悉上一節的內容, 順利執行後, 進一步從 TFLM github 官網下載, 得自行修改部份內容方能順利執行無誤.

動手修改內容

需要修改的內容有
1. 改從 https://github.com/tensorflow 官網下載
2. 將 tensorflow/lite/micro/examples/hello_world/disco_f746ng/ 這目錄改名成為 tensorflow/lite/micro/examples/hello_world/mbed/
其餘從 make 以後的操作維持跟原先內容不變

5.1.2.1 改從 https://github.com/tensorflow 官網下載

# 從我的 github
$ git clone -b example --depth 1 https://github.com/marconi1964/tensorflow.git
# 改到用 Tensorflow 官網的 github
$ git clone --depth 1 https://github.com/marconi1964/tensorflow.git
# 或是
$ git clone --depth 1 https://github.com/tensorflow/tensorflow.git
$ cd tensorflow

5.1.2.2 將 tensorflow/lite/micro/examples/hello_world/disco_f746ng/ 這目錄改名成為 tensorflow/lite/micro/examples/hello_world/mbed/

DISCO_F746NG 的驅動程式 (constant.cc 與 output_handler.cc) 跟標準的示範程式不同, 需要讓 make 把 F746NG 的驅動程式包含在主程式才能在開發板上執行, 這部分已經在 Makefile 完成, 只是目前 Makefile 的寫法是擷取 TARGET=mbed 中的 ‘mbed,’ 再到 hello_world 目錄下尋找 ‘mbed’ 子目錄 (這部分的程式設定有問題, 已經在 TensorFlow github 上發 issue), 而 mbed 子目錄是不存在, 且 Makefile 不會去尋找 disco_f746ng 子目錄.

# 接續上一個動作, 已經在 tensorflow 目錄下, 切換到 hello_world 示範程式目錄
$ cd tensorflow/lite/micro/examples/hello_world/

$ mv disco_f746ng mbed
# 完成後, 回到 tensorflow 主目錄下
$ cd ~/tensorflow

(以上的動作, 看起來很簡單, 卻是我花最多時間的地方, 需要去了解 Makefile 及層層疊加上的 Makefile.inc 和 *_makefile.inc 的複雜架構.)

繼續執行 make 以及後續的動作

$ make -f tensorflow/lite/micro/tools/make/Makefile TARGET=mbed ALL_TAGS=disco_f746ng generate_hello_world_mbed_project
$ cd tensorflow/lite/micro/tools/make/gen/mbed_cortex-m4_default/prj/hello_world/mbed
$ mbed config root .
$ mbed deploy
$ mbed compile -m DISCO_F746NG -t GCC_ARM

5.1.2.3 將 make 後的 mbed.bin 上傳到 DISCO_F746NG 開發板

5.1.3 (痛苦的 debug過程) DISCO_F746NG 執行 hello_world 當機

第一次執行時, 還來不及沒有打開 screen 接收 debug 訊息, 就一顆球在上方定住, 懷疑我的操作/操守有問題… 打開 screen, 出現 ** Error message **

x_value: 1.0*2^-127, y_value: 1.0*2^-127

x_value: 1.4361557*2^-4, y_value: 1.7621826*2^-4

x_value: 1.4361557*2^-3, y_value: 1.8977352*2^-3

x_value: 1.0771168*2^-2, y_value: 1.389413*2^-2

x_value: 1.4361557*2^-2, y_value: 1.5588537*2^-2

x_value: 1.7951952*2^-2, y_value: 1.7960706*2^-2

x_value: 1.0771168*2^-1, y_value: 1.965511*2^-2

x_value: 1.2566366*2^-1, y_value: 1.1183078*2^-1

x_value: 1.4361557*2^-1, y_value: 1.3724688*2^-1

x_value: 1.6156756*2^-1, y_value: 1.4910772*2^-1

x_value: 1.7951952*2^-1, y_value: 1.6605182*2^-1

x_value: 1.9747147*2^-1, y_value: 1.7791265*2^-1

x_value: 1.0771168*2^0, y_value: 1.7791265*2^-1

x_value: 1.1668766*2^0, y_value: 1.8977352*2^-1

x_value: 1.2566366*2^0, y_value: 1.9316229*2^-1

x_value: 1.3463962*2^0, y_value: 1.965511*2^-1

x_value: 1.4361557*2^0, y_value: 1.0166438*2^0

++ MbedOS Fault Handler ++

FaultType: HardFault

Context:
R0: 7C
R1: 8
R2: FFDB4437
R3: 1
R4: 20002D58
R5: 34
R6: A
R7: FFDB4437
R8: 0
R9: 72
R10: 8
R11: 68
R12: 34
SP   : 2004FF8C
LR   : 800051B
PC   : 8000472
xPSR : 1000200
PSP  : 0
MSP  : 2004FF20
CPUID: 410FC271
HFSR : 40000000
MMFSR: 0
BFSR : 4
UFSR : 0
DFSR : 9
AFSR : 0
Mode : Thread
Priv : Privileged
Stack: MSP

-- MbedOS Fault Handler --



++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x8000472
Error Value: 0x20002E34
For more info, visit: https://mbed.com/s/error?error=0x80FF013D&tgt=DISCO_F746NG
-- MbedOS Error Info --

查看 https://mbed.com/s/error?error=0x80FF013D&tgt=DISCO_F746NG 輸入錯誤碼 (error code) 0x80FF013D 後會產生以下訊息


Error Decoder
0x80FF013D
Type:
System
Module
Unknown module
Error Code
HardFault exception
Cortex-M HardFault exception has occurred. Please see https://os.mbed.com/docs/latest/tutorials/analyzing-mbed-os-crash-dump.html for more info.

進一步查看 https://os.mbed.com/docs/latest/tutorials/analyzing-mbed-os-crash-dump.html

The following Cortex-M fault exceptions trigger the Mbed OS fault exception handler.

    MemManage Exception - Memory accesses that violate the setup in the MPU and certain illegal memory accesses trigger memory management faults.
    BusFault Exception - When an error response is received during a transfer on the AHB interfaces, it produces bus faults.
    UsageFault Exception - Division by zero, unaligned accesses and trying to execute coprocessor instructions can cause usage faults.
    HardFault Exception - Triggered on all fault conditions or if the corresponding fault handler (one of the above) is not enabled.

猜可能是記憶體問題, 再看一下螢幕當機時, 球是在螢幕的最上方, 是否是超過螢幕的範圍而造成錯誤, 看一下原始檔案 output_handler.cc 跟 error message 可能是有衝突的.

# error message
x_value: 1.4361557*2^0, y_value: 1.0166438*2^0

# output_handler.cc
    y_pos = dot_radius + static_cast<int>(midpoint * (1.f - y_value));     # 原始程式會有問題

    y_pos = dot_radius + static_cast<int>(midpoint * (1.1f - y_value));    # 小調整後即可正常運作

5.2 在 Arduino Nano 33 BLE 上實現 hello_world

在 §3.4 Arduino IDE 安裝後, 將 Arduino Nano 33 BLE 接上電腦的 USB, 進入 Arduino IDE 的 Tools - Boards 及 Port 確定已經安裝完成, 再到 File - Examples 找到 Arduino_TensorFlowLite 下會有 4 個範例

  • hello_world
  • magic_wand
  • micro_speech
  • person_detection

選擇我們想要的範例 hello_world 執行即可.

執行中, 可以打開 Arduino IDE menu
* Tool - Serial Monitor : 看到 Nano 33 回饋的預測 X、Y 值 * Tool - Serial Plotter : 看到 Nano 33 回饋的預測 X、Y 值展開的圖形

同時, Nano 33 的燈號也會隨著辨識結果, 逐漸變亮到熄滅再變亮

5.3 在 ESP32-CAM 上實現 hello_world

這裡不說明 Arduino 的作法(作法更 Arduino Nano 33 大同小異), 僅就 esp-idf 方法做說明

在 §3.7 esp-idf 安裝且測試完 ESP32 的 hello world 後, 現在測試的是 TensorFlow Lite Micro 的 hello_world. 類似 STM32 DISCO_F746NG 的 Makefile 的作法

在 idf.py build 這步驟出現錯誤

$ git clone https://github.com/tensorflow/tensorflow.git
$ cd tensorflow
$ make -f tensorflow/lite/micro/tools/make/Makefile TARGET=esp generate_hello_world_esp_project
$ cd tensorflow/lite/micro/tools/make/gen/esp_xtensa-esp32/prj/hello_world/esp-idf
$ idf.py build

-- Configuring done
CMake Error at /home/rafael/esp/esp-idf/tools/cmake/project.cmake:461 (target_link_libraries):
Error evaluating generator expression:

$<IN_LIST:-DTF_LITE_STATIC_MEMORY,$<TARGET_PROPERTY:__idf_tfmicro,COMPILE_OPTIONS>>
Expression did not evaluate to a known generator expression
Call Stack (most recent call first):
CMakeLists.txt:3 (project)

CMake Error in main/CMakeLists.txt:
Error evaluating generator expression:

$<IN_LIST:-DTF_LITE_STATIC_MEMORY,$<TARGET_PROPERTY:__idf_tfmicro,COMPILE_OPTIONS>>
Expression did not evaluate to a known generator expression

-- Generating done
-- Build files have been written to: /home/rafael/tensorflow/tensorflow/lite/micro/tools/make/gen/esp_xtensa-esp32/prj/hello_world/esp-idf/build
cmake failed with exit code 1

Google 後發現 ESP32 Hello World project crashing in the target 說明 cmake 的 compile option 需要 3.11 版本以上, 查了我的 cmake 版本是 3.10.2, 所以需要升級

$ cmake --version
cmake version 3.10.2

cmake 升級作法

# 從 https://cmake.org/download/ 下載 tar file, 到下載 tar file 的目錄下執行:

$ cd $CMAKE_DOWNLOAD_PATH
$ ./configure
$ make
$ sudo make install

再執行 idf, 可以結束從開發板傳回來的 X 跟 Y 的值

$ idf.py build
$ idf.py -p PORT flash monitor 

提醒 : 執行 monitor 程式時, 如果要離開, 需要按 ‘Ctrl’ + ‘]’ 的組合鍵.

5.4 在 MaixPy Amigo (RISC-V CPU) 上實現 hello_world

5.4.1 建立 MaixPy tool chains

⚠️注意 截止目前為止, 還有問題, 請不要輕易嘗試, 歡迎提出改善建議

照著 Build Maixpy from source code 步驟執行

5.4.1.1 Get source code

# Clone by https link
$ git clone https://github.com/sipeed/maixpy.git
# Then get submodules
$ cd maixpy
$ git submodule update --init

5.4.1.2 Install dependencies

$ sudo apt update
$ sudo apt install python3 python3-pip build-essential cmake
$ cd maixpy     # if you ever change directory 
$ pip3 install -r requirements.txt

5.4.1.3 Download toolchain

Download the latest toolchain from here (macOS and linux), or kendryte-toolchain-ubuntu-amd64-8.2.0-20190409.tar.xz(CDN) (for linux)

And extract to /opt/kendryte-toolchain/

$ cd ~
$ wget http://dl.cdn.sipeed.com/kendryte-toolchain-ubuntu-amd64-8.2.0-20190409.tar.xz
$ sudo tar -Jxvf kendryte-toolchain-ubuntu-amd64-8.2.0-20190409.tar.xz -C /opt
$ ls /opt/kendryte-toolchain/bin

5.4.1.4 Configure project

5.4.1.4.1 切換到 projects/hello_world 目錄或 projects/maixpy_k210, 必須遵循它的目錄結構才可以順利執行, 參照 Reference 文章說明.
$ cd maixpy
$ cd projects/hello_world
# 或
$ cd maixpy
$ cd projects/maixpy_k210

# 我的作法是複製 hello_world 到新的目錄 amigo_tflm
$ cd maixpy
$ cp -r projects/hello_world/ projects/amigo_tflm/
$ cd projects/amigo_tflm
5.4.1.4.2 Configure project

Usually, just use the default configuration.

If you want to customsize project modules, execute command:

python3 project.py menuconfig

接下來, 在 build 之前, 我們先下載 tensorflow lite micro 程式

5.4.2 下載 TensorFlow lite micro, 執行 make 來產生 source code

5.4.2.1 類似 DISCO_F746NG 的作法下載及執行 make

$ git clone https://github.com/tensorflow/tensorflow.git
$ cd tensorflow
# 修改 tensorflow 命名 riscv32_mcu 與 riscv_mcu / mcu_riscv 不一致處
$ mv tensorflow/lite/micro/tools/make/targets/mcu_riscv_makefile.inc \
     tensorflow/lite/micro/tools/make/targets/riscv32_mcu_makefile.inc
$ mv tensorflow/lite/micro/riscv_mcu/ tensorflow/lite/micro/riscv32_mcu/
$ make -f tensorflow/lite/micro/tools/make/Makefile TARGET=riscv32_mcu generate_hello_world_make_project
# source code 位於 tensorflow/micro/tools/make/gen/riscv32_mcu_riscv32_mcu_micro/prj/hello_world/make/
$ cd tensorflow/micro/tools/make/gen/riscv32_mcu_riscv32_mcu_micro/prj/hello_world/make/
$ ls
LICENSE  Makefile README_MAKE.md  tensorflow  third_party
# 可以先看 Makefile 的內容 
# SRCS := \
# tensorflow/lite/micro/simple_memory_allocator.cc .......
# 需要將這部分的 SRCS 內容複製到 MaixPy 的 maixpy/projects/amigo_tflm/main/CMakeList.txt 的 Add source files 下
# 再度看了全部檔案, 發現並沒有 hello_world 的程式列表 😄 還有一段路要走

5.4.3 將 tensforflow 的 source code 檔案整理成 MaixiPy tool chain 的檔案架構

目前的探索需要手動整理許多檔案, 而且目前為止還有錯誤, 還不確定哪裡需要修正

5.4.3.1 複製 Tensorflow 原始碼到 MaixPy 原始檔目錄

$ cd ~/tensorflow
$ cp -r tensorflow/micro/tools/make/gen/riscv32_mcu_riscv32_mcu_micro/prj/hello_world/make/ \
        ~/maixpy/projects/amigo_tflm
$ cd ~/maixpy/projects/amigo_tflm

5.4.3.2 修改 MaixPy build 的相關設定

  1. 修改 CMakeList.txt 的 C/C++ 原始程式碼檔案設定
  • 修改 ~/maixpy/projects/amigo_tflm/main/CMakeLists.txt 檔案內容
# 將目前目錄 . 設成 include 目錄
############## Add include ###################
list(APPEND ADD_INCLUDE "."
   )
# list(APPEND ADD_PRIVATE_INCLUDE "")
###############################################

# 將上一個動作的結果產生的 ensorflow/micro/tools/make/gen/riscv32_mcu_riscv32_mcu_micro/prj/hello_world/make/Makefile 內容
# SRCS := \
# tensorflow/lite/micro/simple_memory_allocator.cc ....... 
# 的所有 .cc 檔案名稱複製貼上, 用雙引號隔開
############## Add source files ###################
list(APPEND ADD_SRCS
"tensorflow/lite/micro/simple_memory_allocator.c"
.....
   )
###############################################
  1. 修改 的 C/C++ 編譯設定
  • 修改 ~/maixpy/projects/amigo_tflm/compile/compile_flags.cmake
# 原先設定
set(CMAKE_CXX_FLAGS -mcmodel=medany
...
                    -std=gnu11
# 將 -std=gnu11 改成 -std=c++11
set(CMAKE_CXX_FLAGS -mcmodel=medany
...
                    -std=c++11
  1. 出現 error

References: