Snow-throw Prohibition Sign YOLOX-Tiny(投雪防止表示板 YOLOX-Tiny)
モデルラボ(インフラインテリジェンス)が公開している物体検出モデルです。 高速道路の路肩にある投雪防止表示板を、車の前方を撮った画像から見つけます。 投雪防止表示板は、除雪車が路肩の外へ雪を投げてはいけない区間の始まりと終わりを示す板です。
- 見つけるもの: 区間の始まりを示す表示板(
start)と、終わりを示す表示板(end) - 構造: YOLOX-Tiny(パラメータ約503万個)
- 学習: 運営者が撮った走行映像だけを使用。事前学習の重みは使っていない
- 入力: 1280×736のRGB画像(0〜255)
- 出力: 候補200件の枠(
boxes)と、クラスごとのスコア(scores) - ライセンス: Apache-2.0
ファイル
| ファイル | 中身 |
|---|---|
snow_throw_sign_yolox_tiny_v3.pth |
PyTorchの重み(torch.load(weights_only=True)で開ける) |
model.py |
ネットワークの定義と、入出力の例(torchとtorchvisionだけで動く) |
snow_throw_sign_yolox_tiny_v3.onnx |
ONNX(opset 17) |
coreml/snow_throw_sign_yolox_tiny_v3.mlpackage |
CoreML(mlprogram、FLOAT16、iOS 17以降) |
config.json |
入出力・クラス・後処理の設定 |
MODEL_CONTRACT.md |
入出力の決まり |
eval/ |
評価の結果と、形式ごとの出力の一致の記録 |
examples/predict_onnx.py |
ONNXで動かす例 |
LICENSE / NOTICE |
ライセンスと帰属表示 |
使い方
ONNX
pip install onnxruntime numpy pillow
python examples/predict_onnx.py snow_throw_sign_yolox_tiny_v3.onnx frame.jpg --x0 1120 --y0 712
PyTorch
pip install torch torchvision
python model.py snow_throw_sign_yolox_tiny_v3.pth frame.jpg --x0 1120 --y0 712
Pythonから使う例です。
import torch
from torchvision.io import ImageReadMode, decode_image
from model import load_detector, crop_window, postprocess
detector = load_detector("snow_throw_sign_yolox_tiny_v3.pth")
frame = decode_image("frame.jpg", mode=ImageReadMode.RGB) # [3,H,W] の uint8
x, (x0, y0) = crop_window(frame, 1120, 712) # 1280×736 を縮小せずに切り出す
with torch.no_grad():
boxes, scores = detector(x) # [200,4], [200,3]
for name, score, (x1, y1, x2, y2) in postprocess(boxes, scores):
print(name, round(score, 2), x1 + x0, y1 + y0, x2 + x0, y2 + y0)
torch 2.13.0で動くことを確かめています。
CoreML(iOS 17以降)
coreml/snow_throw_sign_yolox_tiny_v3.mlpackageをXcodeのプロジェクトに追加します。
入力はimage(1280×736のRGB画像、0〜255のまま)、出力はboxesとscoresです。
FLOAT16で計算するため、PyTorchとはわずかに値が違います(eval/coreml_parity.json)。
入力の作り方
学習では、4K(3840×2160)の画面から1280×736の範囲を縮小せずに切り出しました。 同じ作り方で使うのが前提です。 学習で使った窓の左上は、1倍ズームの映像で(1120, 712)、2倍ズームの映像で(960, 712)です。
画面の全体を見たいときは、全体を1280×720に縮小し、上下に8画素ずつ黒い帯を足して1280×736にします(--full)。
4Kの画面なら、表示板は切り出しのときの3分の1の大きさで写ります。
この使い方での成績は測っていません。
出力と後処理
boxesは[200, 4]で、各行が入力画像(1280×736)の画素の座標[x1, y1, x2, y2]です。
scoresは[200, 3]で、列はstart・end・hard_negativeの順です。
モデルは、スコアの最大値が大きい順に候補を200件選んで出力します。
しきい値とNMS(重なりの除去)はかけていません。
候補が200件に足りないときは、残りの行を[-1, -1, -1, -1]で埋めています。
boxes[i][0] < 0の行は捨ててください。
3列目のhard_negativeは、紛らわしい物のために用意した列です。
この版の学習データには例がないので、使わないでください。
評価では、startとendの列ごとにスコア0.3以上の候補を残し、列ごとにNMS(IoU 0.6)をかけました。
model.pyのpostprocess()が同じ処理です。
詳しくはMODEL_CONTRACT.mdを見てください。
評価
| 項目 | 検証(37枚) | テスト(57枚) |
|---|---|---|
startの枠を見つけた数 |
2 / 2 | 12 / 18 |
endの枠を見つけた数 |
9 / 11 | 17 / 21 |
startとendの取り違え |
0 | 0 |
| 背景を表示板と誤検出した数 | 1 | 4 |
数えたのは、1280×736の切り出し窓の中にある表示板だけです。
テストでは、startの枠23個のうち18個、endの枠30個のうち21個が窓の中にありました。
予測の枠の中心が、正解の枠の中心から「正解の幅の半分」以内なら、見つけたとしました(4画素未満になるときは4画素)。 mAPは出していません。 小さな枠では数画素のずれで値が大きく変わり、モデルの差より正解の枠の付け方の差を測ってしまうためです。
数値の元データはeval/にあります。
公開しているファイルで同じ集計をやり直し、同じ結果になることを確かめています。
評価についての注意
- テストは画像57枚、表示板の個体18個と少なく、数値のぶれは大きいです。
- テストの結果は開発中に何度も見ており、モデルを選ぶときにも使いました。そのため、テストの数値は実力より良く出ている可能性があります。
- 評価の画像は、色で候補を絞る仕組みで選んだコマと、以前のモデルの検出をきっかけにアプリが保存した写真です。見逃しやすい場面は評価に入りにくくなっています。
- 評価の画像は連続した走行ではないため、走行1時間あたりの誤報の数は測っていません。
- 夜間・雨・雪の場面と、画面全体を縮小して入れる使い方は評価していません。
学習データ
| 分割 | 画像 | 表示板が写った画像 | startの枠 |
endの枠 |
表示板の個体 |
|---|---|---|---|---|---|
| 学習 | 1070 | 247 | 96 | 183 | 61 |
| 検証 | 37 | 13 | 3 | 13 | 3 |
| テスト | 57 | 44 | 23 | 30 | 18 |
運営者が撮った高速道路の走行映像から、画像を切り出して使いました。 第三者のデータは使っていません。 撮影した時期は2026年8月で、時間帯は夕方(17時台〜19時台。日没前後を含む)です。 撮影にはiPhone(4K 3840×2160、1倍と2倍のズーム)を使いました。 撮影した場所は、日本の高速道路の一部の区間です。
同じ表示板が学習と評価の両方に入らないように、表示板の個体と映像のつながりを単位にして分けました。 画像を1枚ずつランダムに分けてはいません。 全部で82個の表示板が写っています。
学習の画像1070枚のうち、表示板が写っているのは247枚です。 残りは背景だけの画像で、誤検出を減らすために入れています。 学習の枠の幅は28〜310画素(中央値71画素)です。
画像そのものは重みに含まれていません。
学習の設定
- 初期値: 乱数で初期化(事前学習の重みは使っていない)
- エポック: 40、バッチ: 4
- 最適化: AdamW(学習率1e-3、重み減衰5e-4)。学習率はコサインで下げる
- 損失: 5×IoU損失+objectness損失+クラス損失(正例の割り当てはSimOTA)
startの表示板を含む画像を2倍に増やした(startはendより少ないため)- エポックごとに、表示板が写った画像1枚に対し、背景だけの画像を3枚の割合で選び直した
- 切り出す窓の位置を、左右±64画素、上下±48画素の範囲でずらした(縮小や拡大はしていない)
- 乱数の種: 0
- 計算機: Apple Silicon(PyTorch MPS)
苦手なこと・使うときの注意
- 雪の時期の映像では、学習も評価もしていません。表示板に雪が付いた状態や、降雪中・除雪作業中の見え方での成績は分かりません。
- 夜間の映像はほとんど学習に入っていません。夜間での成績は確かめていません。
- 撮影したのは日本の高速道路の一部の区間だけです。ほかの道路や地域では成績が落ちることがあります。
- 学習の枠より小さく写った表示板(幅28画素未満)での成績は確かめていません。
- 投雪してよいかの判断を、このモデルの結果だけで行わないでください。作業する人が目で確かめる前提で使ってください。
ライセンスと帰属表示
重みとコードはApache-2.0です(LICENSE)。
著作権表示と帰属はNOTICEにまとめています。
ネットワークの構造はYOLOX-Tinyです。
model.pyは、公式のYOLOX(Megvii、Apache-2.0)の構造とモジュール名に合わせて書いています。
事前学習の重みは使っていません。
構造を引用するときは、次の文献を挙げてください。
@article{ge2021yolox,
title={YOLOX: Exceeding YOLO Series in 2021},
author={Ge, Zheng and Liu, Songtao and Wang, Feng and Li, Zeming and Sun, Jian},
journal={arXiv preprint arXiv:2107.08430},
year={2021}
}
問い合わせ
インフラインテリジェンス(https://infra-intelligence.com/) contact@infra-intelligence.com
English summary
Snow-throw Prohibition Sign YOLOX-Tiny detects snow-throw prohibition signs on the shoulders of Japanese expressways, in images taken from the front of a vehicle. Snowplows must not throw snow off the shoulder between a start sign and an end sign. Published by Model Lab (Infra Intelligence).
- Architecture: YOLOX-Tiny (5.03 M parameters), trained from random initialization (no pretrained weights) on 1164 images from the publisher's own expressway footage only. No third-party data.
- Input
image: float32[1,3,736,1280], RGB, raw 0–255. Training used 1280×736 crops taken from 4K frames without resizing. Normalization is inside the model. - Outputs:
boxes[200,4](x1,y1,x2,y2in input pixels) andscores[200,3](start,end,hard_negative). Top 200 candidates by max score; no threshold, no NMS. Unused rows haveboxes[i][0] < 0. Ignore thehard_negativecolumn. - Evaluation post-processing: per-class threshold 0.3 and per-class NMS (IoU 0.6). mAP is not reported.
- Test set (57 images, 18 physical signs; counting only signs inside the crop window):
startfound 12/18,endfound 17/21, no start/end confusion, 4 false alarms on background. The test set is small and was looked at many times during development, so these numbers may be optimistic. - Not evaluated: night, rain, snow, and feeding the whole frame resized. Do not decide whether snow may be thrown based on this model alone.
- Formats: PyTorch (
model.py+ weights), ONNX, CoreML (FLOAT16, iOS 17+). ONNX and CoreML outputs were checked against PyTorch (seeeval/). - License: Apache-2.0.
- Downloads last month
- 12