YOLOv5の学習済みモデル(best.pt)をHugging Face HubにアップロードしてModel Cardを設定し、GradioデモをSpacesにデプロイするまでの手順と、途中で発生したトラブルの解決策をまとめます。

今回対象にしたのは、古典籍資料の「群集帖」レイアウトを検出するモデルです。

デモ画面


構成の変遷

変更前

yolov5-kunshujo/
├── app.py               # モデルをローカルから起動時にロード
├── best.pt              # 699MB のモデルをリポジトリに直接格納
├── requirements.txt     # 不要パッケージ(gdown, matplotlib, seaborn)含む
└── ultralytics/
    └── yolov5/          # YOLOv5 ソースコードをローカルにコピー
        ├── hubconf.py
        ├── models/
        └── utils/

問題点:

  • best.pt(699MB)がSpacesリポジトリに含まれており、Gitの管理対象になっていた
  • YOLOv5のソースコードをローカルコピーとして持つ必要があった
  • モデルが起動時に即ロードされるため、Spaces起動が遅かった
  • PyTorch 2.6 の破壊的変更に未対応

変更後

yolov5-kunshujo/
├── app.py               # HF Hubからモデルをダウンロード・遅延ロード
└── requirements.txt     # 必要なパッケージのみに整理

改善点:

  • best.pt はモデルリポジトリ(nakamura196/yolov5-kunshujo)に分離
  • ultralytics/yolov5/ を削除し、torch.hub がGitHubから取得・キャッシュ
  • モデルを初回推論時に遅延ロードするよう変更(Spaces起動が高速化)
  • PyTorch 2.6 対応・バグ修正を適用
  • 不要パッケージを削除

1. huggingface-hub のセットアップ

pip install huggingface_hub

インストール後、hf コマンドが見つからない場合はPATHが通っていません。

# フルパスで実行
/Users/nakamura/Library/Python/3.9/bin/hf login

# または永続的にPATHを追加
echo 'export PATH="$HOME/Library/Python/3.9/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

huggingface-cli は非推奨になり、hf コマンドへの移行が推奨されています。

2. モデルリポジトリの作成

hf repo create yolov5-kunshujo --repo-type model

3. モデルファイルのアップロード

hf upload nakamura196/yolov5-kunshujo ./best.pt best.pt

best.pt は約700MBですが、Hugging Faceのxetストレージにより高速にアップロードできます。

4. Model Cardの設定

モデルリポジトリの README.md がModel Cardになります。以下のフォーマットで作成してアップロードします。

---
license: apache-2.0
tags:
  - object-detection
  - yolov5
  - pytorch
pipeline_tag: object-detection
---

# YOLOv5 Kunshujo

...
hf upload nakamura196/yolov5-kunshujo ./README.md README.md

5. Gradioアプリの修正

REPO_ID の修正

app.pyusername/yolov5-kunshujo のようなプレースホルダーが残っていないか確認します。

REPO_ID = "nakamura196/yolov5-kunshujo"

HFモデルからの遅延ロード

起動時にロードするのではなく、初回推論時に hf_hub_download でダウンロード・ロードします。

from huggingface_hub import hf_hub_download

_model = None

def get_model():
    global _model
    if _model is not None:
        return _model
    model_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_FILENAME)
    # ... モデルロード
    return _model

初回はHFからダウンロードされ、以降は ~/.cache/huggingface/hub/ にキャッシュされます。

requirements.txt の整理

yolov5 v7.0 が必要とする依存パッケージをすべて明示します。

torch
torchvision
Pillow
opencv-python-headless
ipython
scipy
pandas
matplotlib
seaborn
psutil
パッケージ理由
torch, torchvisionYOLOv5の推論に必要
Pillow画像処理
opencv-python-headlessutils/dataloaders.pycv2 を使用
ipythonutils/general.py が使用
scipy, pandasYOLOv5の各種ユーティリティが使用
matplotlib, seabornutils/metrics.py, utils/plots.py が使用
psutilutils/dataloaders.py が使用
huggingface-hubHF Spacesに最初からインストール済みのため不要

torch.hub.load がyolov5のコードをGitHubから取得し、その依存関係をrequirements.txtに記載された範囲で解決します。実行時に不足パッケージが判明した場合は随時追加が必要です。


最終的な app.py

# Patch gradio_client bug: additionalProperties: True (bool) causes TypeError/APIInfoParseError
import gradio_client.utils as _gc_utils
_orig_j2p = _gc_utils._json_schema_to_python_type
def _patched_j2p(schema, defs):
    if not isinstance(schema, dict):
        return "any"
    return _orig_j2p(schema, defs)
_gc_utils._json_schema_to_python_type = _patched_j2p

import gradio as gr
import torch
from PIL import Image, ImageDraw
from huggingface_hub import hf_hub_download

REPO_ID = "nakamura196/yolov5-kunshujo"
MODEL_FILENAME = "best.pt"

_model = None


def get_model():
    global _model
    if _model is not None:
        return _model

    model_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_FILENAME)

    # PyTorch 2.6+ weights_only=True breaking change workaround
    _original_load = torch.load
    torch.load = lambda *a, **kw: _original_load(*a, **{**kw, "weights_only": False})
    try:
        _model = torch.hub.load("ultralytics/yolov5:v7.0", "custom", path=model_path, trust_repo=True)
    finally:
        torch.load = _original_load

    return _model


def yolo(im, size=1024):
    model = get_model()
    g = (size / max(im.size))
    im = im.resize(tuple(int(x * g) for x in im.size), Image.BICUBIC)

    results = model(im)
    res = results.pandas().xyxy[0].to_dict(orient="records")

    im_draw = im.copy()
    draw = ImageDraw.Draw(im_draw)

    detected_images = []
    for item in res:
        xmin, ymin, xmax, ymax = item['xmin'], item['ymin'], item['xmax'], item['ymax']
        draw.rectangle([(xmin, ymin), (xmax, ymax)], outline="red", width=2)
        detected_images.append(im.crop((xmin, ymin, xmax, ymax)))

    return [res, im_draw, detected_images]


inputs = [gr.Image(type='pil', label="Original Image")]
outputs = [
    gr.JSON(label="JSON Output"),
    gr.Image(type="pil", label="Output Image"),
    gr.Gallery(label="Detected Objects"),
]

demo = gr.Interface(
    yolo, inputs, outputs,
    title="YOLOv5 Kunshujo",
    description="YOLOv5 Kunshujo Gradio demo for object detection.",
    examples=[['2586696_R0000008.jpg'], ['2586696_R0000009.jpg']],
    flagging_mode="never",
)

demo.launch(show_error=True, server_name="0.0.0.0", server_port=7860, ssr_mode=False)

トラブルシューティング

gradio_client の TypeError / APIInfoParseError

エラー:

TypeError: argument of type 'bool' is not iterable
# または
gradio_client.utils.APIInfoParseError: Cannot parse schema True

原因: gr.JSONgr.Gallery コンポーネントのスキーマに additionalProperties: True(bool値)が含まれており、gradio_client_json_schema_to_python_type() 関数がdictでない値を受け取った際にクラッシュするバグです。これにより /info エンドポイントが500エラーを返し、Gradioが「localhostに接続できない」と判断して起動に失敗します。

修正: app.py の先頭(import gradio より前)でモンキーパッチを当てます。

import gradio_client.utils as _gc_utils
_orig_j2p = _gc_utils._json_schema_to_python_type
def _patched_j2p(schema, defs):
    if not isinstance(schema, dict):
        return "any"
    return _orig_j2p(schema, defs)
_gc_utils._json_schema_to_python_type = _patched_j2p

_json_schema_to_python_type はモジュールのグローバル名前空間で解決されるため、再帰呼び出しにも自動的にパッチが適用されます。

PyTorch 2.6 の weights_only 問題

エラー:

Weights only load failed. WeightsUnpickler error: Unsupported global:
GLOBAL numpy.core.multiarray._reconstruct was not an allowed global by default.

原因: PyTorch 2.6から torch.load のデフォルトが weights_only=True に変更され、numpyオブジェクトを含む古いYOLOv5モデルが読み込めなくなりました。torch.hub.load の内部で呼ばれる torch.load に直接引数を渡せないため、モンキーパッチで対処します。

修正:

_original_load = torch.load
torch.load = lambda *a, **kw: _original_load(*a, **{**kw, "weights_only": False})
try:
    _model = torch.hub.load("ultralytics/yolov5:v7.0", "custom", path=model_path, trust_repo=True)
finally:
    torch.load = _original_load

im.resize() の generator エラー

エラー:

argument 1 must be 2-item sequence, not generator

修正:

# Before
im = im.resize((int(x * g) for x in im.size), Image.BICUBIC)

# After
im = im.resize(tuple(int(x * g) for x in im.size), Image.BICUBIC)

Python 3.13 で gradio が起動しない

エラー:

ModuleNotFoundError: No module named 'pyaudioop'

原因: HF Spaces が Python 3.13 を使用しており、gradio 4.x が依存する pydubaudioop モジュールが Python 3.13 で削除されたためです。

修正1: README.mdsdk_version を gradio 5.x に更新します。

sdk_version: 5.9.1

修正2: gradio 5.x では allow_flagging が廃止され flagging_mode に変更されました。

# Before (gradio 4.x)
demo = gr.Interface(..., allow_flagging="never")

# After (gradio 5.x)
demo = gr.Interface(..., flagging_mode="never")

ModuleNotFoundError: No module named ‘ultralytics’

原因: torch.hub.load("ultralytics/yolov5", ...) でmasterブランチを使うと、新しいultralytics パッケージへの依存が必要になります。

修正: v7.0 に固定します。

_model = torch.hub.load("ultralytics/yolov5:v7.0", "custom", path=model_path, trust_repo=True)

補足: best.pt(旧ultralytics/yolov5リポジトリで訓練)は新しい ultralytics パッケージ(from ultralytics import YOLO)では読み込めません。アーキテクチャが異なる(アンカーフリー)ためです。旧モデルには torch.hub + v7.0 固定が唯一の推奨方法です。

EOFError: EOF when reading a line(trust_repo)

原因: ヘッドレス環境(SpacesやCI)で torch.hub.load が信頼確認のプロンプトを出そうとして失敗します。

修正: trust_repo=True を追加します。

_model = torch.hub.load("ultralytics/yolov5:v7.0", "custom", path=model_path, trust_repo=True)

yolov5 v7.0 の依存パッケージが不足

エラー例:

ModuleNotFoundError: No module named 'cv2'
ModuleNotFoundError: No module named 'IPython'
ModuleNotFoundError: No module named 'matplotlib'
ModuleNotFoundError: No module named 'seaborn'
ModuleNotFoundError: No module named 'psutil'

原因: yolov5 v7.0 は多数のパッケージに依存しており、torch.hub.load はそれらを自動インストールしません。

修正: requirements.txt に必要なパッケージをすべて記載します(前掲の表を参照)。

Spaces が “Starting” のまま動かない

原因1: server_name="127.0.0.1" の場合、HF Spacesのプロキシがポートにアクセスできないためヘルスチェックに失敗します。

原因2: gradio 5.x の SSR(Server-Side Rendering)モードで Node.js サーバーの起動がSpacesのヘルスチェックと競合することがあります。

修正:

demo.launch(
    show_error=True,
    server_name="0.0.0.0",   # ← 127.0.0.1 から変更
    server_port=7860,
    ssr_mode=False,           # ← SSR を無効化
)

動作画面

推論結果(入力・JSON・検出画像)

推論結果の全体表示

JSON出力と検出画像のクローズアップ

gr.JSONコンポーネントと検出結果画像


まとめ

問題対処
モデル(700MB)がリポジトリに格納されていたHF Hubのモデルリポジトリに分離
YOLOv5ソースをローカルコピーで管理torch.hub のGitHubキャッシュを利用
起動時にモデルをロードして遅い初回推論時の遅延ロードに変更
PyTorch 2.6 の weights_only 破壊的変更torch.load のモンキーパッチで対応
gradio_client の bool スキーマバグ_json_schema_to_python_type をモンキーパッチ
im.resize() にgeneratorを渡していたtuple() でラップ
Python 3.13 で audioop が削除され gradio 4.x が起動しないgradio 5.9.1 にアップグレード、flagging_mode に変更
ultralytics/yolov5 masterで依存エラーv7.0 に固定
yolov5 v7.0 の依存パッケージ不足requirements.txtopencv-python-headless, ipython, matplotlib, seaborn, psutil 等を追加
Spaces が “Starting” のままserver_name="0.0.0.0", ssr_mode=False に変更
JSONがテキスト表示で見づらいgr.Textboxgr.JSON コンポーネントに変更