カスタムデータセットでYOLOをファインチューニングする方法#
ファインチューニングは、ランダムな初期化ではなく学習済みの重みから開始することで、事前学習済みモデルを新しいクラスの認識に適応させます。何百エポックもゼロからトレーニングする代わりに、ファインチューニングは事前学習済みのCOCO特徴量を活用し、わずかな時間でカスタムデータに収束させます。
このガイドでは、layer freezingやtwo-stage trainingなどの高度なテクニックに加え、基本的な使い方からカスタムデータセットでのYOLO26のファインチューニングについて解説します。
ファインチューニングとゼロからの学習(トレーニング)の比較#
事前学習済みモデルは、数百万枚の画像から、エッジ検出、テクスチャ認識、形状理解などの一般的な視覚的特徴をすでに学習しています。ファインチューニングを通じた転移学習はその知識を再利用し、新しいクラスがどのように見えるかをモデルに教えるだけであるため、収束が速く、必要なデータも少なくなります。ゼロからトレーニングすると、それらすべてが破棄され、モデルはピクセルレベルのパターンからすべてを強制的に学習させられることになり、大幅により多くのリソースが必要になります。
| ファインチューニング | ゼロからの学習 | |
|---|---|---|
| 開始時の重み | COCOで事前学習済み(80クラス) | ランダムな初期化 |
| コマンド | YOLO("yolo26n.pt") | YOLO("yolo26n.yaml") |
| 収束 | 高速 - バックボーンはすでに学習済み | 低速 - すべてのレイヤーをゼロから学習 |
| 必要なデータ量 | 少ない - 事前学習済み特徴量がデータ不足を補う | 多い - モデルがデータセット単体からすべての特徴を学ぶ必要がある |
| 使用場面 | 自然画像を用いたカスタムクラス | COCOと根本的に異なるドメイン(医療、衛星、レーダーなど) |
.ptファイルをYOLO("yolo26n.pt")で読み込むと、事前学習済みウェイトがモデルに保存されます。その後.train(data="custom.yaml")を呼び出すと、互換性のあるすべてのウェイトが新しいモデルアーキテクチャに自動的に転送され、クラス数が異なる場合の検出ヘッドなど一致しないレイヤーが再初期化されて、トレーニングが開始されます。手動でのウェイトの読み込み、レイヤーの操作、カスタム転移学習コードは不要です。
事前学習済み重みの転送の仕組み#
事前学習済みモデルをクラス数の異なるデータセットでファインチューニングする場合(例:COCOの80クラスから5クラスへ)、Ultralyticsは形状を考慮した重みの転送を行います:
- バックボーンとネックは完全に転送 - これらのレイヤーは一般的な視覚的特徴を抽出し、その形状はクラス数に依存しません。
- 検出ヘッドは部分的に再初始化(再初期化)されます - 分類出力層(
cv3、one2one_cv3)はクラス数(80対5)に結びついた形状を持っているため、転送できず、ランダムに初期化されます。ヘッド内のボックス回帰層(cv2、one2one_cv2)はクラス数に関係なく固定された形状を持っているため、通常通り転送されます。 - クラス数を変更しても、重みの大部分は転送されます。例えば、YOLO26nをCOCO(80クラス)から5クラスのデータセットにファインチューニングする場合、708個の重みテンソルのうち606個が転送されます。クラス数に依存する分類レイヤーのみが再初期化され、バックボーン、ネック、およびボックス回帰のブランチはそのまま維持されます。
事前学習済みモデルと同じクラス数のデータセット(例:COCO事前学習済み重みを別の80クラスデータセットでファインチューニング)の場合、検出ヘッドを含む重みの100%が転送されます。
名前エイリアスを使用したクラスの転移#
Ultralytics は、大文字小文字や前後の空白を無視して、データセット間でクラス名に基づき一致する分類ヘッドの行を転移します。同等のクラスに異なる名前が使用されている場合は、ロードする前にメモリ内でソースチェックポイントのクラス名をリネームします。これにより、未一致として扱われてランダムに初期化されてしまうような共有概念の事前学習済み分類ウェイトが保持されます。
このObjects365 v2からCOCOへの例では、ロードされたチェックポイント上のソースクラスの名前を変更し、それを train() が事前学習済みの重みとして通過させます:
from ultralytics import YOLO
# Source Objects365 v2 name -> target COCO name
ALIASES = {
"wild bird": "bird",
"handbag/satchel": "handbag",
"luggage": "suitcase",
"bowl/basin": "bowl",
"orange/tangerine": "orange",
"monitor/tv": "tv",
"stuffed toy": "teddy bear",
"hair dryer": "hair drier",
}
model = YOLO("path/to/yolo26s-objects365.pt")
model.model.names = {i: ALIASES.get(name, name) for i, name in model.model.names.items()}
model.train(data="coco.yaml", epochs=100, imgsz=640)基本的なファインチューニングの例#
from ultralytics import YOLO
model = YOLO("yolo26n.pt") # load pretrained model
model.train(data="custom.yaml", epochs=50, imgsz=640)モデルサイズの選択#
モデルが大きくなると容量が増加しますが、更新するパラメータも増えるため、トレーニングデータが限られている場合に過学習のリスクが高まる可能性があります。小さなモデル(YOLO26nまたはYOLO26s)から始めて、検証指標が頭打ちになった場合にのみスケールアップするのが実用的なアプローチです。最適なモデルサイズは、タスクの複雑さ、クラスの数、データセットの多様性、およびデプロイに利用可能なハードウェアによって異なります。利用可能なサイズとパフォーマンスのベンチマークについては、完全なYOLO26モデルページを参照してください。
オプティマイザと学習率の選択#
デフォルトの optimizer=auto 設定は、トレーニング反復の総数に基づいてオプティマイザと学習率を選択します:
- 10,000回未満の反復(小さなデータセットや少ないエポック数):低い自動計算学習率でのAdamW
- > 10,000回のエポック/反復(大規模なデータセット):MuSGD(Muon+SGDのハイブリッドオプティマイザ)、lr=0.01
ほとんどのファインチューニングタスクにおいて、デフォルト設定で手動調整なしに良好な結果が得られます。以下のような場合には、明示的にオプティマイザを設定することを検討してください:
- トレーニングが不安定(損失が急増または発散する):より安定した収束のために
optimizer=AdamW, lr0=0.001を試してください - 小規模なデータセットで大規模なモデルをファインチューニングする:
lr0=0.001のような低い学習率は、事前学習済みの特徴量を保持するのに役立ちます
optimizer=auto の場合、lr0 および momentum の値は無視されます。手動で学習率を制御するには、オプティマイザを明示的に設定します:optimizer=SGD, lr0=0.005。
レイヤーの凍結#
凍結(フリージング)を行うことで、トレーニング中の特定のレイヤーの更新を防止できます。これにより、モデルの容量に対してデータセットが小さい場合に、トレーニングが高速化され、過学習が軽減されます。
freeze パラメータは、整数またはリストを受け付けます。整数 freeze=10 は最初の10層(インデックス0〜9)を凍結し、YOLO26のバックボーンの大部分をカバーします。バックボーンはレイヤー0〜10にまたがっているため、freeze=10 は最後のC2PSAブロック(レイヤー10)をトレーニング可能な状態に残します。バックボーン全体を凍結するには freeze=11 を使用します。リストには、バックボーンの部分的な凍結のための freeze=[0, 3, 5] のようなレイヤーインデックスや、レイヤー内の特定のエッジ/ブランチに対するきめ細やかな制御のための freeze=["23.cv2", "23.one2one_cv2"] のようなモジュール名文字列(ここでは検出ヘッドの両方のボックス回帰ブランチ)を含めることができます。
model.train(data="custom.yaml", epochs=50, freeze=10)適切な凍結の深さは、ターゲットドメインが事前学習済みデータとどれだけ似ているか、および学習データがどれだけ利用可能かによって決まります:
| シナリオ | 推奨 | 根拠 |
|---|---|---|
| 大規模データセット、類似ドメイン | freeze=None (デフォルト) | 過学習させずにすべてのレイヤーを適応させるのに十分なデータがある |
| 小規模データセット、類似ドメイン | freeze=10 | バックボーンの特徴を保持し、トレーニング可能なパラメータを削減する |
| 非常に小さなデータセット | freeze=23 | 検出ヘッドのみを学習させ、過学習のリスクを最小限に抑える |
| COCOから遠いドメイン | freeze=None | バックボーンの特徴がうまく転送されない可能性があるため、再学習が必要 |
凍結の深さはハイパーパラメータとして扱うこともできます。いくつかの値(0、5、10)を試し、検証mAPを比較することは、特定のデータセットに最適な設定を見つけるための実用的な方法です。
ファインチューニングにおける重要なハイパーパラメータ#
ファインチューニングは、ゼロからの学習に比べて必要なハイパーパラメータの調整が一般的に少なくなります。最も重要なパラメータは以下の通りです:
epochs:ファインチューニングは、ゼロからトレーニングするよりも速く収束します。中程度の値から始め、検証指標が頭打ちになったときにpatienceを使用して早期終了させます。patience:デフォルトの100は、長時間のトレーニング実行向けに設計されています。これを10〜20に減らすことで、すでに収束している実行に時間を無駄にすることを回避できます。warmup_epochs:デフォルトのウォームアップ(3エポック)はゼロから学習率を徐々に増加させ、初期の反復で大きな勾配更新が事前学習済みの特徴量を損なうのを防ぎます。ファインチューニングであっても、デフォルトを維持することをお勧めします。
トレーニングパラメータの完全なリストについては、トレーニング設定のリファレンスを参照してください。
2段階ファインチューニング#
2段階ファインチューニングは、学習を2つのフェーズに分割します。第1段階ではバックボーンを凍結し、ネックとヘッドのみを学習させることで、事前学習済みの特徴を損なうことなく検出レイヤーを新しいクラスに適応させます。第2段階では全レイヤーの凍結を解除し、より低い学習率でモデル全体を学習させ、ターゲットドメインに合わせてバックボーンを微調整します。
このアプローチは、ターゲットドメインがCOCOと大きく異なる場合(医療画像、航空画像、顕微鏡画像)に特に役立ちます。この場合、バックボーンの適応が必要になる可能性がありますが、すべてを一度にトレーニングすると不安定になります。コールバックベースのアプローチを使用した自動の凍結解除については、バックボーンの凍結と凍結解除を参照してください。
from ultralytics import YOLO
# Stage 1: freeze backbone, train head and neck
model = YOLO("yolo26n.pt")
model.train(data="custom.yaml", epochs=20, freeze=10, name="stage1", exist_ok=True)
# Stage 2: unfreeze all, fine-tune with lower lr
model = YOLO("runs/detect/stage1/weights/best.pt")
model.train(data="custom.yaml", epochs=30, lr0=0.001, name="stage2", exist_ok=True)よくある落とし穴#
モデルが予測を出力しない#
- トレーニングデータが不十分: サンプル数が非常に少ない環境での学習は最も一般的な原因です。データが少なすぎるとモデルは学習できず、汎化もできません。他の原因を調査する前に、クラスごとに十分で多様な例があることを確認してください。
- データセットのパスを確認する:
data.yamlのパスが間違っていると、サイレントにゼロ個のラベルが生成されます。ラベルが正しくロードされることを確認するために、トレーニング前にyolo detect val model=yolo26n.pt data=custom.yamlを実行してください。 - 信頼度閾値を下げる:予測が存在するにもかかわらずフィルタリングされて除外されている場合は、推論中に
conf=0.1を試してください。 - クラス数の確認:
data.yaml内のncが、ラベルファイルの実際のクラス数と一致していることを確認します。
検証mAPが早期に頭打ちになる#
- データの追加: ファインチューニングは、特に角度、照明、背景が多様な例など、追加のトレーニングデータによって大幅に改善されます。
- クラスのバランスを確認する:表現が不足しているクラスはAPが低くなります。逆頻度クラス重み付けを適用するには
cls_pwを使用します(軽度の不均衡の場合はcls_pw=0.25から始め、重度の不均衡の場合は1.0に増やします)。 - 拡張を減らす:非常に小さなデータセットの場合、強力なデータ拡張は逆効果になることがあります。
mosaic=0.5またはmosaic=0.0を試してください。 - 解像度を上げる:小さなオブジェクトを含むデータセットの場合は、詳細を保持するために
imgsz=1280を試してください。
ファインチューニング後に元のクラスでの性能が低下する#
これは破滅的忘却として知られており、新しいデータのみでファインチューニングを行うと、モデルが以前に学習した知識を失う現象です。忘却は、新しいデータと一緒に元のデータセットの画像を含めない限り、ほとんど避けられません。これを軽減するには:
- データセットの結合: ファインチューニング中、新しいクラスと一緒に元のクラスの例を含めてください。これが忘却を防ぐ唯一の信頼できる方法です。
- バックボーンとネックの凍結: バックボーンとネックの両方を凍結して検出ヘッドのみを学習させることは、非常に低い学習率での短いファインチューニングにおいて役立ちます。
- エポック数を減らす: 新しいデータのみでモデルを長く学習させるほど、忘却は増加します。
よくある質問 (FAQ)#
固定された最小値はありません。結果はタスクの複雑さ、クラス数、ドメインがCOCOにどれだけ近いかによって異なります。生の数量よりも多様な画像(照明、角度、背景が変化するもの)が重要です。あるもので開始し、検証メトリクスが不十分な場合はスケールアップしてください。
事前学習済みの
.ptファイルをロードし、カスタムの.train()へのパスを指定してdata.yamlを呼び出します。Ultralyticsは、重みの転送、検出ヘッドの再初期化、およびオプティマイザの選択を自動的に処理します。完全なコード例については、基本的なファインチューニングセクションを参照してください。最も一般的な原因は、
data.yamlのパスの間違い(サイレントにゼロ個のラベルが生成されます)、YAML内のncと実際のラベルファイルの間での不一致、または高すぎる信頼度閾値です。完全なトラブルシューティングのチェックリストについては、よくある問題を参照してください。データセットのサイズとドメインの類似性によって異なります。COCOに似たドメインを持つ小規模なデータセットの場合、バックボーンを凍結する(
freeze=10)ことで過学習を防ぐことができます。COCOとは大きく異なるドメインの場合、すべてのレイヤーを凍結解除したままにする(freeze=None)ことで、バックボーンが適応できるようになります。詳細な推奨事項については、レイヤーの凍結を参照してください。新しいクラスと一緒に、トレーニングデータに元のクラスの例を含めます。それが不可能な場合は、より多くのレイヤーを凍結し(
freeze=10以上)、より低い学習率を使用することが、事前学習済みの知識を保持するのに役立ちます。詳細については、パフォーマンスが元のクラスで低下するを参照してください。