作业记录 WEEK7

消融实验:对比不同embedding dim时模型准确率

在上次的作业基础上,更换训练数据集,添加测试数据集与代码。

步骤

0. 环境

pip install cmake
pip install dlib

要等很久,尝试了永久安装路径,cmake可以装到永久路径,但是dlib一装内存就溢出,环境就被关闭了。也不知道为什么。

!换了一下环境到GPU,发现好像可以了诶,问题解决。
作业记录 WEEK7

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$ 

在这个目录下,是每一个人的照片的文件夹。
作业记录 WEEK7
时间消耗大概需要四五个小时
作业记录 WEEK7
train是原始数据集,
train_face_notmask是对齐后的不戴口罩的人脸照片,!!是训练用的文件夹路径!!,比如:
作业记录 WEEK7
train_face_mask是带口罩的数据,比如:
作业记录 WEEK7
train_mask_notmask下是剩下的人脸的部分的轮廓,比如:
作业记录 WEEK7
mask_mask下全是txt的文件,暂时还不知道有什么用(因为不是图片不太直观,估计是生成的口罩的一些数据。)

作业记录 WEEK7
四个多小时之后终于跑完了。

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,内容格式如下:
作业记录 WEEK7

作业记录 WEEK7
粗略ctrl f了一下,大概十四万行。(点开卡很久,别再开了)

接下来生成三元子(注意前面改了这里也得重跑 因为训练报错才发现的)
(注意重跑记得删掉原来的三元子)

python train_dataset.py

作业记录 WEEK7

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。主要就是改了一下各种文件的路径以及文件夹名称:
作业记录 WEEK7
如下图,运行dataset_lfw.py会生成测试数据,也就是test_pairs_1.npy
作业记录 WEEK7
看一下readme中关于pairs.txt的格式描述:
作业记录 WEEK7
名字 图片 图片 或者 名字 图片 名字 图片 的这种格式。
(这下就可以理解为什么dataset_lfw里面关于是否匹配是通过长度来判断的了,同一个人就len == 3,两个人就len == 4)

运行结束,看下结果:作业记录 WEEK7
跳过了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维。 先在目录下新建一个保存模型的文件夹:
作业记录 WEEK7
作业记录 WEEK7
炼丹结束,看下质量。

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('不存在预训练模型!')

运行一下报错了,
作业记录 WEEK7
看了一下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的:
作业记录 WEEK7
dim = 256的:
作业记录 WEEK7
dim = 64的:
作业记录 WEEK7

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
上一篇:Keras中Embedding的参数解释(小白)


下一篇:图推荐算法在E&E问题上的应用