This post covers the steps to upload a trained YOLOv5 model (best.pt) to Hugging Face Hub, configure a Model Card, and deploy a Gradio demo to Spaces, along with fixes for several issues encountered in the process.
The model in question detects page layouts in classical Japanese manuscript collections ("Kunshujo").
- Model repository: nakamura196/yolov5-kunshujo
- Spaces (demo): nakamura196/yolov5-kunshujo

How the Structure Changed
Before
yolov5-kunshujo/
├── app.py # Loads model from local disk on startup
├── best.pt # 699 MB model stored directly in the repo
├── requirements.txt # Included unnecessary packages (gdown, matplotlib, seaborn)
└── ultralytics/
└── yolov5/ # YOLOv5 source code copied locally
├── hubconf.py
├── models/
└── utils/
Problems:
best.pt(699 MB) was inside the Spaces repo and tracked by Git- YOLOv5 source code had to be maintained as a local copy
- Model loaded at startup, making Spaces boot slow
- Not compatible with PyTorch 2.6 breaking changes
After
yolov5-kunshujo/
├── app.py # Downloads model from HF Hub; lazy-loads on first inference
└── requirements.txt # Trimmed to only what's needed
Improvements:
best.ptmoved to a separate model repository (nakamura196/yolov5-kunshujo)ultralytics/yolov5/removed;torch.hubfetches and caches it from GitHub- Model is lazy-loaded on first inference (faster Spaces startup)
- PyTorch 2.6 compatibility fix applied
- Unnecessary packages removed
1. Setting Up huggingface-hub
pip install huggingface_hub
If the hf command is not found after installation, the binary is not on your PATH.
# Run with full path
/Users/nakamura/Library/Python/3.9/bin/hf login
# Or add permanently to PATH
echo 'export PATH="$HOME/Library/Python/3.9/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
huggingface-cliis deprecated; migrating to thehfcommand is recommended.
2. Creating a Model Repository
hf repo create yolov5-kunshujo --repo-type model
3. Uploading the Model File
hf upload nakamura196/yolov5-kunshujo ./best.pt best.pt
best.pt is about 700 MB, but Hugging Face's xet storage backend makes the upload fast.
4. Setting Up the Model Card
The README.md in the model repository serves as the Model Card. Create it in the following format and upload it.
---
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. Updating the Gradio App
Fixing REPO_ID
Check that app.py does not still contain a placeholder like username/yolov5-kunshujo.
REPO_ID = "nakamura196/yolov5-kunshujo"
Lazy-Loading from HF Hub
Instead of loading at startup, use hf_hub_download to download and load the model on first inference.
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)
# ... load model
return _model
On the first call, the model is downloaded from HF; subsequent calls use the cache at ~/.cache/huggingface/hub/.
Cleaning Up requirements.txt
List all packages required by yolov5 v7.0 explicitly.
torch
torchvision
Pillow
opencv-python-headless
ipython
scipy
pandas
matplotlib
seaborn
psutil
| Package | Reason |
|---|---|
torch, torchvision | Required for YOLOv5 inference |
Pillow | Image processing |
opencv-python-headless | utils/dataloaders.py imports cv2 |
ipython | Used by utils/general.py |
scipy, pandas | Used by various YOLOv5 utilities |
matplotlib, seaborn | Used by utils/metrics.py, utils/plots.py |
psutil | Used by utils/dataloaders.py |
huggingface-hub | Pre-installed in HF Spaces; no need to list |
torch.hub.loadfetches the yolov5 code from GitHub and resolves its dependencies within what is listed in requirements.txt. If a missing package surfaces at runtime, add it as needed.
Final 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)
Troubleshooting
gradio_client TypeError / APIInfoParseError
Error:
TypeError: argument of type 'bool' is not iterable
# or
gradio_client.utils.APIInfoParseError: Cannot parse schema True
Cause: The schema for gr.JSON or gr.Gallery components contains additionalProperties: True (a boolean), and gradio_client's _json_schema_to_python_type() function crashes when it receives a non-dict value. This causes the /info endpoint to return a 500 error, which Gradio interprets as "cannot connect to localhost," aborting startup.
Fix: Apply a monkey-patch at the top of app.py (before 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
Because _json_schema_to_python_type is resolved in the module's global namespace, recursive calls are also automatically patched.
PyTorch 2.6 weights_only Issue
Error:
Weights only load failed. WeightsUnpickler error: Unsupported global:
GLOBAL numpy.core.multiarray._reconstruct was not an allowed global by default.
Cause: Starting with PyTorch 2.6, torch.load defaults to weights_only=True, which prevents loading older YOLOv5 models that contain numpy objects. Since the flag cannot be passed directly to the torch.load call inside torch.hub.load, a monkey-patch is used instead.
Fix:
_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 Error
Error:
argument 1 must be 2-item sequence, not generator
Fix:
# 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)
Gradio Fails to Start on Python 3.13
Error:
ModuleNotFoundError: No module named 'pyaudioop'
Cause: HF Spaces uses Python 3.13, and the audioop module that gradio 4.x depends on (via pydub) was removed in Python 3.13.
Fix 1: Update sdk_version in README.md to gradio 5.x.
sdk_version: 5.9.1
Fix 2: In gradio 5.x, allow_flagging was removed in favor of 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'
Cause: Using the master branch of torch.hub.load("ultralytics/yolov5", ...) now requires the new ultralytics package as a dependency.
Fix: Pin to v7.0.
_model = torch.hub.load("ultralytics/yolov5:v7.0", "custom", path=model_path, trust_repo=True)
Note:
best.pt(trained with the oldultralytics/yolov5repo) cannot be loaded with the newultralyticspackage (from ultralytics import YOLO) because the architecture is different (anchor-free). For old models,torch.hubpinned to v7.0 is the only recommended approach.
EOFError: EOF when reading a line (trust_repo)
Cause: In headless environments (Spaces, CI), torch.hub.load tries to display a trust confirmation prompt and fails.
Fix: Add trust_repo=True.
_model = torch.hub.load("ultralytics/yolov5:v7.0", "custom", path=model_path, trust_repo=True)
Missing Dependencies for yolov5 v7.0
Example errors:
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'
Cause: yolov5 v7.0 depends on many packages, and torch.hub.load does not install them automatically.
Fix: List all required packages in requirements.txt (see the table above).
Spaces Stuck at "Starting"
Cause 1: With server_name="127.0.0.1", the HF Spaces proxy cannot reach the port, causing health checks to fail.
Cause 2: In gradio 5.x SSR (Server-Side Rendering) mode, the Node.js server startup can conflict with Spaces health checks.
Fix:
demo.launch(
show_error=True,
server_name="0.0.0.0", # Changed from 127.0.0.1
server_port=7860,
ssr_mode=False, # Disable SSR
)
Screenshots
Inference Results (Input, JSON, Detected Images)

JSON Output and Detected Image Close-up

Summary
| Problem | Fix |
|---|---|
| Model (700 MB) stored in the Spaces repo | Moved to a separate HF Hub model repository |
| YOLOv5 source managed as a local copy | Used torch.hub GitHub caching instead |
| Slow startup due to model loading at boot | Changed to lazy-load on first inference |
PyTorch 2.6 weights_only breaking change | Monkey-patched torch.load |
gradio_client bool schema bug | Monkey-patched _json_schema_to_python_type |
Generator passed to im.resize() | Wrapped with tuple() |
audioop removed in Python 3.13, breaking gradio 4.x | Upgraded to gradio 5.9.1; changed to flagging_mode |
Dependency error on ultralytics/yolov5 master | Pinned to v7.0 |
| Missing yolov5 v7.0 dependencies | Added opencv-python-headless, ipython, matplotlib, seaborn, psutil, etc. to requirements.txt |
| Spaces stuck at "Starting" | Changed to server_name="0.0.0.0", ssr_mode=False |
| JSON displayed as plain text (hard to read) | Changed from gr.Textbox to gr.JSON component |



Comments
…