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.

meta_yolox_base.py 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. # Mahdi Abdollahpour, 27/11/2021, 02:42 PM, PyCharm, ByteTrack
  2. import torch
  3. import torch.distributed as dist
  4. import torch.nn as nn
  5. import os
  6. import random
  7. from .base_meta_exp import BaseMetaExp
  8. import learn2learn as l2l
  9. class MetaExp(BaseMetaExp):
  10. def __init__(self):
  11. super().__init__()
  12. # ---------------- model config ---------------- #
  13. self.num_classes = 80
  14. self.depth = 1.00
  15. self.width = 1.00
  16. # ---------------- dataloader config ---------------- #
  17. # set worker to 4 for shorter dataloader init time
  18. # TODO: deal with this multi threading
  19. self.data_num_workers = 4
  20. self.input_size = (640, 640)
  21. self.random_size = (14, 26)
  22. self.train_anns = ["instances_train2017.json"]
  23. self.val_anns = ["instances_val2017.json"]
  24. # --------------- transform config ----------------- #
  25. self.degrees = 10.0
  26. self.translate = 0.1
  27. self.scale = (0.1, 2)
  28. self.mscale = (0.8, 1.6)
  29. self.shear = 2.0
  30. self.perspective = 0.0
  31. self.enable_mixup = True
  32. # -------------- training config --------------------- #
  33. self.warmup_epochs = 5
  34. self.max_epoch = 300
  35. self.warmup_lr = 0
  36. self.basic_lr_per_img = 0.01 / 64.0
  37. self.scheduler = "yoloxwarmcos"
  38. self.no_aug_epochs = 15
  39. self.min_lr_ratio = 0.05
  40. self.ema = True
  41. self.weight_decay = 5e-4
  42. self.momentum = 0.9
  43. self.print_interval = 10
  44. self.eval_interval = 10
  45. self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0]
  46. # ----------------- testing config ------------------ #
  47. self.test_size = (640, 640)
  48. self.test_conf = 0.001
  49. self.nmsthre = 0.65
  50. # ----------------- Meta-learning ------------------ #
  51. self.first_order = True
  52. self.inner_lr = 1e-6
  53. # self.inner_lr = 1e-8
  54. def get_model(self):
  55. from yolox.models import YOLOPAFPN, YOLOX, YOLOXHead
  56. def init_yolo(M):
  57. for m in M.modules():
  58. if isinstance(m, nn.BatchNorm2d):
  59. m.eps = 1e-3
  60. m.momentum = 0.03
  61. if getattr(self, "model", None) is None:
  62. in_channels = [256, 512, 1024]
  63. backbone = YOLOPAFPN(self.depth, self.width, in_channels=in_channels)
  64. head = YOLOXHead(self.num_classes, self.width, in_channels=in_channels)
  65. self.model = YOLOX(backbone, head)
  66. self.model.apply(init_yolo)
  67. self.model.head.initialize_biases(1e-2)
  68. return self.model
  69. def get_data_loaders(self, batch_size, is_distributed, no_aug=False):
  70. from yolox.data import (
  71. COCODataset,
  72. DataLoader,
  73. InfiniteSampler,
  74. MosaicDetection,
  75. TrainTransform,
  76. YoloBatchSampler
  77. )
  78. train_loaders = []
  79. for train_ann in self.train_anns:
  80. dataset = COCODataset(
  81. data_dir=None,
  82. json_file=train_ann,
  83. img_size=self.input_size,
  84. preproc=TrainTransform(
  85. rgb_means=(0.485, 0.456, 0.406),
  86. std=(0.229, 0.224, 0.225),
  87. max_labels=50,
  88. ),
  89. )
  90. dataset = MosaicDetection(
  91. dataset,
  92. mosaic=not no_aug,
  93. img_size=self.input_size,
  94. preproc=TrainTransform(
  95. rgb_means=(0.485, 0.456, 0.406),
  96. std=(0.229, 0.224, 0.225),
  97. max_labels=120,
  98. ),
  99. degrees=self.degrees,
  100. translate=self.translate,
  101. scale=self.scale,
  102. shear=self.shear,
  103. perspective=self.perspective,
  104. enable_mixup=self.enable_mixup,
  105. )
  106. self.dataset = dataset
  107. if is_distributed:
  108. batch_size = batch_size // dist.get_world_size()
  109. sampler = InfiniteSampler(len(self.dataset), seed=self.seed if self.seed else 0)
  110. batch_sampler = YoloBatchSampler(
  111. sampler=sampler,
  112. batch_size=batch_size,
  113. drop_last=False,
  114. input_dimension=self.input_size,
  115. mosaic=not no_aug,
  116. )
  117. dataloader_kwargs = {"num_workers": self.data_num_workers, "pin_memory": True}
  118. dataloader_kwargs["batch_sampler"] = batch_sampler
  119. train_loader = DataLoader(self.dataset, **dataloader_kwargs)
  120. train_loaders.append(train_loader)
  121. return train_loaders
  122. def random_resize(self, data_loader, epoch, rank, is_distributed):
  123. tensor = torch.LongTensor(2).cuda()
  124. if rank == 0:
  125. size_factor = self.input_size[1] * 1.0 / self.input_size[0]
  126. size = random.randint(*self.random_size)
  127. size = (int(32 * size), 32 * int(size * size_factor))
  128. tensor[0] = size[0]
  129. tensor[1] = size[1]
  130. if is_distributed:
  131. dist.barrier()
  132. dist.broadcast(tensor, 0)
  133. input_size = data_loader.change_input_dim(
  134. multiple=(tensor[0].item(), tensor[1].item()), random_range=None
  135. )
  136. return input_size
  137. def get_optimizer(self, batch_size):
  138. if "optimizer" not in self.__dict__:
  139. if self.warmup_epochs > 0:
  140. lr = self.warmup_lr
  141. else:
  142. lr = self.basic_lr_per_img * batch_size
  143. pg0, pg1, pg2 = [], [], [] # optimizer parameter groups
  144. for k, v in self.model.named_modules():
  145. if hasattr(v, "bias") and isinstance(v.bias, nn.Parameter):
  146. pg2.append(v.bias) # biases
  147. if isinstance(v, nn.BatchNorm2d) or "bn" in k:
  148. pg0.append(v.weight) # no decay
  149. elif hasattr(v, "weight") and isinstance(v.weight, nn.Parameter):
  150. pg1.append(v.weight) # apply decay
  151. optimizer = torch.optim.SGD(
  152. pg0, lr=lr, momentum=self.momentum, nesterov=True
  153. )
  154. optimizer.add_param_group(
  155. {"params": pg1, "weight_decay": self.weight_decay}
  156. ) # add pg1 with weight_decay
  157. optimizer.add_param_group({"params": pg2})
  158. self.all_parameters = pg0 + pg1 + pg2
  159. self.optimizer = optimizer
  160. return self.optimizer
  161. def get_lr_scheduler(self, lr, iters_per_epoch):
  162. from yolox.utils import LRScheduler
  163. scheduler = LRScheduler(
  164. self.scheduler,
  165. lr,
  166. iters_per_epoch,
  167. self.max_epoch,
  168. warmup_epochs=self.warmup_epochs,
  169. warmup_lr_start=self.warmup_lr,
  170. no_aug_epochs=self.no_aug_epochs,
  171. min_lr_ratio=self.min_lr_ratio,
  172. )
  173. return scheduler
  174. def get_eval_loaders(self, batch_size, is_distributed, testdev=False):
  175. from yolox.data import COCODataset, ValTransform
  176. val_loaders = []
  177. for val_ann in self.val_anns:
  178. valdataset = COCODataset(
  179. data_dir=None,
  180. json_file=val_ann if not testdev else "image_info_test-dev2017.json",
  181. name="val2017" if not testdev else "test2017",
  182. img_size=self.test_size,
  183. preproc=ValTransform(
  184. rgb_means=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)
  185. ),
  186. )
  187. if is_distributed:
  188. batch_size = batch_size // dist.get_world_size()
  189. sampler = torch.utils.data.distributed.DistributedSampler(
  190. valdataset, shuffle=False
  191. )
  192. else:
  193. sampler = torch.utils.data.SequentialSampler(valdataset)
  194. dataloader_kwargs = {
  195. "num_workers": self.data_num_workers,
  196. "pin_memory": True,
  197. "sampler": sampler,
  198. }
  199. dataloader_kwargs["batch_size"] = batch_size
  200. val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs)
  201. val_loaders.append(val_loader)
  202. return val_loaders
  203. def get_evaluators(self, batch_size, is_distributed, testdev=False):
  204. from yolox.evaluators import COCOEvaluator
  205. val_loaders = self.get_eval_loaders(batch_size, is_distributed, testdev=testdev)
  206. evaluators = []
  207. for val_loader in val_loaders:
  208. evaluator = COCOEvaluator(
  209. dataloader=val_loader,
  210. img_size=self.test_size,
  211. confthre=self.test_conf,
  212. nmsthre=self.nmsthre,
  213. num_classes=self.num_classes,
  214. testdev=testdev,
  215. )
  216. evaluators.append(evaluator)
  217. return evaluators
  218. def eval(self, model, evaluators, is_distributed, half=False):
  219. ap50_95s = 0.0
  220. ap50s = 0.0
  221. summarys = ''
  222. for evaluator in evaluators:
  223. ap50_95, ap50, summary = evaluator.evaluate(model, is_distributed, half)
  224. ap50_95s += ap50_95
  225. ap50s += ap50
  226. summarys += ("\n" + summary)
  227. n = len(evaluators)
  228. return (ap50_95s / n), (ap50s / n), summarys