🔄

推論サーバーのコンテナをAMDからARM対応した備忘録

に公開

Fusicのレオナです。2025年新卒のMLOpsエンジニアです。本ブログはMLOps Advent Calendar 2025の12月14日枠への投稿です。
https://qiita.com/advent-calendar/2025/mlops

はじめに

エッジ端末がAMDベースからJetson(ARMベース)に変わったことで、従来使っていたSageMaker推論コンテナが動かなくなりました。新しい環境でもスムーズにモデルをデプロイできるようにするため、以下を整理しながら対応しました。

  • 既存の推論 I/F を極力変更しないこと
  • Jetson上で安定して動く環境を用意すること
  • クラウドとエッジ(ARMとAMD版)で再現性を確保すること
  • クラウド側でも推論コンテナを立てる可能性がある

今回は考え方を備忘録として残します。似たような環境で推論基盤を切り替えたい方の参考になれば幸いです。

SageMaker Deep Learning Containersとは

Amazon SageMakerでは、PyTorchやTensorFlowがプリインストールされたDeep Learning Container(以下、DLCとする)を提供しており、モデルを素早くデプロイできます。PyTorch用のDLCでは標準でTorchServeが起動し、SageMakerエンドポイントからの/ping(ヘルスチェック)と/invocations(推論)のリクエストに応答します。そのため、本番環境へのモデル組み込みが容易でした。

私が担当したプロジェクトでも、以下の構成のDLCを用いてモデルをデプロイしていました。

  • Ubuntu 22.04
  • PyTorch 2.6
  • CUDA 12.4

課題: Jetson環境でのDLC使用制限

Jetson端末はARMアーキテクチャかつJetPackに依存したCUDA/ドライバ構成を持ちます。従来使っていたAMD向けDLCはこの環境ではビルドできず、ARM版のDLCを使うことも検討しましたが、以下の懸念がありました。

  • JetPackに最適化されていないため性能や動作が不安定
  • CUDAやライブラリの組み合わせを柔軟に調整できない
  • エッジ側での再現性を確保しづらい

これらの理由から、既存のI/Fを維持したまま、Jetson向けに最適化された推論コンテナに置き換えることにしました。

解決策: NGCのJetson用PyTorchイメージ

JetsonではNVIDIA公式のNGCイメージが提供されており、JetPackに合わせたCUDA/cuDNN/TensorRTを同梱しています。今回は次のベースイメージを採用し、その上にモデルや推論コードを載せる方針にしました。
https://catalog.ngc.nvidia.com/orgs/nvidia/containers/pytorch
https://docs.nvidia.com/deeplearning/frameworks/pytorch-release-notes/running.html

# Jetson対応NVIDIA NGC PyTorchイメージ
FROM nvcr.io/nvidia/pytorch:25.11-py3-igpu

NGCイメージを使うことで、JetPackとのバージョン不整合によるトラブルを減らし、Jetson上でGPU推論性能を確保できました。

また、TorchServeが格納されていないため、推論サーバーは自前で用意します。

TorchServeを採用しなかった理由

PyTorchモデルのホスティングにはTorchServeが定番ですが、TorchServeは2025年3月1日からLimited Maintenanceモードに移行し、新機能追加やバグ修正・セキュリティパッチが提供されなくなりました。将来的な脆弱性対応やPythonのEOL対応の観点から採用は見送り、別の方法を検討しました。

参照:
https://buildersbox.corp-sansan.com/entry/2025/03/26/100000

SageMaker互換の推論サーバーをFastAPIで実装

実装方針

クラウドからエッジへの移行でも既存コードを変更せずに済むよう、SageMakerのI/Fに合わせたエンドポイントをFastAPIで実装しました。

  • /ping … 推論サーバーのヘルスチェックを返すエンドポイント
  • /invocations … JSONやバイナリを受け取り、推論処理を行って結果を返すエンドポイント

サンプルコード

### 実装したエンドポイント
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/ping")
async def ping():
    # ヘルスチェックのロジックを記載
    ...
    return {"status": "healthy"}

@app.post("/invocations")
async def invocations(request: Request):
    # 推論処理
    ...

この実装なら、SageMakerエンドポイントと同じように/ping/invocationsへリクエストを送れるため、呼び出し側のコード変更は不要です。Jetson上でFastAPIを使ってモデルをロードし、推論処理を返すだけなので、ライブラリのバージョン管理も柔軟に行えます。

最後に

Jetsonへの移行に伴い、SageMaker DLCからNGCベースのコンテナに置き換え、推論サーバーをFastAPIで自前実装した事例を紹介しました。クラウドとエッジの双方で同じインターフェースを維持することで、将来的に推論先を切り替える際の工数を抑えることができまいた。Jetson環境で推論を動かしたい方や、TorchServe以外の選択肢を検討中の方の参考になれば幸いです。

Fusic 技術ブログ

Discussion