Meta Byte Track
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mot_evaluator.py 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. from collections import defaultdict
  2. from loguru import logger
  3. from tqdm import tqdm
  4. import torch
  5. from yolox.utils import (
  6. gather,
  7. is_main_process,
  8. postprocess,
  9. synchronize,
  10. time_synchronized,
  11. xyxy2xywh
  12. )
  13. from yolox.tracker.byte_tracker import BYTETracker
  14. from yolox.sort_tracker.sort import Sort
  15. from yolox.deepsort_tracker.deepsort import DeepSort
  16. from yolox.motdt_tracker.motdt_tracker import OnlineTracker
  17. import contextlib
  18. import io
  19. import os
  20. import itertools
  21. import json
  22. import tempfile
  23. import time
  24. def write_results(filename, results):
  25. save_format = '{frame},{id},{x1},{y1},{w},{h},{s},-1,-1,-1\n'
  26. with open(filename, 'w') as f:
  27. for frame_id, tlwhs, track_ids, scores in results:
  28. for tlwh, track_id, score in zip(tlwhs, track_ids, scores):
  29. if track_id < 0:
  30. continue
  31. x1, y1, w, h = tlwh
  32. line = save_format.format(frame=frame_id, id=track_id, x1=round(x1, 1), y1=round(y1, 1), w=round(w, 1),
  33. h=round(h, 1), s=round(score, 2))
  34. f.write(line)
  35. logger.info('save results to {}'.format(filename))
  36. def write_results_no_score(filename, results):
  37. save_format = '{frame},{id},{x1},{y1},{w},{h},-1,-1,-1,-1\n'
  38. with open(filename, 'w') as f:
  39. for frame_id, tlwhs, track_ids in results:
  40. for tlwh, track_id in zip(tlwhs, track_ids):
  41. if track_id < 0:
  42. continue
  43. x1, y1, w, h = tlwh
  44. line = save_format.format(frame=frame_id, id=track_id, x1=round(x1, 1), y1=round(y1, 1), w=round(w, 1),
  45. h=round(h, 1))
  46. f.write(line)
  47. logger.info('save results to {}'.format(filename))
  48. class MOTEvaluator:
  49. """
  50. COCO AP Evaluation class. All the data in the val2017 dataset are processed
  51. and evaluated by COCO API.
  52. """
  53. def __init__(
  54. self, args, dataloader, img_size, confthre, nmsthre, num_classes):
  55. """
  56. Args:
  57. dataloader (Dataloader): evaluate dataloader.
  58. img_size (int): image size after preprocess. images are resized
  59. to squares whose shape is (img_size, img_size).
  60. confthre (float): confidence threshold ranging from 0 to 1, which
  61. is defined in the config file.
  62. nmsthre (float): IoU threshold of non-max supression ranging from 0 to 1.
  63. """
  64. self.dataloader = dataloader
  65. self.img_size = img_size
  66. self.confthre = confthre
  67. self.nmsthre = nmsthre
  68. self.num_classes = num_classes
  69. self.args = args
  70. def evaluate(
  71. self,
  72. model,
  73. distributed=False,
  74. half=False,
  75. trt_file=None,
  76. decoder=None,
  77. test_size=None,
  78. result_folder=None,
  79. adaptation_period=None,
  80. eval_det=True,
  81. ):
  82. """
  83. COCO average precision (AP) Evaluation. Iterate inference on the test dataset
  84. and the results are evaluated by COCO API.
  85. NOTE: This function will change training mode to False, please save states if needed.
  86. Args:
  87. model : model to evaluate.
  88. Returns:
  89. ap50_95 (float) : COCO AP of IoU=50:95
  90. ap50 (float) : COCO AP of IoU=50
  91. summary (sr): summary info of evaluation.
  92. """
  93. tensor_type = torch.cuda.HalfTensor if half else torch.cuda.FloatTensor
  94. model = model.type(tensor_type)
  95. if adaptation_period is not None:
  96. logger.info('cloning model...')
  97. learner = model.clone()
  98. else:
  99. learner = model
  100. # TODO half to amp_test
  101. self.scaler = torch.cuda.amp.GradScaler(enabled=half, init_scale=2730)
  102. learner = learner.eval()
  103. self.amp_training = False
  104. if half:
  105. logger.info('half...')
  106. learner = learner.half()
  107. self.amp_training = True
  108. ids = []
  109. data_list = []
  110. results = []
  111. video_names = defaultdict()
  112. progress_bar = tqdm if is_main_process() else iter
  113. inference_time = 0
  114. track_time = 0
  115. n_samples = len(self.dataloader) - 1
  116. if trt_file is not None:
  117. from torch2trt import TRTModule
  118. logger.info('Loading trt file')
  119. model_trt = TRTModule()
  120. model_trt.load_state_dict(torch.load(trt_file))
  121. x = torch.ones(1, 3, test_size[0], test_size[1]).cuda()
  122. learner(x)
  123. learner = model_trt
  124. tracker = BYTETracker(self.args)
  125. ori_thresh = self.args.track_thresh
  126. for cur_iter, (imgs, targets, info_imgs, ids) in enumerate(
  127. progress_bar(self.dataloader)
  128. ):
  129. if cur_iter % 100 == 0:
  130. logger.info('cur_iter: {}'.format(cur_iter))
  131. # with torch.no_grad():
  132. # init tracker
  133. # imgs = imgs.to(self.data_type)
  134. # targets = targets.to(self.data_type)
  135. frame_id = info_imgs[2].item()
  136. video_id = info_imgs[3].item()
  137. img_file_name = info_imgs[4]
  138. video_name = img_file_name[0].split('/')[0]
  139. if video_name == 'MOT17-05-FRCNN' or video_name == 'MOT17-06-FRCNN':
  140. self.args.track_buffer = 14
  141. elif video_name == 'MOT17-13-FRCNN' or video_name == 'MOT17-14-FRCNN':
  142. self.args.track_buffer = 25
  143. else:
  144. self.args.track_buffer = 30
  145. if video_name == 'MOT17-01-FRCNN':
  146. self.args.track_thresh = 0.65
  147. elif video_name == 'MOT17-06-FRCNN':
  148. self.args.track_thresh = 0.65
  149. elif video_name == 'MOT17-12-FRCNN':
  150. self.args.track_thresh = 0.7
  151. elif video_name == 'MOT17-14-FRCNN':
  152. self.args.track_thresh = 0.67
  153. else:
  154. self.args.track_thresh = ori_thresh
  155. if video_name == 'MOT20-06' or video_name == 'MOT20-08':
  156. self.args.track_thresh = 0.3
  157. else:
  158. self.args.track_thresh = ori_thresh
  159. if video_name not in video_names:
  160. video_names[video_id] = video_name
  161. if frame_id == 1:
  162. tracker = BYTETracker(self.args)
  163. if len(results) != 0:
  164. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id - 1]))
  165. write_results(result_filename, results)
  166. results = []
  167. imgs = imgs.type(tensor_type)
  168. # skip the the last iters since batchsize might be not enough for batch inference
  169. is_time_record = cur_iter < len(self.dataloader) - 1
  170. if is_time_record:
  171. start = time.time()
  172. if adaptation_period is not None and cur_iter % adaptation_period == 0:
  173. with torch.cuda.amp.autocast(enabled=self.amp_training):
  174. learner.train()
  175. targets = targets.type(tensor_type)
  176. targets.requires_grad = False
  177. outputs = learner(imgs, targets)
  178. loss = outputs["total_loss"]
  179. # loss = outputs["iou_loss"]
  180. # logger.info("loss Norm: {} , scale {}".format(torch.norm(loss), self.scaler.get_scale()))
  181. loss = self.scaler.scale(loss)
  182. # logger.info("loss Norm: {} , scale {}".format(torch.norm(loss), self.scaler.get_scale()))
  183. learner.adapt(loss)
  184. # self.scaler.update()
  185. # learner.adapt(self.scaler.scale(loss))
  186. learner.eval()
  187. learner.half()
  188. with torch.no_grad():
  189. outputs = learner(imgs)
  190. if decoder is not None:
  191. outputs = decoder(outputs, dtype=outputs.type())
  192. # print('outputs', outputs.shape)
  193. outputs = postprocess(outputs, self.num_classes, self.confthre, self.nmsthre)
  194. if is_time_record:
  195. infer_end = time_synchronized()
  196. inference_time += infer_end - start
  197. output_results = self.convert_to_coco_format(outputs, info_imgs, ids)
  198. data_list.extend(output_results)
  199. # run tracking
  200. if outputs[0] is not None:
  201. online_targets = tracker.update(outputs[0], info_imgs, self.img_size)
  202. online_tlwhs = []
  203. online_ids = []
  204. online_scores = []
  205. for t in online_targets:
  206. tlwh = t.tlwh
  207. tid = t.track_id
  208. vertical = tlwh[2] / tlwh[3] > 1.6
  209. if tlwh[2] * tlwh[3] > self.args.min_box_area and not vertical:
  210. online_tlwhs.append(tlwh)
  211. online_ids.append(tid)
  212. online_scores.append(t.score)
  213. # save results
  214. results.append((frame_id, online_tlwhs, online_ids, online_scores))
  215. if is_time_record:
  216. track_end = time_synchronized()
  217. track_time += track_end - infer_end
  218. if cur_iter == len(self.dataloader) - 1:
  219. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id]))
  220. write_results(result_filename, results)
  221. statistics = torch.cuda.FloatTensor([inference_time, track_time, n_samples])
  222. if distributed:
  223. data_list = gather(data_list, dst=0)
  224. data_list = list(itertools.chain(*data_list))
  225. torch.distributed.reduce(statistics, dst=0)
  226. if eval_det:
  227. eval_results = self.evaluate_prediction(data_list, statistics)
  228. else:
  229. eval_results = 0, 0, 'skipped'
  230. synchronize()
  231. return eval_results
  232. def evaluate_sort(
  233. self,
  234. model,
  235. distributed=False,
  236. half=False,
  237. trt_file=None,
  238. decoder=None,
  239. test_size=None,
  240. result_folder=None
  241. ):
  242. """
  243. COCO average precision (AP) Evaluation. Iterate inference on the test dataset
  244. and the results are evaluated by COCO API.
  245. NOTE: This function will change training mode to False, please save states if needed.
  246. Args:
  247. model : model to evaluate.
  248. Returns:
  249. ap50_95 (float) : COCO AP of IoU=50:95
  250. ap50 (float) : COCO AP of IoU=50
  251. summary (sr): summary info of evaluation.
  252. """
  253. # TODO half to amp_test
  254. tensor_type = torch.cuda.HalfTensor if half else torch.cuda.FloatTensor
  255. model = model.eval()
  256. if half:
  257. model = model.half()
  258. ids = []
  259. data_list = []
  260. results = []
  261. video_names = defaultdict()
  262. progress_bar = tqdm if is_main_process() else iter
  263. inference_time = 0
  264. track_time = 0
  265. n_samples = len(self.dataloader) - 1
  266. if trt_file is not None:
  267. from torch2trt import TRTModule
  268. model_trt = TRTModule()
  269. model_trt.load_state_dict(torch.load(trt_file))
  270. x = torch.ones(1, 3, test_size[0], test_size[1]).cuda()
  271. model(x)
  272. model = model_trt
  273. tracker = Sort(self.args.track_thresh)
  274. for cur_iter, (imgs, _, info_imgs, ids) in enumerate(
  275. progress_bar(self.dataloader)
  276. ):
  277. if cur_iter % 250 == 0:
  278. logger.info('cur_iter: {}'.format(cur_iter))
  279. with torch.no_grad():
  280. # init tracker
  281. frame_id = info_imgs[2].item()
  282. video_id = info_imgs[3].item()
  283. img_file_name = info_imgs[4]
  284. video_name = img_file_name[0].split('/')[0]
  285. if video_name not in video_names:
  286. video_names[video_id] = video_name
  287. if frame_id == 1:
  288. tracker = Sort(self.args.track_thresh)
  289. if len(results) != 0:
  290. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id - 1]))
  291. write_results_no_score(result_filename, results)
  292. results = []
  293. imgs = imgs.type(tensor_type)
  294. # skip the the last iters since batchsize might be not enough for batch inference
  295. is_time_record = cur_iter < len(self.dataloader) - 1
  296. if is_time_record:
  297. start = time.time()
  298. outputs = model(imgs)
  299. if decoder is not None:
  300. outputs = decoder(outputs, dtype=outputs.type())
  301. outputs = postprocess(outputs, self.num_classes, self.confthre, self.nmsthre)
  302. if is_time_record:
  303. infer_end = time_synchronized()
  304. inference_time += infer_end - start
  305. output_results = self.convert_to_coco_format(outputs, info_imgs, ids)
  306. data_list.extend(output_results)
  307. # run tracking
  308. online_targets = tracker.update(outputs[0], info_imgs, self.img_size)
  309. online_tlwhs = []
  310. online_ids = []
  311. for t in online_targets:
  312. tlwh = [t[0], t[1], t[2] - t[0], t[3] - t[1]]
  313. tid = t[4]
  314. vertical = tlwh[2] / tlwh[3] > 1.6
  315. if tlwh[2] * tlwh[3] > self.args.min_box_area and not vertical:
  316. online_tlwhs.append(tlwh)
  317. online_ids.append(tid)
  318. # save results
  319. results.append((frame_id, online_tlwhs, online_ids))
  320. if is_time_record:
  321. track_end = time_synchronized()
  322. track_time += track_end - infer_end
  323. if cur_iter == len(self.dataloader) - 1:
  324. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id]))
  325. write_results_no_score(result_filename, results)
  326. statistics = torch.cuda.FloatTensor([inference_time, track_time, n_samples])
  327. if distributed:
  328. data_list = gather(data_list, dst=0)
  329. data_list = list(itertools.chain(*data_list))
  330. torch.distributed.reduce(statistics, dst=0)
  331. eval_results = self.evaluate_prediction(data_list, statistics)
  332. synchronize()
  333. return eval_results
  334. def evaluate_deepsort(
  335. self,
  336. model,
  337. distributed=False,
  338. half=False,
  339. trt_file=None,
  340. decoder=None,
  341. test_size=None,
  342. result_folder=None,
  343. model_folder=None
  344. ):
  345. """
  346. COCO average precision (AP) Evaluation. Iterate inference on the test dataset
  347. and the results are evaluated by COCO API.
  348. NOTE: This function will change training mode to False, please save states if needed.
  349. Args:
  350. model : model to evaluate.
  351. Returns:
  352. ap50_95 (float) : COCO AP of IoU=50:95
  353. ap50 (float) : COCO AP of IoU=50
  354. summary (sr): summary info of evaluation.
  355. """
  356. # TODO half to amp_test
  357. tensor_type = torch.cuda.HalfTensor if half else torch.cuda.FloatTensor
  358. model = model.eval()
  359. if half:
  360. model = model.half()
  361. ids = []
  362. data_list = []
  363. results = []
  364. video_names = defaultdict()
  365. progress_bar = tqdm if is_main_process() else iter
  366. inference_time = 0
  367. track_time = 0
  368. n_samples = len(self.dataloader) - 1
  369. if trt_file is not None:
  370. from torch2trt import TRTModule
  371. model_trt = TRTModule()
  372. model_trt.load_state_dict(torch.load(trt_file))
  373. x = torch.ones(1, 3, test_size[0], test_size[1]).cuda()
  374. model(x)
  375. model = model_trt
  376. tracker = DeepSort(model_folder, min_confidence=self.args.track_thresh)
  377. for cur_iter, (imgs, _, info_imgs, ids) in enumerate(
  378. progress_bar(self.dataloader)
  379. ):
  380. with torch.no_grad():
  381. # init tracker
  382. frame_id = info_imgs[2].item()
  383. video_id = info_imgs[3].item()
  384. img_file_name = info_imgs[4]
  385. video_name = img_file_name[0].split('/')[0]
  386. if video_name not in video_names:
  387. video_names[video_id] = video_name
  388. if frame_id == 1:
  389. tracker = DeepSort(model_folder, min_confidence=self.args.track_thresh)
  390. if len(results) != 0:
  391. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id - 1]))
  392. write_results_no_score(result_filename, results)
  393. results = []
  394. imgs = imgs.type(tensor_type)
  395. # skip the the last iters since batchsize might be not enough for batch inference
  396. is_time_record = cur_iter < len(self.dataloader) - 1
  397. if is_time_record:
  398. start = time.time()
  399. outputs = model(imgs)
  400. if decoder is not None:
  401. outputs = decoder(outputs, dtype=outputs.type())
  402. outputs = postprocess(outputs, self.num_classes, self.confthre, self.nmsthre)
  403. if is_time_record:
  404. infer_end = time_synchronized()
  405. inference_time += infer_end - start
  406. output_results = self.convert_to_coco_format(outputs, info_imgs, ids)
  407. data_list.extend(output_results)
  408. # run tracking
  409. online_targets = tracker.update(outputs[0], info_imgs, self.img_size, img_file_name[0])
  410. online_tlwhs = []
  411. online_ids = []
  412. for t in online_targets:
  413. tlwh = [t[0], t[1], t[2] - t[0], t[3] - t[1]]
  414. tid = t[4]
  415. vertical = tlwh[2] / tlwh[3] > 1.6
  416. if tlwh[2] * tlwh[3] > self.args.min_box_area and not vertical:
  417. online_tlwhs.append(tlwh)
  418. online_ids.append(tid)
  419. # save results
  420. results.append((frame_id, online_tlwhs, online_ids))
  421. if is_time_record:
  422. track_end = time_synchronized()
  423. track_time += track_end - infer_end
  424. if cur_iter == len(self.dataloader) - 1:
  425. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id]))
  426. write_results_no_score(result_filename, results)
  427. statistics = torch.cuda.FloatTensor([inference_time, track_time, n_samples])
  428. if distributed:
  429. data_list = gather(data_list, dst=0)
  430. data_list = list(itertools.chain(*data_list))
  431. torch.distributed.reduce(statistics, dst=0)
  432. eval_results = self.evaluate_prediction(data_list, statistics)
  433. synchronize()
  434. return eval_results
  435. def evaluate_motdt(
  436. self,
  437. model,
  438. distributed=False,
  439. half=False,
  440. trt_file=None,
  441. decoder=None,
  442. test_size=None,
  443. result_folder=None,
  444. model_folder=None
  445. ):
  446. """
  447. COCO average precision (AP) Evaluation. Iterate inference on the test dataset
  448. and the results are evaluated by COCO API.
  449. NOTE: This function will change training mode to False, please save states if needed.
  450. Args:
  451. model : model to evaluate.
  452. Returns:
  453. ap50_95 (float) : COCO AP of IoU=50:95
  454. ap50 (float) : COCO AP of IoU=50
  455. summary (sr): summary info of evaluation.
  456. """
  457. # TODO half to amp_test
  458. tensor_type = torch.cuda.HalfTensor if half else torch.cuda.FloatTensor
  459. model = model.eval()
  460. if half:
  461. model = model.half()
  462. ids = []
  463. data_list = []
  464. results = []
  465. video_names = defaultdict()
  466. progress_bar = tqdm if is_main_process() else iter
  467. inference_time = 0
  468. track_time = 0
  469. n_samples = len(self.dataloader) - 1
  470. if trt_file is not None:
  471. from torch2trt import TRTModule
  472. model_trt = TRTModule()
  473. model_trt.load_state_dict(torch.load(trt_file))
  474. x = torch.ones(1, 3, test_size[0], test_size[1]).cuda()
  475. model(x)
  476. model = model_trt
  477. tracker = OnlineTracker(model_folder, min_cls_score=self.args.track_thresh)
  478. for cur_iter, (imgs, _, info_imgs, ids) in enumerate(
  479. progress_bar(self.dataloader)
  480. ):
  481. with torch.no_grad():
  482. # init tracker
  483. frame_id = info_imgs[2].item()
  484. video_id = info_imgs[3].item()
  485. img_file_name = info_imgs[4]
  486. video_name = img_file_name[0].split('/')[0]
  487. if video_name not in video_names:
  488. video_names[video_id] = video_name
  489. if frame_id == 1:
  490. tracker = OnlineTracker(model_folder, min_cls_score=self.args.track_thresh)
  491. if len(results) != 0:
  492. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id - 1]))
  493. write_results(result_filename, results)
  494. results = []
  495. imgs = imgs.type(tensor_type)
  496. # skip the the last iters since batchsize might be not enough for batch inference
  497. is_time_record = cur_iter < len(self.dataloader) - 1
  498. if is_time_record:
  499. start = time.time()
  500. outputs = model(imgs)
  501. if decoder is not None:
  502. outputs = decoder(outputs, dtype=outputs.type())
  503. outputs = postprocess(outputs, self.num_classes, self.confthre, self.nmsthre)
  504. if is_time_record:
  505. infer_end = time_synchronized()
  506. inference_time += infer_end - start
  507. output_results = self.convert_to_coco_format(outputs, info_imgs, ids)
  508. data_list.extend(output_results)
  509. # run tracking
  510. online_targets = tracker.update(outputs[0], info_imgs, self.img_size, img_file_name[0])
  511. online_tlwhs = []
  512. online_ids = []
  513. online_scores = []
  514. for t in online_targets:
  515. tlwh = t.tlwh
  516. tid = t.track_id
  517. vertical = tlwh[2] / tlwh[3] > 1.6
  518. if tlwh[2] * tlwh[3] > self.args.min_box_area and not vertical:
  519. online_tlwhs.append(tlwh)
  520. online_ids.append(tid)
  521. online_scores.append(t.score)
  522. # save results
  523. results.append((frame_id, online_tlwhs, online_ids, online_scores))
  524. if is_time_record:
  525. track_end = time_synchronized()
  526. track_time += track_end - infer_end
  527. if cur_iter == len(self.dataloader) - 1:
  528. result_filename = os.path.join(result_folder, '{}.txt'.format(video_names[video_id]))
  529. write_results(result_filename, results)
  530. statistics = torch.cuda.FloatTensor([inference_time, track_time, n_samples])
  531. if distributed:
  532. data_list = gather(data_list, dst=0)
  533. data_list = list(itertools.chain(*data_list))
  534. torch.distributed.reduce(statistics, dst=0)
  535. eval_results = self.evaluate_prediction(data_list, statistics)
  536. synchronize()
  537. return eval_results
  538. def convert_to_coco_format(self, outputs, info_imgs, ids):
  539. data_list = []
  540. for (output, img_h, img_w, img_id) in zip(
  541. outputs, info_imgs[0], info_imgs[1], ids
  542. ):
  543. if output is None:
  544. continue
  545. output = output.cpu()
  546. bboxes = output[:, 0:4]
  547. # preprocessing: resize
  548. scale = min(
  549. self.img_size[0] / float(img_h), self.img_size[1] / float(img_w)
  550. )
  551. bboxes /= scale
  552. bboxes = xyxy2xywh(bboxes)
  553. cls = output[:, 6]
  554. scores = output[:, 4] * output[:, 5]
  555. for ind in range(bboxes.shape[0]):
  556. label = self.dataloader.dataset.class_ids[int(cls[ind])]
  557. pred_data = {
  558. "image_id": int(img_id),
  559. "category_id": label,
  560. "bbox": bboxes[ind].numpy().tolist(),
  561. "score": scores[ind].numpy().item(),
  562. "segmentation": [],
  563. } # COCO json format
  564. data_list.append(pred_data)
  565. return data_list
  566. def evaluate_prediction(self, data_dict, statistics):
  567. if not is_main_process():
  568. return 0, 0, None
  569. logger.info("Evaluate in main process...")
  570. annType = ["segm", "bbox", "keypoints"]
  571. inference_time = statistics[0].item()
  572. track_time = statistics[1].item()
  573. n_samples = statistics[2].item()
  574. a_infer_time = 1000 * inference_time / (n_samples * self.dataloader.batch_size)
  575. a_track_time = 1000 * track_time / (n_samples * self.dataloader.batch_size)
  576. time_info = ", ".join(
  577. [
  578. "Average {} time: {:.2f} ms".format(k, v)
  579. for k, v in zip(
  580. ["forward", "track", "inference"],
  581. [a_infer_time, a_track_time, (a_infer_time + a_track_time)],
  582. )
  583. ]
  584. )
  585. info = time_info + "\n"
  586. # Evaluate the Dt (detection) json comparing with the ground truth
  587. if len(data_dict) > 0:
  588. cocoGt = self.dataloader.dataset.coco
  589. # TODO: since pycocotools can't process dict in py36, write data to json file.
  590. _, tmp = tempfile.mkstemp()
  591. json.dump(data_dict, open(tmp, "w"))
  592. cocoDt = cocoGt.loadRes(tmp)
  593. '''
  594. try:
  595. from yolox.layers import COCOeval_opt as COCOeval
  596. except ImportError:
  597. from pycocotools import cocoeval as COCOeval
  598. logger.warning("Use standard COCOeval.")
  599. '''
  600. # I changed it
  601. from pycocotools.cocoeval import COCOeval
  602. # from yolox.layers import COCOeval_opt as COCOeval
  603. cocoEval = COCOeval(cocoGt, cocoDt, annType[1])
  604. cocoEval.evaluate()
  605. cocoEval.accumulate()
  606. redirect_string = io.StringIO()
  607. with contextlib.redirect_stdout(redirect_string):
  608. cocoEval.summarize()
  609. info += redirect_string.getvalue()
  610. return cocoEval.stats[0], cocoEval.stats[1], info
  611. else:
  612. return 0, 0, info