From e447e2f8f980d304e9a963b57ffba363addf25c7 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Mon, 27 Sep 2021 17:40:20 -0700 Subject: [PATCH] Allow YOLOv5 execution from arbitrary `cwd` (#4954) * Allow YOLOv5 execution from arbitrary `cwd` * Fix str bugs --- detect.py | 14 ++++++++------ export.py | 1 + train.py | 14 ++++++++------ val.py | 11 ++++++----- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/detect.py b/detect.py index fae82833c5f6..75ec3ecc5ff3 100644 --- a/detect.py +++ b/detect.py @@ -19,6 +19,7 @@ ROOT = FILE.parents[0] # YOLOv5 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = ROOT.relative_to(Path.cwd()) # relative from models.experimental import attempt_load from utils.datasets import LoadImages, LoadStreams @@ -30,8 +31,8 @@ @torch.no_grad() -def run(weights='yolov5s.pt', # model.pt path(s) - source='data/images', # file/dir/URL/glob, 0 for webcam +def run(weights=ROOT / 'yolov5s.pt', # model.pt path(s) + source=ROOT / 'data/images', # file/dir/URL/glob, 0 for webcam imgsz=640, # inference size (pixels) conf_thres=0.25, # confidence threshold iou_thres=0.45, # NMS IOU threshold @@ -47,7 +48,7 @@ def run(weights='yolov5s.pt', # model.pt path(s) augment=False, # augmented inference visualize=False, # visualize features update=False, # update all models - project='runs/detect', # save results to project/name + project=ROOT / 'runs/detect', # save results to project/name name='exp', # save results to project/name exist_ok=False, # existing project/name ok, do not increment line_thickness=3, # bounding box thickness (pixels) @@ -55,6 +56,7 @@ def run(weights='yolov5s.pt', # model.pt path(s) hide_conf=False, # hide confidences half=False, # use FP16 half-precision inference ): + source = str(source) save_img = not nosave and not source.endswith('.txt') # save inference images webcam = source.isnumeric() or source.endswith('.txt') or source.lower().startswith( ('rtsp://', 'rtmp://', 'http://', 'https://')) @@ -254,8 +256,8 @@ def wrap_frozen_graph(gd, inputs, outputs): def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model path(s)') - parser.add_argument('--source', type=str, default='data/images', help='file/dir/URL/glob, 0 for webcam') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model path(s)') + parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam') parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w') parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold') parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold') @@ -271,7 +273,7 @@ def parse_opt(): parser.add_argument('--augment', action='store_true', help='augmented inference') parser.add_argument('--visualize', action='store_true', help='visualize features') parser.add_argument('--update', action='store_true', help='update all models') - parser.add_argument('--project', default='runs/detect', help='save results to project/name') + parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name') parser.add_argument('--name', default='exp', help='save results to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)') diff --git a/export.py b/export.py index d5b63c410af8..74aca4b6c30a 100644 --- a/export.py +++ b/export.py @@ -34,6 +34,7 @@ ROOT = FILE.parents[0] # YOLOv5 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = ROOT.relative_to(Path.cwd()) # relative from models.common import Conv from models.experimental import attempt_load diff --git a/train.py b/train.py index 40f58bfafb4a..39fe1a0cb14b 100644 --- a/train.py +++ b/train.py @@ -30,6 +30,7 @@ ROOT = FILE.parents[0] # YOLOv5 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = ROOT.relative_to(Path.cwd()) # relative import val # for end-of-epoch mAP from models.experimental import attempt_load @@ -429,10 +430,10 @@ def train(hyp, # path/to/hyp.yaml or hyp dictionary def parse_opt(known=False): parser = argparse.ArgumentParser() - parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path') + parser.add_argument('--weights', type=str, default=ROOT / 'yolov5s.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='', help='model.yaml path') - parser.add_argument('--data', type=str, default='data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--hyp', type=str, default='data/hyps/hyp.scratch.yaml', help='hyperparameters path') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--hyp', type=str, default=ROOT / 'data/hyps/hyp.scratch.yaml', help='hyperparameters path') parser.add_argument('--epochs', type=int, default=300) parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs') parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)') @@ -451,8 +452,8 @@ def parse_opt(known=False): parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer') parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') - parser.add_argument('--project', default='runs/train', help='save to project/name') parser.add_argument('--entity', default=None, help='W&B entity') + parser.add_argument('--project', default=ROOT / 'runs/train', help='save to project/name') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--quad', action='store_true', help='quad dataloader') @@ -486,10 +487,11 @@ def main(opt, callbacks=Callbacks()): opt.cfg, opt.weights, opt.resume = '', ckpt, True # reinstate LOGGER.info(f'Resuming training from {ckpt}') else: - opt.data, opt.cfg, opt.hyp = check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp) # check YAMLs + opt.data, opt.cfg, opt.hyp, opt.weights, opt.project = \ + check_file(opt.data), check_yaml(opt.cfg), check_yaml(opt.hyp), str(opt.weights), str(opt.project) # checks assert len(opt.cfg) or len(opt.weights), 'either --cfg or --weights must be specified' if opt.evolve: - opt.project = 'runs/evolve' + opt.project = str(ROOT / 'runs/evolve') opt.exist_ok, opt.resume = opt.resume, False # pass resume to exist_ok and disable resume opt.save_dir = str(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) diff --git a/val.py b/val.py index 92e0e3b13ae9..4f0b49ae2ca7 100644 --- a/val.py +++ b/val.py @@ -21,6 +21,7 @@ ROOT = FILE.parents[0] # YOLOv5 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH +ROOT = ROOT.relative_to(Path.cwd()) # relative from models.experimental import attempt_load from utils.datasets import create_dataloader @@ -95,7 +96,7 @@ def run(data, save_hybrid=False, # save label+prediction hybrid results to *.txt save_conf=False, # save confidences in --save-txt labels save_json=False, # save a COCO-JSON results file - project='runs/val', # save to project/name + project=ROOT / 'runs/val', # save to project/name name='exp', # save to project/name exist_ok=False, # existing project/name ok, do not increment half=True, # use FP16 half-precision inference @@ -297,8 +298,8 @@ def run(data, def parse_opt(): parser = argparse.ArgumentParser() - parser.add_argument('--data', type=str, default='data/coco128.yaml', help='dataset.yaml path') - parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model.pt path(s)') + parser.add_argument('--data', type=str, default=ROOT / 'data/coco128.yaml', help='dataset.yaml path') + parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model.pt path(s)') parser.add_argument('--batch-size', type=int, default=32, help='batch size') parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='inference size (pixels)') parser.add_argument('--conf-thres', type=float, default=0.001, help='confidence threshold') @@ -312,14 +313,14 @@ def parse_opt(): parser.add_argument('--save-hybrid', action='store_true', help='save label+prediction hybrid results to *.txt') parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels') parser.add_argument('--save-json', action='store_true', help='save a COCO-JSON results file') - parser.add_argument('--project', default='runs/val', help='save to project/name') + parser.add_argument('--project', default=ROOT / 'runs/val', help='save to project/name') parser.add_argument('--name', default='exp', help='save to project/name') parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment') parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference') opt = parser.parse_args() + opt.data = check_yaml(opt.data) # check YAML opt.save_json |= opt.data.endswith('coco.yaml') opt.save_txt |= opt.save_hybrid - opt.data = check_yaml(opt.data) # check YAML print_args(FILE.stem, opt) return opt