yolox フレームワークとその解決記録をカスタマイズおよび改善するときに発生した問題

-------最初に部分を書いてから、フォローアップ更新してください----------

-------2022.07.16 yolox トレーニング プロセス中の検証セット評価中の KeyError エラーの分析と解決策を更新しました。

-------2022.07.28 yoloxがバックボーンからネックに渡されるフィーチャピラミッド部分の3レベルのチャネル番号のサイズをカスタマイズする方法を更新しました

序文

ノート:

yolox コード (ここでは、github 上のチームのオープン ソース コードを指します) は、サイズが大きく、構造が複雑です。開発者のコ​​ード作成とモジュールの配置はまだ非常に標準化されており、合理的であることがわかります。機能モジュール、トレーニング さまざまなフォルダー、Python ファイル、クラス、関数をレイヤーごとに繰り返し呼び出す必要があり、プログラムの理解とその後の yolox の改善に一定の問題が生じます。

(1) 公式 README ファイルの指示に従って、ターミナル ウィンドウから tools/train.py ファイルを実行してトレーニングを開始します。すべてのトレーニング呼び出しはこのファイルに基づいています。

(2) Exp クラスの定義と呼び出しは yolox トレーニングの中核であり、Yolox はトレーニングの具体的な構成とトレーニング プロセス中のいくつかの機能をこの Exp クラスにパッケージ化します。train.py を実行するときは、使用する Exp クラスが配置されている Python ファイルのアドレスをパラメーターとして渡す必要があります。

たとえば、voc 形式のデータ セットを使用する場合、トレーニングに使用する Exp クラスとして yolox ソース コードによって提供される yolox_voc_s.py ファイルに基づいてデータ セットを直接変更します。特に、yolox_voc_s.py ファイルで定義された Exp クラスは 1 つのステップで直接定義されるのではなく、定義時に (yolox_base.py で定義される) yolox/exp/yolox_base.py で定義された Exp クラスを継承することに注意してください。 Exp クラスは、yolox/exp/base_exp.py で継承された BaseExp クラスですが、Exp クラスのほとんどのプロパティとクラス関数は、yolox_base.py で定義された Exp クラスに実装されます。したがって、表面上では yolox_voc_s.py ファイルで定義された Exp クラスのみを使用しますが、Exp クラスの内容を慎重に変更したい場合は、多くの場合、yolox/exp/ ファイルで定義された Exp クラスに戻る必要があります。 yolox_base.py を継承します。yolox_voc_s.py の Exp クラスは、属性とクラス関数を継承するときに yolox_base.py の Exp クラスの個々のクラスに影響を与える可能性があるため、プログラムの実行中および変更プロセス中に yolox_base.py の Exp クラスを見つめないよう特別な注意を払う必要があります。 yolox_base.pyのExpクラスのクラス属性パラメータを参考に見るだけでは判断を誤る可能性があります。(たとえば、yolox_base.pyのExpクラスに定義されている2つのクラス属性self. Depthとself.widthしか見ていなかったため、どこにバグがあるのか​​わかりませんでした。デフォルト値がこれら 2 つのクラス属性のうち、yolox_voc_s にありました。py の Exp クラスは継承後に変更されており、以前に何度も確認しましたが見つからなかったため、これには特に注意する必要があります。)

1. モデル定義ファイルの紹介:

yolox のモジュール化は比較的明確であり、yolox モデルは一般にバックボーン、fpn ベースのネック、ヘッドとしてみなされます。ここで、yolox がモデルを構築すると、モデルのメイン モジュールが yolox/models フォルダーに配置されます。

darknet.py はバックボーンを定義します。

yolo_pafpnは、panモジュールをモデルのネックとするfpn構造体を定義すると同時に、その中に定義されているYOLOPAFPNクラスは、darknet.pyで定義されたモデルバックボーンをクラス属性self.backboneで実際にインスタンス化し、順方向に計算します。バックボーンを関数化し、その結果をバックボーンに出力し、設計したfpnに接続します。したがって、yolo_pafpn には実際には yolox フレームワークのバックボーンと fpn が含まれており、後からヘッド部分を追加することで完全なネットワークを形成できます。

yolo_head.py は、YOLOX のヘッド部分をパックする YOLOXHead クラスを定義します。これは、コード サイズの点でモデルの中で最も長く、最も複雑な部分でもあります。

yolox.pyは主に、上で紹介したYOLOPAFPNクラスとYOLOXHeadクラスに含まれる構造体をyoloxモデルに組み上げ、モデルの出力結果を各部の値を含む辞書に整理します。

2. モデル改善の留意点:

バックボーンはいくつかの線形演算モジュール dark2、dark3、dark4、dark5 に分割されており、dark3、dark4、dark5 の計算結果は個別に保存し、次の 3 レベルの fpn に渡して計算する必要があります。したがって、モデルのバックボーンに変更を加える場合は、dark3、dark4、dark5 によって計算された画像チャネルの数が、対応するレイヤー操作モジュールの実装によって受け入れられる画像チャネルの数と一致しているかどうかに特別な注意を払う必要があります。アクセスする fpn の。(exp クラスの self. Depth と self.width の 2 つのクラス属性が、モデルが画像上で動作するときに設定されるモデルの深さ (レイヤーの総数) とチャネル数に影響を与えることをここで再度強調します)

3. yoloxトレーニングプロセス中の検証セット評価中のKeyErrorエラーの分析と解決

yolox トレーニングでは、一部の指定されたエポックで、トレーニング セットがトレーニングされた後、モデルは検証セットで検証テストのパフォーマンスを実行します。トレーニング セットを置き換えた後、次のエラー メッセージが表示されました。

07-16 13:56:51 | INFO     | yolox.core.trainer:266 - epoch: 1/300, iter: 110/116, mem: 5523Mb, iter_time: 0.229s, data_time: 0.000s, total_loss: 10.5, iou_loss: 3.8, l1_loss: 0.0, conf_loss: 5.7, cls_loss: 0.9, lr: 1.124e-03, size: 640, ETA: 3:04:37
2022-07-16 13:56:52 | INFO     | yolox.core.trainer:370 - Save weights to ./YOLOX_outputs/yolox_voc_s
100%|##########| 29/29 [00:02<00:00, 10.64it/s]
2022-07-16 13:56:55 | INFO     | yolox.evaluators.voc_evaluator:160 - Evaluate in main process...
Writing ship VOC results file
Eval IoU : 0.50
2022-07-16 13:56:58 | INFO     | yolox.core.trainer:208 - Training of experiment is done and the best AP is 0.00, the best AP_50 is 0.00

2022-07-16 13:56:58 | ERROR    | yolox.core.launch:98 - An error has been caught in function 'launch', process 'MainProcess' (25844), thread 'MainThread' (140597191565888):
Traceback (most recent call last):

  File "tools/train.py", line 151, in <module>
    launch(
    └ <function launch at 0x7fde2b82af70>

> File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/core/launch.py", line 98, in launch
    main_func(*args)
    │          └ (╒═══════════════════╤═══════════════════════════════════════════════════════════════════════════════════════════════════════...
    └ <function main at 0x7fde1d3d4280>

  File "tools/train.py", line 134, in main
    trainer.train()#这里运行yolox/core下的trainer.py文件中的类Trainer的一个实例trainer下的类Trainer中定义的类函数train(),其中类Trainer通过定义各种类函数来实现了模型训练过程
    │       └ <function Trainer.train at 0x7fde18897940>
    └ <yolox.core.trainer.Trainer object at 0x7fde188a60a0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/core/trainer.py", line 88, in train
    self.train_in_epoch()
    │    └ <function Trainer.train_in_epoch at 0x7fde1889f040>
    └ <yolox.core.trainer.Trainer object at 0x7fde188a60a0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/core/trainer.py", line 98, in train_in_epoch
    self.after_epoch()
    │    └ <function Trainer.after_epoch at 0x7fde1889f3a0>
    └ <yolox.core.trainer.Trainer object at 0x7fde188a60a0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/core/trainer.py", line 235, in after_epoch
    self.evaluate_and_save_model()
    │    └ <function Trainer.evaluate_and_save_model at 0x7fde1889f670>
    └ <yolox.core.trainer.Trainer object at 0x7fde188a60a0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/core/trainer.py", line 339, in evaluate_and_save_model
    ap50_95, ap50, summary = self.exp.eval(
                             │    │   └ <function Exp.eval at 0x7fde18897f70>
                             │    └ ╒═══════════════════╤════════════════════════════════════════════════════════════════════════════════════════════════════════...
                             └ <yolox.core.trainer.Trainer object at 0x7fde188a60a0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/exp/yolox_base.py", line 335, in eval
    return evaluator.evaluate(model, is_distributed, half)
           │         │        │      │               └ False
           │         │        │      └ False
           │         │        └ fbnet_YOLOX(
           │         │            (backbone): fbnet_YOLOPAFPN(
           │         │              (backbone): fbnet_backbone(
           │         │                (stem): Focus(
           │         │                  (conv): BaseConv(
           │         │            ...
           │         └ <function VOCEvaluator.evaluate at 0x7fde188914c0>
           └ <yolox.evaluators.voc_evaluator.VOCEvaluator object at 0x7fddfc162a00>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/evaluators/voc_evaluator.py", line 128, in evaluate
    eval_results = self.evaluate_prediction(data_list, statistics)
                   │    │                   │          └ tensor([ 2.2012,  0.0739, 28.0000], device='cuda:0')
                   │    │                   └ {0: (tensor([[-7.5409e+01, -6.3225e+01,  5.1623e+02,  2.6991e+02],
                   │    │                             [-1.3955e+02, -6.8198e+00,  5.6981e+02,  2.1258e+0...
                   │    └ <function VOCEvaluator.evaluate_prediction at 0x7fde188915e0>
                   └ <yolox.evaluators.voc_evaluator.VOCEvaluator object at 0x7fddfc162a00>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/evaluators/voc_evaluator.py", line 205, in evaluate_prediction
    mAP50, mAP70 = self.dataloader.dataset.evaluate_detections(
                   │    │          │       └ <function VOCDetection.evaluate_detections at 0x7fde18891e50>
                   │    │          └ <yolox.data.datasets.voc.VOCDetection object at 0x7fde188b6df0>
                   │    └ <torch.utils.data.dataloader.DataLoader object at 0x7fddfc162dc0>
                   └ <yolox.evaluators.voc_evaluator.VOCEvaluator object at 0x7fddfc162a00>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/data/datasets/voc.py", line 271, in evaluate_detections
    mAP = self._do_python_eval(output_dir, iou)
          │    │               │           └ 0.5
          │    │               └ '/tmp/tmpiht1ubmu'
          │    └ <function VOCDetection._do_python_eval at 0x7fde18897040>
          └ <yolox.data.datasets.voc.VOCDetection object at 0x7fde188b6df0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/data/datasets/voc.py", line 337, in _do_python_eval
    rec, prec, ap = voc_eval(
                    └ <function voc_eval at 0x7fde188913a0>

  File "/home/dwt/MyCode/pycharm_projects/YOLOX_sample/yolox/evaluators/voc_eval.py", line 109, in voc_eval
    R = [obj for obj in recs[imagename] if obj["name"] == classname]
                        │    │                            └ 'ship'
                        │    └ '000033'
                        └ {}

KeyError: '000033'
(fbnet_yolox) dwt@dwt-Ubuntu:~/MyCode/pycharm_projects/YOLOX_sample$ python tools/train.py -f exps/example/yolox_voc/yolox_voc_s.py -d 1 -b 8 --fp16 -o
2022-07-16 13:59:59 | INFO     | yolox.core.trainer:142 - args: Namespace(batch_size=8, cache=False, ckpt=None, devices=1, dist_backend='nccl', dist_url=None, exp_file='exps/example/yolox_voc/yolox_voc_s.py', experiment_name='yolox_voc_s', fp16=True, logger='tensorboard', machine_rank=0, name=None, num_machines=1, occupy=True, opts=[], resume=False, s

最初の判断としては、検証セットファイルの読み込み時にエラーが発生したのかと思いますが、検索したところ、同様の問題を抱えたブログを発見しました:yolov5 v3.0 トレーニングで KeyError が発生しました

以下については、このブログのコンテンツを参照してください。

このエラーの理由は、データ キャッシュ ファイルが変更された可能性があるためです。yolov5 はデフォルトで読み取りデータをキャッシュ ファイルに保存するため、ダウンロードと読み取りの速度が非常に速くなります。

同様に、yolox で voc_eval.py ファイルのソース コードを表示します。

def voc_eval(
    detpath,
    annopath,
    imagesetfile,
    classname,
    cachedir,
    ovthresh=0.5,
    use_07_metric=False,
):
    # first load gt
    if not os.path.isdir(cachedir):
        os.mkdir(cachedir)
    cachefile = os.path.join(cachedir, "annots.pkl")
    # read list of images
    with open(imagesetfile, "r") as f:
        lines = f.readlines()
    imagenames = [x.strip() for x in lines]

    if not os.path.isfile(cachefile):
        # load annots
        recs = {}
        for i, imagename in enumerate(imagenames):
            recs[imagename] = parse_rec(annopath.format(imagename))
            if i % 100 == 0:
                print("Reading annotation for {:d}/{:d}".format(i + 1, len(imagenames)))
        # save
        print("Saving cached annotations to {:s}".format(cachefile))
        with open(cachefile, "wb") as f:
            pickle.dump(recs, f)
    else:
        # load
        with open(cachefile, "rb") as f:
            recs = pickle.load(f)

「cachedir」という単語やその他の単語から推測すると、yolox にも後続のデータ読み取りを高速化するための同様のデータ キャッシュ機能があるはずです。そのため、このエラーは、yolox が以前に使用したデータ セット キャッシュも使用していることと、差し替えたデータのセットが原因に該当しません。したがって、キャッシュ ファイル annots.pkl のアドレスが見つかります。 datasets/VOCdevkit/annotations_cache はフォルダーを直接削除します (yolox を再度実行するときに、フォルダーが見つからない場合は、データが再作成され、再キャッシュされます)。トレーニング コマンドを再度実行して開始します。トレーニング後に問題は再発しませんでした。

4. 背骨から首の特徴ピラミッド部分の3層のチャンネル数

yolox フレームワークのネック モジュールを定義するファイル yolox/models/yolo_pafpn.py のソース コード部分から yolox ソース コードを読み取ります (次の図を参照)。

 in_channel = [256, 512, 1024] パラメーターは、yolox がデフォルトで首部分の特徴ピラミッドに 256、512、および 1024 の 3 つのチャネル番号の特徴マップを順番に受信させることを示していることがわかります。もちろん、コードのこの部分では、width パラメーターがあることもわかります。このパラメーターは、後半の in_channel の数値で乗算され、特徴ピラミッドによって受信される特徴マップのチャネル番号サイズを調整します。ある程度までは (次の図に示すように):

 たとえば、元の in_channel パラメーターは [256, 512, 1024] で、幅が 0.5 に等しい場合、特徴ピラミッドによって実際に受信される特徴マップ サイズは、width * in_channel によって [128, 256, 512] に変更できます。 。ただし、幅を調整するだけで、in_channel はある程度変更できますが、特徴ピラミッドの ​​3 つのレベルで受信される特徴マップのチャネル サイズの比率は変化せず、常に 1:2:4 です。 。このように、チャンネル数の調整はまだ柔軟ではないため、in_channel から直接変更する必要があります。

yolox/models/yolo_pafpn.py のクラス YOLOPAFPN は yolox のネック部分の定義ファイルに過ぎないため、in_channels と width パラメータを直接変更することはできません。ここで定義されている in_channels と width は単なるデフォルト値です。実際にトレーニングを実行する際、定義のこの部分を呼び出すと、パラメータ in_channels と width に新しい値が渡されます。したがって、パラメータ in_channels と width を変更するには、ネックを呼び出す部分を見つける必要があります。yoloxのデフォルトのトレーニングファイルでは、yoloxモデルフレームワークの各モジュールファイルを呼び出してyoloxモデルを組み立ててトレーニングする関数は、yolox/exp/yolox_base.pyに定義されているクラス関数get_model()の部分です。以下に示すように:

ここで YOLOPAFPN が呼び出され、新しい in_channels パラメーターが渡されることがわかります。そのため、ここで変更する in_channels パラメーターの値は、実際のトレーニングにおける yolox モデルの特徴ピラミッドの入力特徴マップ チャネルの数を実際に変更します。 。width パラメータの変更は、定義されている EXP クラスを呼び出すファイルによって異なります。exps/example/yolox_voc/yolox_voc_s.py で EXP クラスを呼び出す場合は、ファイル内で width パラメータの変更を見つける必要があります。具体的な理由については、この記事の序文を参照してください。

おすすめ

転載: blog.csdn.net/qq_40641713/article/details/125345836