daisukeの技術ブログ

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

Raspberry Pi 4のTensorFlow Lite C++をVSCodeでリモートデバッグする

今回もAIの量子化について学んでいきます。論文を読むことは継続しつつ、今回は、TensorFlow Lite C++ の動作を見るために、デバッグ環境を立ち上げたいと思います。

前回は、TensorFlow Lite の C++ で、量子化モデルを動かしました。何が実行されてるか分からなかったので、ソースコードを見ていきます。ソースを追うだけで理解するのは難しいので、デバッグ環境を立ち上げて、動かしながら理解していきます。

Raspberry Pi 上で動作するプログラムのデバッグ環境としては、VSCode のリモートデバッグを使います。さらに、今回は、CMake環境のデバッグということで、そのあたりの基礎的なところからやっていきたいと思います。

はじめに

「AIモデルの量子化」の記事一覧です。良かったら参考にしてください。

AIモデルの量子化の記事一覧

エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

それではやっていきます!

Raspberry Pi 4 で C++ のリモートデバッグの環境構築

Raspberry Pi 4 の TensorFlow Lite C++ をリモートデバッグしたいところですが、段階的にやっていきます。

VSCodeの公式サイトを参考にします。

code.visualstudio.com

Raspberry Pi 4 にSSHでリモートに接続する

VSCodeを起動して、拡張機能の「Remote Development」をインストールします。

VSCodeの左のサイドバーの拡張機能のアイコンをクリックし、入力フォームに「Remote Development」と入力して、インストールします。Remote Development をインストールすると、「WSL」、「Dev Containers」、「Remote - SSH」、「Remote - Tunnels」の4つの機能拡張も一緒に入るようです(拡張機能のインストールは特別意識はしていません)。

VSCodeの拡張機能「Remote Development」をインストールする
VSCodeの拡張機能「Remote Development」をインストールする

Remote Developmentをインストールすると、VSCodeの左のサイドバーにリモートエクスプローラーというアイコンが増えるのでクリックします。下図のような画面になるので、SSHのところにマウスを持っていくと、設定アイコンが出るので、クリックします。

すると、下図のように、設定ファイルの選択肢が出るので、C:\Users\ユーザ名.ssh\config をクリックします。

リモートエクスプローラーからSSHの設定を開く
リモートエクスプローラーからSSHの設定を開く

configファイルが開いたら、下図のように、接続先ごとに入力します。今回は Raspberry Pi だけを設定すれば大丈夫です。

  • Host:任意の名前です(接続先が分かる名前を設定するといいと思います)
  • HostName:IPアドレスを指定します(ホスト名でもいいかもしれません)
  • User:接続先にログインするユーザ名を指定します
  • IdentityFile:公開鍵認証の秘密鍵の場所を指定します(この項目を入力しなくてもパスワード認証でログインできると思います)

configファイルの設定
configファイルの設定

ここまで入力したら、「リモート(トンネル/SSH)」にマウスを近づけると更新アイコンが表示されるので、クリックすると、入力したホストが表示されると思います。そのホストにマウスを近づけると→アイコンが表示されるので、クリックして接続します。これでリモート先にSSHで接続できました。

リモートSSHに接続する
リモートSSHに接続する

一応、公開鍵認証を使う場合は、ホストPC(Windows10)に秘密鍵ファイルを置いて、上の「IdentityFile」にパスを指定します。

リモート先に公開鍵ファイルを置きます。ホームディレクトリに「.ssh」をパーミッション700に設定して、公開鍵ファイルを「authorized_keys」に追記して、「authorized_keys」ファイルのパーミッションを600に設定します。

$ cd
$ mkdir .ssh
$ chmod 700 .ssh
$ cat ./id_rsa.pub >> .ssh/authorized_keys
$ chmod 600 .ssh/authorized_keys

Raspberry Pi 4 の C++プログラムを SSH でリモートデバッグする

次は、簡単な C++プログラムをデバッグしてみます。

適当なディレクトリ(cpp_sampleディレクトリとします)を作り、そのディレクトリに、main.cppというファイルを作り、以下の内容をコピペします。

#include <iostream>

int main(void)
{
    std::cout << "Hello, VSCode!" << std::endl;
    
    return 0;
}

この C++プログラムをデバッグしてみます。

VSCode は、SSH で Raspberry Pi 4 に接続できている状態です。ファイル→フォルダを開くをクリックします。すると、下図のような入力が開くので、sample_cppディレクトリまで移動して、OKをクリックします。

VSCodeのC/C+の機能拡張をインストールするかを聞かれると思いますのでOKを押してください。

sample_cppディレクトリを開く
sample_cppディレクトリを開く

先ほど作った main.cpp がツリービューに表示されていると思うので、ダブルクリックで開きます。

main.cppを開く
main.cppを開く

早速デバッグしていきます。

まず、現在のデフォルトで指定されているコンパイラとその場所を確認しておきます。

$ g++ --version
g++ (Debian 12.2.0-14) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ which g++
/usr/bin/g++

ソースコードのmain関数のstd::coutの行にブレークポイントを設定します。ソースコード行数の少し左あたりをクリックするとブレークポイントを設定できます。

左のサイドバーのデバッグアイコンをクリックします。実行とデバッグをクリックします。すると、コンパイラの選択が表示されるので、先ほど調べた g++ を選択します(3つ表示されてますが、3つとも同じものであり、実体はaarch64-linux-gnu-g++です)。

デバッグを開始する
デバッグを開始する

すると、コンパイルされて、下図のように、設定したブレークポイントに止まります。

ブレークポイントに止まった
ブレークポイントに止まった

今回のデバッグで、sample_cppディレクトリに「.vscode」ディレクトリが作成され、「tasks.json」ファイルが作成されています。これで、以降は、すぐにデバッグできるようになります。

「▷」マークを押して、実行を続行して終了させておきます。

簡単な C++プログラムを SSH でリモートデバッグできることが確認できました。

Raspberry Pi 4 の CMakeプロジェクトを SSH でリモートデバッグする

次は、CMakeプロジェクトをやっていきます。

まず、VSCodeの機能拡張の「CMake Tools」をインストールします。一緒に拡張機能の「CMake」もインストールされると思います。

新しいディレクトリを用意します。「cmake_sample」とします。ディレクトリを作ったら、VSCodeでこのディレクトリに移動しておきます。

コマンドパレット(Ctrl+Shift+p)を開き、「cmake」と入力すると、拡張機能がインストールされてると、いろいろ表示されます。

「CMake:クイックスタート」をクリックします。

CMake:クイックスタートを開く
CMake:クイックスタートを開く

次は、コンパイラの指定です。GCCを選択します。

GCCを選択する
GCCを選択する

プロジェクト名が聞かれますので、「sample」としておきます。

プロジェクト名に「sample」を指定する
プロジェクト名に「sample」を指定する

同様に、「C++」か「C」かを聞かれるので、「C++」を選択します。

C++を選択します
C++を選択します

「Library(ライブラリ)」か「Executable(実行ファイル)」かを聞かれるので、「Executable」を選択します。

Executableを選択します
Executableを選択します

ここまでの設定で、「main.cpp」と「CMakeLists.txt」と「buildディレクトリ」が自動生成されました。既にコンフィグが完了している状態です。

CMakeプロジェクトが自動生成された
CMakeプロジェクトが自動生成された

先ほどと同様に、main.cppにブレークポイントを設定して、デバッグしてみます。

コマンドパレット(Ctrl+Shift+p)を開き、「cmake」と入力し、下にスクロールすると「CMake:デバッグ」があるので、クリックします。すると、デバッグビルドされて、ブレークポイントに止まります。

CMake:デバッグを実行する
CMake:デバッグを実行する

「▷」マークを押して、実行を続行して終了させておきます。

CMakeプロジェクトを SSH でリモートデバッグできることが確認できました。

Raspberry Pi 4 の TensorFlow Lite C++プロジェクトを SSH でリモートデバッグする

十分に準備したので、TensorFlow Lite の C++プロジェクトをデバッグしていきます。

前回、TensorFlow のリポジトリをクローンしてるので、それを使います。

daisuke20240310.hatenablog.com

また、launch.json と tasks.json を作っていきますが、それぞれのキーと値については、過去の記事にまとめてるので参考にしてください。

daisuke20240310.hatenablog.com

TensorFlow のリポジトリのトップを VSCode で開きます。

ソースコードは、tensorflow/lite/examples/label_image/label_image.cc を開いておきます。main関数にブレークポイントを設定しておきます。

label_image.ccを開いたところ
label_image.ccを開いたところ

左のサイドバーのデバッグアイコンをクリックします。「launch.jsonファイルを作成します」をクリックします。「構成の追加...」をクリックして、「C/C++:(gdb)起動」をクリックします。

launch.jsonの作成
launch.jsonの作成

すると、launch.json に、C/C++デバッグのひな型が記載されます。これを以下のように編集して完成させます。実行ファイルを指定したのと、コマンドライン引数の指定、事前ビルド設定を指定したぐらいです。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) label_image",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/examples/label_image/label_image",
            "args": [
                "-m",
                "../tflite/models/mobilenet_v1_1.0_224_quant/mobilenet_v1_1.0_224_quant.tflite",
                "-l",
                "../tflite/labels.txt",
                "-i",
                "../tflite/grace_hopper.bmp",
            ],
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "gdb の再フォーマットを有効にする",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "逆アセンブリ フレーバーを Intel に設定",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build",
        }
    ]
}

次に、tasks.json を作ります。メニューのターミナル→タスクの構成をクリックします。下の方に「テンプレートからtasks.jsonを作成」をクリックします。「Others」をクリックします。

tasks.jsonの作成
tasks.jsonの作成

こちらも、ひな型が作成されました。以下のように編集して完成させます。TensorFlowの公式サイトの手順 のビルドを指定したぐらいです。

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "cmake --build build -t label_image",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": ["$gcc"]
        }
    ]
}

準備ができたので、デバッグしてみます。左のサイドバーのデバッグアイコンをクリックして、デバッグの構成から、先ほど作った構成を選択して、「▷」ボタンを押します。すると、ビルドが実行されるので、最初は時間がかかります(約1時間)。ビルドが完了したら、label_image.cc の main関数で止まっていると思います。

デバッグが起動できた
デバッグが起動できた

ステップ実行や、ブレークポイントを設定して、実行など、TensorFlow Lite の動作を確認することができます。

TensorFlow Lite C++プロジェクトでデバッグできないとき

CMakeが絡むと、VSCodeがいろいろ裏でやってくれるので、うまくいかないときの対応が大変です。

問題が発生したときの対策について、ここに書いていきます。

VSCodeのデバッグは開始しているがソースコードが表示されないとき

デバッグコンソールに、mainで停止したという表示はあるし、デバッグするときの「続行」、「ステップイン」などのツールバーが表示されてるが、ソースコードが見えない、追従してくれないときがあります。

私も、この問題が発生しました。私の場合の原因は、デバッグビルドされてなかったという問題でした。

この場合は、いったん、buildディレクトリを作り直した方がいいです。CMakeのキャッシュが残っていてうまくいかないと思います。buildディレクトリを作り直した後、コマンドパレット(Ctrl+Shift+p)で「cmake」と入力して、「CMake:デバッグ」を実行します。

このとき、出力ウィンドウの先頭に、cmakeの実行ログが出ていると思います。私の場合は以下のようになっていました。

[proc] コマンドを実行しています: /usr/bin/cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ -S/home/daisuke/svn_/tensorflow/tensorflow/lite -B/home/daisuke/svn_/tensorflow/build -G "Unix Makefiles"

「-DCMAKE_BUILD_TYPE:STRING=Debug」が存在することを確認してください。

これがあればデバッグビルドされています。

「ターゲットが見つからない」というCMakeのエラーが出るとき

この場合、label_image を直接ターゲットに指定してしまっていることが原因かもしれません。まず、tensorflow/tensorflow/lite/CMakeLists.txt をターゲットにしてビルドする必要があります。

ターゲットの設定は、「.vscode/settings.json」で行います。この名前でファイルを作成して、以下のように書き込みます。パスは自分の環境に合わせて書き換えてください。

{
    "cmake.sourceDirectory": "/home/daisuke/svn_/tensorflow/tensorflow/lite"
}

おわりに

今回は、TensorFlow Lite の C++版のデバッグ環境を構築しました。

次回からは、このデバッグ環境を使って、TensorFlow Lite の動作を理解していきたいと思います。

今回は以上です。

最後までお読みいただき、ありがとうございました。