Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
菜瓜爱吃瓜
yolov4-pytorch
提交
4e783255
Y
yolov4-pytorch
项目概览
菜瓜爱吃瓜
/
yolov4-pytorch
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
yolov4-pytorch
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
4e783255
编写于
5月 17, 2021
作者:
B
Bubbliiiing
提交者:
GitHub
5月 17, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add files via upload
上级
ff0dfcab
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
203 addition
and
460 deletion
+203
-460
FPS_test.py
FPS_test.py
+2
-11
get_dr_txt.py
get_dr_txt.py
+2
-9
nets/CSPdarknet.py
nets/CSPdarknet.py
+0
-1
nets/yolo_training.py
nets/yolo_training.py
+68
-261
test.py
test.py
+0
-1
train.py
train.py
+55
-71
train_with_tensorboard.py
train_with_tensorboard.py
+58
-74
utils/dataloader.py
utils/dataloader.py
+4
-11
utils/utils.py
utils/utils.py
+1
-7
voc_annotation.py
voc_annotation.py
+6
-5
yolo.py
yolo.py
+7
-9
未找到文件。
FPS_test.py
浏览文件 @
4e783255
import
colorsys
import
os
import
time
import
cv2
import
numpy
as
np
import
torch
import
torch.backends.cudnn
as
cudnn
import
torch.nn
as
nn
from
PIL
import
Image
,
ImageDraw
,
ImageFont
from
torch.autograd
import
Variable
from
tqdm
import
tqdm
from
PIL
import
Image
from
nets.yolo4
import
YoloBody
from
utils.utils
import
(
DecodeBox
,
bbox_iou
,
letterbox_image
,
non_max_suppression
,
yolo_correct_boxes
)
from
utils.utils
import
letterbox_image
,
non_max_suppression
,
yolo_correct_boxes
from
yolo
import
YOLO
'''
...
...
get_dr_txt.py
浏览文件 @
4e783255
...
...
@@ -3,21 +3,14 @@
# 具体教程请查看Bilibili
# Bubbliiiing
#-------------------------------------#
import
colorsys
import
os
import
cv2
import
numpy
as
np
import
torch
import
torch.backends.cudnn
as
cudnn
import
torch.nn
as
nn
from
PIL
import
Image
,
ImageDraw
,
ImageFont
from
torch.autograd
import
Variable
from
PIL
import
Image
from
tqdm
import
tqdm
from
nets.yolo4
import
YoloBody
from
utils.utils
import
(
DecodeBox
,
bbox_iou
,
letterbox_image
,
non_max_suppression
,
yolo_correct_boxes
)
from
utils.utils
import
letterbox_image
,
non_max_suppression
,
yolo_correct_boxes
from
yolo
import
YOLO
...
...
nets/CSPdarknet.py
浏览文件 @
4e783255
import
math
from
collections
import
OrderedDict
import
torch
import
torch.nn
as
nn
...
...
nets/yolo_training.py
浏览文件 @
4e783255
import
cv2
from
random
import
shuffle
import
os
import
math
import
numpy
as
np
import
scipy.signal
import
torch
import
torch.nn
as
nn
import
math
import
torch.nn.functional
as
F
from
matplotlib.colors
import
rgb_to_hsv
,
hsv_to_rgb
from
PIL
import
Image
from
utils.utils
import
bbox_iou
,
merge_bboxes
from
matplotlib
import
pyplot
as
plt
def
jaccard
(
_box_a
,
_box_b
):
b1_x1
,
b1_x2
=
_box_a
[:,
0
]
-
_box_a
[:,
2
]
/
2
,
_box_a
[:,
0
]
+
_box_a
[:,
2
]
/
2
...
...
@@ -427,261 +425,70 @@ class YOLOLoss(nn.Module):
noobj_mask
[
i
][
anch_ious_max
>
self
.
ignore_threshold
]
=
0
return
noobj_mask
,
pred_boxes
def
rand
(
a
=
0
,
b
=
1
):
return
np
.
random
.
rand
()
*
(
b
-
a
)
+
a
class
Generator
(
object
):
def
__init__
(
self
,
batch_size
,
train_lines
,
image_size
,
):
self
.
batch_size
=
batch_size
self
.
train_lines
=
train_lines
self
.
train_batches
=
len
(
train_lines
)
self
.
image_size
=
image_size
def
weights_init
(
net
,
init_type
=
'normal'
,
init_gain
=
0.02
):
def
init_func
(
m
):
classname
=
m
.
__class__
.
__name__
if
hasattr
(
m
,
'weight'
)
and
classname
.
find
(
'Conv'
)
!=
-
1
:
if
init_type
==
'normal'
:
torch
.
nn
.
init
.
normal_
(
m
.
weight
.
data
,
0.0
,
init_gain
)
elif
init_type
==
'xavier'
:
torch
.
nn
.
init
.
xavier_normal_
(
m
.
weight
.
data
,
gain
=
init_gain
)
elif
init_type
==
'kaiming'
:
torch
.
nn
.
init
.
kaiming_normal_
(
m
.
weight
.
data
,
a
=
0
,
mode
=
'fan_in'
)
elif
init_type
==
'orthogonal'
:
torch
.
nn
.
init
.
orthogonal_
(
m
.
weight
.
data
,
gain
=
init_gain
)
else
:
raise
NotImplementedError
(
'initialization method [%s] is not implemented'
%
init_type
)
elif
classname
.
find
(
'BatchNorm2d'
)
!=
-
1
:
torch
.
nn
.
init
.
normal_
(
m
.
weight
.
data
,
1.0
,
0.02
)
torch
.
nn
.
init
.
constant_
(
m
.
bias
.
data
,
0.0
)
print
(
'initialize network with %s type'
%
init_type
)
net
.
apply
(
init_func
)
class
LossHistory
():
def
__init__
(
self
,
log_dir
):
import
datetime
curr_time
=
datetime
.
datetime
.
now
()
time_str
=
datetime
.
datetime
.
strftime
(
curr_time
,
'%Y_%m_%d_%H_%M_%S'
)
self
.
log_dir
=
log_dir
self
.
time_str
=
time_str
self
.
save_path
=
os
.
path
.
join
(
self
.
log_dir
,
"loss_"
+
str
(
self
.
time_str
))
self
.
losses
=
[]
self
.
val_loss
=
[]
def
get_random_data
(
self
,
annotation_line
,
input_shape
,
jitter
=
.
3
,
hue
=
.
1
,
sat
=
1.5
,
val
=
1.5
,
random
=
True
):
'''r实时数据增强的随机预处理'''
line
=
annotation_line
.
split
()
image
=
Image
.
open
(
line
[
0
])
iw
,
ih
=
image
.
size
h
,
w
=
input_shape
box
=
np
.
array
([
np
.
array
(
list
(
map
(
int
,
box
.
split
(
','
))))
for
box
in
line
[
1
:]])
if
not
random
:
scale
=
min
(
w
/
iw
,
h
/
ih
)
nw
=
int
(
iw
*
scale
)
nh
=
int
(
ih
*
scale
)
dx
=
(
w
-
nw
)
//
2
dy
=
(
h
-
nh
)
//
2
image
=
image
.
resize
((
nw
,
nh
),
Image
.
BICUBIC
)
new_image
=
Image
.
new
(
'RGB'
,
(
w
,
h
),
(
128
,
128
,
128
))
new_image
.
paste
(
image
,
(
dx
,
dy
))
image_data
=
np
.
array
(
new_image
,
np
.
float32
)
# 调整目标框坐标
box_data
=
np
.
zeros
((
len
(
box
),
5
))
if
len
(
box
)
>
0
:
np
.
random
.
shuffle
(
box
)
box
[:,
[
0
,
2
]]
=
box
[:,
[
0
,
2
]]
*
nw
/
iw
+
dx
box
[:,
[
1
,
3
]]
=
box
[:,
[
1
,
3
]]
*
nh
/
ih
+
dy
box
[:,
0
:
2
][
box
[:,
0
:
2
]
<
0
]
=
0
box
[:,
2
][
box
[:,
2
]
>
w
]
=
w
box
[:,
3
][
box
[:,
3
]
>
h
]
=
h
box_w
=
box
[:,
2
]
-
box
[:,
0
]
box_h
=
box
[:,
3
]
-
box
[:,
1
]
box
=
box
[
np
.
logical_and
(
box_w
>
1
,
box_h
>
1
)]
# 保留有效框
box_data
=
np
.
zeros
((
len
(
box
),
5
))
box_data
[:
len
(
box
)]
=
box
return
image_data
,
box_data
# resize image
new_ar
=
w
/
h
*
rand
(
1
-
jitter
,
1
+
jitter
)
/
rand
(
1
-
jitter
,
1
+
jitter
)
scale
=
rand
(.
25
,
2
)
if
new_ar
<
1
:
nh
=
int
(
scale
*
h
)
nw
=
int
(
nh
*
new_ar
)
else
:
nw
=
int
(
scale
*
w
)
nh
=
int
(
nw
/
new_ar
)
image
=
image
.
resize
((
nw
,
nh
),
Image
.
BICUBIC
)
# place image
dx
=
int
(
rand
(
0
,
w
-
nw
))
dy
=
int
(
rand
(
0
,
h
-
nh
))
new_image
=
Image
.
new
(
'RGB'
,
(
w
,
h
),
(
128
,
128
,
128
))
new_image
.
paste
(
image
,
(
dx
,
dy
))
image
=
new_image
# flip image or not
flip
=
rand
()
<
.
5
if
flip
:
image
=
image
.
transpose
(
Image
.
FLIP_LEFT_RIGHT
)
# distort image
hue
=
rand
(
-
hue
,
hue
)
sat
=
rand
(
1
,
sat
)
if
rand
()
<
.
5
else
1
/
rand
(
1
,
sat
)
val
=
rand
(
1
,
val
)
if
rand
()
<
.
5
else
1
/
rand
(
1
,
val
)
x
=
cv2
.
cvtColor
(
np
.
array
(
image
,
np
.
float32
)
/
255
,
cv2
.
COLOR_RGB2HSV
)
x
[...,
0
]
+=
hue
*
360
x
[...,
0
][
x
[...,
0
]
>
1
]
-=
1
x
[...,
0
][
x
[...,
0
]
<
0
]
+=
1
x
[...,
1
]
*=
sat
x
[...,
2
]
*=
val
x
[
x
[:,:,
0
]
>
360
,
0
]
=
360
x
[:,
:,
1
:][
x
[:,
:,
1
:]
>
1
]
=
1
x
[
x
<
0
]
=
0
image_data
=
cv2
.
cvtColor
(
x
,
cv2
.
COLOR_HSV2RGB
)
*
255
# correct boxes
box_data
=
np
.
zeros
((
len
(
box
),
5
))
if
len
(
box
)
>
0
:
np
.
random
.
shuffle
(
box
)
box
[:,
[
0
,
2
]]
=
box
[:,
[
0
,
2
]]
*
nw
/
iw
+
dx
box
[:,
[
1
,
3
]]
=
box
[:,
[
1
,
3
]]
*
nh
/
ih
+
dy
if
flip
:
box
[:,
[
0
,
2
]]
=
w
-
box
[:,
[
2
,
0
]]
box
[:,
0
:
2
][
box
[:,
0
:
2
]
<
0
]
=
0
box
[:,
2
][
box
[:,
2
]
>
w
]
=
w
box
[:,
3
][
box
[:,
3
]
>
h
]
=
h
box_w
=
box
[:,
2
]
-
box
[:,
0
]
box_h
=
box
[:,
3
]
-
box
[:,
1
]
box
=
box
[
np
.
logical_and
(
box_w
>
1
,
box_h
>
1
)]
# discard invalid box
box_data
=
np
.
zeros
((
len
(
box
),
5
))
box_data
[:
len
(
box
)]
=
box
return
image_data
,
box_data
def
get_random_data_with_Mosaic
(
self
,
annotation_line
,
input_shape
,
hue
=
.
1
,
sat
=
1.5
,
val
=
1.5
):
'''random preprocessing for real-time data augmentation'''
h
,
w
=
input_shape
min_offset_x
=
0.3
min_offset_y
=
0.3
scale_low
=
1
-
min
(
min_offset_x
,
min_offset_y
)
scale_high
=
scale_low
+
0.2
image_datas
=
[]
box_datas
=
[]
index
=
0
place_x
=
[
0
,
0
,
int
(
w
*
min_offset_x
),
int
(
w
*
min_offset_x
)]
place_y
=
[
0
,
int
(
h
*
min_offset_y
),
int
(
h
*
min_offset_y
),
0
]
for
line
in
annotation_line
:
# 每一行进行分割
line_content
=
line
.
split
()
# 打开图片
image
=
Image
.
open
(
line_content
[
0
])
image
=
image
.
convert
(
"RGB"
)
# 图片的大小
iw
,
ih
=
image
.
size
# 保存框的位置
box
=
np
.
array
([
np
.
array
(
list
(
map
(
int
,
box
.
split
(
','
))))
for
box
in
line_content
[
1
:]])
# 是否翻转图片
flip
=
rand
()
<
.
5
if
flip
and
len
(
box
)
>
0
:
image
=
image
.
transpose
(
Image
.
FLIP_LEFT_RIGHT
)
box
[:,
[
0
,
2
]]
=
iw
-
box
[:,
[
2
,
0
]]
# 对输入进来的图片进行缩放
new_ar
=
w
/
h
scale
=
rand
(
scale_low
,
scale_high
)
if
new_ar
<
1
:
nh
=
int
(
scale
*
h
)
nw
=
int
(
nh
*
new_ar
)
os
.
makedirs
(
self
.
save_path
)
def
append_loss
(
self
,
loss
,
val_loss
):
self
.
losses
.
append
(
loss
)
self
.
val_loss
.
append
(
val_loss
)
with
open
(
os
.
path
.
join
(
self
.
save_path
,
"epoch_loss_"
+
str
(
self
.
time_str
)
+
".txt"
),
'a'
)
as
f
:
f
.
write
(
str
(
loss
))
f
.
write
(
"
\n
"
)
with
open
(
os
.
path
.
join
(
self
.
save_path
,
"epoch_val_loss_"
+
str
(
self
.
time_str
)
+
".txt"
),
'a'
)
as
f
:
f
.
write
(
str
(
val_loss
))
f
.
write
(
"
\n
"
)
self
.
loss_plot
()
def
loss_plot
(
self
):
iters
=
range
(
len
(
self
.
losses
))
plt
.
figure
()
plt
.
plot
(
iters
,
self
.
losses
,
'red'
,
linewidth
=
2
,
label
=
'train loss'
)
plt
.
plot
(
iters
,
self
.
val_loss
,
'coral'
,
linewidth
=
2
,
label
=
'val loss'
)
try
:
if
len
(
self
.
losses
)
<
25
:
num
=
5
else
:
nw
=
int
(
scale
*
w
)
nh
=
int
(
nw
/
new_ar
)
image
=
image
.
resize
((
nw
,
nh
),
Image
.
BICUBIC
)
# 进行色域变换
hue
=
rand
(
-
hue
,
hue
)
sat
=
rand
(
1
,
sat
)
if
rand
()
<
.
5
else
1
/
rand
(
1
,
sat
)
val
=
rand
(
1
,
val
)
if
rand
()
<
.
5
else
1
/
rand
(
1
,
val
)
x
=
cv2
.
cvtColor
(
np
.
array
(
image
,
np
.
float32
)
/
255
,
cv2
.
COLOR_RGB2HSV
)
x
[...,
0
]
+=
hue
*
360
x
[...,
0
][
x
[...,
0
]
>
1
]
-=
1
x
[...,
0
][
x
[...,
0
]
<
0
]
+=
1
x
[...,
1
]
*=
sat
x
[...,
2
]
*=
val
x
[
x
[:,:,
0
]
>
360
,
0
]
=
360
x
[:,
:,
1
:][
x
[:,
:,
1
:]
>
1
]
=
1
x
[
x
<
0
]
=
0
image
=
cv2
.
cvtColor
(
x
,
cv2
.
COLOR_HSV2RGB
)
# numpy array, 0 to 1
num
=
15
image
=
Image
.
fromarray
((
image
*
255
).
astype
(
np
.
uint8
))
# 将图片进行放置,分别对应四张分割图片的位置
dx
=
place_x
[
index
]
dy
=
place_y
[
index
]
new_image
=
Image
.
new
(
'RGB'
,
(
w
,
h
),
(
128
,
128
,
128
))
new_image
.
paste
(
image
,
(
dx
,
dy
))
image_data
=
np
.
array
(
new_image
)
plt
.
plot
(
iters
,
scipy
.
signal
.
savgol_filter
(
self
.
losses
,
num
,
3
),
'green'
,
linestyle
=
'--'
,
linewidth
=
2
,
label
=
'smooth train loss'
)
plt
.
plot
(
iters
,
scipy
.
signal
.
savgol_filter
(
self
.
val_loss
,
num
,
3
),
'#8B4513'
,
linestyle
=
'--'
,
linewidth
=
2
,
label
=
'smooth val loss'
)
except
:
pass
index
=
index
+
1
box_data
=
[]
# 对box进行重新处理
if
len
(
box
)
>
0
:
np
.
random
.
shuffle
(
box
)
box
[:,
[
0
,
2
]]
=
box
[:,
[
0
,
2
]]
*
nw
/
iw
+
dx
box
[:,
[
1
,
3
]]
=
box
[:,
[
1
,
3
]]
*
nh
/
ih
+
dy
box
[:,
0
:
2
][
box
[:,
0
:
2
]
<
0
]
=
0
box
[:,
2
][
box
[:,
2
]
>
w
]
=
w
box
[:,
3
][
box
[:,
3
]
>
h
]
=
h
box_w
=
box
[:,
2
]
-
box
[:,
0
]
box_h
=
box
[:,
3
]
-
box
[:,
1
]
box
=
box
[
np
.
logical_and
(
box_w
>
1
,
box_h
>
1
)]
box_data
=
np
.
zeros
((
len
(
box
),
5
))
box_data
[:
len
(
box
)]
=
box
image_datas
.
append
(
image_data
)
box_datas
.
append
(
box_data
)
# 将图片分割,放在一起
cutx
=
np
.
random
.
randint
(
int
(
w
*
min_offset_x
),
int
(
w
*
(
1
-
min_offset_x
)))
cuty
=
np
.
random
.
randint
(
int
(
h
*
min_offset_y
),
int
(
h
*
(
1
-
min_offset_y
)))
new_image
=
np
.
zeros
([
h
,
w
,
3
])
new_image
[:
cuty
,
:
cutx
,
:]
=
image_datas
[
0
][:
cuty
,
:
cutx
,
:]
new_image
[
cuty
:,
:
cutx
,
:]
=
image_datas
[
1
][
cuty
:,
:
cutx
,
:]
new_image
[
cuty
:,
cutx
:,
:]
=
image_datas
[
2
][
cuty
:,
cutx
:,
:]
new_image
[:
cuty
,
cutx
:,
:]
=
image_datas
[
3
][:
cuty
,
cutx
:,
:]
# 对框进行进一步的处理
new_boxes
=
np
.
array
(
merge_bboxes
(
box_datas
,
cutx
,
cuty
))
if
len
(
new_boxes
)
==
0
:
return
new_image
,
[]
if
(
new_boxes
[:,:
4
]
>
0
).
any
():
return
new_image
,
new_boxes
else
:
return
new_image
,
[]
def
generate
(
self
,
train
=
True
,
mosaic
=
True
):
while
True
:
shuffle
(
self
.
train_lines
)
lines
=
self
.
train_lines
inputs
=
[]
targets
=
[]
flag
=
True
n
=
len
(
lines
)
for
i
in
range
(
len
(
lines
)):
if
mosaic
==
True
:
if
flag
and
(
i
+
4
)
<
n
:
img
,
y
=
self
.
get_random_data_with_Mosaic
(
lines
[
i
:
i
+
4
],
self
.
image_size
[
0
:
2
])
i
=
(
i
+
4
)
%
n
else
:
img
,
y
=
self
.
get_random_data
(
lines
[
i
],
self
.
image_size
[
0
:
2
],
random
=
train
)
i
=
(
i
+
1
)
%
n
flag
=
bool
(
1
-
flag
)
else
:
img
,
y
=
self
.
get_random_data
(
lines
[
i
],
self
.
image_size
[
0
:
2
],
random
=
train
)
i
=
(
i
+
1
)
%
n
if
len
(
y
)
!=
0
:
boxes
=
np
.
array
(
y
[:,:
4
],
dtype
=
np
.
float32
)
boxes
[:,
0
]
=
boxes
[:,
0
]
/
self
.
image_size
[
1
]
boxes
[:,
1
]
=
boxes
[:,
1
]
/
self
.
image_size
[
0
]
boxes
[:,
2
]
=
boxes
[:,
2
]
/
self
.
image_size
[
1
]
boxes
[:,
3
]
=
boxes
[:,
3
]
/
self
.
image_size
[
0
]
boxes
=
np
.
maximum
(
np
.
minimum
(
boxes
,
1
),
0
)
boxes
[:,
2
]
=
boxes
[:,
2
]
-
boxes
[:,
0
]
boxes
[:,
3
]
=
boxes
[:,
3
]
-
boxes
[:,
1
]
boxes
[:,
0
]
=
boxes
[:,
0
]
+
boxes
[:,
2
]
/
2
boxes
[:,
1
]
=
boxes
[:,
1
]
+
boxes
[:,
3
]
/
2
y
=
np
.
concatenate
([
boxes
,
y
[:,
-
1
:]],
axis
=-
1
)
img
=
np
.
array
(
img
,
dtype
=
np
.
float32
)
inputs
.
append
(
np
.
transpose
(
img
/
255.0
,(
2
,
0
,
1
)))
targets
.
append
(
np
.
array
(
y
,
dtype
=
np
.
float32
))
if
len
(
targets
)
==
self
.
batch_size
:
tmp_inp
=
np
.
array
(
inputs
)
tmp_targets
=
targets
inputs
=
[]
targets
=
[]
yield
tmp_inp
,
tmp_targets
plt
.
grid
(
True
)
plt
.
xlabel
(
'Epoch'
)
plt
.
ylabel
(
'Loss'
)
plt
.
legend
(
loc
=
"upper right"
)
plt
.
savefig
(
os
.
path
.
join
(
self
.
save_path
,
"epoch_loss_"
+
str
(
self
.
time_str
)
+
".png"
))
test.py
浏览文件 @
4e783255
...
...
@@ -6,7 +6,6 @@
import
torch
from
torchsummary
import
summary
from
nets.CSPdarknet
import
darknet53
from
nets.yolo4
import
YoloBody
if
__name__
==
"__main__"
:
...
...
train.py
浏览文件 @
4e783255
#-------------------------------------#
# 对数据集进行训练
#-------------------------------------#
import
os
import
time
import
numpy
as
np
import
torch
import
torch.backends.cudnn
as
cudnn
import
torch.nn
as
nn
import
torch.nn.functional
as
F
import
torch.optim
as
optim
from
torch.autograd
import
Variable
from
torch.utils.data
import
DataLoader
from
tqdm
import
tqdm
from
nets.yolo4
import
YoloBody
from
nets.yolo_training
import
Generator
,
YOLOLoss
from
nets.yolo_training
import
YOLOLoss
,
LossHistory
,
weights_init
from
utils.dataloader
import
YoloDataset
,
yolo_dataset_collate
...
...
@@ -41,11 +35,12 @@ def get_lr(optimizer):
return
param_group
[
'lr'
]
def
fit_one_epoch
(
net
,
yolo_loss
es
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
genval
,
Epoch
,
cuda
):
def
fit_one_epoch
(
net
,
yolo_loss
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
genval
,
Epoch
,
cuda
):
total_loss
=
0
val_loss
=
0
net
.
train
()
print
(
'Start Train'
)
with
tqdm
(
total
=
epoch_size
,
desc
=
f
'Epoch
{
epoch
+
1
}
/
{
Epoch
}
'
,
postfix
=
dict
,
mininterval
=
0.3
)
as
pbar
:
for
iteration
,
batch
in
enumerate
(
gen
):
if
iteration
>=
epoch_size
:
...
...
@@ -53,12 +48,11 @@ def fit_one_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
images
,
targets
=
batch
[
0
],
batch
[
1
]
with
torch
.
no_grad
():
if
cuda
:
images
=
Variable
(
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
)
).
cuda
()
targets
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets
]
images
=
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
).
cuda
()
targets
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets
]
else
:
images
=
Variable
(
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
))
targets
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
))
for
ann
in
targets
]
images
=
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
)
targets
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets
]
#----------------------#
# 清零梯度
#----------------------#
...
...
@@ -73,7 +67,7 @@ def fit_one_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
# 计算损失
#----------------------#
for
i
in
range
(
3
):
loss_item
,
num_pos
=
yolo_loss
es
[
i
]
(
outputs
[
i
],
targets
)
loss_item
,
num_pos
=
yolo_loss
(
outputs
[
i
],
targets
)
losses
.
append
(
loss_item
)
num_pos_all
+=
num_pos
...
...
@@ -100,27 +94,29 @@ def fit_one_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
with
torch
.
no_grad
():
if
cuda
:
images_val
=
Variable
(
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
)
).
cuda
()
targets_val
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets_val
]
images_val
=
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
).
cuda
()
targets_val
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets_val
]
else
:
images_val
=
Variable
(
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
)
)
targets_val
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets_val
]
images_val
=
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
)
targets_val
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets_val
]
optimizer
.
zero_grad
()
outputs
=
net
(
images_val
)
losses
=
[]
num_pos_all
=
0
for
i
in
range
(
3
):
loss_item
,
num_pos
=
yolo_loss
es
[
i
]
(
outputs
[
i
],
targets_val
)
loss_item
,
num_pos
=
yolo_loss
(
outputs
[
i
],
targets_val
)
losses
.
append
(
loss_item
)
num_pos_all
+=
num_pos
loss
=
sum
(
losses
)
/
num_pos_all
val_loss
+=
loss
.
item
()
pbar
.
set_postfix
(
**
{
'total_loss'
:
val_loss
/
(
iteration
+
1
)})
pbar
.
update
(
1
)
loss_history
.
append_loss
(
total_loss
/
(
epoch_size
+
1
),
val_loss
/
(
epoch_size_val
+
1
))
print
(
'Finish Validation'
)
print
(
'Epoch:'
+
str
(
epoch
+
1
)
+
'/'
+
str
(
Epoch
))
print
(
'Total Loss: %.4f || Val Loss: %.4f '
%
(
total_loss
/
(
epoch_size
+
1
),
val_loss
/
(
epoch_size_val
+
1
)))
print
(
'Saving state, iter:'
,
str
(
epoch
+
1
))
torch
.
save
(
model
.
state_dict
(),
'logs/Epoch%d-Total_Loss%.4f-Val_Loss%.4f.pth'
%
((
epoch
+
1
),
total_loss
/
(
epoch_size
+
1
),
val_loss
/
(
epoch_size_val
+
1
)))
...
...
@@ -134,10 +130,6 @@ if __name__ == "__main__":
# 没有GPU可以设置成False
#-------------------------------#
Cuda
=
True
#-------------------------------#
# Dataloder的使用
#-------------------------------#
Use_Data_Loader
=
True
#------------------------------------------------------#
# 是否对损失进行归一化,用于改变loss的大小
# 用于决定计算最终loss是除上batch_size还是除上正样本数量
...
...
@@ -179,6 +171,7 @@ if __name__ == "__main__":
# 训练前一定要修改classes_path和对应的txt文件
#------------------------------------------------------#
model
=
YoloBody
(
len
(
anchors
[
0
]),
num_classes
)
weights_init
(
model
)
#------------------------------------------------------#
# 权值文件请看README,百度网盘下载
...
...
@@ -200,11 +193,8 @@ if __name__ == "__main__":
cudnn
.
benchmark
=
True
net
=
net
.
cuda
()
# 建立loss函数
yolo_losses
=
[]
for
i
in
range
(
3
):
yolo_losses
.
append
(
YOLOLoss
(
np
.
reshape
(
anchors
,[
-
1
,
2
]),
num_classes
,
\
(
input_shape
[
1
],
input_shape
[
0
]),
smoooth_label
,
Cuda
,
normalize
))
yolo_loss
=
YOLOLoss
(
np
.
reshape
(
anchors
,[
-
1
,
2
]),
num_classes
,
(
input_shape
[
1
],
input_shape
[
0
]),
smoooth_label
,
Cuda
,
normalize
)
loss_history
=
LossHistory
(
"logs/"
)
#----------------------------------------------------#
# 获得图片路径和标签
...
...
@@ -233,36 +223,33 @@ if __name__ == "__main__":
# 提示OOM或者显存不足请调小Batch_size
#------------------------------------------------------#
if
True
:
lr
=
1e-3
Batch_size
=
4
Init_Epoch
=
0
Freeze_Epoch
=
50
lr
=
1e-3
Batch_size
=
4
Init_Epoch
=
0
Freeze_Epoch
=
50
#----------------------------------------------------------------------------#
# 我在实际测试时,发现optimizer的weight_decay起到了反作用,
# 所以去除掉了weight_decay,大家也可以开起来试试,一般是weight_decay=5e-4
#----------------------------------------------------------------------------#
optimizer
=
optim
.
Adam
(
net
.
parameters
(),
lr
)
optimizer
=
optim
.
Adam
(
net
.
parameters
(),
lr
)
if
Cosine_lr
:
lr_scheduler
=
optim
.
lr_scheduler
.
CosineAnnealingLR
(
optimizer
,
T_max
=
5
,
eta_min
=
1e-5
)
else
:
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
if
Use_Data_Loader
:
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
else
:
gen
=
Generator
(
Batch_size
,
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
True
,
mosaic
=
mosaic
)
gen_val
=
Generator
(
Batch_size
,
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
False
,
mosaic
=
mosaic
)
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
epoch_size
=
max
(
1
,
num_train
//
Batch_size
)
epoch_size_val
=
num_val
//
Batch_size
epoch_size
=
num_train
//
Batch_size
epoch_size_val
=
num_val
//
Batch_size
if
epoch_size
==
0
or
epoch_size_val
==
0
:
raise
ValueError
(
"数据集过小,无法进行训练,请扩充数据集。"
)
#------------------------------------#
# 冻结一定部分训练
#------------------------------------#
...
...
@@ -270,40 +257,37 @@ if __name__ == "__main__":
param
.
requires_grad
=
False
for
epoch
in
range
(
Init_Epoch
,
Freeze_Epoch
):
fit_one_epoch
(
net
,
yolo_loss
es
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Freeze_Epoch
,
Cuda
)
fit_one_epoch
(
net
,
yolo_loss
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Freeze_Epoch
,
Cuda
)
lr_scheduler
.
step
()
if
True
:
lr
=
1e-4
Batch_size
=
2
Freeze_Epoch
=
50
Unfreeze_Epoch
=
100
lr
=
1e-4
Batch_size
=
2
Freeze_Epoch
=
50
Unfreeze_Epoch
=
100
#----------------------------------------------------------------------------#
# 我在实际测试时,发现optimizer的weight_decay起到了反作用,
# 所以去除掉了weight_decay,大家也可以开起来试试,一般是weight_decay=5e-4
#----------------------------------------------------------------------------#
optimizer
=
optim
.
Adam
(
net
.
parameters
(),
lr
)
optimizer
=
optim
.
Adam
(
net
.
parameters
(),
lr
)
if
Cosine_lr
:
lr_scheduler
=
optim
.
lr_scheduler
.
CosineAnnealingLR
(
optimizer
,
T_max
=
5
,
eta_min
=
1e-5
)
else
:
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
if
Use_Data_Loader
:
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
else
:
gen
=
Generator
(
Batch_size
,
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
True
,
mosaic
=
mosaic
)
gen_val
=
Generator
(
Batch_size
,
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
False
,
mosaic
=
mosaic
)
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
epoch_size
=
max
(
1
,
num_train
//
Batch_size
)
epoch_size_val
=
num_val
//
Batch_size
epoch_size
=
num_train
//
Batch_size
epoch_size_val
=
num_val
//
Batch_size
if
epoch_size
==
0
or
epoch_size_val
==
0
:
raise
ValueError
(
"数据集过小,无法进行训练,请扩充数据集。"
)
#------------------------------------#
# 解冻后训练
#------------------------------------#
...
...
@@ -311,5 +295,5 @@ if __name__ == "__main__":
param
.
requires_grad
=
True
for
epoch
in
range
(
Freeze_Epoch
,
Unfreeze_Epoch
):
fit_one_epoch
(
net
,
yolo_loss
es
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Unfreeze_Epoch
,
Cuda
)
fit_one_epoch
(
net
,
yolo_loss
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Unfreeze_Epoch
,
Cuda
)
lr_scheduler
.
step
()
train_with_tensorboard.py
浏览文件 @
4e783255
#-------------------------------------#
# 对数据集进行训练
#-------------------------------------#
import
os
import
numpy
as
np
import
time
import
torch
from
torch.autograd
import
Variable
import
torch.nn
as
nn
import
torch.optim
as
optim
import
torch.nn.functional
as
F
import
torch.backends.cudnn
as
cudnn
from
torch.utils.data
import
DataLoader
from
utils.dataloader
import
yolo_dataset_collate
,
YoloDataset
from
nets.yolo_training
import
YOLOLoss
,
Generator
from
nets.yolo4
import
YoloBody
import
torch.optim
as
optim
from
tensorboardX
import
SummaryWriter
from
torch.utils.data
import
DataLoader
from
tqdm
import
tqdm
from
nets.yolo4
import
YoloBody
from
nets.yolo_training
import
YOLOLoss
from
utils.dataloader
import
YoloDataset
,
yolo_dataset_collate
#---------------------------------------------------#
# 获得类和先验框
#---------------------------------------------------#
...
...
@@ -38,12 +35,13 @@ def get_lr(optimizer):
for
param_group
in
optimizer
.
param_groups
:
return
param_group
[
'lr'
]
def
fit_ont_epoch
(
net
,
yolo_loss
es
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
genval
,
Epoch
,
cuda
,
writer
):
def
fit_ont_epoch
(
net
,
yolo_loss
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
genval
,
Epoch
,
cuda
,
writer
):
global
train_tensorboard_step
,
val_tensorboard_step
total_loss
=
0
val_loss
=
0
net
.
train
()
print
(
'Start Train'
)
with
tqdm
(
total
=
epoch_size
,
desc
=
f
'Epoch
{
epoch
+
1
}
/
{
Epoch
}
'
,
postfix
=
dict
,
mininterval
=
0.3
)
as
pbar
:
for
iteration
,
batch
in
enumerate
(
gen
):
if
iteration
>=
epoch_size
:
...
...
@@ -51,11 +49,11 @@ def fit_ont_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
images
,
targets
=
batch
[
0
],
batch
[
1
]
with
torch
.
no_grad
():
if
cuda
:
images
=
Variable
(
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
)
).
cuda
()
targets
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets
]
images
=
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
).
cuda
()
targets
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets
]
else
:
images
=
Variable
(
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
)
)
targets
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets
]
images
=
torch
.
from_numpy
(
images
).
type
(
torch
.
FloatTensor
)
targets
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets
]
#----------------------#
# 清零梯度
...
...
@@ -71,7 +69,7 @@ def fit_ont_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
# 计算损失
#----------------------#
for
i
in
range
(
3
):
loss_item
,
num_pos
=
yolo_loss
es
[
i
]
(
outputs
[
i
],
targets
)
loss_item
,
num_pos
=
yolo_loss
(
outputs
[
i
],
targets
)
losses
.
append
(
loss_item
)
num_pos_all
+=
num_pos
...
...
@@ -104,17 +102,17 @@ def fit_ont_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
with
torch
.
no_grad
():
if
cuda
:
images_val
=
Variable
(
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
)
).
cuda
()
targets_val
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets_val
]
images_val
=
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
).
cuda
()
targets_val
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets_val
]
else
:
images_val
=
Variable
(
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
)
)
targets_val
=
[
Variable
(
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
)
for
ann
in
targets_val
]
images_val
=
torch
.
from_numpy
(
images_val
).
type
(
torch
.
FloatTensor
)
targets_val
=
[
torch
.
from_numpy
(
ann
).
type
(
torch
.
FloatTensor
)
for
ann
in
targets_val
]
optimizer
.
zero_grad
()
outputs
=
net
(
images_val
)
losses
=
[]
num_pos_all
=
0
for
i
in
range
(
3
):
loss_item
,
num_pos
=
yolo_loss
es
[
i
]
(
outputs
[
i
],
targets_val
)
loss_item
,
num_pos
=
yolo_loss
(
outputs
[
i
],
targets_val
)
losses
.
append
(
loss_item
)
num_pos_all
+=
num_pos
...
...
@@ -133,7 +131,6 @@ def fit_ont_epoch(net,yolo_losses,epoch,epoch_size,epoch_size_val,gen,genval,Epo
print
(
'Finish Validation'
)
print
(
'Epoch:'
+
str
(
epoch
+
1
)
+
'/'
+
str
(
Epoch
))
print
(
'Total Loss: %.4f || Val Loss: %.4f '
%
(
total_loss
/
(
epoch_size
+
1
),
val_loss
/
(
epoch_size_val
+
1
)))
print
(
'Saving state, iter:'
,
str
(
epoch
+
1
))
torch
.
save
(
model
.
state_dict
(),
'logs/Epoch%d-Total_Loss%.4f-Val_Loss%.4f.pth'
%
((
epoch
+
1
),
total_loss
/
(
epoch_size
+
1
),
val_loss
/
(
epoch_size_val
+
1
)))
...
...
@@ -144,10 +141,6 @@ if __name__ == "__main__":
# 没有GPU可以设置成False
#-------------------------------#
Cuda
=
True
#-------------------------------#
# Dataloder的使用
#-------------------------------#
Use_Data_Loader
=
True
#------------------------------------------------------#
# 是否对损失进行归一化,用于改变loss的大小
# 用于决定计算最终loss是除上batch_size还是除上正样本数量
...
...
@@ -211,11 +204,8 @@ if __name__ == "__main__":
net
=
net
.
cuda
()
# 建立loss函数
yolo_losses
=
[]
for
i
in
range
(
3
):
yolo_losses
.
append
(
YOLOLoss
(
np
.
reshape
(
anchors
,[
-
1
,
2
]),
num_classes
,
\
(
input_shape
[
1
],
input_shape
[
0
]),
smoooth_label
,
Cuda
,
normalize
))
yolo_loss
=
YOLOLoss
(
np
.
reshape
(
anchors
,[
-
1
,
2
]),
num_classes
,
(
input_shape
[
1
],
input_shape
[
0
]),
smoooth_label
,
Cuda
,
normalize
)
#----------------------------------------------------#
# 获得图片路径和标签
#----------------------------------------------------#
...
...
@@ -252,36 +242,33 @@ if __name__ == "__main__":
train_tensorboard_step
=
1
val_tensorboard_step
=
1
if
True
:
lr
=
1e-3
Batch_size
=
4
Init_Epoch
=
0
Freeze_Epoch
=
50
lr
=
1e-3
Batch_size
=
4
Init_Epoch
=
0
Freeze_Epoch
=
50
#----------------------------------------------------------------------------#
# 我在实际测试时,发现optimizer的weight_decay起到了反作用,
# 所以去除掉了weight_decay,大家也可以开起来试试,一般是weight_decay=5e-4
#----------------------------------------------------------------------------#
optimizer
=
optim
.
Adam
(
net
.
parameters
(),
lr
)
optimizer
=
optim
.
Adam
(
net
.
parameters
(),
lr
)
if
Cosine_lr
:
lr_scheduler
=
optim
.
lr_scheduler
.
CosineAnnealingLR
(
optimizer
,
T_max
=
5
,
eta_min
=
1e-5
)
else
:
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
if
Use_Data_Loader
:
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
else
:
gen
=
Generator
(
Batch_size
,
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
True
,
mosaic
=
mosaic
)
gen_val
=
Generator
(
Batch_size
,
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
False
,
mosaic
=
False
)
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
epoch_size
=
max
(
1
,
num_train
//
Batch_size
)
epoch_size_val
=
num_val
//
Batch_size
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
epoch_size
=
num_train
//
Batch_size
epoch_size_val
=
num_val
//
Batch_size
if
epoch_size
==
0
or
epoch_size_val
==
0
:
raise
ValueError
(
"数据集过小,无法进行训练,请扩充数据集。"
)
#------------------------------------#
# 冻结一定部分训练
#------------------------------------#
...
...
@@ -289,14 +276,14 @@ if __name__ == "__main__":
param
.
requires_grad
=
False
for
epoch
in
range
(
Init_Epoch
,
Freeze_Epoch
):
fit_ont_epoch
(
net
,
yolo_loss
es
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Freeze_Epoch
,
Cuda
,
writer
)
fit_ont_epoch
(
net
,
yolo_loss
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Freeze_Epoch
,
Cuda
,
writer
)
lr_scheduler
.
step
()
if
True
:
lr
=
1e-4
Batch_size
=
2
Freeze_Epoch
=
50
Unfreeze_Epoch
=
100
lr
=
1e-4
Batch_size
=
2
Freeze_Epoch
=
50
Unfreeze_Epoch
=
100
#----------------------------------------------------------------------------#
# 我在实际测试时,发现optimizer的weight_decay起到了反作用,
...
...
@@ -306,23 +293,20 @@ if __name__ == "__main__":
if
Cosine_lr
:
lr_scheduler
=
optim
.
lr_scheduler
.
CosineAnnealingLR
(
optimizer
,
T_max
=
5
,
eta_min
=
1e-5
)
else
:
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
if
Use_Data_Loader
:
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
else
:
gen
=
Generator
(
Batch_size
,
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
True
,
mosaic
=
mosaic
)
gen_val
=
Generator
(
Batch_size
,
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
])).
generate
(
train
=
False
,
mosaic
=
False
)
lr_scheduler
=
optim
.
lr_scheduler
.
StepLR
(
optimizer
,
step_size
=
1
,
gamma
=
0.92
)
epoch_size
=
max
(
1
,
num_train
//
Batch_size
)
epoch_size_val
=
num_val
//
Batch_size
train_dataset
=
YoloDataset
(
lines
[:
num_train
],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
mosaic
,
is_train
=
True
)
val_dataset
=
YoloDataset
(
lines
[
num_train
:],
(
input_shape
[
0
],
input_shape
[
1
]),
mosaic
=
False
,
is_train
=
False
)
gen
=
DataLoader
(
train_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
gen_val
=
DataLoader
(
val_dataset
,
shuffle
=
True
,
batch_size
=
Batch_size
,
num_workers
=
4
,
pin_memory
=
True
,
drop_last
=
True
,
collate_fn
=
yolo_dataset_collate
)
epoch_size
=
num_train
//
Batch_size
epoch_size_val
=
num_val
//
Batch_size
if
epoch_size
==
0
or
epoch_size_val
==
0
:
raise
ValueError
(
"数据集过小,无法进行训练,请扩充数据集。"
)
#------------------------------------#
# 解冻后训练
#------------------------------------#
...
...
@@ -330,5 +314,5 @@ if __name__ == "__main__":
param
.
requires_grad
=
True
for
epoch
in
range
(
Freeze_Epoch
,
Unfreeze_Epoch
):
fit_ont_epoch
(
net
,
yolo_loss
es
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Unfreeze_Epoch
,
Cuda
,
writer
)
fit_ont_epoch
(
net
,
yolo_loss
,
epoch
,
epoch_size
,
epoch_size_val
,
gen
,
gen_val
,
Unfreeze_Epoch
,
Cuda
,
writer
)
lr_scheduler
.
step
()
utils/dataloader.py
浏览文件 @
4e783255
from
random
import
shuffle
import
cv2
import
numpy
as
np
import
torch
import
torch.nn
as
nn
import
math
import
torch.nn.functional
as
F
from
PIL
import
Image
from
torch.autograd
import
Variable
from
torch.utils.data
import
DataLoader
from
torch.utils.data.dataset
import
Dataset
from
utils.utils
import
bbox_iou
,
merge_bboxes
from
matplotlib.colors
import
rgb_to_hsv
,
hsv_to_rgb
from
nets.yolo_training
import
Generator
import
cv2
from
utils.utils
import
merge_bboxes
class
YoloDataset
(
Dataset
):
def
__init__
(
self
,
train_lines
,
image_size
,
mosaic
=
True
,
is_train
=
True
):
...
...
utils/utils.py
浏览文件 @
4e783255
from
__future__
import
division
import
math
import
os
import
time
import
numpy
as
np
import
torch
import
torch.nn
as
nn
import
torch.nn.functional
as
F
from
PIL
import
Image
,
ImageDraw
,
ImageFont
from
torch.autograd
import
Variable
from
PIL
import
Image
from
torchvision.ops
import
nms
...
...
voc_annotation.py
浏览文件 @
4e783255
...
...
@@ -7,7 +7,9 @@ import xml.etree.ElementTree as ET
from
os
import
getcwd
sets
=
[(
'2007'
,
'train'
),
(
'2007'
,
'val'
),
(
'2007'
,
'test'
)]
#-----------------------------------------------------#
# 这里设定的classes顺序要和model_data里的txt一样
#-----------------------------------------------------#
classes
=
[
"aeroplane"
,
"bicycle"
,
"bird"
,
"boat"
,
"bottle"
,
"bus"
,
"car"
,
"cat"
,
"chair"
,
"cow"
,
"diningtable"
,
"dog"
,
"horse"
,
"motorbike"
,
"person"
,
"pottedplant"
,
"sheep"
,
"sofa"
,
"train"
,
"tvmonitor"
]
def
convert_annotation
(
year
,
image_id
,
list_file
):
...
...
@@ -19,20 +21,19 @@ def convert_annotation(year, image_id, list_file):
difficult
=
0
if
obj
.
find
(
'difficult'
)
!=
None
:
difficult
=
obj
.
find
(
'difficult'
).
text
cls
=
obj
.
find
(
'name'
).
text
if
cls
not
in
classes
or
int
(
difficult
)
==
1
:
continue
cls_id
=
classes
.
index
(
cls
)
xmlbox
=
obj
.
find
(
'bndbox'
)
b
=
(
int
(
xmlbox
.
find
(
'xmin'
).
text
),
int
(
xmlbox
.
find
(
'ymin'
).
text
),
int
(
xmlbox
.
find
(
'xmax'
).
text
),
int
(
xmlbox
.
find
(
'ymax'
).
text
))
b
=
(
int
(
float
(
xmlbox
.
find
(
'xmin'
).
text
)),
int
(
float
(
xmlbox
.
find
(
'ymin'
).
text
)),
int
(
float
(
xmlbox
.
find
(
'xmax'
).
text
)),
int
(
float
(
xmlbox
.
find
(
'ymax'
).
text
)
))
list_file
.
write
(
" "
+
","
.
join
([
str
(
a
)
for
a
in
b
])
+
','
+
str
(
cls_id
))
wd
=
getcwd
()
for
year
,
image_set
in
sets
:
image_ids
=
open
(
'VOCdevkit/VOC%s/ImageSets/Main/%s.txt'
%
(
year
,
image_set
)).
read
().
strip
().
split
()
list_file
=
open
(
'%s_%s.txt'
%
(
year
,
image_set
),
'w'
)
image_ids
=
open
(
'VOCdevkit/VOC%s/ImageSets/Main/%s.txt'
%
(
year
,
image_set
)
,
encoding
=
'utf-8'
).
read
().
strip
().
split
()
list_file
=
open
(
'%s_%s.txt'
%
(
year
,
image_set
),
'w'
,
encoding
=
'utf-8'
)
for
image_id
in
image_ids
:
list_file
.
write
(
'%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg'
%
(
wd
,
year
,
image_id
))
convert_annotation
(
year
,
image_id
,
list_file
)
...
...
yolo.py
浏览文件 @
4e783255
...
...
@@ -4,16 +4,13 @@
import
colorsys
import
os
import
cv2
import
numpy
as
np
import
torch
import
torch.backends.cudnn
as
cudnn
import
torch.nn
as
nn
from
PIL
import
Image
,
ImageDraw
,
ImageFont
from
torch.autograd
import
Variable
from
nets.yolo4
import
YoloBody
from
utils.utils
import
(
DecodeBox
,
bbox_iou
,
letterbox_image
,
from
utils.utils
import
(
DecodeBox
,
letterbox_image
,
non_max_suppression
,
yolo_correct_boxes
)
...
...
@@ -94,7 +91,6 @@ class YOLO(object):
print
(
'Finished!'
)
if
self
.
cuda
:
os
.
environ
[
"CUDA_VISIBLE_DEVICES"
]
=
'0'
self
.
net
=
nn
.
DataParallel
(
self
.
net
)
self
.
net
=
self
.
net
.
cuda
()
...
...
@@ -105,7 +101,6 @@ class YOLO(object):
for
i
in
range
(
3
):
self
.
yolo_decodes
.
append
(
DecodeBox
(
self
.
anchors
[
i
],
len
(
self
.
class_names
),
(
self
.
model_image_size
[
1
],
self
.
model_image_size
[
0
])))
print
(
'{} model, anchors, and classes loaded.'
.
format
(
self
.
model_path
))
# 画框设置不同的颜色
hsv_tuples
=
[(
x
/
len
(
self
.
class_names
),
1.
,
1.
)
...
...
@@ -119,8 +114,12 @@ class YOLO(object):
# 检测图片
#---------------------------------------------------#
def
detect_image
(
self
,
image
):
image_shape
=
np
.
array
(
np
.
shape
(
image
)[
0
:
2
])
#---------------------------------------------------------#
# 在这里将图像转换成RGB图像,防止灰度图在预测时报错。
#---------------------------------------------------------#
image
=
image
.
convert
(
'RGB'
)
image_shape
=
np
.
array
(
np
.
shape
(
image
)[
0
:
2
])
#---------------------------------------------------------#
# 给图像增加灰条,实现不失真的resize
# 也可以直接resize进行识别
...
...
@@ -128,8 +127,7 @@ class YOLO(object):
if
self
.
letterbox_image
:
crop_img
=
np
.
array
(
letterbox_image
(
image
,
(
self
.
model_image_size
[
1
],
self
.
model_image_size
[
0
])))
else
:
crop_img
=
image
.
convert
(
'RGB'
)
crop_img
=
crop_img
.
resize
((
self
.
model_image_size
[
1
],
self
.
model_image_size
[
0
]),
Image
.
BICUBIC
)
crop_img
=
image
.
resize
((
self
.
model_image_size
[
1
],
self
.
model_image_size
[
0
]),
Image
.
BICUBIC
)
photo
=
np
.
array
(
crop_img
,
dtype
=
np
.
float32
)
/
255.0
photo
=
np
.
transpose
(
photo
,
(
2
,
0
,
1
))
#---------------------------------------------------------#
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录