YOLO11とは?
(画像は、Geminiで作成されたものです)
YOLO11の概要
2024年9月にUltralytics社が発表したYOLO11は、リアルタイム物体検出・画像セグメンテーションの分野において、精度と速度のトレードオフをさらに押し上げた最先端(SOTA)のビジョンAIモデルです。
YOLO11を一言で表現すると、「より少ないパラメータで、より深く賢く特徴を捉える、極限まで最適化されたリアルタイム・ビジョン・ファウンデーションモデル」です。
前世代のYOLOv8と比較して、パラメータ数を大幅に削減しつつも、平均適合率(mAP)を向上させており、エッジデバイスからクラウドまで、あらゆる環境でのデプロイを容易にしています。
YOLOv8との比較
| 特徴 | YOLOv8 | YOLO11 |
|---|---|---|
| 主要モジュール | C2fブロック | C3k2, C2PSA ブロック |
| パラメータ効率 | 高い | 極めて高い(v8比で約22%削減※mモデル) |
| アテンション機構 | 限定的 | 空間アテンション(PSA)による強化 |
| 対応タスク | 検出, セグメンテーション, 姿勢推定, 追跡, 分類 | 検出, セグメンテーション, 姿勢推定, 追跡, 分類, OBB(回転バウンディングボックス)強化 |
YOLO11の処理概要
(画像は、Geminiで作成されたものです)
YOLO11のネットワーク全体は、大きく「Backbone(特徴抽出)」「Neck(特徴融合)」「Head(予測)」の3つのフェーズに分かれています。図の左から順にどのように画像が処理されていくのかを見ていきましょう。
- Backbone: C3k2による効率的な特徴抽出
入力画像は、畳み込み層と新しいC3k2モジュールを通過し、様々なスケール(解像度)の特徴マップに変換されます。C3k2は情報のボトルネックを防ぎながら、計算コストを抑えつつ深い特徴を抽出します。 - Neck: C2PSAによる空間アテンションと特徴融合
Backboneから得られた特徴マップはNeckに送られ、Pan-FPN(Path Aggregation Network)構造で統合されます。ここで重要なのがC2PSAモジュールです。空間アテンションを適用することで、背景のノイズを抑え、重要なオブジェクトの輪郭やテクスチャにモデルの焦点を絞ります。 - Head: アンカーフリーな予測
統合された特徴マップはHeadに渡され、クラス確率とバウンディングボックスの座標が出力されます。YOLOv8から引き続きアンカーフリー(Anchor-free)設計を採用しており、オブジェクトのスケールやアスペクト比に対する汎化性能が高められています。
YOLO11の構成技術要素(詳細)
YOLO11の飛躍的な性能向上を支えているのは、新設計のアーキテクチャ・モジュール群です。以下に、主要な構成技術要素の詳細を記述します。
1. 洗練された特徴抽出ブロック:C3k2 (CSP Bottleneck with 2 Convolutions)
(画像は、Geminiで作成されたものです)
特徴抽出の要となるBackboneおよびNeckにおいて、従来のYOLOv8で使用されていたC2fモジュールを進化させ、新設計のC3k2ブロックが導入されました。
- 詳細な仕組み:
-
CSP (Cross Stage Partial) 構造の継承: YOLOv5以降主流となっているCSPNet(Cross Stage Partial Network)の設計を継承しています。入力特徴マップを2つのパスに分割し、一方のパスにのみ畳み込みとBottleneck構造(残差ブロックなど)を適用し、最後に再び結合(Concatenate)します。これにより、勾配情報を豊富に保ちつつ、重複する勾配情報を大幅に削減し、学習効率を高めます。
-
Bottleneck構造の最適化: C3k2 の「3k」は、3x3の畳み込みカーネルを持つBottleneckを意味し、「2」は主要なパス内に2つの畳み込み層を持つ構成を示唆しています(Ultralyticsの実装コードに基づくと、n個の残差ブロックを内部に持ちます)。
-
- 技術的な効果:
- 情報のボトルネック防止: 情報の伝達経路を並列化することで、ネットワークが深く、かつパラメータ数が少ない場合でも、重要な特徴情報が失われる「情報のボトルネック」を防ぎます。
- 計算効率と特徴表現の両立: パラメータ数を抑えつつ、深い特徴表現を得ることができるため、高速な推論を維持しながら精度を向上させます。
2. 空間アテンションの強化ブロック:C2PSA (CSP Bottleneck with Parallel Spatial Attention)
(画像は、Geminiで作成されたものです)
YOLO11における最も顕著な革新の一つは、新たに導入されたC2PSAモジュールです。これはアテンション機構(Attention Mechanism)をCSP構造に組み込んだものです。
- 詳細な仕組み:
- 空間アテンション(Spatial Attention): 従来のチャンネルアテンション(どの特徴チャンネルが重要か)に加え、空間アテンション(どの場所が重要か)を適用します。具体的には、特徴マップの各空間位置に対して、その位置がオブジェクトである可能性を計算し、重み付けを行います。
- 並列処理(Parallel): アテンション計算を主要な特徴抽出パスと並列に行い、その結果を最終的に結合します。
- 技術的な効果:
- 「どこに注目すべきか」の正確な学習: モデルは、背景のノイズを抑制し、重要なオブジェクトの輪郭、テクスチャ、および小さなオブジェクトが存在する空間的な場所に焦点を絞ることができます。
- 小さなオブジェクトと複雑なシーンの精度向上: この機構により、オクルージョン(遮蔽)が多い複雑なシーンや、画像内で数ピクセルしか占めない非常に小さなオブジェクトの検出精度が飛躍的に向上しました。
3. 極限のパラメータ効率とタスクの多用性
YOLO11は、アーキテクチャレベルでの最適化により、驚異的なパラメータ効率を実現しています。
- パラメータ数とmAPの比較: 例えばYOLO11m(ミディアムモデル)は、YOLOv8mと比較してパラメータ数を約22%削減しているにもかかわらず、COCOデータセットでのmAP(物体検出精度)が向上しています。これは、「モデルが軽いほど精度が落ちる」という従来の常識を覆す成果です。
- 多用なタスクへの対応: YOLO11は単一のチェックポイント(モデルファイル)から、以下のタスクへネイティブに対応できます。
- 物体検出 (Detection)
- インスタンスセグメンテーション (Segmentation)
- 姿勢推定 (Pose Estimation)
- 回転バウンディングボックス (OBB)
- 画像分類 (Classification)
- マルチオブジェクトトラッキング (Tracking)
YOLO11の実装(概念的なシンプルな実装)
ここでは、YOLO11のアーキテクチャの核心である「C3k2ブロック」と「C2PSA(空間アテンション)」が内部でどのような処理を行なっているのか、PyTorchを用いた擬似的なコードで解説します。深層学習モデルがどのように特徴を抽出・強調しているのか、そのエッセンスを掴んでみましょう。
MiniYOLO11Segの定義
以下のコードでは、PyTorchを用いてYOLO11のセグメンテーションモデルのアーキテクチャ概念を模した、極小規模のモデル MiniYOLO11Seg を定義します。YOLO11の処理フローである「Backbone(特徴抽出)」「Neck(特徴融合)」「Head(予測)」の3フェーズが、オブジェクト指向的なPyTorchモデルのネットワークとしてどのように構成・接続されているかを確認します。
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import numpy as np
import requests
from io import BytesIO
from PIL import Image
import cv2
from skimage import data
from ultralytics import YOLO
class MiniYOLO11Seg(nn.Module):
def __init__(self):
super().__init__()
# ==========================================
# 1. Backbone (特徴抽出)
# ==========================================
# 畳み込みで画像全体の解像度を半分に縮小し、大域的な特徴を抽出 (128x128 -> 64x64)
self.bb_stem = Conv(3, 16, k=3, s=2)
# さらに解像度を縮小し、より深い特徴マップを生成 (64x64 -> 32x32)
self.bb_down = Conv(16, 32, k=3, s=2)
# YOLO11の心臓部C3k2ブロックで、CSP構造による効率的な特徴抽出を実行
self.bb_c3k2 = C3k2(32, 32, n=1)
# ==========================================
# 2. Neck (特徴融合と空間アテンション)
# ==========================================
# Neck部: さらに深いレベルの特徴を捉えるため、解像度を最小に (32x32 -> 16x16)
self.neck_down = Conv(32, 64, k=3, s=2)
# C2PSAブロックで空間アテンションを適用し、オブジェクトの輪郭やテクスチャを強調
self.neck_c2psa = C2PSA(64, 64, n=1)
# 逆畳み込み(Transpose Conv)で解像度を復元し、浅い特徴マップとの融合(FPN)を準備 (16x16 -> 32x32)
self.neck_up = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2)
# ==========================================
# 3. Head (予測)
# ==========================================
# 最終的なマスク生成のため、さらに逆畳み込みで解像度を拡大 (32x32 -> 64x64)
self.head_up1 = nn.ConvTranspose2d(32, 16, kernel_size=2, stride=2)
# 元の入力画像と同じ解像度まで段階的に拡大 (64x64 -> 128x128)
self.head_up2 = nn.ConvTranspose2d(16, 16, kernel_size=2, stride=2)
# 各ピクセルが「オブジェクトか背景か」を示す1チャネルのバイナリマスクとして出力
self.head_pred = nn.Conv2d(16, 1, kernel_size=1)
def forward(self, x):
# --- Backbone ---
x = self.bb_stem(x)
x = self.bb_down(x)
# Backboneで抽出した特徴マップを後段のNeckで融合するため、ここで変数に保存
bb_feat = self.bb_c3k2(x)
# --- Neck ---
x = self.neck_down(bb_feat)
# 空間アテンションを適用して、特徴マップの「どこが重要か」を強調
x = self.neck_c2psa(x)
# 逆畳み込みで解像度を復元
x = self.neck_up(x)
# FPN(Path Aggregation Network)の概念を再現: 浅く詳細な特徴(bb_feat)と、深く意味的な特徴(x)を足し合わせる
neck_feat = x + bb_feat
# --- Head ---
x = self.head_up1(neck_feat)
x = self.head_up2(x)
return self.head_pred(x)
この MiniYOLO11Seg クラスの構造を読み解く上で、まず注目していただきたいのが 「プレフィックス(接頭辞)」 です。
コード内の変数名(レイヤー名)を見ると、Backboneを表す bb_(self.bb_stem、self.bb_down、self.bb_c3k2)、Neckを表す neck_(self.neck_down、self.neck_c2psa、self.neck_up)、そしてHeadを表す head_(self.head_up1、self.head_up2、self.head_pred)と、明確に役割ごとに分かれています。 実は、本家Ultralytics社のYOLOソースコードやその設定ファイル(YAMLファイル)でも、これら3つのフェーズが明確にモジュール化されて記述されています。この対応関係を理解すると、公式コードの全体像もグッと見通しが良くなります。
次に、この極小モデルにおける最も重要な処理が、forward メソッド内の 「特徴融合の再現」 です。
neck_feat = x + bb_feat という記述に注目してください。 ここでは、Backboneの初期フェーズで抽出した解像度が高く浅い特徴(bb_feat)と、Neckフェーズにおいて C2PSA モジュールを通過した「深く、空間アテンションによって重要な領域を際立たせた」意味的な特徴(x)を足し合わせています。 これこそが、先ほど解説した Pan-FPN(Path Aggregation Network)構造 による特徴融合の超シンプル版(エッセンス)です。浅いレイヤーの細かな輪郭情報と、深いレイヤーの高度な意味情報を統合することで、物体の位置と形状(マスク)を高精度に特定できるようになるのです。
Convの定義
ここでは、YOLOシリーズにおける最も基礎的なレイヤー構築の最小単位となる Conv クラスを定義します。PyTorchの標準的な畳み込み層に、バッチ正規化と先進的な活性化関数をシームレスに結合した共通モジュールを構築します。
class Conv(nn.Module):
def __init__(self, c1, c2, k=1, s=1):
super().__init__()
# 空間サイズを維持するためのパディング計算
p = k // 2
self.conv = nn.Conv2d(c1, c2, k, s, p, bias=False)
self.bn = nn.BatchNorm2d(c2)
self.act = nn.SiLU()
def forward(self, x):
return self.act(self.bn(self.conv(x)))
YOLOシリーズを読み解く上で、この Conv クラスは、すべての基礎となる 「最小単位」 と言えます。 単なる2次元の畳み込み層(Convolution)を単体で使うのではなく、ディープラーニングの世界では 「CBA(Conv + BatchNorm + Activation)モジュール」 と呼ばれる、3つの要素をワンセットにした構造を採用するのが鉄板の定石です。
ここでは、それぞれのコンポーネントがなぜ常にセットで使われているのか、その驚くべき役割とテクニックを解説します。
| コンポーネント | 役割と注目ポイント |
|---|---|
| nn.Conv2d | 画像からエッジ(輪郭)やテクスチャといった特徴を抽出する主役です。コード内で bias=False と設定されている点に注目してください。直後にある nn.BatchNorm2d の数式が、畳み込みのバイアス(偏り)項を打ち消してしまうため、ここでバイアスを無効化しています。これにより、計算コストとメモリ消費の無駄を極限まで省く、玄人好みの最適化テクニックが使われています。 |
| nn.BatchNorm2d | ネットワークを流れるデータのスケールや分布を適切に整える裏方です。ミニバッチごとに特徴マップの平均・分散を1に正規化することで、勾配消失を防ぎ、学習の進行を大幅に安定化・高速化させます。 |
| nn.SiLU | 特徴マップに非線形な表現力を追加する活性化関数です。YOLOv5以降で広く標準採用されているモダンな関数で、数式 ( はシグモイド関数)で定義されます。従来の単純なReLUに比べて、原点付近で滑らかなS字カーブを描き、一部負の値も通すため、ディープなネットワークにおける勾配消失を効果的に防ぎ、最終的なモデル精度の向上が期待できます。 |
C3k2の定義
以下のコードでは、YOLO11で新たに採用された特徴抽出の中核ブロックである C3k2 クラスを定義します。CSP(Cross Stage Partial)Netの設計思想を活かし、入力チャンネルを並列に2系統へ分割して処理することで、計算量を節約しながら深い特徴抽出を行います。
class C3k2(nn.Module):
def __init__(self, c1, c2, n=1):
super().__init__()
c_ = c2 // 2
self.cv1 = Conv(c1, c_, k=1)
self.cv2 = Conv(c1, c_, k=1)
self.cv3 = Conv(2 * c_, c2, k=1)
self.m = nn.Sequential(*(Bottleneck(c_, c_) for _ in range(n)))
def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))
C3k2(CSP Bottleneck with 2 Convolutions)は、特徴マップの豊かな表現力と圧倒的な計算効率を両立するためのモジュールです。
初期化メソッド init 内で、まず入力チャンネルを c_ = c2 // 2 として半分に削減した領域を作成します。 その後、並列処理として2つの入力パスを準備します。1つのパスでは self.cv1 を通した後に残差ブロック群である self.m(Bottleneck のシーケンス)に特徴マップを流します。もう1つのパスでは、self.cv2 で1x1畳み込みを行っただけの「浅い」特徴マップを保持します。
forward メソッドでは、torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1) の部分で、この「深く精緻に抽出された特徴」と「浅くそのまま残した特徴」をチャンネル方向に結合します。
最後に、self.cv3 によって、結合されて倍(2 * c_)になったチャンネル数を、目的の出力チャンネル数である c2 へと復元します。
このように入力をパス分割して後から統合するCSP構造のおかげで、勾配情報がダイレクトかつ豊富に伝わり、ネットワークを深くしても「情報のボトルネック」や「勾配消失」を起こさず、非常に高いパラメータ効率を実現できます。
Bottleneckの定義
ここでは、C3k2 や C2PSA などの上位特徴抽出ブロックの内部で繰り返し使用される Bottleneck クラスを定義します。3x3畳み込み層を2段階に重ね、入力情報を出力へバイパスする残差接続(Skip Connection)の実装です。
class Bottleneck(nn.Module):
def __init__(self, c1, c2, shortcut=True):
super().__init__()
self.cv1 = Conv(c1, c2, k=3)
self.cv2 = Conv(c2, c2, k=3)
self.add = shortcut and c1 == c2
def forward(self, x):
return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
Bottleneck クラスは、深層学習モデルが「勾配消失」を起こさずに極めて深いネットワークを構成するための、いわゆる「残差ブロック(Residual Block)」を表現したものです。
内部では、2つの 3x3 畳み込みを含む Conv レイヤー(self.cv1 および self.cv2)を直列に接続して局所的な特徴マップを抽出しています。
注目すべきは forward メソッドにおける条件分岐です。 self.add フラグが True で、かつ入力チャンネル数 c1 と出力チャンネル数 c2 が同一(チャンネル次元が不変)である場合、x + self.cv2(self.cv1(x)) という 残差接続(Skip Connection) が適用されます。 畳み込み処理によって生成される新しい特徴量に対して、入力された元の信号 x を直接足し合わせることで、逆伝播時に勾配が障害物なしに直接前方の層へ伝わるようになります。これにより、過学習や精度劣化を起こさず、安全に安定した学習を進めることができます。
C2PSAの定義
以下のコードでは、YOLO11の最も大きな技術的ブレイクスルーの一つである、空間アテンションを搭載した C2PSA モジュールを定義します。C3k2 で抽出した特徴をパラレルに分割し、一部に空間アテンションを適用したのち再び統合することで、ターゲット(物体)の輪郭や空間的な重要度を劇的に強調する仕組みを構築します。
class C2PSA(nn.Module):
def __init__(self, c1, c2, n=1):
super().__init__()
c_ = c2 // 2
self.cv1 = Conv(c1, c_, k=1)
self.cv2 = Conv(c1, c_, k=1)
self.cv3 = Conv(2 * c_, c2, k=1)
self.m = nn.Sequential(*(Bottleneck(c_, c_) for _ in range(n)))
self.attn = SpatialAttention()
def forward(self, x):
y1 = self.attn(self.m(self.cv1(x)))
return self.cv3(torch.cat((y1, self.cv2(x)), dim=1))
C2PSA(CSP Bottleneck with Parallel Spatial Attention)モジュールは、特徴マップの抽出効率を高めるCSP構造の中に、空間アテンションを直接インテグレート(並列統合)した革新的なアーキテクチャです。
初期化メソッド init 内で、入力チャンネル数を半分(c_ = c2 // 2)に削減し、2つのパスに処理を分けます。 1つ目のパスでは、self.m(Bottleneck のシーケンス)によってチャンネルを絞ったまま特徴抽出し、それを空間アテンションモジュールである self.attn に入力して、「画像のどのピクセルに注目すべきか」という空間的な重み付け情報(アテンション)を掛け合わせます(これにより、背景のノイズが大幅にカットされます)。 もう1つのパスは、そのままもう一つの1x1畳み込み self.cv2 へと素通しされます。
forward メソッドでは、アテンションが適用された特徴マップ y1 と、浅く素通ししたパスの self.cv2(x) を torch.cat でチャンネル方向に結合し、最後に self.cv3 によって、目的の出力チャンネル数である c2 に再投影して出力します。
この「空間情報の強調(アテンション)」と「並列処理」の合わせ技により、画像のどこに目的のオブジェクトが存在するかがより正確にモデルへ伝わるようになり、特にオクルージョン(遮蔽)の多いシーンや、極小オブジェクトのセグメンテーション精度を大幅に引き上げる原動力となっています。
SpatialAttentionの定義
ここでは、C2PSA の核心を担う SpatialAttention(空間アテンション)クラスを定義します。特徴マップ内のチャンネル情報を空間方向(縦・横)に圧縮して「どこが重要か」を示す1チャンネルのアテンションマップを生成し、それによって元の特徴をフィルタリングします。
class SpatialAttention(nn.Module):
def __init__(self, kernel_size=7):
super().__init__()
self.conv = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
y = self.sigmoid(self.conv(torch.cat([avg_out, max_out], dim=1)))
return x * y
SpatialAttention クラスは、特徴マップ全体の「空間的な重要度(位置情報)」にフォーカスを当てるモジュールです。
forward メソッド内の処理フローは、以下のステップで非常にエレガントに構成されています。
- チャンネル情報の圧縮: 入力テンソル x(次元は
[batch_size, channels, H, W])に対し、チャンネル次元(dim=1)方向に平均プーリング(torch.mean)と最大値プーリング(torch.max)をそれぞれ実行し、結果を torch.cat で結合します。これにより、空間上の全チャンネルの「平均的なアクティベーション」と「最大の反応」を凝縮した、2チャンネルのテンソル[batch_size, 2, H, W]が生成されます。 - 広広な空間コンテキストの抽出: 生成された2チャンネルのテンソルに対し、カーネルサイズが
7x7と大きめの畳み込み層 self.conv を適用します。カーネルを大きくすることで、各ピクセルの周辺の広い範囲(空間的文脈)を考慮しながらアテンションを決定できます。 - アテンションマップの生成: 畳み込み結果を torch.sigmoid(シグモイド関数)に通すことで、値を
0.0〜1.0の範囲に収めた「空間アテンションマップ」y を作成します。 - フィルタリングの適用: 最後に、元の入力テンソル x にこのアテンションマップ y を要素ごとに掛け合わせます(x * y)。
この一連の処理により、背景や無関係な物体の特徴は 0 に近づいて抑制され、検出したいターゲットの輪郭線やテクスチャといった重要な部分のみが強く保持されて、次の層へ送られます。
画像データと教師データの準備
以下のコードでは、自作の MiniYOLO11Seg を学習させるための入力画像データと、教師データ(正解セグメンテーションマスク)を準備します。scikit-imageに内蔵されている猫の画像を使用し、Ultralytics社の本家YOLO11モデルで事前に取得した高精度の推論結果を、自作モデルの「正解(教師)データ」として活用します。
print("画像を準備し、YOLO11-segで正解マスクを生成中...")
IMG_SIZE = 128
# scikit-imageライブラリに内包されている標準の猫画像を取得
img_array = data.chelsea()
# 公式のYOLO11セグメンテーションモデル(ナノサイズ)を読み込み
yolo_model = YOLO("yolo11n-seg.pt")
# 公式モデルで推論を実行し、猫のセグメンテーションマスクを取得
results = yolo_model(img_array, verbose=False)
# YOLOが検出した最初のオブジェクト(猫)のマスクデータを取得
if results[0].masks is not None:
# テンソルをNumPy配列に変換 (YOLOの内部推論サイズになっているもの)
yolo_mask_np = results[0].masks.data[0].cpu().numpy()
else:
raise ValueError("画像からオブジェクト(猫)が検出されませんでした。")
# 自作モデルの入力サイズ(128x128)に合わせて画像とマスクをリサイズ
img_resized = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
img_tensor = torch.tensor(img_resized, dtype=torch.float32).permute(2, 0, 1).unsqueeze(0) / 255.0
# マスクのリサイズ (0 or 1のバイナリマスクにするため、ニアレストネイバー補間を使用)
target_mask_np = cv2.resize(yolo_mask_np, (IMG_SIZE, IMG_SIZE), interpolation=cv2.INTER_NEAREST)
mask_tensor = torch.tensor(target_mask_np, dtype=torch.float32).unsqueeze(0).unsqueeze(0)
ここでは、自作モデルに「猫の輪郭(セグメンテーション)」を学習させるため、本物の画像と、公式モデルを教師とした高精度なマスク画像をペアにして読み込んでいます。
処理のポイントは以下の通りです。
- 画像の準備: data.chelsea() を利用して、温かみのある3チャンネルの猫画像を読み込みます。
- 公式モデルを教師とした擬似的な正解マスクの生成: 初期化された公式の軽量モデル YOLO("yolo11n-seg.pt") に対して猫画像を入力し、推論(yolo_model())を実行します。検出結果(results[0])の masks.data[0] から、公式が検出した猫のセグメンテーションマスク情報をNumPy配列として取り出し、これを自作モデルの学習ターゲット(正解データ)として設定します。
- 入力サイズへの適合化と正規化: 自作の MiniYOLO11Seg が受け入れる入力サイズ(
128x128)に合わせて画像をリサイズします。さらに、ピクセル値を[0.0, 1.0]の範囲に正規化し、PyTorchのテンソル([batch, channels, H, W])の形状へと変換します。 - マスク画像のリサイズにおける定石: 正解マスクも同様に
128x128にリサイズしますが、ここで interpolation=cv2.INTER_NEAREST(ニアレストネイバー補間)を指定しているのが最大のポイントです。通常の線形補間(バイリニアなど)を使うと、境界部分に0.5などの曖昧な中間値が生成されてしまいます。マスクデータは「猫である(1.0)」か「背景である(0.0)」かの2値のバイナリである必要があるため、最も近い元の値をそのまま採用するニアレストネイバー法を使うのがディープラーニングにおける鉄則です。
モデルの定義と学習
自作した MiniYOLO11Seg を適切なデバイス(GPUまたはCPU)に転送し、セグメンテーション学習に適した損失関数(BCEWithLogitsLoss)と最適化アルゴリズム(Adam)を設定して、猫画像のセグメンテーション学習を開始します。
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MiniYOLO11Seg().to(device)
img_tensor, mask_tensor = img_tensor.to(device), mask_tensor.to(device)
criterion = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
epochs = 150
print(f"学習を開始します (Device: {device})")
model.train()
for epoch in range(epochs):
optimizer.zero_grad()
outputs = model(img_tensor)
loss = criterion(outputs, mask_tensor)
loss.backward()
optimizer.step()
if (epoch + 1) % 30 == 0:
print(f"Epoch [{epoch+1:3d}/{epochs}], Loss: {loss.item():.4f}")
ここでは、自作したモデルを実際に学習させるループを定義しています。
処理の流れとPyTorchの実装における定石を解説します。
- 学習デバイスの自動判定: GPU(CUDA)が使用可能であればGPUを、利用できなければCPUを自動で判定(torch.device)して選択し、モデル(model)と各テンソルを
.to(device)で転送して計算の高速化を図ります。 - 損失関数の定石(BCEWithLogitsLossの採用): 今回のモデルの最終出力(Head)は、あえて Sigmoid 関数(値を0〜1に収める関数)を通さず、生の数値(Logits)を直接出力するように設計されています。 PyTorchの nn.BCEWithLogitsLoss は、内部で「シグモイド関数の適用」と「バイナリ交差エントロピー(BCE)損失の計算」をまとめて一つの処理として実行してくれます。これらを別々に計算するよりも、数学的に桁落ち(アンダーフローやオーバーフロー)が防げるため計算精度が高く、学習が圧倒的に安定します。実務でも2値分類やセグメンテーションではこの関数を使うのが鉄板の定石です。
- 学習ループ: 最適化には optim.Adam を使用し、学習率を
0.01に設定しています。1エポックごとに optimizer.zero_grad() で勾配を初期化し、順伝播、損失計算、逆伝播(loss.backward())、そしてパラメータの更新(optimizer.step())を行います。150エポック(epochs = 150)を通じて、30エポックごとに進捗状況(Lossの値)を出力させています。
モデルを用いた推論
学習を終えた自作モデルを推論(評価)モードに切り替え、入力画像に対するセグメンテーション(マスク予測)を実行します。推論結果はシグモイド関数と閾値処理を適用して二値化した上で、matplotlibを用いて元の画像、正解マスク、自作モデルの予測マスクの3枚を並べて描画し、視覚的に比較します。
model.eval()
with torch.no_grad():
pred_logits = model(img_tensor)
pred_mask = torch.sigmoid(pred_logits) > 0.5
# NumPy配列に戻す
img_np = img_tensor[0].permute(1, 2, 0).cpu().numpy()
target_mask_np = mask_tensor[0, 0].cpu().numpy()
pred_mask_np = pred_mask[0, 0].cpu().numpy()
# 描画
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
axes[0].imshow(img_np)
axes[0].set_title("Input Image")
axes[0].axis('off')
axes[1].imshow(target_mask_np, cmap='gray')
axes[1].set_title("Target Mask (from YOLO11-seg)")
axes[1].axis('off')
axes[2].imshow(pred_mask_np, cmap='gray')
axes[2].set_title("Predicted Mask (Mini YOLO11)")
axes[2].axis('off')
plt.tight_layout()
plt.show()
学習が完了したモデルの推論と結果の可視化を行います。
実装におけるポイントは以下の2点です。
- 評価モードへの切り替えと勾配の無効化: 推論を行う際、モデルを model.eval()(評価モード)に切り替えています。これにより、BatchNormなどの挙動が学習用から推論用の固定パラメータに切り替わります。さらに with torch.no_grad(): ブロックを使用することで、推論中の不要な勾配計算(メモリや計算量の消費)を完全に停止させ、超高速かつメモリ効率の良い推論処理を担保します。
- 出力の二値化(マスク変換): モデルから出力される生の値(Logits)に対して、torch.sigmoid(pred_logits) > 0.5 を適用しています。これにより、確率が 50% を超えたピクセルを
True(1:白)、それ以外をFalse(0:黒)と判定した二値の予測マスク(pred_mask)に変換します。
描画のためにテンソルをNumPy配列(.cpu().numpy())に変換し、plt.subplots を使って、「元画像」「公式YOLO11が作った正解マスク」「自作MiniYOLO11の予測マスク」の3つを並べて表示(axes[].imshow)します。これによって、自作モデルが猫の輪郭をどれだけ正確に学習できたかを目で見て確認できます。
実行結果
上記までのコードを実行すると以下の結果が得られます。
画像を準備し、YOLO11-segで正解マスクを生成中...
学習を開始します (Device: cpu)
Epoch [ 30/150], Loss: 0.0338
Epoch [ 60/150], Loss: 0.0106
Epoch [ 90/150], Loss: 0.0040
Epoch [120/150], Loss: 0.0008
Epoch [150/150], Loss: 0.0002
実行結果を見ると、学習が進むにつれてLossが 0.0338 から 0.0002 へと、順調にほぼゼロ付近まで減少していることが分かります。
今回のコードでは、あえて「たった1枚の画像」だけを150回繰り返し学習させています。 「それだと過学習を起こして未知の画像に対応できないのでは?」と疑問に思うかもしれません。しかし、実はこれはAI開発における超重要な デバッグテクニック(サニティチェック:Sanity Check) なのです。
新しく自作したモデル(今回の MiniYOLO11Seg など)を組んだ際、いきなり数万枚のデータで何時間も学習を回すのは非常にリスクが高く、時間の無駄になりかねません。もしコードにバグがあったり、ネットワークの形状や接続順序に致命的な欠陥があれば、どれだけ学習しても Loss は下がりません。
そこで、まずは「たった1枚の画像を完璧に記憶(過学習)できるか」を数秒間でテストします。この段階で Loss が順調にゼロ付近まで下がれば、「このモデルは仕様通り設計されており、少なくとも十分に学習する能力(表現力)を持っている」という強力な証明(サニティチェック)になります。これが確認できた後、初めて大規模なデータセットでの本学習へと移行するのがプロの定石です。
実際のUltralyticsライブラリを用いた推論テスト
以下のコードでは、Ultralytics社の公式 ultralytics パッケージと学習済みの公式YOLO11モデル(Nanoサイズ)を使用して、実用的なセグメンテーション推論を実行します。わずか数行の記述でモデルのロードから推論、検出したオブジェクト情報、バウンディングボックス、セグメンテーションマスクの可視化画像を出力するプロセスを示します。
from ultralytics import YOLO
from skimage import data
import matplotlib.pyplot as plt
import cv2
print("公式のYOLO11セグメンテーションモデルによる推論を実行します...")
# 1. 画像の準備(scikit-imageの内蔵データから猫の画像を読み込み)
img_array = data.chelsea()
# 2. 公式モデルのロード(初回実行時は自動で yolo11n-seg.pt がダウンロードされます)
# 'n' は Nano(最軽量)モデルを意味します
model = YOLO("yolo11n-seg.pt")
# 3. 推論の実行
# 画像を渡すだけで、物体検出とセグメンテーションが同時に行われます
results = model(img_array)
# 結果はリストで返るため、最初の画像の結果を取得
result = results[0]
# 4. 公式の強力な可視化機能(plotメソッド)を使用
# バウンディングボックス、クラス名、確信度、セグメンテーションマスクがすべて描画された配列を生成します
annotated_img = result.plot()
# OpenCVのBGR順序からMatplotlib用のRGB順序に変換
annotated_img_rgb = cv2.cvtColor(annotated_img, cv2.COLOR_BGR2RGB)
# 5. 結果の描画
plt.figure(figsize=(8, 6))
plt.imshow(annotated_img_rgb)
plt.axis("off")
plt.title("Inference by Official YOLO11-seg")
plt.show()
ここでは、本物の ultralytics パッケージを用いた実務的な推論コードを解説します。
コードの簡潔さと公式ライブラリの強力な機能に注目してください。
- モデルの自動セットアップ: YOLO("yolo11n-seg.pt") をインスタンス化するだけで、初回実行時にインターネット経由で事前学習済み重みファイルが自動ダウンロードされ、PyTorch上に読み込まれます(
'n'は軽量かつ超高速なNanoモデルを指します)。 - 一瞬で終わる推論: 推論自体は画像データを引数として渡す(model(img_array))だけで、内部の最適な画像リサイズ、正規化、デバイス転送、そして推論と後処理(NMSなど)がすべて完了し、検出結果(Results オブジェクト)のリストが返されます。
- 強力なビジュアル描画機能: 最も便利なのが、公式が提供している result.plot() メソッドです。これを呼び出すだけで、元画像に対して「物体の境界ボックス(BBOX)」「クラス名(猫:cat)」「確信度(Confidence Score)」「着色された精密なセグメンテーションマスク」が重ね書きされたNumPy配列(BGR形式)を即座に作成できます。
最後に、OpenCVのBGR順序からMatplotlib用のRGB順序へ cv2.cvtColor でカラーチャンネルを変換し、plt.imshow を用いて結果を描画します。自作したような複雑な可視化ロジックを書く必要が一切なく、わずか数行の記述で最高精度のセグメンテーションモデルを自作アプリに統合できることが分かります。
上記のコードを実行すると以下の結果が得られます。
実行結果
公式のYOLO11セグメンテーションモデルによる推論を実行します...
0: 448x640 1 cat, 70.4ms
Speed: 2.0ms preprocess, 70.4ms inference, 1.7ms postprocess per image at shape (1, 3, 448, 640)
実行結果のログを見ると、猫が cat として検出され、推論時間(Inference)が一般的なCPU環境でもわずか 70.4ms(約0.07秒)程度と、驚異的なリアルタイム性能で処理できていることが確認できます。
前処理(Preprocess)に 2.0ms、後処理(Postprocess)に 1.7ms という極小のオーバーヘッドも含め、YOLO11の処理パイプライン全体が徹底的に無駄を削ぎ落として最適化されていることがログからよく読み取れます。
最終的に可視化された画像では、猫の細かな毛並みや体の輪郭線に沿って、驚くほど滑らかで正確なセグメンテーションマスクが描画されています。YOLO11が新しく採用した C3k2 ブロックによる効率的な特徴抽出と、並列空間アテンションを司る C2PSA ブロックによるノイズ抑制の効果が、この極めて高精度で高速なビジュアル結果として実証されているのです。
まとめ
本記事では、リアルタイム物体検出・セグメンテーションの最高峰であるYOLO11の驚異的なアーキテクチャとその実力について解説しました。
記事を通じて、以下の内容を学び、実践しました。
- 新設計モジュールの理解: 特徴抽出の中核をなす C3k2 ブロックと、空間アテンションを並列化して「どこに注目すべきか」を正確に学習する C2PSA ブロックが、YOLO11の圧倒的なパラメータ効率と精度の高さを支えていることを学びました。
- アーキテクチャのスクラッチシミュレーション: PyTorchを用いて、YOLO11の「Backbone」「Neck」「Head」を再現した概念モデル MiniYOLO11Seg を定義し、1枚の画像を学習させるサニティチェック(過学習テスト)を通じて、ネットワークの学習性能や特徴融合(FPN)の流れをコードレベルで検証しました。
- 公式パッケージを用いた推論: Ultralytics社の ultralytics ライブラリを活用し、わずか数行のシンプルなコードで学習済みモデル yolo11n-seg.pt をロードし、瞬時に精密なセグメンテーション結果と可視化画像を得られることを実証しました。
YOLO11は、アーキテクチャの革新(C3k2, C2PSA)により、パラメータ効率を極限まで高めており、驚異的な軽さと高精度を両立しています。公式ライブラリの実装も極めてシンプル化されており、数行のコードで最先端のビジョンAIを構築できるため、リアルタイム性が求められるエッジデバイスからクラウドアプリケーションまで、幅広い領域での今後の活用がさらに期待されます。ぜひ、ご自身のプロジェクトでもこの強力なビジョンモデルを取り入れてみてください!
ライセンスに関する重要な注意点:AGPL-3.0
Ultralytics社のYOLOv11は、強力な機能を提供する一方で、その標準ライセンスとして AGPL-3.0 を採用しています。これは、このソフトウェアを利用する上で非常に重要な点ですので、ここで簡単に解説します。
AGPL-3.0ライセンスのポイント
- ソースコード開示義務(強いコピーレフト): AGPL-3.0ライセンスのソフトウェア(YOLOv11など)を改変したり、ライブラリとして組み込んで新しいソフトウェアを開発した場合、その新しいソフトウェア全体のソースコードもAGPL-3.0として公開・提供する義務が生じます。
- ネットワーク経由の利用にも適用: このライセンスの最大の特徴は、開発したソフトウェアをサーバー上で実行し、ネットワーク経由でユーザーにサービスとして提供する場合(例: 画像認識APIサービス)にも、ソースコードの開示義務が適用される点です。
- 商用利用への影響: 上記の強力なソースコード開示義務があるため、自社のソフトウェア資産を非公開にしたい企業が商用製品やサービスに組み込む際には、そのままでは利用が難しい場合があります。そのため、Ultralytics社はソースコード開示義務が免除される、別途有償の商用ライセンスも提供しています。
個人での学習、研究、またはソースコードを公開するオープンソースプロジェクトで利用する分には問題ありませんが、クローズドな商用サービスで利用を検討する際は、Ultralytics社から商用ライセンスの購入を検討する必要があります。
本ブログの記述内容について
今回のように、YOLOv11の機能やアーキテクチャを解説する目的で、その利用方法を示す短いサンプルコードや、概念を説明するための擬似的なコードをブログ記事に掲載することは、AGPL-3.0が定める「ソフトウェアの配布」や「ネットワークサービスとしての提供」には該当しないため、ライセンス上の問題は発生しないと考えられます。
ただし、これはあくまで一般的な解釈であり、法的な助言ではありません。 実際の製品やサービスにYOLOv11を組み込む場合は、必ずご自身でライセンス条文を確認するか、法務部門や専門家にご相談ください。
注釈・用語解説
- ※1 パラメータ削減率について: YOLOv8m(約20.1M)とYOLO11m(約15.6M)の比較によるものです。NanoやSmallなど、他のモデルサイズでは削減率が異なりますが、全体として高い性能・パラメータ効率の向上が達成されています。
- ※2 COCOデータセット (Common Objects in Context): 33万枚以上の画像と80個のオブジェクトカテゴリを含む、コンピュータビジョン分野における世界標準のデータセット。物体検出やインスタンスセグメンテーションモデルのベンチマーク測定に広く採用されています。
- ※3 mAP (mean Average Precision): 物体検出・セグメンテーションタスクにおける予測精度の総合的な評価指標。値が高いほど、物体の検出漏れが少なく、位置(バウンディングボックス)やマスクの推定精度が高いことを意味します。
- ※4 Chelsea(猫画像): Pythonの画像処理ライブラリ
scikit-imageに組み込まれている標準テスト用画像。シロハラネコ(Chelsea)を撮影したもので、深層学習や画像処理のデモ、サニティチェックで広く活用されています。
引用・参考文献:
公式リポジトリ: Ultralytics YOLO11 GitHub Repository
公式ドキュメント: Ultralytics YOLO11 Documentation
(※Ultralytics社はYOLOv8以降、従来の学術論文(arXivなど)ではなく、公式GitHubリポジトリおよびドキュメントを通じてモデルの詳細やベンチマークを発表する形式を採用しています。)
学術論文やプロジェクトにおいてYOLO11を引用する際は、以下のBibTeXを使用してください。
@software{yolo11_ultralytics,
author = {Glenn Jocher and Jing Qiu},
title = {Ultralytics YOLO11},
version = {11.0.0},
year = {2024},
url = {https://github.com/ultralytics/ultralytics},
orcid = {0000-0001-5950-6979, 0000-0003-3783-7069},
license = {AGPL-3.0}
}
本記事の文章・構成の一部に生成AIを使用しています。