A predictor that runs the model asynchronously, possibly on >1 GPUs. Because rendering the visualization takes considerably amount of time, this helps improve throughput a little bit when rendering videos.
| 135 | |
| 136 | |
| 137 | class AsyncPredictor: |
| 138 | """ |
| 139 | A predictor that runs the model asynchronously, possibly on >1 GPUs. |
| 140 | Because rendering the visualization takes considerably amount of time, |
| 141 | this helps improve throughput a little bit when rendering videos. |
| 142 | """ |
| 143 | |
| 144 | class _StopToken: |
| 145 | pass |
| 146 | |
| 147 | class _PredictWorker(mp.Process): |
| 148 | def __init__(self, cfg, task_queue, result_queue): |
| 149 | self.cfg = cfg |
| 150 | self.task_queue = task_queue |
| 151 | self.result_queue = result_queue |
| 152 | super().__init__() |
| 153 | |
| 154 | def run(self): |
| 155 | predictor = DefaultPredictor(self.cfg) |
| 156 | |
| 157 | while True: |
| 158 | task = self.task_queue.get() |
| 159 | if isinstance(task, AsyncPredictor._StopToken): |
| 160 | break |
| 161 | idx, data = task |
| 162 | result = predictor(data) |
| 163 | self.result_queue.put((idx, result)) |
| 164 | |
| 165 | def __init__(self, cfg, num_gpus: int = 1): |
| 166 | """ |
| 167 | Args: |
| 168 | cfg (CfgNode): |
| 169 | num_gpus (int): if 0, will run on CPU |
| 170 | """ |
| 171 | num_workers = max(num_gpus, 1) |
| 172 | self.task_queue = mp.Queue(maxsize=num_workers * 3) |
| 173 | self.result_queue = mp.Queue(maxsize=num_workers * 3) |
| 174 | self.procs = [] |
| 175 | for gpuid in range(max(num_gpus, 1)): |
| 176 | cfg = cfg.clone() |
| 177 | cfg.defrost() |
| 178 | cfg.MODEL.DEVICE = "cuda:{}".format(gpuid) if num_gpus > 0 else "cpu" |
| 179 | self.procs.append( |
| 180 | AsyncPredictor._PredictWorker(cfg, self.task_queue, self.result_queue) |
| 181 | ) |
| 182 | |
| 183 | self.put_idx = 0 |
| 184 | self.get_idx = 0 |
| 185 | self.result_rank = [] |
| 186 | self.result_data = [] |
| 187 | |
| 188 | for p in self.procs: |
| 189 | p.start() |
| 190 | atexit.register(self.shutdown) |
| 191 | |
| 192 | def put(self, image): |
| 193 | self.put_idx += 1 |
| 194 | self.task_queue.put((self.put_idx, image)) |