目标
- 使用triplet loss跑通人脸识别器的小样本的训练代码
步骤
- triplet计算细节
- 训练过程中的调用
triplet计算细节
import torch
from torch.autograd import Function
from torch.nn.modules.distance import PairwiseDistance
class TripletLoss(Function):
def __init__(self, margin):
super(TripletLoss, self).__init__()
self.margin = margin
self.pdist = PairwiseDistance(2)
def forward(self, anchor, positive, negative):
# [在triplet_loss.py 的 13行位置处,填写代码,完成triplet loss的计算]
pos_dist=self.pdist.forward(anchor,positive)
neg_dist=self.pdist.forward(anchor,negative)
hinge_dist = torch.clamp(self.margin + pos_dist - neg_dist, min=0.0)
loss = torch.mean(hinge_dist)
return loss
T
r
i
p
l
e
t
L
o
s
s
=
m
a
x
(
0
,
m
a
r
g
i
n
+
d
s
+
d
n
s
)
TripletLoss = max(0, margin + d_s +d_{ns})
TripletLoss=max(0,margin+ds+dns)
其中
d
s
d_s
ds 为anchor和正样本的距离,
d
n
s
d_{ns}
dns为anchor和负样本的距离,margin为自己设置的一个控制loss严苛程度的值。将anchor、正样本、负样本分别通过网络得到feature,计算A与P、 A与N之间的差的L2norm,得到
d
s
d_s
ds 、
d
n
s
d_{ns}
dns,代入计算。
训练调用
triplet_loss = TripletLoss(margin=0.1).forward(anc_embedding,pos_embedding,neg_embedding)
调试运行
因为本次是小数据集训练,所以没有将原始数据集解压,而是用的小样本的数据集。所以要修改训练数据的生成路径:
# 训练数据生成器
train_dataloader = torch.utils.data.DataLoader(
dataset=TrainDataset(
face_dir="../../Datasets/vggface2_train_face",
csv_name='../../Datasets/vggface2_train_face.csv',
num_triplets=1000,
training_triplets_path='../../Datasets/training_triplets_1000_20201101.npy',
transform=train_data_transforms,
predicter_path='shape_predictor_68_face_landmarks.dat',
img_size=256
),
batch_size=30,
num_workers=0,
shuffle=False
)
顺便还发现没有上传landmark模型,补上了。
再次训练:
发现已经成功加载进1000个三元组了,然后报错是在训练完保存模型的时候,没有对应目录。新建一个对应的目录。可以makedir也可以直接手动新建。
增加了epoch的显示,让训练过程心里有个数,原始数据是1900个epoch,等不了那么久,先跑通更重要,于是改了50。
# 打卡时间、epoch
total_time_start = time.time()
start_epoch = start_epoch
end_epoch = start_epoch + 50 #原来是1900 太多了
# 导入l2计算的
l2_distance = PairwiseDistance(2)
# 为了打日志先预制个最低auc和最佳acc在前头
best_roc_auc = -1
best_accuracy = -1
大概十几个epoch就收敛到0了,感觉是过拟合了,估计是样本太少了。相比这些小数量的样本,训练的epoch太多使其产生过拟合的情况。