def test_ctdet_decode(): np.random.seed(32) hm = np.random.randn(2, 64, 64, 80) reg = np.random.randn(2, 64, 64, 2) * 10.0 wh = np.random.randn(2, 64, 64, 2) * 20.0 keras_hm = K.constant(hm) keras_reg = K.constant(reg) keras_wh = K.constant(wh) keras_detections = K.eval( _ctdet_decode(keras_hm, keras_reg, keras_wh, output_stride=1)) gold_fn = 'path_for_colab/tests/data/ctdet_decode_gold.p' if not os.path.exists(gold_fn): import torch as th import sys sys.path.append(os.path.expanduser('~/Pytorch/CenterNet/src')) from lib.models.decode import ctdet_decode # noqa py_hm = th.from_numpy(hm.transpose(0, 3, 1, 2)).float() py_hm.sigmoid_() py_reg = th.from_numpy(reg.transpose(0, 3, 1, 2)).float() py_wh = th.from_numpy(wh.transpose(0, 3, 1, 2)).float() py_detections = ctdet_decode(py_hm, py_reg, py_wh).detach().numpy() with open(gold_fn, 'wb') as f: pickle.dump(py_detections, f) else: with open(gold_fn, 'rb') as f: py_detections = pickle.load(f) assert np.allclose(keras_detections, py_detections)
def save_result1(self, outputs, batch, results): # 这里的outputs包含model输出的所有特征图(3个特征图) # 对每一个output特征图都计算dets_out,然后将3个dets_out整合起来,根据score来排序,然后用NMS或者其他方法来过滤!!! dets_list = [] dets_score_list = [] for idx in range(len(outputs)): output = outputs[idx] reg = output['reg'] if self.opt.reg_offset else None dets = ctdet_decode(output['hm'], output['wh'], reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) dets = dets.detach().cpu().numpy().reshape(1, -1, dets.shape[2]) # print(type(dets), dets.shape) dets_list.append(dets) dets_300 = np.concatenate( (dets_list[0], dets_list[1], dets_list[2]), axis=1) # 将3个dets:array[1,100,6]连接起来成为dets_300:array[1,300,6] dets_300_sort = dets_300.copy() array_for_sort = dets_300.reshape( -1, dets.shape[2])[:, :5] # 将dets_300的最后一列改变成score,方便下面排序 sort_idx = np.lexsort( -array_for_sort.T) # sort_idx是dets_300按照score从大到小排序的索引 # print(array_for_sort.shape, sort_idx) for key, item in enumerate(sort_idx): dets_300_sort[0][key] = dets_300[0][ item] # 将排序后的numpy数组保存到 dets_300_sort # print(dets_300_sort.shape, dets_300_sort[0][0][4],dets_300_sort[0][101][4]) # dets_300_sort = dets_300_sort[:,:100,:] # 检测结果只取前100?? dets = dets_300_sort # 这个命名只是为了不改下面的两个语句中的变量名 dets_outs = ctdet_post_process(dets.copy(), batch['meta']['c'].cpu().numpy(), batch['meta']['s'].cpu().numpy(), output['hm'].shape[2], output['hm'].shape[3], output['hm'].shape[1]) for j in range(1, self.opt.num_classes + 1): # 给数组reshape一下,要不然不符合NMS需要输入2维数组的输入要求 dets_outs[0][j] = np.array(dets_outs[0][j], dtype=np.float32).reshape(-1, 5) # print(type(dets_outs),len(dets_outs[0])) results_nms = {} for j in range(1, self.opt.num_classes + 1): results_nms[j] = np.concatenate( [dets_out[j] for dets_out in dets_outs], axis=0).astype(np.float32) # print(j, results_nms[j]) soft_nms(results_nms[j], Nt=0.5, method=2) # print(111, type(dets_outs[0]), dets_outs[0].keys()) # print(222, type(results_nms), results_nms.keys()) # results_nms是dets_outs[0]经过NMS之后得到的结果 # results[batch['meta']['img_id'].cpu().numpy()[0]] = dets_outs[0] results[batch['meta']['img_id'].cpu().numpy()[0]] = results_nms
def save_result(self, output, batch, results): reg = output['reg'] if self.opt.reg_offset else None dets = ctdet_decode(output['hm'], output['wh'], reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) dets = dets.detach().cpu().numpy().reshape(1, -1, dets.shape[2]) dets_out = ctdet_post_process(dets.copy(), batch['meta']['c'].cpu().numpy(), batch['meta']['s'].cpu().numpy(), output['hm'].shape[2], output['hm'].shape[3], output['hm'].shape[1]) results[batch['meta']['img_id'].cpu().numpy()[0]] = dets_out[0]
def process(self, images, return_time=False): with torch.no_grad(): output = self.model(images)[-1] hm = output['hm'].sigmoid_() wh = output['wh'] # reg = output['reg'] torch.cuda.synchronize() forward_time = time.time() # dets = ctdet_decode(hm, wh, reg=reg) dets = ctdet_decode(hm, wh) if return_time: return output, dets, forward_time else: return output, dets
def debug(self, batch, output, iter_id): opt = self.opt reg = output['reg'] if opt.reg_offset else None dets = ctdet_decode(output['hm'], output['wh'], reg=reg, cat_spec_wh=opt.cat_spec_wh, K=opt.K) dets = dets.detach().cpu().numpy().reshape(1, -1, dets.shape[2]) dets[:, :, :4] *= opt.down_ratio dets_gt = batch['meta']['gt_det'].numpy().reshape(1, -1, dets.shape[2]) dets_gt[:, :, :4] *= opt.down_ratio for i in range(1): debugger = Debugger(dataset=opt.dataset, ipynb=(opt.debug == 3), theme=opt.debugger_theme) img = batch['input'][i].detach().cpu().numpy().transpose(1, 2, 0) img = np.clip(((img * opt.std + opt.mean) * 255.), 0, 255).astype(np.uint8) pred = debugger.gen_colormap( output['hm'][i].detach().cpu().numpy()) gt = debugger.gen_colormap(batch['hm'][i].detach().cpu().numpy()) debugger.add_blend_img(img, pred, 'pred_hm') debugger.add_blend_img(img, gt, 'gt_hm') debugger.add_img(img, img_id='out_pred') for k in range(len(dets[i])): if dets[i, k, 4] > opt.center_thresh: # add_coco_bbox(bbox, cat, conf=1, show_txt=True, img_id='default'): debugger.add_coco_bbox(dets[i, k, :4], dets[i, k, -1], dets[i, k, 4], img_id='out_pred') debugger.add_img(img, img_id='out_gt') for k in range(len(dets_gt[i])): if dets_gt[i, k, 4] > opt.center_thresh: # add_coco_bbox(bbox, cat, conf=1, show_txt=True, img_id='default'): debugger.add_coco_bbox(dets_gt[i, k, :4], dets_gt[i, k, -1], dets_gt[i, k, 4], img_id='out_gt') if opt.debug == 4: debugger.save_all_imgs(opt.debug_dir, prefix='{}'.format(iter_id)) else: debugger.show_all_imgs(pause=True)
def process(self, images, return_time=False): with torch.no_grad(): output = self.model(images)[-1] hm = output['hm'].sigmoid_() wh = output['wh'] reg = output['reg'] if self.opt.reg_offset else None if self.opt.flip_test: hm = (hm[0:1] + flip_tensor(hm[1:2])) / 2 wh = (wh[0:1] + flip_tensor(wh[1:2])) / 2 reg = reg[0:1] if reg is not None else None torch.cuda.synchronize() forward_time = time.time() dets = ctdet_decode(hm, wh, reg=reg, K=self.opt.K) if return_time: return output, dets, forward_time else: return output, dets
def save_result(self, output, batch, results): # 能不能尽量不改这里面的小函数,只改变针对函数的输入????? # print(output['hm'].size(), output['wh'].size(), output['reg'].size()) # [1, 20, 128, 128] [1, 2, 128, 128] [1, 2, 128, 128] reg = output[ 'reg'] if self.opt.reg_offset else None # self.opt.reg_offset = True dets = ctdet_decode(output['hm'], output['wh'], reg=reg, cat_spec_wh=self.opt.cat_spec_wh, K=self.opt.K) # print(dets.size()) #[1, 100, 6] ,其中的6代表了 [tlx, tly, brx, bry, scores, clses], 按照score的高低排序 dets = dets.detach().cpu().numpy().reshape( 1, -1, dets.shape[2]) # detach()用来切断梯度的传播 # print(dets.shape) #(1, 100, 6) dets_out = ctdet_post_process(dets.copy(), batch['meta']['c'].cpu().numpy(), batch['meta']['s'].cpu().numpy(), output['hm'].shape[2], output['hm'].shape[3], output['hm'].shape[1]) # print(len(dets_out), dets_out) # len(dets_out) = 1 ; dets_out = [{1: [...], 2: [], 3: [[130.917, 491.190, 285.635, 504.33, 0.797]], 4: [...],...}, 20: [...]] results[batch['meta']['img_id'].cpu().numpy()[0]] = dets_out[0]
def val(self, epoch, data_loader): model_with_loss = self.model_with_loss if len(self.opt.gpus) > 1: model_with_loss = self.model_with_loss.module model_with_loss.eval() torch.cuda.empty_cache() opt = self.opt results = {} data_time, batch_time = AverageMeter(), AverageMeter() avg_loss_stats = {l: AverageMeter() for l in self.loss_stats} num_iters = len(data_loader) if opt.num_iters < 0 else opt.num_iters bar = Bar('{}/{}'.format(opt.task, opt.exp_id), max=num_iters) end = time.time() for iter_id, batch in enumerate(data_loader): if iter_id >= num_iters: break data_time.update(time.time() - end) for k in batch: if k != 'meta': batch[k] = batch[k].to(device=opt.device, non_blocking=True) output, loss, loss_stats = model_with_loss(batch) results.setdefault('img_id', []).extend(batch['meta']['img_id']) boxes = ctdet_decode(output['hm'], output['wh'], output['reg'], K=self.opt.K) meta = batch['meta'] c = meta['c'].numpy() s = meta['s'].numpy() _, _, out_h, out_w = output['hm'].shape dets = ctdet_post_process(boxes.cpu().numpy(), [c], [s], out_h, out_w, opt.num_classes) # breakpoint() results.setdefault('detections', []).extend(dets) loss = loss.mean() batch_time.update(time.time() - end) end = time.time() Bar.suffix = '{phase}: [{0}][{1}/{2}]|Tot: {total:} |ETA: {eta:} '.format( epoch, iter_id, num_iters, phase='val', total=bar.elapsed_td, eta=bar.eta_td) for l in avg_loss_stats: # breakpoint() loss_t = loss_stats[l] or torch.zeros(1) avg_loss_stats[l].update(loss_t.mean().item(), batch['input'].size(0)) Bar.suffix += '|{} {:.4f} '.format(l, avg_loss_stats[l].avg) self.val_writer.add_scalar(l, avg_loss_stats[l].avg, self.global_steps, 1) if not opt.hide_data_time: Bar.suffix = Bar.suffix + '|Data {dt.val:.3f}s({dt.avg:.3f}s) ' \ '|Net {bt.avg:.3f}s'.format(dt=data_time, bt=batch_time) if opt.print_iter > 0: if iter_id % opt.print_iter == 0: print('{}/{}| {}'.format(opt.task, opt.exp_id, Bar.suffix)) else: bar.next() if opt.debug > 0: self.debug(batch, output, iter_id) if opt.test: self.save_result(output, batch, results) del output, loss, loss_stats # break ret = {k: v.avg for k, v in avg_loss_stats.items()} for l in avg_loss_stats: self.val_writer.add_scalar(l, avg_loss_stats[l].avg, self.global_steps) bar.next() bar.finish() ret['time'] = bar.elapsed_td.total_seconds() / 60. return ret, results