WongKinYiu / yolov9

Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information
GNU General Public License v3.0
8.89k stars 1.4k forks source link

AttributeError: 'list' object has no attribute 'device' #363

Open roscoekerby opened 5 months ago

roscoekerby commented 5 months ago

On inference: !python detect.py --source '/content/yolov9/woman-5059062_960_720.jpg' --img 640 --device 0 --weights '/content/yolov9/yolov9-e.pt' --name yolov9_c_c_640_detect

Getting output error: AttributeError: 'list' object has no attribute 'device'

detect: weights=['/content/yolov9/yolov9-e.pt'], source=/content/yolov9/woman-5059062_960_720.jpg, data=data/coco128.yaml, imgsz=[640, 640], conf_thres=0.25, iou_thres=0.45, max_det=1000, device=0, view_img=False, save_txt=False, save_conf=False, save_crop=False, nosave=False, classes=None, agnostic_nms=False, augment=False, visualize=False, update=False, project=runs/detect, name=yolov9_c_c_640_detect, exist_ok=False, line_thickness=3, hide_labels=False, hide_conf=False, half=False, dnn=False, vid_stride=1 YOLO 🚀 v0.1-88-g03f920b Python-3.10.12 torch-2.2.1+cu121 CUDA:0 (Tesla T4, 15102MiB)

Fusing layers... Model summary: 839 layers, 68669632 parameters, 0 gradients Traceback (most recent call last): File "/content/yolov9/detect.py", line 231, in main(opt) File "/content/yolov9/detect.py", line 226, in main run(*vars(opt)) File "/usr/local/lib/python3.10/dist-packages/torch/utils/_contextlib.py", line 115, in decorate_context return func(args, **kwargs) File "/content/yolov9/detect.py", line 102, in run pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) File "/content/yolov9/utils/general.py", line 905, in non_max_suppression device = prediction.device AttributeError: 'list' object has no attribute 'device'

roscoekerby commented 5 months ago
for pred in prediction:

iterating over the prediction and swapping out 'prediction' with pred in general.py fixes this issue

"""Non-Maximum Suppression (NMS) on inference results to reject overlapping detections

Returns:
     list of detections, on (n,6) tensor per image [xyxy, conf, cls]
"""

if isinstance(prediction, (list, tuple)):  # YOLO model in validation model, output = (inference_out, loss_out)
    prediction = prediction[0]  # select only inference output

for pred in prediction:
  device = pred.device
  mps = 'mps' in device.type  # Apple MPS
  if mps:  # MPS not fully supported yet, convert tensors to CPU before NMS
      pred = pred.cpu()
  bs = pred.shape[0]  # batch size
  nc = pred.shape[1] - nm - 4  # number of classes
  mi = 4 + nc  # mask start index
  xc = pred[:, 4:mi].amax(1) > conf_thres  # candidates

  # Checks
  assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0'
  assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0'

  # Settings
  # min_wh = 2  # (pixels) minimum box width and height
  max_wh = 7680  # (pixels) maximum box width and height
  max_nms = 30000  # maximum number of boxes into torchvision.ops.nms()
  time_limit = 2.5 + 0.05 * bs  # seconds to quit after
  redundant = True  # require redundant detections
  multi_label &= nc > 1  # multiple labels per box (adds 0.5ms/img)
  merge = False  # use merge-NMS

  t = time.time()
  output = [torch.zeros((0, 6 + nm), device=pred.device)] * bs
  for xi, x in enumerate(pred):  # image index, image inference
      # Apply constraints
      # x[((x[:, 2:4] < min_wh) | (x[:, 2:4] > max_wh)).any(1), 4] = 0  # width-height
      x = x.T[xc[xi]]  # confidence

      # Cat apriori labels if autolabelling
      if labels and len(labels[xi]):
          lb = labels[xi]
          v = torch.zeros((len(lb), nc + nm + 5), device=x.device)
          v[:, :4] = lb[:, 1:5]  # box
          v[range(len(lb)), lb[:, 0].long() + 4] = 1.0  # cls
          x = torch.cat((x, v), 0)

      # If none remain process next image
      if not x.shape[0]:
          continue

      # Detections matrix nx6 (xyxy, conf, cls)
      box, cls, mask = x.split((4, nc, nm), 1)
      box = xywh2xyxy(box)  # center_x, center_y, width, height) to (x1, y1, x2, y2)
      if multi_label:
          i, j = (cls > conf_thres).nonzero(as_tuple=False).T
          x = torch.cat((box[i], x[i, 4 + j, None], j[:, None].float(), mask[i]), 1)
      else:  # best class only
          conf, j = cls.max(1, keepdim=True)
          x = torch.cat((box, conf, j.float(), mask), 1)[conf.view(-1) > conf_thres]

      # Filter by class
      if classes is not None:
          x = x[(x[:, 5:6] == torch.tensor(classes, device=x.device)).any(1)]

      # Apply finite constraint
      # if not torch.isfinite(x).all():
      #     x = x[torch.isfinite(x).all(1)]

      # Check shape
      n = x.shape[0]  # number of boxes
      if not n:  # no boxes
          continue
      elif n > max_nms:  # excess boxes
          x = x[x[:, 4].argsort(descending=True)[:max_nms]]  # sort by confidence
      else:
          x = x[x[:, 4].argsort(descending=True)]  # sort by confidence

      # Batched NMS
      c = x[:, 5:6] * (0 if agnostic else max_wh)  # classes
      boxes, scores = x[:, :4] + c, x[:, 4]  # boxes (offset by class), scores
      i = torchvision.ops.nms(boxes, scores, iou_thres)  # NMS
      if i.shape[0] > max_det:  # limit detections
          i = i[:max_det]
      if merge and (1 < n < 3E3):  # Merge NMS (boxes merged using weighted mean)
          # update boxes as boxes(i,4) = weights(i,n) * boxes(n,4)
          iou = box_iou(boxes[i], boxes) > iou_thres  # iou matrix
          weights = iou * scores[None]  # box weights
          x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True)  # merged boxes
          if redundant:
              i = i[iou.sum(1) > 1]  # require redundancy

      output[xi] = x[i]
      if mps:
          output[xi] = output[xi].to(device)
      if (time.time() - t) > time_limit:
          LOGGER.warning(f'WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded')
          break  # time limit exceeded

return output
roscoekerby commented 5 months ago

Easier fix: prediction = prediction[0][0] # select only inference output Line 903 in general.py