消融实验:对比不同embedding dim时模型准确率
在上次的作业基础上,更换训练数据集,添加测试数据集与代码。
步骤
0. 环境
pip install cmake
pip install dlib
要等很久,尝试了永久安装路径,cmake可以装到永久路径,但是dlib一装内存就溢出,环境就被关闭了。也不知道为什么。
!换了一下环境到GPU,发现好像可以了诶,问题解决。
1. 训练集
训练数据集选择:VGGFACE2 的训练集 或者 VGGFACE2的测试集
- 下载完成vggface2_train.zip解压缩,得到vggface2_train文件夹
- 由于人脸检测,对齐需要预先处理,所以我们运行week6/image_processing.py,对图片进行检测对齐处理
- 这个时间耗时会非常长,注意时间安排。
- 代码功能一:对齐后的图片保存到vggface2_train_notmask文件夹内
- 代码功能二:对齐后的图片加口罩,保存到vggface2_train_mask文件夹内
- 再运行make_csv_file.py,生成csv文件,为生成triplet做准备。
- 运行 train_dataset.py 检查数据集是否正常。
“====================================================================”
训练集30G, 测试集2G。 选择2G的测试集当做数据集。
修改了项目挂载的数据集,选了一个VGG2的数据集挂载,里面包含了train和test的数据,选择test解压。
压缩week6.zip并上传。
备用一个目录,万一后面修改要用到
aistudio@jupyter-565087-1471370:~/work/liv_ob_detection/week6/Datasets/vggface2_train$
在这个目录下,是每一个人的照片的文件夹。
时间消耗大概需要四五个小时。
train是原始数据集,
train_face_notmask是对齐后的不戴口罩的人脸照片,!!是训练用的文件夹路径!!,比如:
train_face_mask是带口罩的数据,比如:
train_mask_notmask下是剩下的人脸的部分的轮廓,比如:
mask_mask下全是txt的文件,暂时还不知道有什么用(因为不是图片不太直观,估计是生成的口罩的一些数据。)
四个多小时之后终于跑完了。
python make_csv.py
python make_csv_file.py
一开始跑错了,后来发现生成的csv名字不对,掉头重跑。(make_csv的路径是不一样的:
# make_csv_file下的路径
# 定义路径
data_path = os.path.join(pwd, f'Datasets{os.sep}vggface2_train_face_notmask')
csv_path = os.path.join(pwd, f'Datasets{os.sep}vggface2_train_face_notmask.csv')
# ================================================================================
# make_csv下的路径
# 定义路径
data_path = './Datasets/vggface2_train'
csv_path = './Datasets/vggface2_train.csv'
生成csv文件,名称是vggface2_train_face_notmask.csv,内容格式如下:
粗略ctrl f了一下,大概十四万行。(点开卡很久,别再开了)
接下来生成三元子(注意前面改了这里也得重跑 因为训练报错才发现的)
(注意重跑记得删掉原来的三元子)
python train_dataset.py
2. 测试集
测试数据集选择:lfw所有数据,
- 下载方法:打开http://vis-www.cs.umass.edu/lfw/#download,
- 下载All images aligned with funneling,
- 具体下载地址为:http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz
- 之后再下载文件pairs.txt,地址为:http://vis-www.cs.umass.edu/lfw/pairs.txt
- pairs.txt文件是图片对文件,含有测试的图片对,以及标注。
- pairs.txt文件的详细信息说明在readme里:http://vis-www.cs.umass.edu/lfw/README.txt
- 下载完成后,编写dataset_lfw.py文件,配合torchvision.dataloader对测试数据进行读取
- 参考代码位置在:week6/dataset_lfw.py
一开始在aistudio的共享数据集上找到了lfw,该数据集一点备注都没写,不放心又从官网下了一遍,发现内容一样。
准备修改dataset_lfw.py。主要就是改了一下各种文件的路径以及文件夹名称:
如下图,运行dataset_lfw.py会生成测试数据,也就是test_pairs_1.npy
看一下readme中关于pairs.txt的格式描述:
是 名字 图片 图片 或者 名字 图片 名字 图片 的这种格式。
(这下就可以理解为什么dataset_lfw里面关于是否匹配是通过长度来判断的了,同一个人就len == 3,两个人就len == 4)
运行结束,看下结果:
跳过了565个图片对,根据注释,如果每一行记录里面的两张图在数据集里面找不到,就算没匹配上,这个跳过的计数也就会+=1,看起来这个565还不小,想看一下这个pairs.txt发现这个路径包含在一个同级文件数量超过500的文件夹里面,平台上看不到了。只能选择重新上传一份到/week6目录下,方便点开看看。 pairs.txt包含了6000行图像对,看样子跳过了565对也没什么关系。
3. 训练
训练代码:可在上周作业的基础上修改得到。
- 这里需要添加 保存模型功能。方便测试是调用。
week21_homework.py里好像本来就有保存模型的功能吧,应该是不用自己写的。
修改了一下保存模型时候使用的名字,加了一个存embedding的,防止后面换embedding分不清。
torch.save(state, 'Model_training_checkpoints/model_{}_triplet_em_{}_epoch_{}.pt'.format('resnet18',128,epoch + 1))
改个参数,直接跑。
首先是路径,
# 训练数据生成器
train_dataloader = torch.utils.data.DataLoader(
dataset=TrainDataset(
face_dir="././Datasets/vggface2_train_face_notmask",
csv_name='././Datasets/vggface2_train_face_notmask.csv',
num_triplets=1000,
training_triplets_path='././Datasets/training_triplets_1000.npy',
transform=train_data_transforms,
predicter_path='shape_predictor_68_face_landmarks.dat',
img_size=256
),
batch_size=30,
num_workers=0,
shuffle=False
)
根据上次的经验,这模型跑个十几epoch loss就快变0了,但是上次数据相对小,这次数据非常多,时间紧张选个20epoch先试试。先用的默认embedding 128维。 先在目录下新建一个保存模型的文件夹:
炼丹结束,看下质量。
4. 测试
测试代码:week6/week6_test.py,其内调用的具体计算evaluate_lfw函数在代码 eval_lfw_tool.py里。
- 修改week6_test.py 里的模型路径,然后运行测试
config = {'name':'config'}
config['test_pairs_paths'] = './Datasets/test_pairs_1.npy'
config['LFW_data_path'] = './Datasets/lfw_funneled' # 测试数据集选择:lfw所有数据
config['LFW_pairs'] = './lfw_pairs.txt'
config['predicter_path'] = './shape_predictor_68_face_landmarks.dat'
config['image_size']=256
config['test_batch_size'] = 30
config['num_workers']=0
修改模型路径:
#修改模型路径
# 模型加载
model = Resnet18Triplet(pretrained=False,embedding_dimension = 128)
if torch.cuda.is_available():
model.cuda()
print('Using single-gpu testing.')
model_pathi="./Model_training_checkpoints/model_resnet18_triplet_em_128_epoch_20.pt" # 修改模型路径
if os.path.exists(model_pathi):
model_state = torch.load(model_pathi)
model.load_state_dict(model_state['model_state_dict'])
start_epoch = model_state['epoch']
print('loaded %s' % model_pathi)
else:
print('不存在预训练模型!')
运行一下报错了,
看了一下torchvision.models里面也没有这个,就干脆直接把这个类从训练文件week21_homework.py里复制进来了。。
class Resnet18Triplet(nn.Module):
"""Constructs a ResNet-18 model for FaceNet training using triplet loss.
Args:
embedding_dimension (int): Required dimension of the resulting embedding layer that is outputted by the model.
using triplet loss. Defaults to 128.
pretrained (bool): If True, returns a model pre-trained on the ImageNet dataset from a PyTorch repository.
Defaults to False.
"""
def __init__(self, embedding_dimension=128, pretrained=False):
super(Resnet18Triplet, self).__init__()
self.model = models.resnet18(pretrained=pretrained)
input_features_fc_layer = self.model.fc.in_features
# Output embedding
self.model.fc = nn.Linear(input_features_fc_layer, embedding_dimension)
def l2_norm(self, input):
"""Perform l2 normalization operation on an input vector.
code copied from liorshk's repository: https://github.com/liorshk/facenet_pytorch/blob/master/model.py
"""
input_size = input.size()
buffer = torch.pow(input, 2)
normp = torch.sum(buffer, 1).add_(1e-10)
norm = torch.sqrt(normp)
_output = torch.div(input, norm.view(-1, 1).expand_as(input))
output = _output.view(input_size)
return output
def forward(self, images):
"""Forward pass to output the embedding vector (feature vector) after l2-normalization and multiplication
by scalar (alpha)."""
embedding = self.model(images)
embedding = self.l2_norm(embedding)
# Multiply by alpha = 10 as suggested in https://arxiv.org/pdf/1703.09507.pdf
# Equation 9: number of classes in VGGFace2 dataset = 9131
# lower bound on alpha = 5, multiply alpha by 2; alpha = 10
alpha = 10
embedding = embedding * alpha
return embedding
测试结果:
dim = 128的:
dim = 256的:
dim = 64的:
5. 消融实验整理
序号 | epoch | embedding维度 dim | acc | auc |
---|---|---|---|---|
1 | 20 | 128 | 0.585±0.018 | 0.618 |
2 | 20 | 256 | 0.568±0.018 | 0.598 |
3 | 20 | 64 | 0.619±0.031 | 0.669 |