Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
PaddleClas
提交
505c9309
P
PaddleClas
项目概览
PaddlePaddle
/
PaddleClas
大约 1 年 前同步成功
通知
115
Star
4999
Fork
1114
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
19
列表
看板
标记
里程碑
合并请求
6
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleClas
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
19
Issue
19
列表
看板
标记
里程碑
合并请求
6
合并请求
6
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
505c9309
编写于
6月 04, 2021
作者:
D
dongshuilong
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add vehicle neck
上级
76fcde59
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
198 addition
and
38 deletion
+198
-38
ppcls/arch/__init__.py
ppcls/arch/__init__.py
+17
-24
ppcls/arch/gears/__init__.py
ppcls/arch/gears/__init__.py
+6
-3
ppcls/arch/gears/vehicle_neck.py
ppcls/arch/gears/vehicle_neck.py
+52
-0
ppcls/configs/Vehicle/ResNet50.yaml
ppcls/configs/Vehicle/ResNet50.yaml
+8
-5
ppcls/configs/Vehicle/ResNet50_ReID.yaml
ppcls/configs/Vehicle/ResNet50_ReID.yaml
+8
-6
ppcls/loss/supconloss.py
ppcls/loss/supconloss.py
+107
-0
未找到文件。
ppcls/arch/__init__.py
浏览文件 @
505c9309
...
...
@@ -21,7 +21,7 @@ from . import backbone
from
.
import
gears
from
.backbone
import
*
from
.gears
import
*
from
.gears
import
build_gear
from
.utils
import
*
__all__
=
[
"build_model"
,
"RecModel"
]
...
...
@@ -38,34 +38,27 @@ def build_model(config):
class
RecModel
(
nn
.
Layer
):
def
__init__
(
self
,
**
config
):
super
().
__init__
()
backbone_config
=
config
[
"Backbone"
]
backbone_name
=
backbone_config
.
pop
(
"name"
)
self
.
backbone
=
eval
(
backbone_name
)(
**
backbone_config
)
assert
"Stoplayer"
in
config
,
"Stoplayer should be specified in retrieval task
\
please specified a Stoplayer config"
stop_layer_config
=
config
[
"Stoplayer"
]
self
.
backbone
.
stop_after
(
stop_layer_config
[
"name"
])
self
.
backbone
=
getattr
(
backbone_name
)(
**
backbone_config
)
if
"BackboneStopLayer"
in
config
:
backbone_stop_layer
=
config
[
"BackboneStopLayer"
]
self
.
backbone
.
stop_layer
(
backbone_stop_layer
)
if
stop_layer_config
.
get
(
"embedding_size"
,
0
)
>
0
:
self
.
neck
=
nn
.
Linear
(
stop_layer_config
[
"output_dim"
],
stop_layer_config
[
"embedding_size"
])
embedding_size
=
stop_layer_config
[
"embedding_size"
]
if
"Neck"
in
config
:
self
.
neck
=
build_gear
(
config
[
"Neck"
])
else
:
self
.
neck
=
None
embedding_size
=
stop_layer_config
[
"output_dim"
]
assert
"Head"
in
config
,
"Head should be specified in retrieval task
\
please specify a Head config"
config
[
"Head"
][
"embedding_size"
]
=
embedding_size
self
.
head
=
build_head
(
config
[
"Head"
])
if
"Head"
in
config
:
self
.
head
=
build_gear
(
config
[
"Head"
])
else
:
self
.
head
=
None
def
forward
(
self
,
x
,
label
):
x
=
self
.
backbone
(
x
)
def
forward
(
self
,
x
):
y
=
self
.
backbone
(
x
)
if
self
.
neck
is
not
None
:
x
=
self
.
neck
(
x
)
y
=
self
.
head
(
x
,
label
)
return
{
"features"
:
x
,
"logits"
:
y
}
y
=
self
.
neck
(
y
)
if
self
.
head
is
not
None
:
y
=
self
.
head
(
y
)
return
y
ppcls/arch/gears/__init__.py
浏览文件 @
505c9309
...
...
@@ -16,12 +16,15 @@ from .arcmargin import ArcMargin
from
.cosmargin
import
CosMargin
from
.circlemargin
import
CircleMargin
from
.fc
import
FC
from
.vehicle_neck
import
VehicleNeck
__all__
=
[
'build_
head
'
]
__all__
=
[
'build_
gear
'
]
def
build_head
(
config
):
support_dict
=
[
'ArcMargin'
,
'CosMargin'
,
'CircleMargin'
,
'FC'
]
def
build_gear
(
config
):
support_dict
=
[
'ArcMargin'
,
'CosMargin'
,
'CircleMargin'
,
'FC'
,
'VehicleNeck'
]
module_name
=
config
.
pop
(
'name'
)
assert
module_name
in
support_dict
,
Exception
(
'head only support {}'
.
format
(
support_dict
))
...
...
ppcls/arch/gears/vehicle_neck.py
0 → 100644
浏览文件 @
505c9309
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from
__future__
import
absolute_import
,
division
,
print_function
import
paddle
import
paddle.nn
as
nn
class
VehicleNeck
(
nn
.
Layer
):
def
__init__
(
self
,
in_channels
,
out_channels
,
kernel_size
=
1
,
stride
=
1
,
padding
=
0
,
dilation
=
1
,
groups
=
1
,
padding_mode
=
'zeros'
,
weight_attr
=
None
,
bias_attr
=
None
,
data_format
=
'NCHW'
):
super
().
__init__
()
self
.
conv
=
nn
.
Conv2D
(
in_channels
=
in_channels
,
out_channels
=
out_channels
,
kernel_size
=
kernel_size
,
stride
=
stride
,
padding
=
padding
,
dilation
=
dilation
,
groups
=
groups
,
padding_mode
=
padding_mode
,
weight_attr
=
weight_attr
,
bias_attr
=
weight_attr
,
data_format
=
data_format
)
self
.
flatten
=
nn
.
Flatten
()
def
forward
(
self
,
x
):
x
=
self
.
conv
(
x
)
x
=
self
.
flatten
(
x
)
return
x
ppcls/configs/Vehicle/ResNet50.yaml
浏览文件 @
505c9309
...
...
@@ -19,11 +19,14 @@ Global:
Arch
:
name
:
"
RecModel"
Backbone
:
name
:
"
ResNet50"
Stoplayer
:
name
:
"
flatten_0"
output_dim
:
2048
embedding_size
:
512
name
:
"
ResNet50_last_stage_stride1"
pretrained
:
True
BackboneStoplayer
:
name
:
"
adaptive_avg_pool2d_1"
Neck
:
name
:
"
VehicleNeck"
in_channels
:
2048
out_channels
:
512
Head
:
name
:
"
ArcMargin"
embedding_size
:
512
...
...
ppcls/configs/Vehicle/ResNet50_ReID.yaml
浏览文件 @
505c9309
...
...
@@ -19,16 +19,18 @@ Global:
num_split
:
1
feature_normalize
:
True
# model architecture
Arch
:
name
:
"
RecModel"
Backbone
:
name
:
"
ResNet50"
Stoplayer
:
name
:
"
flatten_0"
output_dim
:
2048
embedding_size
:
512
name
:
"
ResNet50_last_stage_stride1"
pretrained
:
True
BackboneStoplayer
:
name
:
"
adaptive_avg_pool2d_1"
Neck
:
name
:
"
VehicleNeck"
in_channels
:
2048
out_channels
:
512
Head
:
name
:
"
ArcMargin"
embedding_size
:
512
...
...
ppcls/loss/supconloss.py
0 → 100644
浏览文件 @
505c9309
import
paddle
from
paddle
import
nn
class
SupConLoss
(
nn
.
Layer
):
"""Supervised Contrastive Learning: https://arxiv.org/pdf/2004.11362.pdf.
It also supports the unsupervised contrastive loss in SimCLR"""
def
__init__
(
self
,
views
=
16
,
temperature
=
0.07
,
contrast_mode
=
'all'
,
base_temperature
=
0.07
,
normalize_feature
=
True
):
super
(
SupConLoss
,
self
).
__init__
()
self
.
temperature
=
paddle
.
to_tensor
(
temperature
)
self
.
contrast_mode
=
contrast_mode
self
.
base_temperature
=
paddle
.
to_tensor
(
base_temperature
)
self
.
num_ids
=
None
self
.
views
=
views
self
.
normalize_feature
=
normalize_feature
def
forward
(
self
,
features
,
labels
,
mask
=
None
):
"""Compute loss for model. If both `labels` and `mask` are None,
it degenerates to SimCLR unsupervised loss:
https://arxiv.org/pdf/2002.05709.pdf
Args:
features: hidden vector of shape [bsz, n_views, ...].
labels: ground truth of shape [bsz].
mask: contrastive mask of shape [bsz, bsz], mask_{i,j}=1 if sample j
has the same class as sample i. Can be asymmetric.
Returns:
A loss scalar.
"""
if
self
.
num_ids
is
None
:
self
.
num_ids
=
int
(
features
.
shape
[
0
]
/
self
.
views
)
if
self
.
normalize_feature
:
features
=
1.
*
features
/
(
paddle
.
expand_as
(
paddle
.
norm
(
features
,
p
=
2
,
axis
=-
1
,
keepdim
=
True
),
features
)
+
1e-12
)
features
=
features
.
reshape
([
self
.
num_ids
,
self
.
views
,
-
1
])
labels
=
labels
.
reshape
([
self
.
num_ids
,
self
.
views
])[:,
0
]
if
len
(
features
.
shape
)
<
3
:
raise
ValueError
(
'`features` needs to be [bsz, n_views, ...],'
'at least 3 dimensions are required'
)
if
len
(
features
.
shape
)
>
3
:
features
=
features
.
reshape
(
[
features
.
shape
[
0
],
features
.
shape
[
1
],
-
1
])
batch_size
=
features
.
shape
[
0
]
if
labels
is
not
None
and
mask
is
not
None
:
raise
ValueError
(
'Cannot define both `labels` and `mask`'
)
elif
labels
is
None
and
mask
is
None
:
mask
=
paddle
.
eye
(
batch_size
,
dtype
=
'float32'
)
elif
labels
is
not
None
:
labels
=
labels
.
reshape
([
-
1
,
1
])
if
labels
.
shape
[
0
]
!=
batch_size
:
raise
ValueError
(
'Num of labels does not match num of features'
)
mask
=
paddle
.
cast
(
paddle
.
equal
(
labels
,
paddle
.
t
(
labels
)),
'float32'
)
else
:
mask
=
paddle
.
cast
(
mask
,
'float32'
)
contrast_count
=
features
.
shape
[
1
]
contrast_feature
=
paddle
.
concat
(
paddle
.
unbind
(
features
,
axis
=
1
),
axis
=
0
)
if
self
.
contrast_mode
==
'one'
:
anchor_feature
=
features
[:,
0
]
anchor_count
=
1
elif
self
.
contrast_mode
==
'all'
:
anchor_feature
=
contrast_feature
anchor_count
=
contrast_count
else
:
raise
ValueError
(
'Unknown mode: {}'
.
format
(
self
.
contrast_mode
))
# compute logits
anchor_dot_contrast
=
paddle
.
divide
(
paddle
.
matmul
(
anchor_feature
,
paddle
.
t
(
contrast_feature
)),
self
.
temperature
)
# for numerical stability
logits_max
=
paddle
.
max
(
anchor_dot_contrast
,
axis
=
1
,
keepdim
=
True
)
logits
=
anchor_dot_contrast
-
logits_max
.
detach
()
# tile mask
mask
=
paddle
.
tile
(
mask
,
[
anchor_count
,
contrast_count
])
logits_mask
=
1
-
paddle
.
eye
(
batch_size
*
anchor_count
)
mask
=
mask
*
logits_mask
# compute log_prob
exp_logits
=
paddle
.
exp
(
logits
)
*
logits_mask
log_prob
=
logits
-
paddle
.
log
(
paddle
.
sum
(
exp_logits
,
axis
=
1
,
keepdim
=
True
))
# compute mean of log-likelihood over positive
mean_log_prob_pos
=
paddle
.
sum
((
mask
*
log_prob
),
axis
=
1
)
/
paddle
.
sum
(
mask
,
axis
=
1
)
# loss
loss
=
-
(
self
.
temperature
/
self
.
base_temperature
)
*
mean_log_prob_pos
loss
=
paddle
.
mean
(
loss
.
reshape
([
anchor_count
,
batch_size
]))
return
loss
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录