Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dcuai
dlexamples
Commits
5a567950
Commit
5a567950
authored
Dec 29, 2022
by
lidc
Browse files
yolov5增加了mpi单机多卡和多机多卡启动方式,其readme文件进行了更新,对maskrcnn的debug输出日志进行了删除,并更新了该模型的readme文件
parent
a30b77fe
Changes
84
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
188 additions
and
218 deletions
+188
-218
PyTorch/Compute-Vision/Objection/yolov5/utils/metrics.py
PyTorch/Compute-Vision/Objection/yolov5/utils/metrics.py
+16
-23
PyTorch/Compute-Vision/Objection/yolov5/utils/plots.py
PyTorch/Compute-Vision/Objection/yolov5/utils/plots.py
+61
-84
PyTorch/Compute-Vision/Objection/yolov5/utils/torch_utils.py
PyTorch/Compute-Vision/Objection/yolov5/utils/torch_utils.py
+41
-19
PyTorch/Compute-Vision/Objection/yolov5/val.py
PyTorch/Compute-Vision/Objection/yolov5/val.py
+70
-92
No files found.
PyTorch/Compute-Vision/Objection/yolov5/utils/metrics.py
View file @
5a567950
...
...
@@ -18,7 +18,7 @@ def fitness(x):
return
(
x
[:,
:
4
]
*
w
).
sum
(
1
)
def
ap_per_class
(
tp
,
conf
,
pred_cls
,
target_cls
,
plot
=
False
,
save_dir
=
'.'
,
names
=
()
,
eps
=
1e-16
):
def
ap_per_class
(
tp
,
conf
,
pred_cls
,
target_cls
,
plot
=
False
,
save_dir
=
'.'
,
names
=
()):
""" Compute the average precision, given the recall and precision curves.
Source: https://github.com/rafaelpadilla/Object-Detection-Metrics.
# Arguments
...
...
@@ -37,7 +37,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names
tp
,
conf
,
pred_cls
=
tp
[
i
],
conf
[
i
],
pred_cls
[
i
]
# Find unique classes
unique_classes
,
nt
=
np
.
unique
(
target_cls
,
return_counts
=
True
)
unique_classes
=
np
.
unique
(
target_cls
)
nc
=
unique_classes
.
shape
[
0
]
# number of classes, number of detections
# Create Precision-Recall curve and compute AP for each class
...
...
@@ -45,7 +45,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names
ap
,
p
,
r
=
np
.
zeros
((
nc
,
tp
.
shape
[
1
])),
np
.
zeros
((
nc
,
1000
)),
np
.
zeros
((
nc
,
1000
))
for
ci
,
c
in
enumerate
(
unique_classes
):
i
=
pred_cls
==
c
n_l
=
nt
[
ci
]
# number of labels
n_l
=
(
target_cls
==
c
).
sum
()
# number of labels
n_p
=
i
.
sum
()
# number of predictions
if
n_p
==
0
or
n_l
==
0
:
...
...
@@ -56,7 +56,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names
tpc
=
tp
[
i
].
cumsum
(
0
)
# Recall
recall
=
tpc
/
(
n_l
+
eps
)
# recall curve
recall
=
tpc
/
(
n_l
+
1e-16
)
# recall curve
r
[
ci
]
=
np
.
interp
(
-
px
,
-
conf
[
i
],
recall
[:,
0
],
left
=
0
)
# negative x, xp because xp decreases
# Precision
...
...
@@ -70,9 +70,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names
py
.
append
(
np
.
interp
(
px
,
mrec
,
mpre
))
# precision at mAP@0.5
# Compute F1 (harmonic mean of precision and recall)
f1
=
2
*
p
*
r
/
(
p
+
r
+
eps
)
names
=
[
v
for
k
,
v
in
names
.
items
()
if
k
in
unique_classes
]
# list: only classes that have data
names
=
{
i
:
v
for
i
,
v
in
enumerate
(
names
)}
# to dict
f1
=
2
*
p
*
r
/
(
p
+
r
+
1e-16
)
if
plot
:
plot_pr_curve
(
px
,
py
,
ap
,
Path
(
save_dir
)
/
'PR_curve.png'
,
names
)
plot_mc_curve
(
px
,
f1
,
Path
(
save_dir
)
/
'F1_curve.png'
,
names
,
ylabel
=
'F1'
)
...
...
@@ -80,10 +78,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names
plot_mc_curve
(
px
,
r
,
Path
(
save_dir
)
/
'R_curve.png'
,
names
,
ylabel
=
'Recall'
)
i
=
f1
.
mean
(
0
).
argmax
()
# max F1 index
p
,
r
,
f1
=
p
[:,
i
],
r
[:,
i
],
f1
[:,
i
]
tp
=
(
r
*
nt
).
round
()
# true positives
fp
=
(
tp
/
(
p
+
eps
)
-
tp
).
round
()
# false positives
return
tp
,
fp
,
p
,
r
,
f1
,
ap
,
unique_classes
.
astype
(
'int32'
)
return
p
[:,
i
],
r
[:,
i
],
ap
,
f1
[:,
i
],
unique_classes
.
astype
(
'int32'
)
def
compute_ap
(
recall
,
precision
):
...
...
@@ -165,12 +160,6 @@ class ConfusionMatrix:
def
matrix
(
self
):
return
self
.
matrix
def
tp_fp
(
self
):
tp
=
self
.
matrix
.
diagonal
()
# true positives
fp
=
self
.
matrix
.
sum
(
1
)
-
tp
# false positives
# fn = self.matrix.sum(0) - tp # false negatives (missed detections)
return
tp
[:
-
1
],
fp
[:
-
1
]
# remove background class
def
plot
(
self
,
normalize
=
True
,
save_dir
=
''
,
names
=
()):
try
:
import
seaborn
as
sn
...
...
@@ -222,22 +211,26 @@ def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=
union
=
w1
*
h1
+
w2
*
h2
-
inter
+
eps
iou
=
inter
/
union
if
C
IoU
or
DIoU
or
G
IoU
:
if
G
IoU
or
DIoU
or
C
IoU
:
cw
=
torch
.
max
(
b1_x2
,
b2_x2
)
-
torch
.
min
(
b1_x1
,
b2_x1
)
# convex (smallest enclosing box) width
ch
=
torch
.
max
(
b1_y2
,
b2_y2
)
-
torch
.
min
(
b1_y1
,
b2_y1
)
# convex height
if
CIoU
or
DIoU
:
# Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
c2
=
cw
**
2
+
ch
**
2
+
eps
# convex diagonal squared
rho2
=
((
b2_x1
+
b2_x2
-
b1_x1
-
b1_x2
)
**
2
+
(
b2_y1
+
b2_y2
-
b1_y1
-
b1_y2
)
**
2
)
/
4
# center distance squared
if
CIoU
:
# https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
if
DIoU
:
return
iou
-
rho2
/
c2
# DIoU
elif
CIoU
:
# https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
v
=
(
4
/
math
.
pi
**
2
)
*
torch
.
pow
(
torch
.
atan
(
w2
/
h2
)
-
torch
.
atan
(
w1
/
h1
),
2
)
with
torch
.
no_grad
():
alpha
=
v
/
(
v
-
iou
+
(
1
+
eps
))
return
iou
-
(
rho2
/
c2
+
v
*
alpha
)
# CIoU
return
iou
-
rho2
/
c2
# DIoU
c_area
=
cw
*
ch
+
eps
# convex area
return
iou
-
(
c_area
-
union
)
/
c_area
# GIoU https://arxiv.org/pdf/1902.09630.pdf
return
iou
# IoU
else
:
# GIoU https://arxiv.org/pdf/1902.09630.pdf
c_area
=
cw
*
ch
+
eps
# convex area
return
iou
-
(
c_area
-
union
)
/
c_area
# GIoU
else
:
return
iou
# IoU
def
box_iou
(
box1
,
box2
):
# https://github.com/pytorch/vision/blob/master/torchvision/ops/boxes.py
...
...
PyTorch/Compute-Vision/Objection/yolov5/utils/plots.py
View file @
5a567950
...
...
@@ -17,8 +17,7 @@ import seaborn as sn
import
torch
from
PIL
import
Image
,
ImageDraw
,
ImageFont
from
utils.general
import
(
LOGGER
,
Timeout
,
check_requirements
,
clip_coords
,
increment_path
,
is_ascii
,
is_chinese
,
try_except
,
user_config_dir
,
xywh2xyxy
,
xyxy2xywh
)
from
utils.general
import
user_config_dir
,
is_ascii
,
is_chinese
,
xywh2xyxy
,
xyxy2xywh
from
utils.metrics
import
fitness
# Settings
...
...
@@ -59,10 +58,7 @@ def check_font(font='Arial.ttf', size=10):
url
=
"https://ultralytics.com/assets/"
+
font
.
name
print
(
f
'Downloading
{
url
}
to
{
font
}
...'
)
torch
.
hub
.
download_url_to_file
(
url
,
str
(
font
),
progress
=
False
)
try
:
return
ImageFont
.
truetype
(
str
(
font
),
size
)
except
TypeError
:
check_requirements
(
'Pillow>=8.4.0'
)
# known issue https://github.com/ultralytics/yolov5/issues/5374
return
ImageFont
.
truetype
(
str
(
font
),
size
)
class
Annotator
:
...
...
@@ -121,34 +117,6 @@ class Annotator:
return
np
.
asarray
(
self
.
im
)
def
feature_visualization
(
x
,
module_type
,
stage
,
n
=
32
,
save_dir
=
Path
(
'runs/detect/exp'
)):
"""
x: Features to be visualized
module_type: Module type
stage: Module stage within model
n: Maximum number of feature maps to plot
save_dir: Directory to save results
"""
if
'Detect'
not
in
module_type
:
batch
,
channels
,
height
,
width
=
x
.
shape
# batch, channels, height, width
if
height
>
1
and
width
>
1
:
f
=
save_dir
/
f
"stage
{
stage
}
_
{
module_type
.
split
(
'.'
)[
-
1
]
}
_features.png"
# filename
blocks
=
torch
.
chunk
(
x
[
0
].
cpu
(),
channels
,
dim
=
0
)
# select batch index 0, block by channels
n
=
min
(
n
,
channels
)
# number of plots
fig
,
ax
=
plt
.
subplots
(
math
.
ceil
(
n
/
8
),
8
,
tight_layout
=
True
)
# 8 rows x n/8 cols
ax
=
ax
.
ravel
()
plt
.
subplots_adjust
(
wspace
=
0.05
,
hspace
=
0.05
)
for
i
in
range
(
n
):
ax
[
i
].
imshow
(
blocks
[
i
].
squeeze
())
# cmap='gray'
ax
[
i
].
axis
(
'off'
)
print
(
f
'Saving
{
f
}
... (
{
n
}
/
{
channels
}
)'
)
plt
.
savefig
(
f
,
dpi
=
300
,
bbox_inches
=
'tight'
)
plt
.
close
()
np
.
save
(
str
(
f
.
with_suffix
(
'.npy'
)),
x
[
0
].
cpu
().
numpy
())
# npy save
def
hist2d
(
x
,
y
,
n
=
100
):
# 2d histogram used in labels.png and evolve.png
xedges
,
yedges
=
np
.
linspace
(
x
.
min
(),
x
.
max
(),
n
),
np
.
linspace
(
y
.
min
(),
y
.
max
(),
n
)
...
...
@@ -187,7 +155,7 @@ def plot_images(images, targets, paths=None, fname='images.jpg', names=None, max
if
isinstance
(
targets
,
torch
.
Tensor
):
targets
=
targets
.
cpu
().
numpy
()
if
np
.
max
(
images
[
0
])
<=
1
:
images
*=
255
# de-normalise (optional)
images
*=
255
.0
# de-normalise (optional)
bs
,
_
,
h
,
w
=
images
.
shape
# batch size, _, height, width
bs
=
min
(
bs
,
max_subplots
)
# limit plot images
ns
=
np
.
ceil
(
bs
**
0.5
)
# number of subplots (square)
...
...
@@ -282,7 +250,7 @@ def plot_targets_txt(): # from utils.plots import *; plot_targets_txt()
fig
,
ax
=
plt
.
subplots
(
2
,
2
,
figsize
=
(
8
,
8
),
tight_layout
=
True
)
ax
=
ax
.
ravel
()
for
i
in
range
(
4
):
ax
[
i
].
hist
(
x
[
i
],
bins
=
100
,
label
=
f
'
{
x
[
i
].
mean
():.
3
g
}
+/-
{
x
[
i
].
std
()
:.
3
g
}
'
)
ax
[
i
].
hist
(
x
[
i
],
bins
=
100
,
label
=
'%.3g +/- %.3g'
%
(
x
[
i
].
mean
(),
x
[
i
].
std
()
)
)
ax
[
i
].
legend
()
ax
[
i
].
set_title
(
s
[
i
])
plt
.
savefig
(
'targets.jpg'
,
dpi
=
200
)
...
...
@@ -325,11 +293,9 @@ def plot_val_study(file='', dir='', x=None): # from utils.plots import *; plot_
plt
.
savefig
(
f
,
dpi
=
300
)
@
try_except
# known issue https://github.com/ultralytics/yolov5/issues/5395
@
Timeout
(
30
)
# known issue https://github.com/ultralytics/yolov5/issues/5611
def
plot_labels
(
labels
,
names
=
(),
save_dir
=
Path
(
''
)):
# plot dataset labels
LOGGER
.
info
(
f
"
Plotting labels
to
{
save_dir
/
'labels.jpg'
}
...
"
)
print
(
'
Plotting labels...
'
)
c
,
b
=
labels
[:,
0
],
labels
[:,
1
:].
transpose
()
# classes, boxes
nc
=
int
(
c
.
max
()
+
1
)
# number of classes
x
=
pd
.
DataFrame
(
b
.
transpose
(),
columns
=
[
'x'
,
'y'
,
'width'
,
'height'
])
...
...
@@ -371,6 +337,37 @@ def plot_labels(labels, names=(), save_dir=Path('')):
plt
.
close
()
def
profile_idetection
(
start
=
0
,
stop
=
0
,
labels
=
(),
save_dir
=
''
):
# Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection()
ax
=
plt
.
subplots
(
2
,
4
,
figsize
=
(
12
,
6
),
tight_layout
=
True
)[
1
].
ravel
()
s
=
[
'Images'
,
'Free Storage (GB)'
,
'RAM Usage (GB)'
,
'Battery'
,
'dt_raw (ms)'
,
'dt_smooth (ms)'
,
'real-world FPS'
]
files
=
list
(
Path
(
save_dir
).
glob
(
'frames*.txt'
))
for
fi
,
f
in
enumerate
(
files
):
try
:
results
=
np
.
loadtxt
(
f
,
ndmin
=
2
).
T
[:,
90
:
-
30
]
# clip first and last rows
n
=
results
.
shape
[
1
]
# number of rows
x
=
np
.
arange
(
start
,
min
(
stop
,
n
)
if
stop
else
n
)
results
=
results
[:,
x
]
t
=
(
results
[
0
]
-
results
[
0
].
min
())
# set t0=0s
results
[
0
]
=
x
for
i
,
a
in
enumerate
(
ax
):
if
i
<
len
(
results
):
label
=
labels
[
fi
]
if
len
(
labels
)
else
f
.
stem
.
replace
(
'frames_'
,
''
)
a
.
plot
(
t
,
results
[
i
],
marker
=
'.'
,
label
=
label
,
linewidth
=
1
,
markersize
=
5
)
a
.
set_title
(
s
[
i
])
a
.
set_xlabel
(
'time (s)'
)
# if fi == len(files) - 1:
# a.set_ylim(bottom=0)
for
side
in
[
'top'
,
'right'
]:
a
.
spines
[
side
].
set_visible
(
False
)
else
:
a
.
remove
()
except
Exception
as
e
:
print
(
'Warning: Plotting error for %s; %s'
%
(
f
,
e
))
ax
[
1
].
legend
()
plt
.
savefig
(
Path
(
save_dir
)
/
'idetection_profile.png'
,
dpi
=
200
)
def
plot_evolve
(
evolve_csv
=
'path/to/evolve.csv'
):
# from utils.plots import *; plot_evolve()
# Plot evolve.csv hyp evolution results
evolve_csv
=
Path
(
evolve_csv
)
...
...
@@ -387,10 +384,10 @@ def plot_evolve(evolve_csv='path/to/evolve.csv'): # from utils.plots import *;
plt
.
subplot
(
6
,
5
,
i
+
1
)
plt
.
scatter
(
v
,
f
,
c
=
hist2d
(
v
,
f
,
20
),
cmap
=
'viridis'
,
alpha
=
.
8
,
edgecolors
=
'none'
)
plt
.
plot
(
mu
,
f
.
max
(),
'k+'
,
markersize
=
15
)
plt
.
title
(
f
'
{
k
}
=
{
mu
:.
3
g
}
'
,
fontdict
=
{
'size'
:
9
})
# limit to 40 characters
plt
.
title
(
'%s = %.3g'
%
(
k
,
mu
)
,
fontdict
=
{
'size'
:
9
})
# limit to 40 characters
if
i
%
5
!=
0
:
plt
.
yticks
([])
print
(
f
'
{
k
:
>
15
}
:
{
mu
:.
3
g
}
'
)
print
(
'%
15
s
:
%.3g'
%
(
k
,
mu
)
)
f
=
evolve_csv
.
with_suffix
(
'.png'
)
# filename
plt
.
savefig
(
f
,
dpi
=
200
)
plt
.
close
()
...
...
@@ -423,48 +420,28 @@ def plot_results(file='path/to/results.csv', dir=''):
plt
.
close
()
def
profile_idetection
(
start
=
0
,
stop
=
0
,
labels
=
(),
save_dir
=
''
):
# Plot iDetection '*.txt' per-image logs. from utils.plots import *; profile_idetection()
ax
=
plt
.
subplots
(
2
,
4
,
figsize
=
(
12
,
6
),
tight_layout
=
True
)[
1
].
ravel
()
s
=
[
'Images'
,
'Free Storage (GB)'
,
'RAM Usage (GB)'
,
'Battery'
,
'dt_raw (ms)'
,
'dt_smooth (ms)'
,
'real-world FPS'
]
files
=
list
(
Path
(
save_dir
).
glob
(
'frames*.txt'
))
for
fi
,
f
in
enumerate
(
files
):
try
:
results
=
np
.
loadtxt
(
f
,
ndmin
=
2
).
T
[:,
90
:
-
30
]
# clip first and last rows
n
=
results
.
shape
[
1
]
# number of rows
x
=
np
.
arange
(
start
,
min
(
stop
,
n
)
if
stop
else
n
)
results
=
results
[:,
x
]
t
=
(
results
[
0
]
-
results
[
0
].
min
())
# set t0=0s
results
[
0
]
=
x
for
i
,
a
in
enumerate
(
ax
):
if
i
<
len
(
results
):
label
=
labels
[
fi
]
if
len
(
labels
)
else
f
.
stem
.
replace
(
'frames_'
,
''
)
a
.
plot
(
t
,
results
[
i
],
marker
=
'.'
,
label
=
label
,
linewidth
=
1
,
markersize
=
5
)
a
.
set_title
(
s
[
i
])
a
.
set_xlabel
(
'time (s)'
)
# if fi == len(files) - 1:
# a.set_ylim(bottom=0)
for
side
in
[
'top'
,
'right'
]:
a
.
spines
[
side
].
set_visible
(
False
)
else
:
a
.
remove
()
except
Exception
as
e
:
print
(
f
'Warning: Plotting error for
{
f
}
;
{
e
}
'
)
ax
[
1
].
legend
()
plt
.
savefig
(
Path
(
save_dir
)
/
'idetection_profile.png'
,
dpi
=
200
)
def
feature_visualization
(
x
,
module_type
,
stage
,
n
=
32
,
save_dir
=
Path
(
'runs/detect/exp'
)):
"""
x: Features to be visualized
module_type: Module type
stage: Module stage within model
n: Maximum number of feature maps to plot
save_dir: Directory to save results
"""
if
'Detect'
not
in
module_type
:
batch
,
channels
,
height
,
width
=
x
.
shape
# batch, channels, height, width
if
height
>
1
and
width
>
1
:
f
=
f
"stage
{
stage
}
_
{
module_type
.
split
(
'.'
)[
-
1
]
}
_features.png"
# filename
blocks
=
torch
.
chunk
(
x
[
0
].
cpu
(),
channels
,
dim
=
0
)
# select batch index 0, block by channels
n
=
min
(
n
,
channels
)
# number of plots
fig
,
ax
=
plt
.
subplots
(
math
.
ceil
(
n
/
8
),
8
,
tight_layout
=
True
)
# 8 rows x n/8 cols
ax
=
ax
.
ravel
()
plt
.
subplots_adjust
(
wspace
=
0.05
,
hspace
=
0.05
)
for
i
in
range
(
n
):
ax
[
i
].
imshow
(
blocks
[
i
].
squeeze
())
# cmap='gray'
ax
[
i
].
axis
(
'off'
)
def
save_one_box
(
xyxy
,
im
,
file
=
'image.jpg'
,
gain
=
1.02
,
pad
=
10
,
square
=
False
,
BGR
=
False
,
save
=
True
):
# Save image crop as {file} with crop size multiple {gain} and {pad} pixels. Save and/or return crop
xyxy
=
torch
.
tensor
(
xyxy
).
view
(
-
1
,
4
)
b
=
xyxy2xywh
(
xyxy
)
# boxes
if
square
:
b
[:,
2
:]
=
b
[:,
2
:].
max
(
1
)[
0
].
unsqueeze
(
1
)
# attempt rectangle to square
b
[:,
2
:]
=
b
[:,
2
:]
*
gain
+
pad
# box wh * gain + pad
xyxy
=
xywh2xyxy
(
b
).
long
()
clip_coords
(
xyxy
,
im
.
shape
)
crop
=
im
[
int
(
xyxy
[
0
,
1
]):
int
(
xyxy
[
0
,
3
]),
int
(
xyxy
[
0
,
0
]):
int
(
xyxy
[
0
,
2
]),
::(
1
if
BGR
else
-
1
)]
if
save
:
file
.
parent
.
mkdir
(
parents
=
True
,
exist_ok
=
True
)
# make directory
cv2
.
imwrite
(
str
(
increment_path
(
file
).
with_suffix
(
'.jpg'
)),
crop
)
return
crop
print
(
f
'Saving
{
save_dir
/
f
}
... (
{
n
}
/
{
channels
}
)'
)
plt
.
savefig
(
save_dir
/
f
,
dpi
=
300
,
bbox_inches
=
'tight'
)
plt
.
close
()
PyTorch/Compute-Vision/Objection/yolov5/utils/torch_utils.py
View file @
5a567950
...
...
@@ -4,6 +4,7 @@ PyTorch utils
"""
import
datetime
import
logging
import
math
import
os
import
platform
...
...
@@ -17,14 +18,15 @@ import torch
import
torch.distributed
as
dist
import
torch.nn
as
nn
import
torch.nn.functional
as
F
from
utils.general
import
LOGGER
import
torchvision
try
:
import
thop
# for FLOPs computation
except
ImportError
:
thop
=
None
LOGGER
=
logging
.
getLogger
(
__name__
)
@
contextmanager
def
torch_distributed_zero_first
(
local_rank
:
int
):
...
...
@@ -53,7 +55,7 @@ def git_describe(path=Path(__file__).parent): # path must be a directory
return
''
# not a git repository
def
select_device
(
device
=
''
,
batch_size
=
0
,
newline
=
Tru
e
):
def
select_device
(
device
=
''
,
batch_size
=
Non
e
):
# device = 'cpu' or '0' or '0,1,2,3'
s
=
f
'YOLOv5 🚀
{
git_describe
()
or
date_modified
()
}
torch
{
torch
.
__version__
}
'
# string
device
=
str
(
device
).
strip
().
lower
().
replace
(
'cuda:'
,
''
)
# to string, 'cuda:0' to '0'
...
...
@@ -68,17 +70,15 @@ def select_device(device='', batch_size=0, newline=True):
if
cuda
:
devices
=
device
.
split
(
','
)
if
device
else
'0'
# range(torch.cuda.device_count()) # i.e. 0,1,6,7
n
=
len
(
devices
)
# device count
if
n
>
1
and
batch_size
>
0
:
# check batch_size is divisible by device_count
if
n
>
1
and
batch_size
:
# check batch_size is divisible by device_count
assert
batch_size
%
n
==
0
,
f
'batch-size
{
batch_size
}
not multiple of GPU count
{
n
}
'
space
=
' '
*
(
len
(
s
)
+
1
)
for
i
,
d
in
enumerate
(
devices
):
p
=
torch
.
cuda
.
get_device_properties
(
i
)
s
+=
f
"
{
''
if
i
==
0
else
space
}
CUDA:
{
d
}
(
{
p
.
name
}
,
{
p
.
total_memory
/
1024
**
2
:.
0
f
}
M
i
B)
\n
"
# bytes to MB
s
+=
f
"
{
''
if
i
==
0
else
space
}
CUDA:
{
d
}
(
{
p
.
name
}
,
{
p
.
total_memory
/
1024
**
2
}
MB)
\n
"
# bytes to MB
else
:
s
+=
'CPU
\n
'
if
not
newline
:
s
=
s
.
rstrip
()
LOGGER
.
info
(
s
.
encode
().
decode
(
'ascii'
,
'ignore'
)
if
platform
.
system
()
==
'Windows'
else
s
)
# emoji-safe
return
torch
.
device
(
'cuda:0'
if
cuda
else
'cpu'
)
...
...
@@ -100,6 +100,7 @@ def profile(input, ops, n=10, device=None):
# profile(input, [m1, m2], n=100) # profile over 100 iterations
results
=
[]
logging
.
basicConfig
(
format
=
"%(message)s"
,
level
=
logging
.
INFO
)
device
=
device
or
select_device
()
print
(
f
"
{
'Params'
:
>
12
s
}{
'GFLOPs'
:
>
12
s
}{
'GPU_mem (GB)'
:
>
14
s
}{
'forward (ms)'
:
>
14
s
}{
'backward (ms)'
:
>
14
s
}
"
f
"
{
'input'
:
>
24
s
}{
'output'
:
>
24
s
}
"
)
...
...
@@ -110,7 +111,7 @@ def profile(input, ops, n=10, device=None):
for
m
in
ops
if
isinstance
(
ops
,
list
)
else
[
ops
]:
m
=
m
.
to
(
device
)
if
hasattr
(
m
,
'to'
)
else
m
# device
m
=
m
.
half
()
if
hasattr
(
m
,
'half'
)
and
isinstance
(
x
,
torch
.
Tensor
)
and
x
.
dtype
is
torch
.
float16
else
m
tf
,
tb
,
t
=
0
,
0
,
[
0
,
0
,
0
]
# dt forward, backward
tf
,
tb
,
t
=
0
.
,
0
.
,
[
0
.
,
0
.
,
0
.
]
# dt forward, backward
try
:
flops
=
thop
.
profile
(
m
,
inputs
=
(
x
,),
verbose
=
False
)[
0
]
/
1E9
*
2
# GFLOPs
except
:
...
...
@@ -122,10 +123,10 @@ def profile(input, ops, n=10, device=None):
y
=
m
(
x
)
t
[
1
]
=
time_sync
()
try
:
_
=
(
sum
(
yi
.
sum
()
for
yi
in
y
)
if
isinstance
(
y
,
list
)
else
y
).
sum
().
backward
()
_
=
(
sum
(
[
yi
.
sum
()
for
yi
in
y
]
)
if
isinstance
(
y
,
list
)
else
y
).
sum
().
backward
()
t
[
2
]
=
time_sync
()
except
Exception
as
e
:
# no backward method
#
print(e)
# for debug
print
(
e
)
t
[
2
]
=
float
(
'nan'
)
tf
+=
(
t
[
1
]
-
t
[
0
])
*
1000
/
n
# ms per op forward
tb
+=
(
t
[
2
]
-
t
[
1
])
*
1000
/
n
# ms per op backward
...
...
@@ -152,6 +153,11 @@ def de_parallel(model):
return
model
.
module
if
is_parallel
(
model
)
else
model
def
intersect_dicts
(
da
,
db
,
exclude
=
()):
# Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values
return
{
k
:
v
for
k
,
v
in
da
.
items
()
if
k
in
db
and
not
any
(
x
in
k
for
x
in
exclude
)
and
v
.
shape
==
db
[
k
].
shape
}
def
initialize_weights
(
model
):
for
m
in
model
.
modules
():
t
=
type
(
m
)
...
...
@@ -160,7 +166,7 @@ def initialize_weights(model):
elif
t
is
nn
.
BatchNorm2d
:
m
.
eps
=
1e-3
m
.
momentum
=
0.03
elif
t
in
[
nn
.
Hardswish
,
nn
.
LeakyReLU
,
nn
.
ReLU
,
nn
.
ReLU6
,
nn
.
SiLU
]:
elif
t
in
[
nn
.
Hardswish
,
nn
.
LeakyReLU
,
nn
.
ReLU
,
nn
.
ReLU6
]:
m
.
inplace
=
True
...
...
@@ -171,7 +177,7 @@ def find_modules(model, mclass=nn.Conv2d):
def
sparsity
(
model
):
# Return global model sparsity
a
,
b
=
0
,
0
a
,
b
=
0
.
,
0
.
for
p
in
model
.
parameters
():
a
+=
p
.
numel
()
b
+=
(
p
==
0
).
sum
()
...
...
@@ -217,7 +223,7 @@ def model_info(model, verbose=False, img_size=640):
n_p
=
sum
(
x
.
numel
()
for
x
in
model
.
parameters
())
# number parameters
n_g
=
sum
(
x
.
numel
()
for
x
in
model
.
parameters
()
if
x
.
requires_grad
)
# number gradients
if
verbose
:
print
(
f
"
{
'layer'
:
>
5
}
{
'name'
:
>
40
}
{
'gradient'
:
>
9
}
{
'parameters'
:
>
12
}
{
'shape'
:
>
20
}
{
'mu'
:
>
10
}
{
'sigma'
:
>
10
}
"
)
print
(
'%5s %40s %9s %12s %20s %10s %10s'
%
(
'layer'
,
'name'
,
'gradient'
,
'parameters'
,
'shape'
,
'mu'
,
'sigma'
)
)
for
i
,
(
name
,
p
)
in
enumerate
(
model
.
named_parameters
()):
name
=
name
.
replace
(
'module_list.'
,
''
)
print
(
'%5g %40s %9s %12g %20s %10.3g %10.3g'
%
...
...
@@ -236,6 +242,25 @@ def model_info(model, verbose=False, img_size=640):
LOGGER
.
info
(
f
"Model Summary:
{
len
(
list
(
model
.
modules
()))
}
layers,
{
n_p
}
parameters,
{
n_g
}
gradients
{
fs
}
"
)
def
load_classifier
(
name
=
'resnet101'
,
n
=
2
):
# Loads a pretrained model reshaped to n-class output
model
=
torchvision
.
models
.
__dict__
[
name
](
pretrained
=
True
)
# ResNet model properties
# input_size = [3, 224, 224]
# input_space = 'RGB'
# input_range = [0, 1]
# mean = [0.485, 0.456, 0.406]
# std = [0.229, 0.224, 0.225]
# Reshape output to n classes
filters
=
model
.
fc
.
weight
.
shape
[
1
]
model
.
fc
.
bias
=
nn
.
Parameter
(
torch
.
zeros
(
n
),
requires_grad
=
True
)
model
.
fc
.
weight
=
nn
.
Parameter
(
torch
.
zeros
(
n
,
filters
),
requires_grad
=
True
)
model
.
fc
.
out_features
=
n
return
model
def
scale_img
(
img
,
ratio
=
1.0
,
same_shape
=
False
,
gs
=
32
):
# img(16,3,256,416)
# scales img(bs,3,y,x) by ratio constrained to gs-multiple
if
ratio
==
1.0
:
...
...
@@ -245,7 +270,7 @@ def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416)
s
=
(
int
(
h
*
ratio
),
int
(
w
*
ratio
))
# new size
img
=
F
.
interpolate
(
img
,
size
=
s
,
mode
=
'bilinear'
,
align_corners
=
False
)
# resize
if
not
same_shape
:
# pad/crop img
h
,
w
=
(
math
.
ceil
(
x
*
ratio
/
gs
)
*
gs
for
x
in
(
h
,
w
)
)
h
,
w
=
[
math
.
ceil
(
x
*
ratio
/
gs
)
*
gs
for
x
in
(
h
,
w
)
]
return
F
.
pad
(
img
,
[
0
,
w
-
s
[
1
],
0
,
h
-
s
[
0
]],
value
=
0.447
)
# value = imagenet mean
...
...
@@ -274,10 +299,7 @@ class EarlyStopping:
self
.
possible_stop
=
delta
>=
(
self
.
patience
-
1
)
# possible stop may occur next epoch
stop
=
delta
>=
self
.
patience
# stop training if patience exceeded
if
stop
:
LOGGER
.
info
(
f
'Stopping training early as no improvement observed in last
{
self
.
patience
}
epochs. '
f
'Best results observed at epoch
{
self
.
best_epoch
}
, best model saved as best.pt.
\n
'
f
'To update EarlyStopping(patience=
{
self
.
patience
}
) pass a new patience value, '
f
'i.e. `python train.py --patience 300` or use `--patience 0` to disable EarlyStopping.'
)
LOGGER
.
info
(
f
'EarlyStopping patience
{
self
.
patience
}
exceeded, stopping training.'
)
return
stop
...
...
@@ -311,7 +333,7 @@ class ModelEMA:
for
k
,
v
in
self
.
ema
.
state_dict
().
items
():
if
v
.
dtype
.
is_floating_point
:
v
*=
d
v
+=
(
1
-
d
)
*
msd
[
k
].
detach
()
v
+=
(
1
.
-
d
)
*
msd
[
k
].
detach
()
def
update_attr
(
self
,
model
,
include
=
(),
exclude
=
(
'process_group'
,
'reducer'
)):
# Update EMA attributes
...
...
PyTorch/Compute-Vision/Objection/yolov5/val.py
View file @
5a567950
...
...
@@ -3,19 +3,7 @@
Validate a trained YOLOv5 model accuracy on a custom dataset
Usage:
$ python path/to/val.py --weights yolov5s.pt --data coco128.yaml --img 640
Usage - formats:
$ python path/to/val.py --weights yolov5s.pt # PyTorch
yolov5s.torchscript # TorchScript
yolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnn
yolov5s.xml # OpenVINO
yolov5s.engine # TensorRT
yolov5s.mlmodel # CoreML (MacOS-only)
yolov5s_saved_model # TensorFlow SavedModel
yolov5s.pb # TensorFlow GraphDef
yolov5s.tflite # TensorFlow Lite
yolov5s_edgetpu.tflite # TensorFlow Edge TPU
$ python path/to/val.py --data coco128.yaml --weights yolov5s.pt --img 640
"""
import
argparse
...
...
@@ -35,15 +23,15 @@ if str(ROOT) not in sys.path:
sys
.
path
.
append
(
str
(
ROOT
))
# add ROOT to PATH
ROOT
=
Path
(
os
.
path
.
relpath
(
ROOT
,
Path
.
cwd
()))
# relative
from
models.common
import
DetectMultiBackend
from
utils.callbacks
import
Callbacks
from
models.experimental
import
attempt_load
from
utils.datasets
import
create_dataloader
from
utils.general
import
(
LOGGER
,
box_iou
,
check_dataset
,
check_img_size
,
check_requirements
,
check_yaml
,
coco80_to_coco91_class
,
colorstr
,
increment_path
,
non_max_suppression
,
print_args
,
scale_
coor
ds
,
xywh2xyxy
,
xyxy2xywh
)
from
utils.metrics
import
ConfusionMatrix
,
ap_per_class
from
utils.general
import
coco80_to_coco91_class
,
check_dataset
,
check_img_size
,
check_requirements
,
\
check_suffix
,
check_yaml
,
box_iou
,
non_max_suppression
,
scale_coords
,
xyxy2xywh
,
xywh2xyxy
,
set_logging
,
\
increment_path
,
co
l
or
str
,
print_args
from
utils.metrics
import
ap_per_class
,
ConfusionMatrix
from
utils.plots
import
output_to_target
,
plot_images
,
plot_val_study
from
utils.torch_utils
import
select_device
,
time_sync
from
utils.callbacks
import
Callbacks
def
save_one_txt
(
predn
,
save_conf
,
shape
,
file
):
...
...
@@ -101,7 +89,6 @@ def run(data,
iou_thres
=
0.6
,
# NMS IoU threshold
task
=
'val'
,
# train, val, test, speed or study
device
=
''
,
# cuda device, i.e. 0 or 0,1,2,3 or cpu
workers
=
8
,
# max dataloader workers (per RANK in DDP mode)
single_cls
=
False
,
# treat as single-class dataset
augment
=
False
,
# augmented inference
verbose
=
False
,
# verbose output
...
...
@@ -113,7 +100,6 @@ def run(data,
name
=
'exp'
,
# save to project/name
exist_ok
=
False
,
# existing project/name ok, do not increment
half
=
True
,
# use FP16 half-precision inference
dnn
=
False
,
# use OpenCV DNN for ONNX inference
model
=
None
,
dataloader
=
None
,
save_dir
=
Path
(
''
),
...
...
@@ -124,10 +110,8 @@ def run(data,
# Initialize/load model and set device
training
=
model
is
not
None
if
training
:
# called by train.py
device
,
pt
,
jit
,
engine
=
next
(
model
.
parameters
()).
device
,
True
,
False
,
False
# get model device
, PyTorch model
device
=
next
(
model
.
parameters
()).
device
# get model device
half
&=
device
.
type
!=
'cpu'
# half precision only supported on CUDA
model
.
half
()
if
half
else
model
.
float
()
else
:
# called directly
device
=
select_device
(
device
,
batch_size
=
batch_size
)
...
...
@@ -136,23 +120,22 @@ def run(data,
(
save_dir
/
'labels'
if
save_txt
else
save_dir
).
mkdir
(
parents
=
True
,
exist_ok
=
True
)
# make dir
# Load model
model
=
DetectMultiBackend
(
weights
,
device
=
device
,
dnn
=
dnn
,
data
=
data
)
stride
,
pt
,
jit
,
onnx
,
engine
=
model
.
stride
,
model
.
pt
,
model
.
jit
,
model
.
onnx
,
model
.
engine
imgsz
=
check_img_size
(
imgsz
,
s
=
stride
)
# check image size
half
&=
(
pt
or
jit
or
onnx
or
engine
)
and
device
.
type
!=
'cpu'
# FP16 supported on limited backends with CUDA
if
pt
or
jit
:
model
.
model
.
half
()
if
half
else
model
.
model
.
float
()
elif
engine
:
batch_size
=
model
.
batch_size
else
:
half
=
False
batch_size
=
1
# export.py models default to batch-size 1
device
=
torch
.
device
(
'cpu'
)
LOGGER
.
info
(
f
'Forcing --batch-size 1 square inference shape(1,3,
{
imgsz
}
,
{
imgsz
}
) for non-PyTorch backends'
)
check_suffix
(
weights
,
'.pt'
)
model
=
attempt_load
(
weights
,
map_location
=
device
)
# load FP32 model
gs
=
max
(
int
(
model
.
stride
.
max
()),
32
)
# grid size (max stride)
imgsz
=
check_img_size
(
imgsz
,
s
=
gs
)
# check image size
# Multi-GPU disabled, incompatible with .half() https://github.com/ultralytics/yolov5/issues/99
# if device.type != 'cpu' and torch.cuda.device_count() > 1:
# model = nn.DataParallel(model)
# Data
data
=
check_dataset
(
data
)
# check
# Half
half
&=
device
.
type
!=
'cpu'
# half precision only supported on CUDA
model
.
half
()
if
half
else
model
.
float
()
# Configure
model
.
eval
()
is_coco
=
isinstance
(
data
.
get
(
'val'
),
str
)
and
data
[
'val'
].
endswith
(
'coco/val2017.txt'
)
# COCO dataset
...
...
@@ -162,11 +145,12 @@ def run(data,
# Dataloader
if
not
training
:
model
.
warmup
(
imgsz
=
(
1
,
3
,
imgsz
,
imgsz
),
half
=
half
)
# warmup
if
device
.
type
!=
'cpu'
:
model
(
torch
.
zeros
(
1
,
3
,
imgsz
,
imgsz
).
to
(
device
).
type_as
(
next
(
model
.
parameters
())))
# run once
pad
=
0.0
if
task
==
'speed'
else
0.5
task
=
task
if
task
in
(
'train'
,
'val'
,
'test'
)
else
'val'
# path to train/val/test images
dataloader
=
create_dataloader
(
data
[
task
],
imgsz
,
batch_size
,
s
tride
,
single_cls
,
pad
=
pad
,
rect
=
pt
,
workers
=
workers
,
prefix
=
colorstr
(
f
'
{
task
}
: '
))[
0
]
dataloader
=
create_dataloader
(
data
[
task
],
imgsz
,
batch_size
,
g
s
,
single_cls
,
pad
=
pad
,
rect
=
True
,
prefix
=
colorstr
(
f
'
{
task
}
: '
))[
0
]
seen
=
0
confusion_matrix
=
ConfusionMatrix
(
nc
=
nc
)
...
...
@@ -176,34 +160,32 @@ def run(data,
dt
,
p
,
r
,
f1
,
mp
,
mr
,
map50
,
map
=
[
0.0
,
0.0
,
0.0
],
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
,
0.0
loss
=
torch
.
zeros
(
3
,
device
=
device
)
jdict
,
stats
,
ap
,
ap_class
=
[],
[],
[],
[]
pbar
=
tqdm
(
dataloader
,
desc
=
s
,
bar_format
=
'{l_bar}{bar:10}{r_bar}{bar:-10b}'
)
# progress bar
for
batch_i
,
(
im
,
targets
,
paths
,
shapes
)
in
enumerate
(
pbar
):
for
batch_i
,
(
img
,
targets
,
paths
,
shapes
)
in
enumerate
(
tqdm
(
dataloader
,
desc
=
s
)):
t1
=
time_sync
()
if
pt
or
jit
or
engine
:
im
=
im
.
to
(
device
,
non_blocking
=
True
)
targets
=
targets
.
to
(
device
)
im
=
im
.
half
()
if
half
else
im
.
float
()
# uint8 to fp16/32
im
/=
255
# 0 - 255 to 0.0 - 1.0
nb
,
_
,
height
,
width
=
im
.
shape
# batch size, channels, height, width
img
=
img
.
to
(
device
,
non_blocking
=
True
)
img
=
img
.
half
()
if
half
else
img
.
float
()
# uint8 to fp16/32
img
/=
255.0
# 0 - 255 to 0.0 - 1.0
targets
=
targets
.
to
(
device
)
nb
,
_
,
height
,
width
=
img
.
shape
# batch size, channels, height, width
t2
=
time_sync
()
dt
[
0
]
+=
t2
-
t1
#
Inference
out
,
train_out
=
model
(
im
)
if
training
else
model
(
im
,
augment
=
augment
,
val
=
True
)
# inference
, loss
outputs
#
Run model
out
,
train_out
=
model
(
im
g
,
augment
=
augment
)
# inference
and training
outputs
dt
[
1
]
+=
time_sync
()
-
t2
#
L
oss
#
Compute l
oss
if
compute_loss
:
loss
+=
compute_loss
([
x
.
float
()
for
x
in
train_out
],
targets
)[
1
]
# box, obj, cls
# NMS
#
Run
NMS
targets
[:,
2
:]
*=
torch
.
Tensor
([
width
,
height
,
width
,
height
]).
to
(
device
)
# to pixels
lb
=
[
targets
[
targets
[:,
0
]
==
i
,
1
:]
for
i
in
range
(
nb
)]
if
save_hybrid
else
[]
# for autolabelling
t3
=
time_sync
()
out
=
non_max_suppression
(
out
,
conf_thres
,
iou_thres
,
labels
=
lb
,
multi_label
=
True
,
agnostic
=
single_cls
)
dt
[
2
]
+=
time_sync
()
-
t3
#
Metrics
#
Statistics per image
for
si
,
pred
in
enumerate
(
out
):
labels
=
targets
[
targets
[:,
0
]
==
si
,
1
:]
nl
=
len
(
labels
)
...
...
@@ -220,12 +202,12 @@ def run(data,
if
single_cls
:
pred
[:,
5
]
=
0
predn
=
pred
.
clone
()
scale_coords
(
im
[
si
].
shape
[
1
:],
predn
[:,
:
4
],
shape
,
shapes
[
si
][
1
])
# native-space pred
scale_coords
(
im
g
[
si
].
shape
[
1
:],
predn
[:,
:
4
],
shape
,
shapes
[
si
][
1
])
# native-space pred
# Evaluate
if
nl
:
tbox
=
xywh2xyxy
(
labels
[:,
1
:
5
])
# target boxes
scale_coords
(
im
[
si
].
shape
[
1
:],
tbox
,
shape
,
shapes
[
si
][
1
])
# native-space labels
scale_coords
(
im
g
[
si
].
shape
[
1
:],
tbox
,
shape
,
shapes
[
si
][
1
])
# native-space labels
labelsn
=
torch
.
cat
((
labels
[:,
0
:
1
],
tbox
),
1
)
# native-space labels
correct
=
process_batch
(
predn
,
labelsn
,
iouv
)
if
plots
:
...
...
@@ -239,19 +221,19 @@ def run(data,
save_one_txt
(
predn
,
save_conf
,
shape
,
file
=
save_dir
/
'labels'
/
(
path
.
stem
+
'.txt'
))
if
save_json
:
save_one_json
(
predn
,
jdict
,
path
,
class_map
)
# append to COCO-JSON dictionary
callbacks
.
run
(
'on_val_image_end'
,
pred
,
predn
,
path
,
names
,
im
[
si
])
callbacks
.
run
(
'on_val_image_end'
,
pred
,
predn
,
path
,
names
,
im
g
[
si
])
# Plot images
if
plots
and
batch_i
<
3
:
f
=
save_dir
/
f
'val_batch
{
batch_i
}
_labels.jpg'
# labels
Thread
(
target
=
plot_images
,
args
=
(
im
,
targets
,
paths
,
f
,
names
),
daemon
=
True
).
start
()
Thread
(
target
=
plot_images
,
args
=
(
im
g
,
targets
,
paths
,
f
,
names
),
daemon
=
True
).
start
()
f
=
save_dir
/
f
'val_batch
{
batch_i
}
_pred.jpg'
# predictions
Thread
(
target
=
plot_images
,
args
=
(
im
,
output_to_target
(
out
),
paths
,
f
,
names
),
daemon
=
True
).
start
()
Thread
(
target
=
plot_images
,
args
=
(
im
g
,
output_to_target
(
out
),
paths
,
f
,
names
),
daemon
=
True
).
start
()
# Compute
metr
ics
# Compute
statist
ics
stats
=
[
np
.
concatenate
(
x
,
0
)
for
x
in
zip
(
*
stats
)]
# to numpy
if
len
(
stats
)
and
stats
[
0
].
any
():
t
p
,
fp
,
p
,
r
,
f1
,
ap
,
ap_class
=
ap_per_class
(
*
stats
,
plot
=
plots
,
save_dir
=
save_dir
,
names
=
names
)
p
,
r
,
a
p
,
f1
,
ap_class
=
ap_per_class
(
*
stats
,
plot
=
plots
,
save_dir
=
save_dir
,
names
=
names
)
ap50
,
ap
=
ap
[:,
0
],
ap
.
mean
(
1
)
# AP@0.5, AP@0.5:0.95
mp
,
mr
,
map50
,
map
=
p
.
mean
(),
r
.
mean
(),
ap50
.
mean
(),
ap
.
mean
()
nt
=
np
.
bincount
(
stats
[
3
].
astype
(
np
.
int64
),
minlength
=
nc
)
# number of targets per class
...
...
@@ -260,18 +242,18 @@ def run(data,
# Print results
pf
=
'%20s'
+
'%11i'
*
2
+
'%11.3g'
*
4
# print format
LOGGER
.
info
(
pf
%
(
'all'
,
seen
,
nt
.
sum
(),
mp
,
mr
,
map50
,
map
))
print
(
pf
%
(
'all'
,
seen
,
nt
.
sum
(),
mp
,
mr
,
map50
,
map
))
# Print results per class
if
(
verbose
or
(
nc
<
50
and
not
training
))
and
nc
>
1
and
len
(
stats
):
for
i
,
c
in
enumerate
(
ap_class
):
LOGGER
.
info
(
pf
%
(
names
[
c
],
seen
,
nt
[
c
],
p
[
i
],
r
[
i
],
ap50
[
i
],
ap
[
i
]))
print
(
pf
%
(
names
[
c
],
seen
,
nt
[
c
],
p
[
i
],
r
[
i
],
ap50
[
i
],
ap
[
i
]))
# Print speeds
t
=
tuple
(
x
/
seen
*
1E3
for
x
in
dt
)
# speeds per image
if
not
training
:
shape
=
(
batch_size
,
3
,
imgsz
,
imgsz
)
LOGGER
.
info
(
f
'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape
{
shape
}
'
%
t
)
print
(
f
'Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape
{
shape
}
'
%
t
)
# Plots
if
plots
:
...
...
@@ -283,7 +265,7 @@ def run(data,
w
=
Path
(
weights
[
0
]
if
isinstance
(
weights
,
list
)
else
weights
).
stem
if
weights
is
not
None
else
''
# weights
anno_json
=
str
(
Path
(
data
.
get
(
'path'
,
'../coco'
))
/
'annotations/instances_val2017.json'
)
# annotations json
pred_json
=
str
(
save_dir
/
f
"
{
w
}
_predictions.json"
)
# predictions json
LOGGER
.
info
(
f
'
\n
Evaluating pycocotools mAP... saving
{
pred_json
}
...'
)
print
(
f
'
\n
Evaluating pycocotools mAP... saving
{
pred_json
}
...'
)
with
open
(
pred_json
,
'w'
)
as
f
:
json
.
dump
(
jdict
,
f
)
...
...
@@ -302,13 +284,13 @@ def run(data,
eval
.
summarize
()
map
,
map50
=
eval
.
stats
[:
2
]
# update results (mAP@0.5:0.95, mAP@0.5)
except
Exception
as
e
:
LOGGER
.
info
(
f
'pycocotools unable to run:
{
e
}
'
)
print
(
f
'pycocotools unable to run:
{
e
}
'
)
# Return results
model
.
float
()
# for training
if
not
training
:
s
=
f
"
\n
{
len
(
list
(
save_dir
.
glob
(
'labels/*.txt'
)))
}
labels saved to
{
save_dir
/
'labels'
}
"
if
save_txt
else
''
LOGGER
.
info
(
f
"Results saved to
{
colorstr
(
'bold'
,
save_dir
)
}{
s
}
"
)
print
(
f
"Results saved to
{
colorstr
(
'bold'
,
save_dir
)
}{
s
}
"
)
maps
=
np
.
zeros
(
nc
)
+
map
for
i
,
c
in
enumerate
(
ap_class
):
maps
[
c
]
=
ap
[
i
]
...
...
@@ -325,7 +307,6 @@ def parse_opt():
parser
.
add_argument
(
'--iou-thres'
,
type
=
float
,
default
=
0.6
,
help
=
'NMS IoU threshold'
)
parser
.
add_argument
(
'--task'
,
default
=
'val'
,
help
=
'train, val, test, speed or study'
)
parser
.
add_argument
(
'--device'
,
default
=
''
,
help
=
'cuda device, i.e. 0 or 0,1,2,3 or cpu'
)
parser
.
add_argument
(
'--workers'
,
type
=
int
,
default
=
8
,
help
=
'max dataloader workers (per RANK in DDP mode)'
)
parser
.
add_argument
(
'--single-cls'
,
action
=
'store_true'
,
help
=
'treat as single-class dataset'
)
parser
.
add_argument
(
'--augment'
,
action
=
'store_true'
,
help
=
'augmented inference'
)
parser
.
add_argument
(
'--verbose'
,
action
=
'store_true'
,
help
=
'report mAP by class'
)
...
...
@@ -337,7 +318,6 @@ def parse_opt():
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'
)
parser
.
add_argument
(
'--dnn'
,
action
=
'store_true'
,
help
=
'use OpenCV DNN for ONNX inference'
)
opt
=
parser
.
parse_args
()
opt
.
data
=
check_yaml
(
opt
.
data
)
# check YAML
opt
.
save_json
|=
opt
.
data
.
endswith
(
'coco.yaml'
)
...
...
@@ -347,34 +327,32 @@ def parse_opt():
def
main
(
opt
):
check_requirements
(
requirements
=
ROOT
/
'requirements.txt'
,
exclude
=
(
'tensorboard'
,
'thop'
))
set_logging
()
check_requirements
(
exclude
=
(
'tensorboard'
,
'thop'
))
if
opt
.
task
in
(
'train'
,
'val'
,
'test'
):
# run normally
if
opt
.
conf_thres
>
0.001
:
# https://github.com/ultralytics/yolov5/issues/1466
LOGGER
.
info
(
f
'WARNING: confidence threshold
{
opt
.
conf_thres
}
>> 0.001 will produce invalid mAP values.'
)
run
(
**
vars
(
opt
))
else
:
weights
=
opt
.
weights
if
isinstance
(
opt
.
weights
,
list
)
else
[
opt
.
weights
]
opt
.
half
=
True
# FP16 for fastest results
if
opt
.
task
==
'speed'
:
# speed benchmarks
# python val.py --task speed --data coco.yaml --batch 1 --weights yolov5n.pt yolov5s.pt...
opt
.
conf_thres
,
opt
.
iou_thres
,
opt
.
save_json
=
0.25
,
0.45
,
False
for
opt
.
weights
in
weights
:
run
(
**
vars
(
opt
),
plots
=
False
)
elif
opt
.
task
==
'study'
:
# speed vs mAP benchmarks
# python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n.pt yolov5s.pt...
for
opt
.
weights
in
weights
:
f
=
f
'study_
{
Path
(
opt
.
data
).
stem
}
_
{
Path
(
opt
.
weights
).
stem
}
.txt'
# filename to save to
x
,
y
=
list
(
range
(
256
,
1536
+
128
,
128
)),
[]
# x axis (image sizes), y axis
for
opt
.
imgsz
in
x
:
# img-size
LOGGER
.
info
(
f
'
\n
Running
{
f
}
--imgsz
{
opt
.
imgsz
}
...'
)
r
,
_
,
t
=
run
(
**
vars
(
opt
),
plots
=
False
)
y
.
append
(
r
+
t
)
# results and times
np
.
savetxt
(
f
,
y
,
fmt
=
'%10.4g'
)
# save
os
.
system
(
'zip -r study.zip study_*.txt'
)
plot_val_study
(
x
=
x
)
# plot
elif
opt
.
task
==
'speed'
:
# speed benchmarks
# python val.py --task speed --data coco.yaml --batch 1 --weights yolov5n.pt yolov5s.pt...
for
w
in
opt
.
weights
if
isinstance
(
opt
.
weights
,
list
)
else
[
opt
.
weights
]:
run
(
opt
.
data
,
weights
=
w
,
batch_size
=
opt
.
batch_size
,
imgsz
=
opt
.
imgsz
,
conf_thres
=
.
25
,
iou_thres
=
.
45
,
device
=
opt
.
device
,
save_json
=
False
,
plots
=
False
)
elif
opt
.
task
==
'study'
:
# run over a range of settings and save/plot
# python val.py --task study --data coco.yaml --iou 0.7 --weights yolov5n.pt yolov5s.pt...
x
=
list
(
range
(
256
,
1536
+
128
,
128
))
# x axis (image sizes)
for
w
in
opt
.
weights
if
isinstance
(
opt
.
weights
,
list
)
else
[
opt
.
weights
]:
f
=
f
'study_
{
Path
(
opt
.
data
).
stem
}
_
{
Path
(
w
).
stem
}
.txt'
# filename to save to
y
=
[]
# y axis
for
i
in
x
:
# img-size
print
(
f
'
\n
Running
{
f
}
point
{
i
}
...'
)
r
,
_
,
t
=
run
(
opt
.
data
,
weights
=
w
,
batch_size
=
opt
.
batch_size
,
imgsz
=
i
,
conf_thres
=
opt
.
conf_thres
,
iou_thres
=
opt
.
iou_thres
,
device
=
opt
.
device
,
save_json
=
opt
.
save_json
,
plots
=
False
)
y
.
append
(
r
+
t
)
# results and times
np
.
savetxt
(
f
,
y
,
fmt
=
'%10.4g'
)
# save
os
.
system
(
'zip -r study.zip study_*.txt'
)
plot_val_study
(
x
=
x
)
# plot
if
__name__
==
"__main__"
:
...
...
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment