天天看點

行人重識别02-07:fast-reid(BoT)-pytorch程式設計規範(fast-reid為例)4-疊代器建構,資料加載-2

以下連結是個人關于fast-reid(BoT行人重識别) 所有見解,如有錯誤歡迎大家指出,我會第一時間糾正。有興趣的朋友可以加微信:17575010159 互相讨論技術。若是幫助到了你什麼,一定要記得點贊!因為這是對我最大的鼓勵。 文 末 附 帶 \color{blue}{文末附帶} 文末附帶 公 衆 号 − \color{blue}{公衆号 -} 公衆号− 海 量 資 源 。 \color{blue}{ 海量資源}。 海量資源。

行人重識别02-00:fast-reid(BoT)-目錄-史上最新無死角講解

極 度 推 薦 的 商 業 級 項 目 : \color{red}{極度推薦的商業級項目:} 極度推薦的商業級項目:這是本人落地的行為分析項目,主要包含(1.行人檢測,2.行人追蹤,3.行為識别三大子產品):行為分析(商用級别)00-目錄-史上最新無死角講解

前言

在上篇部落格中,我們留下了一個疑問,那就是在fastreid\data\build.py檔案

def build_reid_train_loader(cfg):
	......
    for d in cfg.DATASETS.NAMES:
        # 根據資料集名稱,建立對應資料集疊代的類,本人調試為類 fastreid.data.datasets.market1501.Market1501對象
        dataset = DATASET_REGISTRY.get(d)(root=_root, combineall=cfg.DATASETS.COMBINEALL)
        train_items.extend(dataset.train)
           

中的 dataset.train 是如何獲得的。在這篇部落格中,我會為打大家解答這個疑問。

Market1501

首先,我們已經知道 dataset 為 fastreid.data.datasets.market1501.Market150 建立的對象,那麼我們就找到這個Market150類:

@DATASET_REGISTRY.register()
class Market1501(ImageDataset):
    """Market1501.

    Reference:
        Zheng et al. Scalable Person Re-identification: A Benchmark. ICCV 2015.

    URL: `<http://www.liangzheng.org/Project/project_reid.html>`_

    Dataset statistics:
        - identities: 1501 (+1 for background).
        - images: 12936 (train) + 3368 (query) + 15913 (gallery).
    """
    _junk_pids = [0, -1]
    dataset_dir = '' # 資料集目錄,預設為空
    dataset_url = 'http://188.138.127.15:81/Datasets/Market-1501-v15.09.15.zip' # 資料集現在位址
    dataset_name = "market1501" # 資料集名稱

    def __init__(self, root='datasets', market1501_500k=False, **kwargs):
        # self.root = osp.abspath(osp.expanduser(root))
        # 資料集根目錄
        self.root = root
        # 拼接資料集路徑
        self.dataset_dir = osp.join(self.root, self.dataset_dir)

        # allow alternative directory structure  # 允許替換目錄結構
        self.data_dir = self.dataset_dir

        # 獲得資料集目錄
        data_dir = osp.join(self.data_dir, 'Market-1501-v15.09.15')
        # 判斷是否為一個目錄。如果是則複制給self.data_dir
        if osp.isdir(data_dir):
            self.data_dir = data_dir
        # 否則給出警告
        else:
            warnings.warn('The current data structure is deprecated. Please '
                          'put data folders such as "bounding_box_train" under '
                          '"Market-1501-v15.09.15".')

        # 訓練資料的目錄,“bounding_box_train”——用于訓練集的 751 人,包含 12,936 張圖像
        self.train_dir = osp.join(self.data_dir, 'bounding_box_train')

        # 為 750 人在每個攝像頭中随機選擇一張圖像作為query,是以一個人的query最多有 6 個,共有 3,368 張圖像
        self.query_dir = osp.join(self.data_dir, 'query')

        #“bounding_box_test”——用于測試集的 750 人,包含 19,732 張圖像,字首為 0000 表示在提取這 750 人的過程中DPM檢測錯的圖
        # (可能與query是同一個人),-1 表示檢測出來其他人的圖(不在這 750 人中)
        self.gallery_dir = osp.join(self.data_dir, 'bounding_box_test')

        # 額外畫廊的資料,可以了解為為bounding_box_test添加額外的資料
        self.extra_gallery_dir = osp.join(self.data_dir, 'images')

        # 設定self.market1501_500k标志,設定了該标志位,這表示為 self.gallery_dir 添加額外的 self.extra_gallery_dir資料
        self.market1501_500k = market1501_500k

        # 需要的檔案目錄
        required_files = [
            self.data_dir,
            self.train_dir,
            self.query_dir,
            self.gallery_dir,
        ]
        # 如果設定了 market1501_500k=Ture,則添加 extra_gallery_dir 到 required_files 之中
        if self.market1501_500k:
            required_files.append(self.extra_gallery_dir)

        # 在運作之前對 required_files 進行檢查
        self.check_before_run(required_files)

        # 對訓練目錄進行處理
        train = self.process_dir(self.train_dir)
        # 對 query 目錄資料進行處理
        query = self.process_dir(self.query_dir, is_train=False)
        # 對 gallery 目錄進行處理
        gallery = self.process_dir(self.gallery_dir, is_train=False)

        # 如果設定market1501_500k=Ture,則對extra_gallery_dir進行處理,并且添加到gallery之中
        if self.market1501_500k:
            gallery += self.process_dir(self.extra_gallery_dir, is_train=False)

        # 調用父類的初始化函數
        super(Market1501, self).__init__(train, query, gallery, **kwargs)

    def process_dir(self, dir_path, is_train=True):
        # 獲得目錄下的所有jpg圖檔名稱
        img_paths = glob.glob(osp.join(dir_path, '*.jpg'))
        # 用于正規表達式
        pattern = re.compile(r'([-\d]+)_c(\d)')

        data = []
        # 對每一張圖檔進行處理
        # 以 0001_c1s1_000151_01.jpg 為例
        # 1) 0001 表示每個人的标簽編号,從0001到1501;
        # 2) c1 表示第一個攝像頭(camera1),共有6個攝像頭;
        # 3) s1 表示第一個錄像片段(sequece1),每個錄影機都有數個錄像段;
        # 4) 000151 表示 c1s1 的第000151幀圖檔,視訊幀率25fps;
        # 5) 01 表示 c1s1_001051 這一幀上的第1個檢測框,由于采用DPM檢測器,對于每一幀上的行人可能會框出好幾個bbox。00 表示手工标注框
        for img_path in img_paths:
            # 獲得圖檔對應的pid(身份ID)以及攝像頭編号
            pid, camid = map(int, pattern.search(img_path).groups())
            # -1表示身份不在1051中,則忽略不進行處理
            if pid == -1:
                continue  # junk images are just ignored
            # 檢測id是否正确,不正确則報錯
            assert 0 <= pid <= 1501  # pid == 0 means background
            # 檢測攝像頭标号是否正确,不正确則報錯
            assert 1 <= camid <= 6
            # 攝像頭的标号預設從0開始
            camid -= 1  # index starts from 0

            # 如果進行訓練,則在前面加上'market1501',因為預設支援多個資料集訓練,
            # 是以每個身份ID都會加上對應的資料集字首
            if is_train:
                pid = self.dataset_name + "_" + str(pid)
            # 把單張名稱路徑,身份ID,以及攝像頭标号放置到data中
            data.append((img_path, pid, camid))

        return data
           

上面的代碼,注釋已經比較詳細了,就不進行講解了。大家或許奇怪為什麼沒有看到__getitem__函數,其實在上篇部落格中已經進行講解了。他是在 class CommDataset(Dataset) 中實作的。從上面可以看到 Market1501 繼承于ImageDataset。

ImageDataset

class ImageDataset(Dataset):
    """
    ImageDataset是一個基類,所有的資料疊代器都應該繼承于他,__getitem__傳回
    img,pid,camid,以及img_path。其中img包含了(channel, height, width)資訊。
    每次訓練疊代返資料形狀為batch_size, channel, height, width
    A base class representing ImageDataset.
    All other image datasets should subclass it.
    ``__getitem__`` returns an image given index.
    It will return ``img``, ``pid``, ``camid`` and ``img_path``
    where ``img`` has shape (channel, height, width). As a result,
    data in each batch has shape (batch_size, channel, height, width).
    """

    def __init__(self, train, query, gallery, **kwargs):
        super(ImageDataset, self).__init__(train, query, gallery, **kwargs)

    def show_train(self):
        """
        列印訓練資料相關資訊
        """
        # 對訓練資料進行進行解析,獲得id身份總數目,以及攝像頭标号總數目
        num_train_pids, num_train_cams = self.parse_data(self.train)

        headers = ['subset', '# ids', '# images', '# cameras']
        csv_results = [['train', num_train_pids, len(self.train), num_train_cams]]

        # tabulate it,進行資訊列印
        table = tabulate(
            csv_results,
            tablefmt="pipe",
            headers=headers,
            numalign="left",
        )
        logger.info(f"=> Loaded {self.__class__.__name__} in csv format: \n" + colored(table, "cyan"))

    def show_test(self):
        # 獲得需要gallery,query的ID以及攝像頭數目。然後進行列印顯示
        num_query_pids, num_query_cams = self.parse_data(self.query)
        num_gallery_pids, num_gallery_cams = self.parse_data(self.gallery)

        headers = ['subset', '# ids', '# images', '# cameras']
        csv_results = [
            ['query', num_query_pids, len(self.query), num_query_cams],
            ['gallery', num_gallery_pids, len(self.gallery), num_gallery_cams],
        ]

        # tabulate it
        table = tabulate(
            csv_results,
            tablefmt="pipe",
            headers=headers,
            numalign="left",
        )
        logger.info(f"=> Loaded {self.__class__.__name__} in csv format: \n" + colored(table, "cyan"))

           

ImageDataset主要實作了兩個列印資訊的函數,其實都無關要緊。

結語

到這裡為止,我們已經翻譯了論文,知道資料是如何擷取的,并且熟悉了訓練總體過程,那麼剩下的,就是對網絡總體結構的解析了。

行人重識别02-07:fast-reid(BoT)-pytorch程式設計規範(fast-reid為例)4-疊代器建構,資料加載-2

繼續閱讀