JustinLeee commited on
Commit
8cd6463
·
verified ·
1 Parent(s): 22ea8de

upload model.pth, model.onnx, model.py

Browse files
ArcFace_iResNet50_CASIA_FaceV5.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d76ca98845004f130f017a4778612ee36e3b47f5a8b86351363be12ff71252ce
3
+ size 174398650
ArcFace_iResNet50_CASIA_FaceV5.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c15a06ee387aa4fe62fed50e71f336ce56330a5366629fece100cb8809f3709a
3
+ size 175710586
README.md CHANGED
@@ -1,3 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
- license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
1
+ # FaceMind_ArcFace:针对亚洲人脸 SFT 的 ArcFace 人脸识别模型
2
+ 本模型为以iResNet50为基座的ArcFace模型,在预训练的基础上,使用数据增强的亚洲人脸数据集CASIA_FaceV5进行SFT,旨在提高ArcFace人脸识别模型针对亚洲人脸识别的精确度。
3
+
4
+ ## Reference
5
+ 本模型用于我个人的人脸识别系统 FaceMind:https://github.com/Justin-ljw/FaceMind
6
+
7
+ SFT使用的数据集(我个人清洗并数据增强的CASIA_FaceV5):https://modelscope.cn/datasets/JustinLeee/Cleaned_Augmented_CASIA_FaceV5
8
+
9
+ 预训练模型和训练代码来自GitHub大佬:https://github.com/bubbliiiing/arcface-pytorch
10
+
11
+ ## 仓库说明
12
+ 仓库包含了 pth 和 onnx 格式的模型文件,您可以使用pytorch进一步对pth模型文件进行微调,模型结构文件为iresnet.python、arcface.py,本模型使用iResNet50为基座。
13
+ onnx文件可以直接用于推理,其中已经包含了模型结构,无序显示定义模型结构。
14
+
15
+ ## 快速开始
16
+ 模型文件和权重,可浏览“模型文件”页面获取。您可以通过如下git clone命令,或者ModelScope SDK来下载模型
17
+
18
+ SDK下载
19
+ ```bash
20
+ #安装ModelScope
21
+ pip install modelscope
22
+ ```
23
+ ```python
24
+ #SDK模型下载
25
+ from modelscope import snapshot_download
26
+ model_dir = snapshot_download('JustinLeee/FaceMind_ArcFace_iResNet50_CASIA_FaceV5')
27
+ ```
28
+ Git下载
29
+ ```
30
+ #Git模型下载
31
+ git clone https://www.modelscope.cn/JustinLeee/FaceMind_ArcFace_iResNet50_CASIA_FaceV5.git
32
+ ```
33
+
34
+
35
  ---
36
+ frameworks:
37
+ - Pytorch
38
+
39
+ license: Apache License 2.0
40
+
41
+ tasks:
42
+ - face-recognition
43
+
44
+ model-type:
45
+ - ArcFace_iResNet50
46
+
47
+ domain:
48
+ - cv
49
+
50
+ language:
51
+ - zh
52
+ - en
53
+
54
+ base_model_relation: finetune
55
+
56
+ metrics:
57
+ - accuracy
58
+
59
+ tags:
60
+ - ArcFace
61
+ - CASIA_FaceV5
62
+ - 亚洲人脸
63
+ - 中国人脸
64
+ - fine-tuned
65
+
66
+ datasets:
67
+ - JustinLeee/Cleaned_Augmented_CASIA_FaceV5
68
  ---
69
+
arcface.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+ from torch.nn import Module, Parameter
7
+
8
+ from nets.iresnet import (iresnet18, iresnet34, iresnet50, iresnet100,
9
+ iresnet200)
10
+ from nets.mobilefacenet import get_mbf
11
+ from nets.mobilenet import get_mobilenet
12
+
13
+ class Arcface_Head(Module):
14
+ def __init__(self, embedding_size=128, num_classes=10575, s=64., m=0.5):
15
+ super(Arcface_Head, self).__init__()
16
+ self.s = s
17
+ self.m = m
18
+ self.weight = Parameter(torch.FloatTensor(num_classes, embedding_size))
19
+ nn.init.xavier_uniform_(self.weight)
20
+
21
+ self.cos_m = math.cos(m)
22
+ self.sin_m = math.sin(m)
23
+ self.th = math.cos(math.pi - m)
24
+ self.mm = math.sin(math.pi - m) * m
25
+
26
+ def forward(self, input, label):
27
+ cosine = F.linear(input, F.normalize(self.weight))
28
+ sine = torch.sqrt((1.0 - torch.pow(cosine, 2)).clamp(0, 1))
29
+ phi = cosine * self.cos_m - sine * self.sin_m
30
+ phi = torch.where(cosine.float() > self.th, phi.float(), cosine.float() - self.mm)
31
+
32
+ one_hot = torch.zeros(cosine.size()).type_as(phi).long()
33
+ one_hot.scatter_(1, label.view(-1, 1).long(), 1)
34
+ output = (one_hot * phi) + ((1.0 - one_hot) * cosine)
35
+ output *= self.s
36
+ return output
37
+
38
+ class Arcface(nn.Module):
39
+ def __init__(self, num_classes=None, backbone="mobilefacenet", pretrained=False, mode="train"):
40
+ super(Arcface, self).__init__()
41
+ if backbone=="mobilefacenet":
42
+ embedding_size = 128
43
+ s = 32
44
+ self.arcface = get_mbf(embedding_size=embedding_size, pretrained=pretrained)
45
+
46
+ elif backbone=="mobilenetv1":
47
+ embedding_size = 512
48
+ s = 64
49
+ self.arcface = get_mobilenet(dropout_keep_prob=0.5, embedding_size=embedding_size, pretrained=pretrained)
50
+
51
+ elif backbone=="iresnet18":
52
+ embedding_size = 512
53
+ s = 64
54
+ self.arcface = iresnet18(dropout_keep_prob=0.5, embedding_size=embedding_size, pretrained=pretrained)
55
+
56
+ elif backbone=="iresnet34":
57
+ embedding_size = 512
58
+ s = 64
59
+ self.arcface = iresnet34(dropout_keep_prob=0.5, embedding_size=embedding_size, pretrained=pretrained)
60
+
61
+ elif backbone=="iresnet50":
62
+ embedding_size = 512
63
+ s = 64
64
+ self.arcface = iresnet50(dropout_keep_prob=0.5, embedding_size=embedding_size, pretrained=pretrained)
65
+
66
+ elif backbone=="iresnet100":
67
+ embedding_size = 512
68
+ s = 64
69
+ self.arcface = iresnet100(dropout_keep_prob=0.5, embedding_size=embedding_size, pretrained=pretrained)
70
+
71
+ elif backbone=="iresnet200":
72
+ embedding_size = 512
73
+ s = 64
74
+ self.arcface = iresnet200(dropout_keep_prob=0.5, embedding_size=embedding_size, pretrained=pretrained)
75
+ else:
76
+ raise ValueError('Unsupported backbone - `{}`, Use mobilefacenet, mobilenetv1.'.format(backbone))
77
+
78
+ self.mode = mode
79
+ if mode == "train":
80
+ self.head = Arcface_Head(embedding_size=embedding_size, num_classes=num_classes, s=s)
81
+
82
+ def forward(self, x, y = None, mode = "predict"):
83
+ x = self.arcface(x)
84
+ x = x.view(x.size()[0], -1)
85
+ x = F.normalize(x)
86
+ if mode == "predict":
87
+ return x
88
+ else:
89
+ x = self.head(x, y)
90
+ return x
configuration.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_name": "ArcFace_iResNet50_CASIA_FaceV5",
3
+ "architecture": "iresnet50",
4
+ "framework": "PyTorch",
5
+ "task":"face-recognition",
6
+ "input_size": [112, 112, 3],
7
+ "num_classes": 512,
8
+ "pretrained": true,
9
+ "description": "ArcFace model based on iResNet50 backbone for face recognition. This model has been fine-tuned on the CASIA_FaceV5 dataset.",
10
+ "training_dataset": "CASIA_FaceV5",
11
+ "embedding_size": 512,
12
+ "margin": 0.5,
13
+ "scale": 64.0,
14
+ "optimizer": "Adam",
15
+ "learning_rate": 1e-4,
16
+ "lr_decay_type": "cos",
17
+ "weight_decay": 0,
18
+ "momentum": 0.9,
19
+ "loss_function": "ArcFaceLoss",
20
+ "license": "Apache License 2.0",
21
+ "notes": "This model is trained for face recognition tasks and outputs a 512-dimensional embedding vector. It has been fine-tuned on the CASIA_FaceV5 dataset for improved performance."
22
+ }
iresnet.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ from torch import nn
4
+
5
+ __all__ = ['iresnet18', 'iresnet34', 'iresnet50', 'iresnet100', 'iresnet200']
6
+
7
+
8
+ def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
9
+ return nn.Conv2d(in_planes,
10
+ out_planes,
11
+ kernel_size=3,
12
+ stride=stride,
13
+ padding=dilation,
14
+ groups=groups,
15
+ bias=False,
16
+ dilation=dilation)
17
+
18
+
19
+ def conv1x1(in_planes, out_planes, stride=1):
20
+ return nn.Conv2d(in_planes,
21
+ out_planes,
22
+ kernel_size=1,
23
+ stride=stride,
24
+ bias=False)
25
+
26
+
27
+ class IBasicBlock(nn.Module):
28
+ expansion = 1
29
+ def __init__(self, inplanes, planes, stride=1, downsample=None,
30
+ groups=1, base_width=64, dilation=1):
31
+ super(IBasicBlock, self).__init__()
32
+ if groups != 1 or base_width != 64:
33
+ raise ValueError('BasicBlock only supports groups=1 and base_width=64')
34
+ if dilation > 1:
35
+ raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
36
+ self.bn1 = nn.BatchNorm2d(inplanes, eps=1e-05,)
37
+ self.conv1 = conv3x3(inplanes, planes)
38
+ self.bn2 = nn.BatchNorm2d(planes, eps=1e-05,)
39
+ self.prelu = nn.PReLU(planes)
40
+ self.conv2 = conv3x3(planes, planes, stride)
41
+ self.bn3 = nn.BatchNorm2d(planes, eps=1e-05,)
42
+ self.downsample = downsample
43
+ self.stride = stride
44
+
45
+ def forward(self, x):
46
+ identity = x
47
+ out = self.bn1(x)
48
+ out = self.conv1(out)
49
+ out = self.bn2(out)
50
+ out = self.prelu(out)
51
+ out = self.conv2(out)
52
+ out = self.bn3(out)
53
+ if self.downsample is not None:
54
+ identity = self.downsample(x)
55
+ out += identity
56
+ return out
57
+
58
+
59
+ class IResNet(nn.Module):
60
+ fc_scale = 7 * 7
61
+ def __init__(self,
62
+ block, layers, dropout_keep_prob=0, embedding_size=512, zero_init_residual=False,
63
+ groups=1, width_per_group=64, replace_stride_with_dilation=None, fp16=False):
64
+ super(IResNet, self).__init__()
65
+ self.fp16 = fp16
66
+ self.inplanes = 64
67
+ self.dilation = 1
68
+ if replace_stride_with_dilation is None:
69
+ replace_stride_with_dilation = [False, False, False]
70
+ if len(replace_stride_with_dilation) != 3:
71
+ raise ValueError("replace_stride_with_dilation should be None "
72
+ "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
73
+ self.groups = groups
74
+ self.base_width = width_per_group
75
+ self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
76
+ self.bn1 = nn.BatchNorm2d(self.inplanes, eps=1e-05)
77
+ self.prelu = nn.PReLU(self.inplanes)
78
+ self.layer1 = self._make_layer(block, 64, layers[0], stride=2)
79
+ self.layer2 = self._make_layer(block,
80
+ 128,
81
+ layers[1],
82
+ stride=2,
83
+ dilate=replace_stride_with_dilation[0])
84
+ self.layer3 = self._make_layer(block,
85
+ 256,
86
+ layers[2],
87
+ stride=2,
88
+ dilate=replace_stride_with_dilation[1])
89
+ self.layer4 = self._make_layer(block,
90
+ 512,
91
+ layers[3],
92
+ stride=2,
93
+ dilate=replace_stride_with_dilation[2])
94
+ self.bn2 = nn.BatchNorm2d(512 * block.expansion, eps=1e-05,)
95
+ self.dropout = nn.Dropout(p=dropout_keep_prob, inplace=True)
96
+ self.fc = nn.Linear(512 * block.expansion * self.fc_scale, embedding_size)
97
+ self.features = nn.BatchNorm1d(embedding_size, eps=1e-05)
98
+ nn.init.constant_(self.features.weight, 1.0)
99
+ self.features.weight.requires_grad = False
100
+
101
+ for m in self.modules():
102
+ if isinstance(m, nn.Conv2d):
103
+ nn.init.normal_(m.weight, 0, 0.1)
104
+ elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
105
+ nn.init.constant_(m.weight, 1)
106
+ nn.init.constant_(m.bias, 0)
107
+
108
+ if zero_init_residual:
109
+ for m in self.modules():
110
+ if isinstance(m, IBasicBlock):
111
+ nn.init.constant_(m.bn2.weight, 0)
112
+
113
+ def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
114
+ downsample = None
115
+ previous_dilation = self.dilation
116
+ if dilate:
117
+ self.dilation *= stride
118
+ stride = 1
119
+ if stride != 1 or self.inplanes != planes * block.expansion:
120
+ downsample = nn.Sequential(
121
+ conv1x1(self.inplanes, planes * block.expansion, stride),
122
+ nn.BatchNorm2d(planes * block.expansion, eps=1e-05, ),
123
+ )
124
+ layers = []
125
+ layers.append(
126
+ block(self.inplanes, planes, stride, downsample, self.groups,
127
+ self.base_width, previous_dilation))
128
+ self.inplanes = planes * block.expansion
129
+ for _ in range(1, blocks):
130
+ layers.append(
131
+ block(self.inplanes,
132
+ planes,
133
+ groups=self.groups,
134
+ base_width=self.base_width,
135
+ dilation=self.dilation))
136
+
137
+ return nn.Sequential(*layers)
138
+
139
+ def forward(self, x):
140
+ x = self.conv1(x)
141
+ x = self.bn1(x)
142
+ x = self.prelu(x)
143
+ x = self.layer1(x)
144
+ x = self.layer2(x)
145
+ x = self.layer3(x)
146
+ x = self.layer4(x)
147
+ x = self.bn2(x)
148
+ x = torch.flatten(x, 1)
149
+ x = self.dropout(x)
150
+ x = self.fc(x)
151
+ x = self.features(x)
152
+ return x
153
+
154
+
155
+ def _iresnet(arch, block, layers, pretrained, progress, **kwargs):
156
+ model = IResNet(block, layers, **kwargs)
157
+ if pretrained:
158
+ raise ValueError("No pretrained model for iresnet")
159
+ return model
160
+
161
+
162
+ def iresnet18(pretrained=False, progress=True, **kwargs):
163
+ return _iresnet('iresnet18', IBasicBlock, [2, 2, 2, 2], pretrained,
164
+ progress, **kwargs)
165
+
166
+
167
+ def iresnet34(pretrained=False, progress=True, **kwargs):
168
+ return _iresnet('iresnet34', IBasicBlock, [3, 4, 6, 3], pretrained,
169
+ progress, **kwargs)
170
+
171
+
172
+ def iresnet50(pretrained=False, progress=True, **kwargs):
173
+ return _iresnet('iresnet50', IBasicBlock, [3, 4, 14, 3], pretrained,
174
+ progress, **kwargs)
175
+
176
+
177
+ def iresnet100(pretrained=False, progress=True, **kwargs):
178
+ return _iresnet('iresnet100', IBasicBlock, [3, 13, 30, 3], pretrained,
179
+ progress, **kwargs)
180
+
181
+
182
+ def iresnet200(pretrained=False, progress=True, **kwargs):
183
+ return _iresnet('iresnet200', IBasicBlock, [6, 26, 60, 6], pretrained,
184
+ progress, **kwargs)