Markdownで表示

画像分類

画像分類は画像全体に1つのラベル分布を割り当て、画像内の位置は特定しません。タスクキーはclassifyです。

定義

画像分類は画像全体に対してクラスごとに1つのスコアを生成し、座標はまったく生成しません。画像に何が写っているかを答え、どこにあるかは答えません。この点が物体検出との違いです。

classifyが標準タスクキーで、チェックポイントのファイル名にある-cls接尾辞が選択します。画像分類ファミリーではこの接尾辞は任意ではなく必須なので、LibreResNet50.ptは分類器として読み取られず、LibreResNet50-cls.ptだけが該当します。

predict()はresult.probsを設定し、boxesを空のままにします。.dataは完全なスコアベクトル、.top1は最高スコアのインデックス、.top1confはその値です。.top5は降順の上位5インデックス、.top5confはそのスコアです。インデックスはresult.namesを参照します。Resultsオブジェクトをスライスしてもprobsは切り詰められません。このベクトルは1つの行ではなく画像全体に属するためです。

モデル

学習に対応する画像分類器には、以下があります。ResNet、ConvNeXt、MobileNetV4、EfficientNetV2、DINOv2です。最初の4つは基本パッケージで実行でき、公開済みの重みがあります。DINOv2にはpip install "libreyolo[rfdetr]"が必要で、LibreYOLOがホストするチェックポイントはありません。ランダムに初期化された線形ヘッドを持つアップストリームのバックボーンを読み込むため、すぐに使える推論器ではなくファインチューニングの出発点です。

さらに5つのファミリーが推論、検証、エクスポートに対応しますが、train()はNotImplementedErrorを送出します。ViT、Swin、VGG、AlexNet、DeiTです。

CLIPとSigLIP2は固定ラベル集合なしで分類します。画像をテキストプロンプトと比較するため、set_classes()で呼び出し時にクラスを定義でき、新しいラベル集合のための学習手順はありません。どちらもembedタスクに対応します。

ConvNeXt V2は、CC-BY-NC-4.0の学習済み重みを使う教師あり分類を追加します。PEはゼロショット分類に対応し、V-JEPA 2は動画分類プローブを学習します。

推論

重みは初回使用時にHugging Faceからダウンロードされ、ローカルにキャッシュされます。

Python
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファイル名の-cls接尾辞がタスクを選択するためtask引数は不要model = LibreYOLO("LibreResNet50-cls.pt")result = model(SAMPLE_IMAGE, save=True) print(result.names[result.probs.top1], float(result.probs.top1conf))print(result.probs.top5)
CLI
libreyolo predict model=LibreResNet50-cls.pt save=True \  source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg
分布全体
from libreyolo import LibreYOLO, SAMPLE_IMAGE result = LibreYOLO("LibreResNet50-cls.pt")(SAMPLE_IMAGE)probs = result.probs # .dataは完全な(C,)ベクトル top5とtop5confは順序付きのビューprint(probs.data.shape)for index, score in zip(probs.top5, probs.top5conf):    print(result.names[index], float(score))
学習不要のゼロショット
from libreyolo import LibreYOLO, SAMPLE_IMAGE # CLIPは画像をテキストプロンプトと比較するためラベル集合は# チェックポイントに埋め込まず呼び出し時に設定するmodel = LibreYOLO("LibreCLIPb32-cls.pt")model.set_classes(["a person jumping", "an empty street", "a parked car"])result = model(SAMPLE_IMAGE) print(model.names[result.probs.top1], float(result.probs.top1conf))

ここではしきい値処理や抑制を行う候補はなく、分布が1つだけなので、conf、iou、max_detは効果がありません。入力ソース、ストリーミング、結果の処理については推論を参照してください。

データセット形式

画像分類ではラベルファイルやYAMLではなくディレクトリツリーを使用し、dataにはデータセットのルートを指定します。

dataset/  train/    tench/000001.jpg    parachute/000002.jpg  val/    tench/000101.jpg    parachute/000102.jpg

学習にはtrain/が必須で、並べ替えたフォルダー名によってクラスとインデックスの対応を定義します。そのため、アルファベット順で最初のフォルダーがクラス0になります。検証にはval/が必須です。test/分割が存在しても構いませんが、デフォルトの学習と検証コマンドでは使用しません。train以外の分割には、期待されるクラス集合と同じクラスフォルダー名が必要です。この仕組みにより、不一致を誤った予測として採点せず、明示的に失敗させます。対応する画像の拡張子は.jpg、.jpeg、.png、.bmp、.webp、.tif、.tiffです。

dataには3種類の値を指定できます。train/分割を含むディレクトリへのパス、.zipのURL、または既知のデータセット名であるimagenette160とsmoke10です。既知のデータセットは初回使用時にダウンロードされ、キャッシュされます。

標準ローダーはlibreyolo.data.classify_datasetです。

学習

Python
from libreyolo import LibreYOLO # imagenette160は既知のデータセット名で初回使用時にダウンロードされる# 独自データではtrain/分割を含むディレクトリを渡すmodel = LibreYOLO("LibreResNet50-cls.pt")model.train(data="imagenette160", epochs=5)
CLI
libreyolo train model=LibreResNet50-cls.pt data=imagenette160 epochs=5
マルチGPU
libreyolo train model=LibreResNet50-cls.pt data=imagenette160 \  epochs=50 device=0,1 batch=-1

ncを宣言する必要はありません。クラス数はtrain/下のフォルダー名から取得され、最終線形レイヤーがその数に合わせて再構築される一方、バックボーンは変更せず転用されます。データセット、データ拡張、マルチGPU、ロガーについては学習を参照してください。

ResNet、ConvNeXt、ConvNeXt V2、MobileNetV4、EfficientNetV2、DINOv2は、cls_pwまたはclass_weightsによる損失の重み付けに対応します。分類のscaleはクロップ面積、crop_pctは評価時のクロップを制御します。データ拡張を参照してください。

リサイズフィルターはモデルの一部です。学習の前にmodel.interpolationを"bilinear"、"bicubic"、"nearest"、"bilinear_no_antialias"のいずれかに設定してください。学習、val()、predict()、INT8キャリブレーション、エクスポートがすべてこれを使い、save()、best.pt、last.ptが記録するため、再読み込みしても維持されます。それ以外の名前はValueErrorを送出します。"bilinear_no_antialias"は、RandomResizedCropも含めてあらゆる場所でアンチエイリアスなしのプレーンなバイリニアでリサイズします。アンチエイリアスなしのランタイムリサイズの後ろで動かすモデル向けです。MobileNetV4、ResNet、ConvNeXt、ConvNeXt V2、EfficientNetV2、DeiT、Swin、ViTはデフォルトがバイキュービックで、AlexNetとVGGはバイリニアです。

検証

val()はデータセットルートのval/分割に対して計算したmetrics/キーを持つ辞書を返します。

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreResNet50-cls.pt") # metrics/キーのdictで、top1、top5、confusion_matrixも保持metrics = model.val(data="imagenette160") print(metrics["metrics/accuracy_top1"])print(metrics["metrics/accuracy_top5"])print(metrics.top1, metrics.top5)
CLI
libreyolo val model=LibreResNet50-cls.pt data=imagenette160

metrics/accuracy_top1は、最高スコアのクラスが正解だった画像の割合です。主要な数値であり、学習でも最良エポックの選択に使用します。metrics/accuracy_top5は、正解クラスが上位5クラスのどこかに含まれた画像の割合です。データセットのクラス数が少ないほど情報量も少なくなります。辞書にはtop-1値のコピーであるfitnessも含まれます。

ImageFolderの検証では、マクロ平均のmetrics/precision、metrics/recall、metrics/f1も返します。検証対象に存在するクラスで平均し、一度も予測されなかったクラスの適合率は0として計算します。デフォルトの適合度は引き続きtop-1精度です。検証とキャリブレーションではモデルの評価用変換を使います。

結果は3つの属性を持つdictのサブクラスです。top1とtop5は2つの精度の値を保持し、confusion_matrixは各画像をtop-1クラスとラベルの組で数え、matrix[predicted, true]でインデックスします。plots=Trueは、件数をconfusion_matrix.pngに、各ラベルに対する割合をconfusion_matrix_normalized.pngに書き出します。クラス数が2,000を超えると、密な行列とそのプロットは使えず、代わりにnonzero()、tp_fp()、class_accuracy()が件数を読み取ります。検証と指標を参照してください。

エクスポート

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreResNet50-cls.pt")model.export(format="onnx")
CLI
libreyolo export model=LibreResNet50-cls.pt format=onnx
エクスポートしたファイルを使用
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファクトリはファイルの拡張子に応じて振り分けるためエクスポートした# アーティファクトもチェックポイントと同様に読み込まれ同じResultsオブジェクトを返すmodel = LibreYOLO("LibreResNet50-cls.onnx")result = model(SAMPLE_IMAGE) print(result.probs.top1, result.probs.top1conf)

エクスポートしたアーティファクトはファイルの拡張子に基づいてLibreYOLO()で再読み込みできるため、.onnxや.engineファイルもチェックポイントと同様に動作し、同じResultsを返します。対応形式はファミリーごとに異なり、各モデルページのマトリックスは手入力ではなく検証済みの集合から生成されます。形式、追加パッケージ、制約についてはエクスポートとデプロイを参照してください。

LibreYOLO v1.6.0で検証済みです。