タンスの奥に眠っていた Jetson TX2 を叩き起こして画像生成させる – 2026年

押し入れから 2017年発売世代の Jetson TX2(NVIDIA の小型 AI ボード)が出てきた(ΦωΦ) 2026年のいま、これを叩き起こして画像を生成するマシンにできないか?と思いました。なかなか一筋縄ではいかず、母艦(作業用PC)が新しすぎることでひっかかったりとか。最終的に JetPack を更新して、画像生成ができるところまでできました!

この記事でやったこと

  • 古い JetPack 3.1 を、TX2 が公式対応する最終世代 JetPack 4.6 系(L4T 32.7.1 / CUDA 10.2) に焼き直した
  • C++ 実装 stable-diffusion.cpp を自前ビルドし、SD1.5 で画像を生成できた

スポンサーリンク

JetPack 4.6 系へ焼き直す

今回は TX2 にモニタもキーボードも繋がず、母艦から SSH だけで操作します(headless)。初回起動の設定ウィザードを画面で操作できないので、ユーザー作成を焼き込みより先に済ませておく必要があります(後回しにすると焼き直しのやり直し)。以下の流れで作業をします。

  1. 配布物(BSP と rootfs)を展開する
  2. デフォルトユーザーを事前に作る(初回起動のウィザードを飛ばすため)
  3. 母艦側の互換性対策をする
  4. TX2 をリカバリーモードにする
  5. flash.sh で焼き込む
  6. 初回起動して SSH で入る

なぜ 4.6 系までなのか

元は L4T R28.1(JetPack 3.1相当)で CUDA 未インストール。TX2 が公式対応する JetPack は 4.6 系が最後(5 以降は非対応)なので、この個体で使える上限が CUDA 10.2。画像生成もこの範囲でやる話になります。

用意するもの

  • x86_64 の Linux 母艦(焼き込みツールが x86 バイナリのため)。今回は Ubuntu 26.04(今回の沼の原因)
  • データ通信対応の「micro-USB(オス) ⇔ USB Type-A(オス)」ケーブル。昔のスマホのデータケーブルです。

焼き込みは手動の flash.sh を使います(GUI の SDK Manager は母艦が 18.04 / 20.04 でないと弾かれる)。配布物(L4T 32.7.1 の BSP と rootfs)は 2026年でも落とせます。展開して apply_binaries.sh → sudo ./flash.sh jetson-tx2 mmcblk0p1。

母艦が新しすぎることで踏む4つの落とし穴

NVIDIA の焼き込みスクリプトは 2022年製。これを 2026年の新しい母艦(Ubuntu 26.04 / OpenSSH 10.x / Python 3.14)で動かすと、4つの落とし穴を踏みます。どれもエラーの見た目と真因がズレていて、素直に読むと誤診する。

落とし穴1: qemu-user-static が無い

  • 症状: 準備段階の apply_binaries.sh が qemu を見つけられない。
  • 原因: 26.04 では qemu-user-static パッケージが廃止済み。
  • 対処: 代替を入れ、スクリプトが探す「-static付き」の名前を別名で用意する。
sudo apt-get install -y qemu-user-binfmt qemu-user
sudo ln -sf /usr/bin/qemu-aarch64 /usr/bin/qemu-aarch64-static

落とし穴2: DSA 鍵生成が OpenSSH 10.x で死ぬ

command is failed
  • 症状: 最初の flash.sh が「recovery ramdisk の再生成」の途中で上のエラーを出して止まる。
  • 原因: スクリプトが内部で ssh-keygen -t dsa を呼ぶが、いまの OpenSSH 10.x は DSA を完全撤廃していて失敗する。それが全体を巻き添えにする。
  • 対処: DSA ホスト鍵は現行 sshd では使われないので、該当行を無害化(|| true)して先へ進める。

落とし穴3: 「probing failed」の正体は “UIDは1回きり”

flash.sh の前に tegrarcm_v2 --uid を実行しないこと。

Error: probing the target board failed
  • 症状: リカバリーモードには入れている(lsusb に見えている)のに、ボードの探索で上のエラーが出て止まる。
  • 原因: Tegra の bootrom は、1回のリカバリーセッションにつき UID(基板の識別子)を一度しか返さない。デバッグのつもりで自分で tegrarcm_v2 --uid を叩くと、その唯一の応答を消費してしまい、直後の flash.sh の問い合わせが空になる。
  • 紛らわしさ: dmesg に USB エラーは出ないので「ケーブル不良かな」と誤診しやすい。
  • 対処: リカバリーモードに入れた直後、最初に通信させるプログラムを flash.sh にする(自分で tegrarcm を先に実行しない)。UID はセッションで1回しか返らないので、その1回を flash.sh に使わせる。

落とし穴4: python が無い

env: 'python': No such file or directory
  • 症状: 実書き込み直前の署名処理で上のエラー。
  • 原因: ツールの shebang が #!/usr/bin/env python なのに、26.04 には python3 しか無い。名前だけの問題。
  • 対処: symlink を1本張る。
sudo ln -sf /usr/bin/python3 /usr/local/bin/python

この4つを越えると、ようやく成功メッセージが出ます。

*** The target t186ref has been flashed successfully. ***

覚えておくと楽な2つ

  • リカバリーモードは SSH から。ボタン操作(REC+RST)でタイミングに悩むより、旧OSに SSH して sudo reboot --force forced-recovery が確実です。
  • ユーザーの事前作成は l4t_create_default_user.sh で。焼く前に流しておけば、headless でも初回起動でそのまま SSH に入れます。

CUDA と GPU の動作を確認する

焼けても、GPU が計算に使えなければ意味がない。CUDA ツールキット(nvcc)を apt で入れて(リポジトリは 2026年でも生きている)、公式サンプルで実測しました。

種別テスト結果何が分かるか
必須deviceQueryPASSCUDA から GPU を認識できる(Tegra X2 / CC 6.2 / 256コア / 8GB共有)
必須vectorAddPASSGPU 計算と検算が通る
必須GPU使用率99%負荷時に実際に GPU が回る(アイドルは0%)
参考matrixMul71 GFlop/sおおよその演算性能
参考bandwidthTestH2D 10.2 / D2H 17.0 / D2D 30.6 GB/sメモリ転送性能

特に重要なのが Compute Capability 6.2(GPU の世代を表す番号。sm_62)。この後 stable-diffusion.cpp をビルドするとき、GPU アーキテクチャに 62 を指定する必要があります(よく参考にされる Jetson Nano は 53 で、ここが違う)。


stable-diffusion.cpp で画像を生成する

なぜ stable-diffusion.cpp なのか

最新の PyTorch / Diffusers / ComfyUI は CUDA 11 以降が前提で、TX2 の CUDA 10.2 では動きません。そこで、PyTorch を使わない軽量な C++ 実装 stable-diffusion.cpp を使います。さらに Jetson 向けに CUDA 10.2 でビルドできる派生版をベースにしました。

ビルドで踏む落とし穴

  • cmake が古い。OS 標準の apt の cmake は 3.10 でバージョン不足。公式の aarch64 バイナリ(3.28 系)を落として使う。
  • CUDA アーキテクチャを 62 に。ベースが Nano 向けで 53 にハードコードされているので 62 へ。configure で Using CUDA architectures: 62 が出るのを確認する(黙って 53 でビルドされると、実行時のカーネル起動で初めて失敗する)。
  • NEON 組み込み関数の不足。量子化コードが使う一部の NEON 命令(x4ロード)は gcc 9 以降にしか無い。ところが CUDA 10.2 が使えるホストコンパイラは gcc-8 が上限で、板挟みになる。該当の関数だけを gcc-8 でも通る形に手当てして回避した。

要点だけ抜き出すと、ビルドはこんな指定になります。

# CUDA アーキテクチャを 62 に(Nano の 53 ではない)
sed -i 's/CMAKE_CUDA_ARCHITECTURES "53"/CMAKE_CUDA_ARCHITECTURES "62"/' CMakeLists.txt

# CUDA 10.2 のホストコンパイラ上限は gcc-8
cmake .. -DSD_CUDA=ON -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=gcc-8 -DCMAKE_CXX_COMPILER=g++-8 \
  -DCMAKE_CUDA_HOST_COMPILER=g++-8
cmake --build . -j4

これで CUDA(GPU)を使う sd バイナリができます。

最初の作例(SD1.5)

最初に試したのは、扱いが軽い SD1.5(Stable Diffusion 1.5)。いくつか生成してみたのが下の3枚です。

3枚とも生成条件は共通です。

項目値
モデルStable Diffusion 1.5 (f16)
解像度768 × 512
ステップ数20
サンプラー / CFGdpm++2m / 8
VAEフルVAE(--vae-tiling)
電力モードMAXN + jetson_clocks
生成時間1枚あたり約6分(実測で385秒前後)
SD1.5でTX2が生成した海辺の風景
海辺の風景
SD1.5でTX2が生成したカフェの画像
カフェ
SD1.5でTX2が生成した森の画像
森

まとめ

  • TX2 の最終世代は JetPack 4.6 系(CUDA 10.2 / sm_62)。配布物も apt も 2026年でまだ生きている。
  • 詰まるのは母艦が新しすぎるところ。qemu / DSA / python / UID の4つは、どれもエラーの見た目と真因がズレている。
  • 今回の「probing failed」の原因は、flash.sh より先に tegrarcm_v2 --uid を自分で叩いたことだった。ボードが UID を返すのはリカバリーモードに入ってから1回だけなので、先に叩くと flash.sh が UID を受け取れなくなる。リカバリーモードに入れたら、最初に通信させるのは flash.sh にする。
  • 成功の確認はドライバの有無で終わらせない。deviceQuery / vectorAdd の PASS と GPU 使用率まで見る。
  • 焼き直し → CUDA → ビルド と進めて、SD1.5 で最初の1枚まで到達できた。
スポンサーリンク

コメント

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA