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