YOLO26とは
2026年1月にUltralyticsからリリースされた最新の物体検出モデル。前世代のYOLO11と比べてCPU推論が最大43%高速化され、エッジデバイスでの実用性が大幅に向上しています。
最大の特徴はNMS不要のEnd-to-End推論。従来のYOLOでは必須だったNon-Maximum Suppression(NMS)の後処理ステップが不要になり、モデルから直接最終的な検出結果が出力されます。
| モデル | mAP | CPU推論 | パラメータ |
|---|---|---|---|
| YOLO26n | 40.9 | 38.9ms | 2.5M |
| YOLO26s | 48.6 | 63.3ms | 9.2M |
| YOLO26m | 53.1 | 155ms | 18.7M |
なぜiPhoneで動かすのか
- リアルタイム推論: Neural Engineを活用して30FPS以上で動作
- プライバシー: データがデバイス外に出ない
- オフライン: ネットワーク不要で動作
- 低レイテンシ: サーバー往復がないので即座に結果が返る
CoreMLモデルの準備
方法1: 変換済みモデルをダウンロード
CoreML-Modelsリポジトリから変換済みのモデルをダウンロードできます。
方法2: 自分で変換
pip install ultralytics coremltools==8.1
python -c "
from ultralytics import YOLO
model = YOLO('yolo26s.pt')
model.export(format='coreml', nms=False)
"
注意: coremltools 9.0には
_castのバグがあるため、8.1を推奨します。
iOSアプリの実装
モデルの読み込み
import CoreML
import Vision
let config = MLModelConfiguration()
config.computeUnits = .all // Neural Engine + GPU + CPU
let mlModel = try MLModel(contentsOf: modelURL, configuration: config)
let vnModel = try VNCoreMLModel(for: mlModel)
カメラフレームの推論
func captureOutput(_ output: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
let request = VNCoreMLRequest(model: vnModel) { request, _ in
self.handleDetections(request)
}
request.imageCropAndScaleOption = .scaleFill
try? VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: .up)
.perform([request])
}
NMS不要の出力デコード
YOLO26の出力は [1, 300, 6] のテンソル。各行が [x1, y1, x2, y2, confidence, class_id] で、すでにフィルタリング済みの最終結果です。
func handleDetections(_ request: VNRequest) {
guard let results = request.results as? [VNCoreMLFeatureValueObservation],
let array = results.first?.featureValue.multiArrayValue else { return }
let shape = array.shape.map { $0.intValue } // [1, 300, 6]
for i in 0..<shape[1] {
let confidence = array[[0, i, 4] as [NSNumber]].floatValue
guard confidence >= 0.25 else { continue }
let x1 = CGFloat(array[[0, i, 0] as [NSNumber]].floatValue) / 640
let y1 = CGFloat(array[[0, i, 1] as [NSNumber]].floatValue) / 640
let x2 = CGFloat(array[[0, i, 2] as [NSNumber]].floatValue) / 640
let y2 = CGFloat(array[[0, i, 3] as [NSNumber]].floatValue) / 640
let classId = Int(array[[0, i, 5] as [NSNumber]].floatValue)
// x1,y1,x2,y2 は正規化座標 [0,1]
// これをそのまま画面座標に変換して描画
}
}
従来のYOLO(v5, v8, v9, v11)では、この段階でNMSの処理が必要でした。YOLO26ではモデル内部でDual Assignmentによる重複排除が完了しているため、閾値でフィルタリングするだけで最終結果が得られます。
NMS付きYOLOとの比較
| YOLO26 (NMS不要) | YOLO11 (NMS必要) | |
|---|---|---|
| 出力 |
[1, 300, 6] — 直接結果 |
[1, 84, 8400] — 要デコード+NMS |
| 後処理 | 閾値フィルタのみ | box decode → NMS → フィルタ |
| CoreML変換 |
nms=False でシンプル |
nms=True でパイプライン構築が必要 |
| 推論速度 | 43%高速 (CPU) | ベースライン |
バウンディングボックスの描画
高速描画には CAShapeLayer を使います。SwiftUIの ForEach で描画すると毎フレーム再生成されて遅くなります。
class BoundingBoxView {
let shapeLayer = CAShapeLayer()
let textLayer = CATextLayer()
func show(frame: CGRect, label: String, color: UIColor) {
CATransaction.begin()
CATransaction.setDisableActions(true) // アニメーション無効化
shapeLayer.path = UIBezierPath(roundedRect: frame, cornerRadius: 10).cgPath
shapeLayer.strokeColor = color.cgColor
textLayer.string = label
CATransaction.commit()
}
}
ポイント:
-
CATransaction.setDisableActions(true)で暗黙のアニメーションを無効化。これがないとラベルがフレーム遅れで追従する - 100個程度のレイヤーをプール化して再利用。毎フレームのalloc/deallocを回避
カメラプレビューとの座標合わせ
ここが一番ハマるポイント。
// カメラ出力のvideoOrientationを.portraitに設定
// これでpixelBufferがポートレート回転済みで届く
let connection = videoOutput.connection(with: .video)
connection?.videoOrientation = .portrait
// VNImageRequestHandlerには .up を渡す(既に回転済みなので)
VNImageRequestHandler(cvPixelBuffer: pb, orientation: .up)
プレビューが resizeAspectFill でクロップされるため、カメラのアスペクト比と画面のアスペクト比の差を補正する必要があります。
let cameraRatio = shortSide / longSide // e.g., 1080/1920
let displayRatio = screenWidth / screenHeight
let ratio = (screenHeight / screenWidth) / (longSide / shortSide)
if ratio >= 1 {
// 画面がカメラより縦長 → 横方向にスケール補正
let offset = (1 - ratio) * (0.5 - rect.minX)
// ... アフィン変換で補正
}
サンプルアプリ
CoreML-Models リポジトリに完全なサンプルアプリがあります。
-
YOLO26Demo (
sample_apps/YOLO26Demo/) — NMS不要モデル用- カメラリアルタイム推論 + FPS/レイテンシ表示
- 写真ライブラリからの画像推論
- 動画のフレームごと推論
セットアップ:
- モデルをダウンロードして解凍
-
.mlpackageをXcodeプロジェクトにドラッグ - 実機でビルド&ラン
出力形状 [1, N, 6] を持つモデルなら、ファイル名に関わらず自動で読み込まれます。
変換時のTips
今回の変換で得た知見:
-
coremltools 9.0 + numpy 2.x は
_castでクラッシュする → coremltools 8.1 + numpy<2 を使う -
ultralytics 8.4.31 の
nms=TrueCoreMLエクスポートはpipeline_coremlのバグで失敗する → NMS不要のYOLO26ならそもそもnms=Falseで問題なし - Python 3.14はcoremltools非対応 → Python 3.12を使う
まとめ
YOLO26はNMS不要の設計により、CoreML変換もアプリ実装もシンプルになりました。従来のYOLOではNMSパイプラインの構築やデコード処理が必要でしたが、YOLO26では閾値フィルタリングだけで済みます。
iPhoneのNeural Engineを活用すれば30FPS以上のリアルタイム検出が可能。エッジAIの実用化がまた一歩近づいた感じがします。
参考リンク
🐣
最新のAI機能を使ったアプリやサービスを最速で試作したい。
そんなご要望にお応えします。
ご相談はこちらまで。
rockyshikoku@gmail.com