Road Sign YOLOX-Tiny(道路標識 YOLOX-Tiny)
モデルラボ(インフラインテリジェンス)が公開している物体検出モデルです。 車に載せたスマートフォンやドライブレコーダーで撮った道路の画像から、日本の道路標識の板を見つけ、形と色で5つに分けます。 道路標識の位置の台帳を作るときの、下調べに使うことを考えて作りました。
- 見つけるもの: 道路標識の板(案内・警戒・規制・指示・補助の5クラス)
- 構造: YOLOX-Tiny(パラメータ約503万個)
- 学習: Mapillary に投稿された日本国内の路上の画像。事前学習の重みは使っていない(最初から学習)
- 入力: 1280×736のRGB画像(0〜255)
- 出力: 候補200件の枠(
boxes)と、クラスごとのスコア(scores、6列) - 使うしきい値: 0.5
- ライセンス: Apache-2.0
- 紹介のページ: https://infra-intelligence.com/services/modellab/road-sign-yolox-tiny/
何を見つけるか
道路標識令の分け方に合わせて、板の形と色で5つに分けます。標識の種類(「一時停止」「最高速度」など)までは分けません。
| 番号 | クラス | 中身 |
|---|---|---|
| 0 | guide |
案内標識。青地・緑地の長方形で文字が主のもの(方面・距離・地名・路線番号・出口など)。交差点名の板も含む |
| 1 | warning |
警戒標識。黄色の菱形に黒い縁と黒い図(道路工事中を含む) |
| 2 | regulatory |
規制標識。赤い縁の円形、逆三角形の一時停止、青い円に白い矢印、青い長方形の一方通行など。青くても規制のものはここ |
| 3 | indication |
指示標識。青地の正方形・長方形で図が主のもの(横断歩道・駐車可など)。優先道路の黄色の菱形もここ |
| 4 | supplementary |
補助標識。主標識の上下に付く、白地に黒文字の小さい長方形(「ここから」「8-20」「通学路」など) |
- 枠は板だけを囲みます。支柱・金具・門型の枠は含めません。
- 1本の支柱に主標識と補助標識が付いていれば、板ごとに別の枠になります。
- 板の裏側(無地の面)は、種類が分からないので見つけません。
6つ目のクラスhard_negativeは、標識と紛らわしい物(板の裏側・店の看板・信号機・視線誘導標・電光の情報板・工事の看板・カーブミラーなど)です。
誤報を減らすために学習させたクラスで、出力の6列目にスコアがありますが、標識としては使いません。
評価と同じ後処理では、6列の中でhard_negativeのスコアが一番大きい候補は捨てます(「出力と後処理」)。
ファイル
| ファイル | 中身 |
|---|---|
road_sign_yolox_tiny_v9.pth |
PyTorchの重み(torch.load(weights_only=True)で開ける) |
model.py |
ネットワークの定義と、入力の作り方・後処理の例(torch・torchvision・Pillowだけで動く) |
road_sign_yolox_tiny_v9.onnx |
ONNX(opset 17、入力1280×736で固定) |
config.json |
入出力・クラス・後処理の設定 |
MODEL_CONTRACT.md |
入出力の決まり |
eval/ |
評価の結果と、形式ごとの出力の一致の記録 |
examples/predict_onnx.py |
ONNXで動かす例 |
LICENSE / NOTICE |
ライセンスと帰属表示 |
使い方
ONNX
pip install onnxruntime numpy pillow
python examples/predict_onnx.py road_sign_yolox_tiny_v9.onnx frame.jpg
PyTorch
pip install torch torchvision pillow
python model.py road_sign_yolox_tiny_v9.pth frame.jpg
Pythonから使う例です。
import torch
from PIL import Image
from model import load_detector, letterbox, postprocess, to_original
detector = load_detector("road_sign_yolox_tiny_v9.pth") # 入力 1280×736
image = Image.open("frame.jpg")
x, scale = letterbox(image, detector.input_size) # 縦横比を保って縮め、右と下を灰色で埋める
with torch.no_grad():
boxes, scores = detector(x) # [200,4], [200,6]
for score, name, box in postprocess(boxes, scores): # しきい値 0.5
print(name, round(score, 2), to_original(box, scale, image.size))
torch 2.13.0 で動くことを確かめています。
入力の作り方
画像を縦横比を保って縮め、左上に置き、右と下の余りを灰色(画素値114)で埋めます。
- 16:9の画像(1920×1080・2048×1152など): 1280×720に縮め、下に16画素の灰色を足して1280×736にします。評価と同じ作り方です。
- 4:3の画像(2048×1536など): 評価では、長辺を1280に縮めた1280×960をそのまま入れました。
これはPyTorch(
model.py)でだけできます(load_detector(..., input_size=(1280, 960))、python model.pyの既定)。 ONNXは入力が1280×736で固定なので、4:3の画像は981×736に縮めて入れることになります。 検証の4:3の画像(369枚)で比べると、1280×960で入れたときは見つけた割合0.869・誤報13.7件、 981×736で入れたときは見つけた割合0.740・誤報17.6件でした(誤報は標識の写っていない画像100枚あたり)。
詳しくはMODEL_CONTRACT.mdを見てください。
出力と後処理
boxesは[200, 4]で、各行が入力画像の画素の座標[x1, y1, x2, y2]です。
scoresは[200, 6]で、列はguide・warning・regulatory・indication・supplementary・hard_negativeの順です。
モデルは、6列のスコアの最大値が大きい順に候補を200件選んで出力します。
しきい値とNMS(重なりの除去)はかけていません。
候補が200件に足りないときは、残りの行を[-1, -1, -1, -1]で埋めています。boxes[i][0] < 0の行は捨ててください。
評価では、次の後処理をしました。model.pyのpostprocess()とexamples/predict_onnx.pyが同じ処理です。
- 行ごとに、6列の中でスコアが一番大きいクラスを選ぶ。
hard_negativeになった行は標識として数えない。 - クラスごとにNMS(IoU 0.65)をかける。
- スコアが0.5以上のものを標識の板とする。
しきい値0.5は、検証の画像で0.05きざみに調べ、F1が一番大きくなった値です。評価用の画像を見る前に決めました。 見逃しを減らしたいときはしきい値を下げ、誤報を減らしたいときは上げてください。
大きな板を出さないとき
近くで大きく写った板は苦手です(下の「検証の数」で、幅128画素以上の板のAP50は0.611)。
大きな板を出したくないときは、枠を元の画像に戻したあと、長辺を2048画素にしたときの枠の幅が128画素以上の枠を捨ててください。
model.pyではpostprocess(boxes, scores, scale=scale, image_size=image.size, max_w2048=128)、
examples/predict_onnx.pyとpython model.pyでは--max-w2048 128です。
評価の数は、この絞り込みをしないときのものです。
評価
学習にも検証にも使っていない、別の7地域の画像596枚で、最後に1回だけ評価しました。 標識の板の枠は988個、標識の写っていない画像は117枚です。 同じ標識が学習と評価の両方に入らないように、地域ごと分けています。
| 項目 | 値 |
|---|---|
| 見つけた割合(recall、しきい値0.5、クラスを問わない) | 0.857(847/988) |
| 適合率(precision、しきい値0.5) | 0.877 |
| 見つけた板のクラスが合っていた割合 | 0.980 |
| 誤報(標識の写っていない画像100枚あたり) | 12.0件 |
| AP50(5クラスを区別しない) | 0.902 |
| AP50-95(5クラスを区別しない) | 0.700 |
クラス別です。見つけた割合は、クラスを問わず枠が合ったものの割合です。AP50は、そのクラスの予測とそのクラスの正解だけで数えたもので、クラスの取り違えはここで下がります。
| クラス | 枠の数 | 見つけた割合(0.5) | AP50 |
|---|---|---|---|
案内(guide) |
127 | 0.661(84/127) | 0.594 |
警戒(warning) |
9 | 0.889(8/9) | 0.958 |
規制(regulatory) |
637 | 0.923(588/637) | 0.937 |
指示(indication) |
96 | 0.875(84/96) | 0.893 |
補助(supplementary) |
119 | 0.698(83/119) | 0.748 |
板の大きさ別です。大きさは、画像の長辺を2048画素にしたときの板の幅です。
| 大きさ | 枠の数 | 見つけた割合(0.5) | AP50 |
|---|---|---|---|
| 〜32画素 | 279 | 0.821 | 0.759 |
| 32〜64画素 | 398 | 0.857 | 0.861 |
| 64〜128画素 | 264 | 0.894 | 0.878 |
| 128画素以上 | 47 | 0.872 | 0.642 |
予測の枠と正解の枠が IoU 0.5 以上で重なれば、見つけたとしました。
数値の元データはeval/evaluation.jsonにあります。
評価についての注意
- 評価用の正解の枠も、AIアシスタントが付けました。 開発者は一部を見て、おおむね合っていることを確かめましたが、1枚ずつは確かめていません。
- 案内と補助は、検証より大きく下がりました(AP50は案内0.795→0.594、補助0.894→0.748)。 検証の画像は、枠の付いていない標識が写った画像を除いて作りました。そのため検証には、下書きにもモデルにも見つけにくい板 (交差点名・通り名の板、主標識の下の小さい補助標識)があまり入っていません。 評価用はそうした画像も除かず、残った板に枠を描き足したので、こちらが実際の使い方に近い数です。
- 警戒標識は評価用に9個しかなく、この数は目安になりません。
- 元の画像で幅か高さが20画素未満の板、半分以上隠れた板、形や色が決められない板は、正解にも誤りにも数えていません(ignore)。 住所・町名の板(電柱に付く「〇〇町3」など)は交差点名の板と見分けがつかないので、学習にも評価にも使っていません。
検証の数
学習と同じ地域の、学習とは別の画像992枚(標識の板の枠1,866個、標識の写っていない画像158枚)での数です。 しきい値を決め、重みを選ぶのに使いました。
| 項目 | 値 |
|---|---|
| 見つけた割合(0.5) | 0.869(1,622/1,866) |
| 適合率(0.5) | 0.906 |
| 見つけた板のクラスが合っていた割合 | 0.977 |
| 誤報(標識の写っていない画像100枚あたり) | 19.0件 |
| AP50 / AP50-95(5クラスを区別しない) | 0.925 / 0.701 |
| クラス・大きさ | 枠の数 | 見つけた割合(0.5) | AP50 |
|---|---|---|---|
| 案内 | 302 | 0.805 | 0.795 |
| 警戒 | 19 | 0.895 | 0.914 |
| 規制 | 1063 | 0.894 | 0.926 |
| 指示 | 138 | 0.927 | 0.878 |
| 補助 | 344 | 0.826 | 0.894 |
| 〜32画素 | 498 | 0.805 | 0.796 |
| 32〜64画素 | 788 | 0.883 | 0.912 |
| 64〜128画素 | 460 | 0.920 | 0.898 |
| 128画素以上 | 120 | 0.850 | 0.611 |
この公開物(model.pyと重み、CPU)で検証の画像を予測し直すと、AP50は0.925で、しきい値0.5での数は記録と同じでした(eval/evaluation.json)。
苦手なこと・使うときの注意
- 近くで大きく写った板の枠が合いにくいです(幅128画素以上の板のAP50は検証で0.611、評価で0.642)。 大きな板を出したくないときは、「大きな板を出さないとき」の絞り込みを使ってください。
- 交差点名・通り名の小さな板と、主標識の下の小さい補助標識を見落としやすいです。
- 住所・町名の板、店の看板、白い板を、案内標識や補助標識と間違えることがあります。
- 青い長方形の板は、案内(文字が主)・指示(図が主)・規制(一方通行など)の見分けを間違えることがあります。
- 夜間の画像では評価していません。 雨・雪・霧の場面での成績も分かりません。
- 学習も評価も日本国内の画像だけです。ほかの国の標識には使えません。
- 画像1枚ずつの検出です。同じ標識が続くコマに何度も写るので、台帳にするときは位置でまとめてください。
- 交通の安全にかかわる判断を、このモデルの結果だけで行わないでください。台帳を作るときは、人が写真で確かめる前提で使ってください。
学習データ
Mapillary(https://www.mapillary.com/)に投稿された、日本国内の路上の画像を使いました。 画像のライセンスはCC BY-SA 4.0です。 15地域から、学習4,585枚・検証992枚を選びました。評価用の7地域は、これとは別の地域です。
| 分割 | 画像 | 標識が写った画像 | 標識の板の無い画像 | 案内 | 警戒 | 規制 | 指示 | 補助 | ignoreの板 | 紛らわしい物の枠 |
|---|---|---|---|---|---|---|---|---|---|---|
| 学習 | 4,585 | 3,499 | 826 | 1,833 | 363 | 3,878 | 634 | 1,100 | 2,048 | 13,348 |
| 検証 | 992 | 755 | 158 | 302 | 19 | 1,063 | 138 | 344 | 567 | 3,888 |
ラベルの付け方
- Mapillaryが画像から自動で見つけた標識の検出を下書きにしました。
- 下書きの枠を、AIアシスタントが、文書にまとめた決まり(クラスの見分け方・枠の付け方・紛らわしい物の扱い)に沿って判定し、ずれた枠は描き直しました。 前の版のモデルで、枠の付いていない標識の候補や、案内標識が写っていそうな画像も探し、同じように判定しました。
- 決まりは開発者が決めました。学習と検証のラベルを、人が1枚ずつ確かめてはいません。
- 枠の付いていない標識が写っている画像、道路でない画像、画質の悪い画像は、学習と検証から除きました。
- 画像とラベル(データセット)は、この公開物には含めていません。画像そのものは重みに含まれていません。
- 帰属表示: Contains imagery from Mapillary contributors, licensed CC BY-SA 4.0(https://www.mapillary.com/)。投稿者の一覧は`NOTICE`にあります。
学習の設定
- 初期値: 乱数で初期化(事前学習の重みは使っていない)
- 学習の回数: 学習を 7 回つないだ。1 回目は乱数の初期値から(94 エポックで止め、検証の AP50 が一番よかったエポック 55 の重み)。2〜7 回目は、ラベルを直したり画像を足したりしたデータで、前の回の一番よい重みから続けて学習した(各回 8〜60 エポック)。公開する重みは 7 回目(30 エポック)のうち、検証の標識の AP50(5 クラスを区別しない)が一番よかったエポック 28 の重み(重みの移動平均 EMA 0.9998)
- バッチ: 8
- 最適化: AdamW(学習率 1e-3、最初に上げ(1 回目は 3 エポック、2 回目以降は 1 エポック)、コサインで 5% まで下げる。重み減衰 5e-4、BN とバイアスは 0)
- 損失: 5×IoU 損失+objectness 損失+クラス損失(正例の割り当ては SimOTA)
- 入力: 1280×736 の切り出し。長辺 1280 を基準の縮尺にし、×0.75〜1.5 の縮尺のゆらぎ
- 拡張: 切り出し・左右反転・明るさ・コントラスト・彩度・モザイク(確率 0.5、最後の 10 エポックは止める)
- 標識が写った画像を 1.5 倍に増やした
- 乱数の種: 0
- 計算機: Apple Silicon(PyTorch MPS)
ライセンスと帰属表示
重みとコードはApache-2.0です(LICENSE)。
著作権表示と帰属はNOTICEにまとめています。
学習に使った画像はCC BY-SA 4.0ですが、画像そのものは公開物に含めていません。
学習済みの重みは画像そのものではないと考え、重みはApache-2.0で公開しています。
この考え方は作者の解釈で、これを確かめた判例はありません。
学習に使った画像への帰属として、Mapillaryとその投稿者を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
Road Sign YOLOX-Tiny detects Japanese road sign plates in road images taken from a vehicle (car-mounted smartphone or dashcam) and sorts them into five classes by shape and colour, for building asset inventories. It does not identify the individual sign type. Published by Model Lab (Infra Intelligence). Project page: https://infra-intelligence.com/services/modellab/road-sign-yolox-tiny/
- Classes (output order):
guide(blue/green rectangular plates mainly with text, incl. intersection-name plates),warning(yellow diamonds),regulatory(red-rimmed circles, inverted-triangle stop, blue circles with white arrows, one-way plates),indication(blue squares/rectangles mainly with a pictogram),supplementary(small white plates with black text attached above/below a main sign). Boxes cover the plate only (no pole). A sixth score column,hard_negative(look-alikes such as the backs of plates, shop signboards, traffic lights, delineators, electronic message boards), exists only to reduce false alarms: rows whose argmax ishard_negativeare not signs. - Architecture: YOLOX-Tiny (5.03 M parameters), trained from scratch (no pretrained weights).
- Input
image: float32[1,3,736,1280], RGB, raw 0–255; normalization is inside the model. Resize keeping the aspect ratio, place top-left, pad right/bottom with 114. 16:9 images become 1280×720 + 16 padding rows, exactly as in the evaluation. In the evaluation, 4:3 images were fed at 1280×960 (possible withmodel.py; ONNX is fixed at 1280×736, so 4:3 images become 981×736 — on the 4:3 validation images recall was 0.869 at 1280×960 vs 0.740 at 981×736). - Outputs:
boxes[200,4](x1,y1,x2,y2in input pixels) andscores[200,6](the five classes, thenhard_negative). Top 200 candidates by max score; no threshold, no NMS. Unused rows haveboxes[i][0] < 0. - Post-processing: argmax class per row over all 6 columns (drop
hard_negative), class-wise NMS (IoU 0.65), keep score ≥ 0.5 (the max-F1 threshold on validation data, chosen before looking at the test set). Optional: to suppress large plates, drop boxes whose width (in original pixels, clipped to the image) × 2048 / long side ≥ 128. - Held-out test (596 images from 7 Japanese areas not used for training, split by region; 988 sign boxes; 117 images without signs), threshold 0.5: recall 0.857 (847/988, class-agnostic), precision 0.877, class accuracy on matched plates 0.980, 12.0 false alarms per 100 images without signs, AP50 0.902, AP50-95 0.700. AP50 per class: guide 0.594, warning 0.958 (only 9 boxes, not meaningful), regulatory 0.937, indication 0.893, supplementary 0.748. Guide and supplementary are much lower than on validation (0.795 / 0.894) because the validation set excluded images with unlabelled signs, which removed hard plates such as small intersection-name plates and small supplementary plates; the test set kept them. The test labels were made by an AI assistant and spot-checked by the developer, not reviewed image by image.
- Validation (992 images): AP50 0.925, recall 0.869, precision 0.906 at 0.5. Large plates (≥ 128 px wide at 2048 px long side) are weak: AP50 0.611.
- Limitations: large/near plates, small intersection-name and supplementary plates, address plates and shop signs confused with guide/supplementary; night, rain and snow not evaluated; Japan only. Not for safety-critical decisions.
- Training data: street-level images from Mapillary contributors in Japan (CC BY-SA 4.0): 4,585 training and 992 validation images from 15 areas, separate from the 7 test areas. Mapillary's automatic sign detections were used as drafts; an AI assistant checked, re-classified and redrew the boxes following written rules set by the developer. Labels were not reviewed by a human image by image. The dataset is not included in this release. Contains imagery from Mapillary contributors, licensed CC BY-SA 4.0 (https://www.mapillary.com/).
- License: Apache-2.0 for weights and code. Architecture: YOLOX (Megvii, Apache-2.0). Contact: contact@infra-intelligence.com
- Downloads last month
- -