mmdet3d は、waymo データセットのトレーニングと視覚化を使用します

1.mmdet3d環境構築

参考:

Ubuntu22.04 インストール mmdet 2.25.1+ mmdet3d 1.0.0rc6 icon-default.png?t=N7T8https://blog.csdn.net/weixin_44013732/article/details/130675061

2. Waymo データセット

1. Waymo データセットをダウンロードする

注: データセットをダウンロードする前に、科学インターネットを設定してください。

公式サイトのダウンロードアドレス:

https://waymo.com/open/download/ icon-default.png?t=N7T8https://waymo.com/open/download/以下に示すページに入ります

 バージョン 1.4.0 以降では 3D セマンティック セグメンテーションのみが変更されるため、3D ターゲット検出に関してこれらのバージョンの問題を考慮する必要はありません。ここではバージョン 1.4.1 を例に挙げます。

 ページに入ると、archived_files/Individual_files/が表示されますが、上の archived_files/ ではデータ ファイルが圧縮パッケージにパックされていることが違います。次の Individual_files/ は、データ ファイルを 1 つずつ区切ります。以下は、archived_files の解凍後の結果であり、individual_files/download の結果と同じです。

ここでは例として Individual_files/ を選択します。ダウンロード方法は 2 つあります。

1、gsutil

ここでテスト、トレーニング、検証を選択してダウンロードすると、次の指示がポップアップ表示されます。

 上記の gsutil コマンドを呼び出すことでデータ セットをダウンロードできますが、注意すべき点がいくつかあります。

① 科学的インターネット アクセス用に ubuntu を構成します。gsutil は事前にプロキシ関連サービスを構成する必要があります。そうしないと、リンクがネットワークに接続できないことが表示されます。

②ネットワークがスムーズである必要があります。ダウンロード中はネットワークがスムーズである必要があります。そうでないと、途中で切断され、再起動する必要があります。

2. マニュアルのダウンロード

この方法も私がオススメする方法で、手順は面倒ですが失敗はしません。

ダウンロードする必要があるフォルダー testing/ に移動し、gsutil コマンド インターフェイスがポップアップしないように、それらを 1 つずつダウンロードします。

 トレーニングと検証も同様にダウンロードされますが、ダウンロードされる形式は *.tfrecord バイナリ ファイルなので、データ形式を変換する必要があります。

2. Waymo データセットを KITTI データセットに変換する

公式チュートリアル:

データセットの準備 — MMDetection3D 1.2.0 ドキュメントicon-default.png?t=N7T8https://mmdetection3d.readthedocs.io/en/latest/user_guides/dataset_prepare.html

1. データセットのストレージ

データ セットを /mmmdet3d-master/data/waymo/waymo_format にコピーします。waymo_format ファイルは自分で作成する必要があります。waymo_format フォルダーは変換中に自動的に取得されます。全体的な構造は次のとおりです。

 フォルダーに入ると、ファイルは次のようになります。

2. ソースコードを変更します: create.py

位置:mmdetection3d-master/tools/create_data.py

変換処理では、正しいImageSets/training.txtなどを生成するためにソースコードの一部を変更し、create.pyにImageSetを自動生成する関数を記述する必要があります。

def create_ImageSets_img_ids(root_dir):
    names_dict=dict()
    save_dir = osp.join(root_dir, 'ImageSets/')
    if not osp.exists(save_dir): os.mkdir(save_dir)

    load_01 =osp.join(root_dir, 'training/calib')
    load_2 = osp.join(root_dir, 'testing/calib')
    
    RawNames = os.listdir(load_01) + os.listdir(load_2) 
    split = [[],[],[]]
    for name in RawNames:
        if name.endswith('.txt'):
            idx = name.replace('.txt', '\n')
            split[int(idx[0])].append(idx)
    for i in range(3): 
        split[i].sort()

    open(save_dir+'train.txt','w').writelines(split[0])
    open(save_dir+'val.txt','w').writelines(split[1])
    open(save_dir+'trainval.txt','w').writelines(split[0]+split[1])
    open(save_dir+'test.txt','w').writelines(split[2])

同時に、waymo_data_prep 関数を通じて呼び出します。

def waymo_data_prep(root_path,
                    info_prefix,
                    version,
                    out_dir,
                    workers,
                    max_sweeps=5):
    """Prepare the info file for waymo dataset.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        out_dir (str): Output directory of the generated info file.
        workers (int): Number of threads to be used.
        max_sweeps (int, optional): Number of input consecutive frames.
            Default: 5. Here we store pose information of these frames
            for later use.
    """
    from tools.data_converter import waymo_converter as waymo

    splits = ['training', 'validation', 'testing']
    for i, split in enumerate(splits):
        load_dir = osp.join(root_path, 'waymo_format', split)
        if split == 'validation':
            save_dir = osp.join(out_dir, 'kitti_format', 'training')
        else:
            save_dir = osp.join(out_dir, 'kitti_format', split)
        converter = waymo.Waymo2KITTI(
            load_dir,
            save_dir,
            prefix=str(i),
            workers=workers,
            test_mode=(split == 'testing'))
        converter.convert()
    # Generate waymo infos
    out_dir = osp.join(out_dir, 'kitti_format')
    create_ImageSets_img_ids(out_dir)
    kitti.create_waymo_info_file(
        out_dir, info_prefix, max_sweeps=max_sweeps, workers=workers)
    GTDatabaseCreater(
        'WaymoDataset',
        out_dir,
        info_prefix,
        f'{out_dir}/{info_prefix}_infos_train.pkl',
        relative_path=False,
        with_mask=False,
        num_worker=workers).create()

最後に、完全なコードを添付します。

# Copyright (c) OpenMMLab. All rights reserved.
import argparse
from os import path as osp

from tools.data_converter import indoor_converter as indoor
from tools.data_converter import kitti_converter as kitti
from tools.data_converter import lyft_converter as lyft_converter
from tools.data_converter import nuscenes_converter as nuscenes_converter
from tools.data_converter.create_gt_database import (
    GTDatabaseCreater, create_groundtruth_database)
import os

def kitti_data_prep(root_path,
                    info_prefix,
                    version,
                    out_dir,
                    with_plane=False):
    """Prepare data related to Kitti dataset.

    Related data consists of '.pkl' files recording basic infos,
    2D annotations and groundtruth database.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        version (str): Dataset version.
        out_dir (str): Output directory of the groundtruth database info.
        with_plane (bool, optional): Whether to use plane information.
            Default: False.
    """
    kitti.create_kitti_info_file(root_path, info_prefix, with_plane)
    kitti.create_reduced_point_cloud(root_path, info_prefix)

    info_train_path = osp.join(root_path, f'{info_prefix}_infos_train.pkl')
    info_val_path = osp.join(root_path, f'{info_prefix}_infos_val.pkl')
    info_trainval_path = osp.join(root_path,
                                  f'{info_prefix}_infos_trainval.pkl')
    info_test_path = osp.join(root_path, f'{info_prefix}_infos_test.pkl')
    kitti.export_2d_annotation(root_path, info_train_path)
    kitti.export_2d_annotation(root_path, info_val_path)
    kitti.export_2d_annotation(root_path, info_trainval_path)
    kitti.export_2d_annotation(root_path, info_test_path)

    create_groundtruth_database(
        'KittiDataset',
        root_path,
        info_prefix,
        f'{out_dir}/{info_prefix}_infos_train.pkl',
        relative_path=False,
        mask_anno_path='instances_train.json',
        with_mask=(version == 'mask'))


def nuscenes_data_prep(root_path,
                       info_prefix,
                       version,
                       dataset_name,
                       out_dir,
                       max_sweeps=10):
    """Prepare data related to nuScenes dataset.

    Related data consists of '.pkl' files recording basic infos,
    2D annotations and groundtruth database.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        version (str): Dataset version.
        dataset_name (str): The dataset class name.
        out_dir (str): Output directory of the groundtruth database info.
        max_sweeps (int, optional): Number of input consecutive frames.
            Default: 10
    """
    nuscenes_converter.create_nuscenes_infos(
        root_path, info_prefix, version=version, max_sweeps=max_sweeps)

    if version == 'v1.0-test':
        info_test_path = osp.join(root_path, f'{info_prefix}_infos_test.pkl')
        nuscenes_converter.export_2d_annotation(
            root_path, info_test_path, version=version)
        return

    info_train_path = osp.join(root_path, f'{info_prefix}_infos_train.pkl')
    info_val_path = osp.join(root_path, f'{info_prefix}_infos_val.pkl')
    nuscenes_converter.export_2d_annotation(
        root_path, info_train_path, version=version)
    nuscenes_converter.export_2d_annotation(
        root_path, info_val_path, version=version)
    create_groundtruth_database(dataset_name, root_path, info_prefix,
                                f'{out_dir}/{info_prefix}_infos_train.pkl')


def lyft_data_prep(root_path, info_prefix, version, max_sweeps=10):
    """Prepare data related to Lyft dataset.

    Related data consists of '.pkl' files recording basic infos.
    Although the ground truth database and 2D annotations are not used in
    Lyft, it can also be generated like nuScenes.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        version (str): Dataset version.
        max_sweeps (int, optional): Number of input consecutive frames.
            Defaults to 10.
    """
    lyft_converter.create_lyft_infos(
        root_path, info_prefix, version=version, max_sweeps=max_sweeps)


def scannet_data_prep(root_path, info_prefix, out_dir, workers):
    """Prepare the info file for scannet dataset.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        out_dir (str): Output directory of the generated info file.
        workers (int): Number of threads to be used.
    """
    indoor.create_indoor_info_file(
        root_path, info_prefix, out_dir, workers=workers)


def s3dis_data_prep(root_path, info_prefix, out_dir, workers):
    """Prepare the info file for s3dis dataset.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        out_dir (str): Output directory of the generated info file.
        workers (int): Number of threads to be used.
    """
    indoor.create_indoor_info_file(
        root_path, info_prefix, out_dir, workers=workers)


def sunrgbd_data_prep(root_path, info_prefix, out_dir, workers, num_points):
    """Prepare the info file for sunrgbd dataset.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        out_dir (str): Output directory of the generated info file.
        workers (int): Number of threads to be used.
    """
    indoor.create_indoor_info_file(
        root_path,
        info_prefix,
        out_dir,
        workers=workers,
        num_points=num_points)

def create_ImageSets_img_ids_1(root_dir):
    names_dict=dict()
    save_dir = osp.join(root_dir, 'ImageSets/')
    if not osp.exists(save_dir): os.mkdir(save_dir)

    load_01 =osp.join(root_dir, 'training/calib')
    load_2 = osp.join(root_dir, 'testing/calib')
    
    RawNames = os.listdir(load_01) + os.listdir(load_2) 
    split = [[],[],[]]
    for name in RawNames:
        if name.endswith('.txt'):
            idx = name.replace('.txt', '\n')
            split[int(idx[0])].append(idx)
    for i in range(3): 
        split[i].sort()

    open(save_dir+'train.txt','w').writelines(split[0])
    open(save_dir+'val.txt','w').writelines(split[1])
    open(save_dir+'trainval.txt','w').writelines(split[0]+split[1])
    open(save_dir+'test.txt','w').writelines(split[2])


def create_ImageSets_img_ids(root_dir):
    names_dict = dict()
    save_dir = osp.join(root_dir, 'ImageSets/')
    if not osp.exists(save_dir): os.mkdir(save_dir)

    load_01 = osp.join(root_dir, 'training/calib')
    load_2 = osp.join(root_dir, 'testing/calib')

    RawNames = os.listdir(load_01) + os.listdir(load_2)
    split = [[], [], []]
    for name in RawNames:
        if name.endswith('.txt'):
            idx = name.replace('.txt', '\n')
            split[int(idx[0])].append(idx)
    for i in range(3):
        split[i].sort()

    open(save_dir + 'train.txt', 'w').writelines(split[0])
    open(save_dir + 'val.txt', 'w').writelines(split[1])
    open(save_dir + 'trainval.txt', 'w').writelines(split[0] + split[1])
    open(save_dir + 'test.txt', 'w').writelines(split[2])

def waymo_data_prep(root_path,
                    info_prefix,
                    version,
                    out_dir,
                    workers,
                    max_sweeps=5):
    """Prepare the info file for waymo dataset.

    Args:
        root_path (str): Path of dataset root.
        info_prefix (str): The prefix of info filenames.
        out_dir (str): Output directory of the generated info file.
        workers (int): Number of threads to be used.
        max_sweeps (int, optional): Number of input consecutive frames.
            Default: 5. Here we store pose information of these frames
            for later use.
    """
    from tools.data_converter import waymo_converter as waymo

    splits = ['training', 'validation', 'testing']
    for i, split in enumerate(splits):
        load_dir = osp.join(root_path, 'waymo_format', split)
        if split == 'validation':
            save_dir = osp.join(out_dir, 'kitti_format', 'training')
        else:
            save_dir = osp.join(out_dir, 'kitti_format', split)
        converter = waymo.Waymo2KITTI(
            load_dir,
            save_dir,
            prefix=str(i),
            workers=workers,
            test_mode=(split == 'testing'))
        converter.convert()
    # Generate waymo infos
    out_dir = osp.join(out_dir, 'kitti_format')
    create_ImageSets_img_ids(out_dir)
    kitti.create_waymo_info_file(
        out_dir, info_prefix, max_sweeps=max_sweeps, workers=workers)
    GTDatabaseCreater(
        'WaymoDataset',
        out_dir,
        info_prefix,
        f'{out_dir}/{info_prefix}_infos_train.pkl',
        relative_path=False,
        with_mask=False,
        num_worker=workers).create()



parser = argparse.ArgumentParser(description='Data converter arg parser')
parser.add_argument('dataset', metavar='kitti', help='name of the dataset')
parser.add_argument(
    '--root-path',
    type=str,
    default='./data/kitti',
    help='specify the root path of dataset')
parser.add_argument(
    '--version',
    type=str,
    default='v1.0',
    required=False,
    help='specify the dataset version, no need for kitti')
parser.add_argument(
    '--max-sweeps',
    type=int,
    default=10,
    required=False,
    help='specify sweeps of lidar per example')
parser.add_argument(
    '--with-plane',
    action='store_true',
    help='Whether to use plane information for kitti.')
parser.add_argument(
    '--num-points',
    type=int,
    default=-1,
    help='Number of points to sample for indoor datasets.')
parser.add_argument(
    '--out-dir',
    type=str,
    default='./data/kitti',
    required=False,
    help='name of info pkl')
parser.add_argument('--extra-tag', type=str, default='kitti')
parser.add_argument(
    '--workers', type=int, default=4, help='number of threads to be used')
args = parser.parse_args()

if __name__ == '__main__':
    if args.dataset == 'kitti':
        kitti_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=args.version,
            out_dir=args.out_dir,
            with_plane=args.with_plane)
    elif args.dataset == 'nuscenes' and args.version != 'v1.0-mini':
        train_version = f'{args.version}-trainval'
        nuscenes_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=train_version,
            dataset_name='NuScenesDataset',
            out_dir=args.out_dir,
            max_sweeps=args.max_sweeps)
        test_version = f'{args.version}-test'
        nuscenes_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=test_version,
            dataset_name='NuScenesDataset',
            out_dir=args.out_dir,
            max_sweeps=args.max_sweeps)
    elif args.dataset == 'nuscenes' and args.version == 'v1.0-mini':
        train_version = f'{args.version}'
        nuscenes_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=train_version,
            dataset_name='NuScenesDataset',
            out_dir=args.out_dir,
            max_sweeps=args.max_sweeps)
    elif args.dataset == 'lyft':
        train_version = f'{args.version}-train'
        lyft_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=train_version,
            max_sweeps=args.max_sweeps)
        test_version = f'{args.version}-test'
        lyft_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=test_version,
            max_sweeps=args.max_sweeps)
    elif args.dataset == 'waymo':
        waymo_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            version=args.version,
            out_dir=args.out_dir,
            workers=args.workers,
            max_sweeps=args.max_sweeps)
    elif args.dataset == 'scannet':
        scannet_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            out_dir=args.out_dir,
            workers=args.workers)
    elif args.dataset == 's3dis':
        s3dis_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            out_dir=args.out_dir,
            workers=args.workers)
    elif args.dataset == 'sunrgbd':
        sunrgbd_data_prep(
            root_path=args.root_path,
            info_prefix=args.extra_tag,
            num_points=args.num_points,
            out_dir=args.out_dir,
            workers=args.workers)

参考ブログ: mmdet3d 純粋なビジュアル ベースラインのデータ準備: waymo データセット v1.3.1_ZLT の処理: waymo データセット v1.3.1_ZLTの処理 純粋なビジュアル ベースライン (マルチカメラ モード) を waymo でテストし、多くのステップに分かれています: データ セットを kitti 形式に処理し、データローダーのコード修正 モデルコンフィグの修正、モデルのターゲットとロスの修正、evalパイプラインのコード修正 mmdet3d公式サイトのwaymoデータセットのチュートリアルが簡単すぎる 処理結果はpointpillarでしか使えず、データセットの古いバージョン。初心者の私にはとても不親切です。mmdet に基づく次のチュートリアル (以下、チュートリアルと呼びます) では、具体的なプロセスを簡単に要約し、detr3d が waymo に対処する際に一歩前進できるように mmdet3d のコードを変更する方法を説明しますhttps://blog.csdn.net/ ZLTJohn/記事/詳細/125010804

3. 変換を開始します

mmdet3d-master/ フォルダーに入り、次のコマンドを実行します。

python ./tools/create_data.py waymo --root-path ./data/waymo --out-dir ./data/waymo --extra-tag waymo

ここで注意すべき点が 2 つあります。1 つは、create_data.py の後に waymo を追加して waymo データセットを変換することです。2 つ目は、余分なタグ waymo を追加して最終的な pkl の名前を変更することです。

コマンドの形式は次のとおりです: python ./tools/create_data.py waymo --root-path  + waymo データセットが配置されているファイル (tfファイル)  --out-dir +データセットの出力場所--extra-tag waymo

実行の結果、次のインターフェイスが表示されます。これは、変換が開始されることを意味します。

 最後に、./data/waymo/ フォルダーの下の kitti_format を確認します。

waymo pkl ファイルが生成されたら、変換は完了です。

4. トレーニングを開始する

点柱を例に挙げます。

 python ./tools/train.py ./configs/pointpillars/hv_pointpillars_secfpn_sbn_2x16_2x_waymo-3d-car.py

 命令形式は: python ./tools/train.py +モデルファイル (config)

 実行結果は次のとおりです。

 5. 推論と視覚化

点柱を例に挙げます。

python ./tools/test.py ./configs/pointpillars/hv_pointpillars_secfpn_sbn_2x16_2x_waymo-3d-car.py ./work_dirs/hv_pointpillars_secfpn_sbn_2x16_2x_waymo-3d-car/pv_rcnn.pth --eval 'kitti' --eval-options 'show=True' 'out_dir=./test_results/pointpillars_test_result'

 命令形式は: python ./tools/test.py +モデルファイル (config) +重みファイル pth --eval 'kitti' --eval-options 'show=True' +出力場所

評価指標は、コマンド --eval 'kitti' に対応する kitti を使用します。waymo の評価方法を選択することもできますが、インストール手順が面倒なので、自分でインストールしてみる必要があります。

実行結果は以下の通りです。

a. 推論結果

b. 結果を視覚化する 

おすすめ

転載: blog.csdn.net/weixin_44013732/article/details/131735153