* initial commit * remove yolov3-spp from test.py study * update study --img range * update mAP * cleanup and speed updates * update README plot5.0
# Build and Push | # Build and Push | ||||
# t=ultralytics/yolov5:latest && sudo docker build -t $t . && sudo docker push $t | # t=ultralytics/yolov5:latest && sudo docker build -t $t . && sudo docker push $t | ||||
# for v in {300..303}; do t=ultralytics/coco:v$v && sudo docker build -t $t . && sudo docker push $t; done | |||||
# Pull and Run | # Pull and Run | ||||
# t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host $t | # t=ultralytics/yolov5:latest && sudo docker pull $t && sudo docker run -it --ipc=host $t | ||||
# sudo docker commit 092b16b25c5b usr/resume && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco --entrypoint=sh usr/resume | # sudo docker commit 092b16b25c5b usr/resume && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco --entrypoint=sh usr/resume | ||||
# Send weights to GCP | # Send weights to GCP | ||||
# python -c "from utils.general import *; strip_optimizer('runs/exp0_*/weights/last.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://* | |||||
# python -c "from utils.general import *; strip_optimizer('runs/exp0_*/weights/best.pt', 'tmp.pt')" && gsutil cp tmp.pt gs://*.pt | |||||
# Clean up | # Clean up | ||||
# docker system prune -a --volumes | # docker system prune -a --volumes |
This repository represents Ultralytics open-source research into future object detection methods, and incorporates our lessons learned and best practices evolved over training thousands of models on custom client datasets with our previous YOLO repository https://github.com/ultralytics/yolov3. **All code and models are under active development, and are subject to modification or deletion without notice.** Use at your own risk. | This repository represents Ultralytics open-source research into future object detection methods, and incorporates our lessons learned and best practices evolved over training thousands of models on custom client datasets with our previous YOLO repository https://github.com/ultralytics/yolov3. **All code and models are under active development, and are subject to modification or deletion without notice.** Use at your own risk. | ||||
<img src="https://user-images.githubusercontent.com/26833433/85340570-30360a80-b49b-11ea-87cf-bdf33d53ae15.png" width="1000">** GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 8, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. | |||||
<img src="https://user-images.githubusercontent.com/26833433/90187293-6773ba00-dd6e-11ea-8f90-cd94afc0427f.png" width="1000">** GPU Speed measures end-to-end time per image averaged over 5000 COCO val2017 images using a V100 GPU with batch size 32, and includes image preprocessing, PyTorch FP16 inference, postprocessing and NMS. EfficientDet data from [google/automl](https://github.com/google/automl) at batch size 8. | |||||
- **August 13, 2020**: [v3.0 release](https://github.com/ultralytics/yolov5/releases/tag/v3.0): nn.Hardswish() activations, data autodownload, native AMP. | |||||
- **July 23, 2020**: [v2.0 release](https://github.com/ultralytics/yolov5/releases/tag/v2.0): improved model definition, training and mAP. | - **July 23, 2020**: [v2.0 release](https://github.com/ultralytics/yolov5/releases/tag/v2.0): improved model definition, training and mAP. | ||||
- **June 22, 2020**: [PANet](https://arxiv.org/abs/1803.01534) updates: new heads, reduced parameters, improved speed and mAP [364fcfd](https://github.com/ultralytics/yolov5/commit/364fcfd7dba53f46edd4f04c037a039c0a287972). | - **June 22, 2020**: [PANet](https://arxiv.org/abs/1803.01534) updates: new heads, reduced parameters, improved speed and mAP [364fcfd](https://github.com/ultralytics/yolov5/commit/364fcfd7dba53f46edd4f04c037a039c0a287972). | ||||
- **June 19, 2020**: [FP16](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.half) as new default for smaller checkpoints and faster inference [d4c6674](https://github.com/ultralytics/yolov5/commit/d4c6674c98e19df4c40e33a777610a18d1961145). | - **June 19, 2020**: [FP16](https://pytorch.org/docs/stable/nn.html#torch.nn.Module.half) as new default for smaller checkpoints and faster inference [d4c6674](https://github.com/ultralytics/yolov5/commit/d4c6674c98e19df4c40e33a777610a18d1961145). | ||||
| Model | AP<sup>val</sup> | AP<sup>test</sup> | AP<sub>50</sub> | Speed<sub>GPU</sub> | FPS<sub>GPU</sub> || params | FLOPS | | | Model | AP<sup>val</sup> | AP<sup>test</sup> | AP<sub>50</sub> | Speed<sub>GPU</sub> | FPS<sub>GPU</sub> || params | FLOPS | | ||||
|---------- |------ |------ |------ | -------- | ------| ------ |------ | :------: | | |---------- |------ |------ |------ | -------- | ------| ------ |------ | :------: | | ||||
| [YOLOv5s](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 36.1 | 36.1 | 55.3 | **2.1ms** | **476** || 7.5M | 13.2B | |||||
| [YOLOv5m](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 43.5 | 43.5 | 62.5 | 3.0ms | 333 || 21.8M | 39.4B | |||||
| [YOLOv5l](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 47.0 | 47.1 | 65.6 | 3.9ms | 256 || 47.8M | 88.1B | |||||
| [YOLOv5x](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | **49.0** | **49.0** | **67.4** | 6.1ms | 164 || 89.0M | 166.4B | |||||
| [YOLOv5s](https://github.com/ultralytics/yolov5/releases/tag/v3.0) | 37.0 | 37.0 | 56.2 | **2.4ms** | **476** || 7.5M | 13.2B | |||||
| [YOLOv5m](https://github.com/ultralytics/yolov5/releases/tag/v3.0) | 44.3 | 44.3 | 63.2 | 3.4ms | 333 || 21.8M | 39.4B | |||||
| [YOLOv5l](https://github.com/ultralytics/yolov5/releases/tag/v3.0) | 47.7 | 47.7 | 66.5 | 4.4ms | 256 || 47.8M | 88.1B | |||||
| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/tag/v3.0) | **49.2** | **49.2** | **67.7** | 6.9ms | 164 || 89.0M | 166.4B | |||||
| | | | | | || | | | | | | | | || | | ||||
| [YOLOv3-SPP](https://drive.google.com/open?id=1Drs_Aiu7xx6S-ix95f9kNsA6ueKRpN2J) | 45.6 | 45.5 | 65.2 | 4.5ms | 222 || 63.0M | 118.0B | |||||
| [YOLOv5x](https://github.com/ultralytics/yolov5/releases/tag/v3.0) + TTA|**50.8**| **50.8** | **68.9** | 25.5ms | 39 || 89.0M | 354.3B | |||||
| | | | | | || | | |||||
| [YOLOv3-SPP](https://github.com/ultralytics/yolov5/releases/tag/v3.0) | 45.6 | 45.5 | 65.2 | 4.5ms | 222 || 63.0M | 118.0B | |||||
** AP<sup>test</sup> denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results in the table denote val2017 accuracy. | ** AP<sup>test</sup> denotes COCO [test-dev2017](http://cocodataset.org/#upload) server results, all other AP results in the table denote val2017 accuracy. | ||||
** All AP numbers are for single-model single-scale without ensemble or test-time augmentation. Reproduce by `python test.py --data coco.yaml --img 672 --conf 0.001` | |||||
** Speed<sub>GPU</sub> measures end-to-end time per image averaged over 5000 COCO val2017 images using a GCP [n1-standard-16](https://cloud.google.com/compute/docs/machine-types#n1_standard_machine_types) instance with one V100 GPU, and includes image preprocessing, PyTorch FP16 image inference at --batch-size 32 --img-size 640, postprocessing and NMS. Average NMS time included in this chart is 1-2ms/img. Reproduce by `python test.py --data coco.yaml --img 640 --conf 0.1` | |||||
** All AP numbers are for single-model single-scale without ensemble or test-time augmentation. **Reproduce** by `python test.py --data coco.yaml --img 640 --conf 0.001` | |||||
** Speed<sub>GPU</sub> measures end-to-end time per image averaged over 5000 COCO val2017 images using a GCP [n1-standard-16](https://cloud.google.com/compute/docs/machine-types#n1_standard_machine_types) instance with one V100 GPU, and includes image preprocessing, PyTorch FP16 image inference at --batch-size 32 --img-size 640, postprocessing and NMS. Average NMS time included in this chart is 1-2ms/img. **Reproduce** by `python test.py --data coco.yaml --img 640 --conf 0.1` | |||||
** All checkpoints are trained to 300 epochs with default settings and hyperparameters (no autoaugmentation). | ** All checkpoints are trained to 300 epochs with default settings and hyperparameters (no autoaugmentation). | ||||
** Test Time Augmentation ([TTA](https://github.com/ultralytics/yolov5/issues/303)) runs at 3 image sizes. **Reproduce** by `python test.py --data coco.yaml --img 832 --augment` | |||||
## Requirements | ## Requirements | ||||
## Training | ## Training | ||||
Download [COCO](https://github.com/ultralytics/yolov5/blob/master/data/get_coco2017.sh) and run command below. Training times for YOLOv5s/m/l/x are 2/4/6/8 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices). | |||||
Download [COCO](https://github.com/ultralytics/yolov5/blob/master/data/scripts/get_coco.sh) and run command below. Training times for YOLOv5s/m/l/x are 2/4/6/8 days on a single V100 (multi-GPU times faster). Use the largest `--batch-size` your GPU allows (batch sizes shown for 16 GB devices). | |||||
```bash | ```bash | ||||
$ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64 | $ python train.py --data coco.yaml --cfg yolov5s.yaml --weights '' --batch-size 64 | ||||
yolov5m 48 | |||||
yolov5l 32 | |||||
yolov5m 40 | |||||
yolov5l 24 | |||||
yolov5x 16 | yolov5x 16 | ||||
``` | ``` | ||||
<img src="https://user-images.githubusercontent.com/26833433/84186698-c4d54d00-aa45-11ea-9bde-c632c1230ccd.png" width="900"> | <img src="https://user-images.githubusercontent.com/26833433/84186698-c4d54d00-aa45-11ea-9bde-c632c1230ccd.png" width="900"> |
hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) | ||||
hsv_v: 0.4 # image HSV-Value augmentation (fraction) | hsv_v: 0.4 # image HSV-Value augmentation (fraction) | ||||
degrees: 0.0 # image rotation (+/- deg) | degrees: 0.0 # image rotation (+/- deg) | ||||
translate: 0.5 # image translation (+/- fraction) | |||||
translate: 0.1 # image translation (+/- fraction) | |||||
scale: 0.5 # image scale (+/- gain) | scale: 0.5 # image scale (+/- gain) | ||||
shear: 0.0 # image shear (+/- deg) | shear: 0.0 # image shear (+/- deg) | ||||
perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 |
hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) | ||||
hsv_v: 0.4 # image HSV-Value augmentation (fraction) | hsv_v: 0.4 # image HSV-Value augmentation (fraction) | ||||
degrees: 0.0 # image rotation (+/- deg) | degrees: 0.0 # image rotation (+/- deg) | ||||
translate: 0.5 # image translation (+/- fraction) | |||||
translate: 0.1 # image translation (+/- fraction) | |||||
scale: 0.5 # image scale (+/- gain) | scale: 0.5 # image scale (+/- gain) | ||||
shear: 0.0 # image shear (+/- deg) | shear: 0.0 # image shear (+/- deg) | ||||
perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 |
super(Conv, self).__init__() | super(Conv, self).__init__() | ||||
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) | self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) | ||||
self.bn = nn.BatchNorm2d(c2) | self.bn = nn.BatchNorm2d(c2) | ||||
self.act = nn.LeakyReLU(0.1, inplace=True) if act else nn.Identity() | |||||
self.act = nn.Hardswish() if act else nn.Identity() | |||||
def forward(self, x): | def forward(self, x): | ||||
return self.act(self.bn(self.conv(x))) | return self.act(self.bn(self.conv(x))) |
logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
class Detect(nn.Module): | class Detect(nn.Module): | ||||
stride = None # strides computed during build | |||||
export = False # onnx export | |||||
def __init__(self, nc=80, anchors=(), ch=()): # detection layer | def __init__(self, nc=80, anchors=(), ch=()): # detection layer | ||||
super(Detect, self).__init__() | super(Detect, self).__init__() | ||||
self.stride = None # strides computed during build | |||||
self.nc = nc # number of classes | self.nc = nc # number of classes | ||||
self.no = nc + 5 # number of outputs per anchor | self.no = nc + 5 # number of outputs per anchor | ||||
self.nl = len(anchors) # number of detection layers | self.nl = len(anchors) # number of detection layers | ||||
self.register_buffer('anchors', a) # shape(nl,na,2) | self.register_buffer('anchors', a) # shape(nl,na,2) | ||||
self.register_buffer('anchor_grid', a.clone().view(self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2) | self.register_buffer('anchor_grid', a.clone().view(self.nl, 1, -1, 1, 1, 2)) # shape(nl,1,na,1,1,2) | ||||
self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv | self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv | ||||
self.export = False # onnx export | |||||
def forward(self, x): | def forward(self, x): | ||||
# x = x.copy() # for profiling | # x = x.copy() # for profiling |
opt.verbose) | opt.verbose) | ||||
elif opt.task == 'study': # run over a range of settings and save/plot | elif opt.task == 'study': # run over a range of settings and save/plot | ||||
for weights in ['yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt', 'yolov3-spp.pt']: | |||||
for weights in ['yolov5s.pt', 'yolov5m.pt', 'yolov5l.pt', 'yolov5x.pt']: | |||||
f = 'study_%s_%s.txt' % (Path(opt.data).stem, Path(weights).stem) # filename to save to | f = 'study_%s_%s.txt' % (Path(opt.data).stem, Path(weights).stem) # filename to save to | ||||
x = list(range(352, 832, 64)) # x axis | |||||
x = list(range(320, 800, 64)) # x axis | |||||
y = [] # y axis | y = [] # y axis | ||||
for i in x: # img-size | for i in x: # img-size | ||||
print('\nRunning %s point %s...' % (f, i)) | print('\nRunning %s point %s...' % (f, i)) | ||||
y.append(r + t) # results and times | y.append(r + t) # results and times | ||||
np.savetxt(f, y, fmt='%10.4g') # save | np.savetxt(f, y, fmt='%10.4g') # save | ||||
os.system('zip -r study.zip study_*.txt') | os.system('zip -r study.zip study_*.txt') | ||||
# plot_study_txt(f, x) # plot | |||||
# utils.general.plot_study_txt(f, x) # plot |
logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
def train(hyp, opt, device, tb_writer=None): | def train(hyp, opt, device, tb_writer=None): | ||||
logger.info(f'Hyperparameters {hyp}') | logger.info(f'Hyperparameters {hyp}') | ||||
log_dir = Path(tb_writer.log_dir) if tb_writer else Path(opt.logdir) / 'evolve' # logging directory | log_dir = Path(tb_writer.log_dir) if tb_writer else Path(opt.logdir) / 'evolve' # logging directory | ||||
start_epoch = ckpt['epoch'] + 1 | start_epoch = ckpt['epoch'] + 1 | ||||
if epochs < start_epoch: | if epochs < start_epoch: | ||||
logger.info('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % | logger.info('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' % | ||||
(weights, ckpt['epoch'], epochs)) | |||||
(weights, ckpt['epoch'], epochs)) | |||||
epochs += ckpt['epoch'] # finetune additional epochs | epochs += ckpt['epoch'] # finetune additional epochs | ||||
del ckpt, state_dict | del ckpt, state_dict | ||||
parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') | parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode') | ||||
parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') | parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify') | ||||
parser.add_argument('--logdir', type=str, default='runs/', help='logging directory') | parser.add_argument('--logdir', type=str, default='runs/', help='logging directory') | ||||
parser.add_argument('--workers', type=int, default=8, help='maximum number of workers for dataloader') | |||||
parser.add_argument('--workers', type=int, default=8, help='maximum number of dataloader workers') | |||||
opt = parser.parse_args() | opt = parser.parse_args() | ||||
# Set DDP variables | # Set DDP variables | ||||
if last and not opt.weights: | if last and not opt.weights: | ||||
logger.info(f'Resuming training from {last}') | logger.info(f'Resuming training from {last}') | ||||
opt.weights = last if opt.resume and not opt.weights else opt.weights | opt.weights = last if opt.resume and not opt.weights else opt.weights | ||||
if opt.global_rank in [-1,0]: | |||||
if opt.global_rank in [-1, 0]: | |||||
check_git_status() | check_git_status() | ||||
opt.hyp = opt.hyp or ('data/hyp.finetune.yaml' if opt.weights else 'data/hyp.scratch.yaml') | opt.hyp = opt.hyp or ('data/hyp.finetune.yaml' if opt.weights else 'data/hyp.scratch.yaml') |
return x * torch.sigmoid(x) | return x * torch.sigmoid(x) | ||||
class HardSwish(nn.Module): | |||||
@staticmethod | |||||
def forward(x): | |||||
return x * F.hardtanh(x + 3, 0., 6., True) / 6. | |||||
class MemoryEfficientSwish(nn.Module): | class MemoryEfficientSwish(nn.Module): | ||||
class F(torch.autograd.Function): | class F(torch.autograd.Function): | ||||
@staticmethod | @staticmethod |
labels4 = [] | labels4 = [] | ||||
s = self.img_size | s = self.img_size | ||||
yc, xc = s, s # mosaic center x, y | |||||
yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border] # mosaic center x, y | |||||
indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices | indices = [index] + [random.randint(0, len(self.labels) - 1) for _ in range(3)] # 3 additional image indices | ||||
for i, index in enumerate(indices): | for i, index in enumerate(indices): | ||||
# Load image | # Load image | ||||
return img, targets | return img, targets | ||||
def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.2): # box1(4,n), box2(4,n) | |||||
def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1): # box1(4,n), box2(4,n) | |||||
# Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio | # Compute candidate boxes: box1 before augment, box2 after augment, wh_thr (pixels), aspect_ratio_thr, area_ratio | ||||
w1, h1 = box1[2] - box1[0], box1[3] - box1[1] | w1, h1 = box1[2] - box1[0], box1[3] - box1[1] | ||||
w2, h2 = box2[2] - box2[0], box2[3] - box2[1] | w2, h2 = box2[2] - box2[0], box2[3] - box2[1] |
ax = ax.ravel() | ax = ax.ravel() | ||||
fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) | fig2, ax2 = plt.subplots(1, 1, figsize=(8, 4), tight_layout=True) | ||||
for f in ['coco_study/study_coco_yolov5%s.txt' % x for x in ['s', 'm', 'l', 'x']]: | |||||
for f in ['study/study_coco_yolov5%s.txt' % x for x in ['s', 'm', 'l', 'x']]: | |||||
y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T | y = np.loadtxt(f, dtype=np.float32, usecols=[0, 1, 2, 3, 7, 8, 9], ndmin=2).T | ||||
x = np.arange(y.shape[1]) if x is None else np.array(x) | x = np.arange(y.shape[1]) if x is None else np.array(x) | ||||
s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] | s = ['P', 'R', 'mAP@.5', 'mAP@.5:.95', 't_inference (ms/img)', 't_NMS (ms/img)', 't_total (ms/img)'] | ||||
ax2.plot(y[6, :j], y[3, :j] * 1E2, '.-', linewidth=2, markersize=8, | ax2.plot(y[6, :j], y[3, :j] * 1E2, '.-', linewidth=2, markersize=8, | ||||
label=Path(f).stem.replace('study_coco_', '').replace('yolo', 'YOLO')) | label=Path(f).stem.replace('study_coco_', '').replace('yolo', 'YOLO')) | ||||
ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [33.8, 39.6, 43.0, 47.5, 49.4, 50.7], | |||||
ax2.plot(1E3 / np.array([209, 140, 97, 58, 35, 18]), [34.6, 40.5, 43.0, 47.5, 49.7, 51.5], | |||||
'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') | 'k.-', linewidth=2, markersize=8, alpha=.25, label='EfficientDet') | ||||
ax2.grid() | ax2.grid() | ||||
ax2.set_ylabel('COCO AP val') | ax2.set_ylabel('COCO AP val') | ||||
ax2.legend(loc='lower right') | ax2.legend(loc='lower right') | ||||
plt.savefig('study_mAP_latency.png', dpi=300) | plt.savefig('study_mAP_latency.png', dpi=300) | ||||
plt.savefig(f.replace('.txt', '.png'), dpi=200) | |||||
plt.savefig(f.replace('.txt', '.png'), dpi=300) | |||||
def plot_labels(labels, save_dir=''): | def plot_labels(labels, save_dir=''): | ||||
s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', | s = ['GIoU', 'Objectness', 'Classification', 'Precision', 'Recall', | ||||
'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] | 'val GIoU', 'val Objectness', 'val Classification', 'mAP@0.5', 'mAP@0.5:0.95'] | ||||
if bucket: | if bucket: | ||||
os.system('rm -rf storage.googleapis.com') | |||||
files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] | |||||
# os.system('rm -rf storage.googleapis.com') | |||||
# files = ['https://storage.googleapis.com/%s/results%g.txt' % (bucket, x) for x in id] | |||||
files = ['results%g.txt' % x for x in id] | |||||
c = ('gsutil cp ' + '%s ' * len(files) + '.') % tuple('gs://%s/results%g.txt' % (bucket, x) for x in id) | |||||
os.system(c) | |||||
else: | else: | ||||
files = glob.glob(str(Path(save_dir) / 'results*.txt')) + glob.glob('../../Downloads/results*.txt') | files = glob.glob(str(Path(save_dir) / 'results*.txt')) + glob.glob('../../Downloads/results*.txt') | ||||
for fi, f in enumerate(files): | for fi, f in enumerate(files): | ||||
ax[i].set_title(s[i]) | ax[i].set_title(s[i]) | ||||
# if i in [5, 6, 7]: # share train and val loss y axes | # if i in [5, 6, 7]: # share train and val loss y axes | ||||
# ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) | # ax[i].get_shared_y_axes().join(ax[i], ax[i - 5]) | ||||
except: | |||||
print('Warning: Plotting error for %s, skipping file' % f) | |||||
except Exception as e: | |||||
print('Warning: Plotting error for %s; %s' % (f, e)) | |||||
fig.tight_layout() | fig.tight_layout() | ||||
ax[1].legend() | ax[1].legend() |