以下連結是個人關于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主要實作了兩個列印資訊的函數,其實都無關要緊。
結語
到這裡為止,我們已經翻譯了論文,知道資料是如何擷取的,并且熟悉了訓練總體過程,那麼剩下的,就是對網絡總體結構的解析了。