当前位置: 首页 > 科技观察

使用深度学习进行人脸解锁

时间:2023-03-13 17:48:20 科技观察

今天我们将使用深度学习来创建人脸解锁算法。完成我们的任务需要三个主要部分。寻找人脸的算法一种在向量空间中嵌入人脸的方法编码人脸的比较函数人脸寻找和定位首先,我们需要一种在图像中寻找人脸的方法。我们可以使用称为MTCNN(多任务级联卷积网络)的端到端方法。只是一点技术背景,之所以称为Cascaded,是因为它由多个阶段组成,每个阶段都有其神经网络。下图显示了框架。我们依赖于facenet-pytorch中的MTCNN实现。数据我们需要图像!我整理了一些照片,莱昂纳多迪卡普里奥和马特达蒙。遵循PyTorch最佳实践,我使用ImageFolder加载数据集。我创建了MTCNN实例并使用转换参数将数据集传递给它。我的文件夹结构如下:./faces├──di_caprio│├──....jpg├──matt_demon│├──....jpg└──me│├──....jpgMTCNN自动裁剪并调整输入大小,我使用image_size=160因为模型将使用该大小的图像进行训练。我还添加了18px的边距以确保我们包含整个面部。importtorchimporttorchvision.transformsasTimportmatplotlib.pyplotaspltfromtorch.utils.dataimportDataset,DataLoaderfromtorchvision.datasetsimportImageFolderfromfacenet_pytorchimportMTCNN,InceptionResnetV1frompathlibimportPathfromtypingimportUnion,Callabledata_root=Path('.')#createtheMTCNNnetworktransform=MTCNN(image_size=160,margin=18)ds=ImageFolder(root=data_root/'faces',transform=transform)#ourdatasetissosmallthatthebatch_sizecanequaltoitslenghtdl=DataLoader(ds,batch_size=len(ds))ds[1]ds结构如下:(tensor([[0.9023,0.9180,0.9180,...,0.8398,0.8242,0.8242],[0.9023,0.9414,0.9492,...,0.8555,0.8320,0.8164],[0.9336,0.9805,0.9727,...,0.8555,0.8320,0.7930],...,[-0.7070,-0.7383,-0.7305,...,0.4102,0.3320,0.3711],[-0.7539,-0.7383,-0.7305,...,0.3789,0.3633,0.4102],[-0.7383,-0.7070,-0.7227,...,0.3242,0.3945,0.4023]],[[0.9492,0.9492,0.9492,...,0.9336,0.9258,0.9258],[0.9336,0.9492,0.9492,...,0.9492,0.9336,0.9258],[0.9414,0.9648,0.9414,...,0.9570,0.9414,0.9258],...,[-0.3633,-0.3867,-0.3867,...,0.6133,0.5352,0.5820],[-0.3945,-0.3867,-0.3945,...,0.5820,0.5742,0.6211],[-0.3711,-0.3633,-0.4023,...,0.5273,0.6055,0.6211]],[[0.8867,0.8867,0.8945,...,0.8555,0.8477,0.8477],[0.8789,0.8867,0.8789,...,0.8789,0.8633,0.8477],[0.8867,0.9023,0.8633,...,0.9023,0.8789,0.8555],...,[-0.0352,-0.0586,-0.0977,...,0.7617,0.7070,0.7461],[-0.0586,-0.0586,-0.0977,...,0.7617,0.7617,0.8086],[-0.0352,-0.0352,-0.1211,...,0.7227,0.8086,0.8086]]]),0)数据集返回张量让我们可视化所有输入。它们已经通过MTCNN图像归一化,最后一行的最后三张图像是我自己的自拍:)Embeddingvectorspace我们的数据准备好了。为了比较人脸并找出两张脸是否相似,我们需要在向量空间中对它们进行编码,如果两张脸相似,那么与它们关联的两个向量也相似(接近)。我们可以使用在众所周知的人脸数据集(例如vgg_face2)上训练的模型,并使用分类头之前最后一层的输出(潜在空间)作为编码器。在这些数据集之一上训练的模型必须学习有关输入的重要特征。最后一层(在全连接层之前)编码高级特征。因此,我们可以用它把输入嵌入到一个向量空间中,希望相似的图像彼此接近。具体来说,我们将使用在vggface2数据集上训练的初始Resnet。嵌入空间的维度是512。resnet=InceptionResnetV1(pretrained='vggface2').eval()withtorch.no_grad():for(imgs,labels)indl:embs=resnet(imgs)breakembs.shapetorch.Size([8,512])完美,我们有8张图像,我们得到了8个向量相似度计算为了比较向量,我们可以使用cosine_similarity来查看它们彼此之间的接近程度。余弦相似度会输出一个介于[-1,1]之间的值。在朴素的情况下,两个比较向量相同,它们的相似度为1。因此,最接近1的相似度。现在,我们可以找到数据集中每对之间的所有距离。importseabornassnsimportnumpyasnpsimilarity_matrix=torch.zeros(embs.shape[0],embs.shape[0])foriinrange(embs.shape[0]):forjinrange(embs.shape[0]):similarity_matrix[i,j]=torch.cosine_similarity(embs[i].view(1,-1),embs[j].view(1,-1))fig=plt.figure(figsize=(15,15))sns.heatmap(similarity_matrix.numpy(),annot=True,)numicons=8foriinrange(numicons):axicon=fig.add_axes([0.12+0.082*i,0.01,0.05,0.05])axicon.imshow(un_normalize(ds[i][0]).permute(1,2,0).numpy())axicon.set_xticks([])axicon.set_yticks([])axicon=fig.add_axes([0,0.15+0.092*i,.05,0.05])axicon.imshow(un_normalize(ds[len(ds)-1-i][0]).permute(1,2,0).numpy())axicon.set_xticks([])axicon.set_yticks([])显然,我同意Matt或Leo不太相似,但他们有一些共同点!我们可以更进一步,在嵌入向量上运行PCA,并将图像投影到二维平面中frommatplotlib.offsetboximportOffsetImage,AnnotationBboxdefpca(x:torch.Tensor,k:int=2)->torch.Tensor:"""Fromhttp://agnesmustar.com/2017/11/01/principal-component-analysis-pca-implemented-pytorch/"""#preprocessthedataX_mean=torch.mean(x,0)x=x-X_mean.expand_as(x)#svdU,S,V=torch.svd(torch.t(x))返回torch.mm(x,U[:,:k])points=pca(embs,k=2)plt.rcParams["figure.figsize"]=(12,12)fig,ax=plt.figure(),plt.subplot(111)plt.scatter(点[:,0],points[:,1])fori,pinenumerate(points):x,y=p[0],p[1]img=un_normalize(ds[i][0])img_np=img.permute(1,2,0).numpy().squeeze()ab=AnnotationBbox(OffsetImage(img_np,zoom=0.6),(x,y),frameon=False)ax.add_artist(ab)plt.plot()我们将512维压缩为2,所以我们丢失了很多数据好吧,所以我们有办法找到面孔并查看它们是否彼此相似,现在我们可以创建我们的面孔解锁算法。我的想法是拍摄n张允许的人的图像,在嵌入空间中找到中心,选择一个阈值,看中心与新图像的余弦相似度是小于还是大于它。fromdataclassesimportdataclass,fieldfromtypingimportList,CallablefromPILimportImage@dataclassclassFaceUnlock:images:List[Image.Image]=field(default_factory=list)th:float=0.8transform:Callable=MTCNN(image_size=160,margin=18)嵌入器:torch.nn.Module=InceptionResnetV1(pretrained='vggface2').eval()center:torch.Tensor=Nonedef__post_init__(self):faces=torch.stack(list(map(self.transform,self.images)))embds=self.embedder(面)self.center=embds.sum(0)/embds.shape[0]def__call__(self,x:Image.Image)->bool:face=self.transform(x)emb=self.embedder(face.unsqueeze(0))similarity=torch.cosine_similarity(emb.view(1,-1),self.center.view(1,-1))is_me=similarity>self.threturnis_me,similarity#loadpicturesofmyselfme=data_root/'面'/'me'images=list(map(Image.open,me.glob('*')))#initializefaceunlockwithmyimagesface_unlock=FaceUnlock(images)fromipywidgetsimportinteract,interactive,fixed,interact_manualdefunlock_with_filepath(path):img=Image.open(path)is_me,相似度ty=face_unlock(img)print(f"{''ifis_meelse''}similarity={similarity.item():.3f}")fig=plt.figure()plt.imshow(img)plt.plot()test_root=data_root/'faces_test'interact(unlock_with_filepath,path=list(test_root.glob('*')))相似度得分比上一张图高,所以我猜对了!让我们尝试自己的新自拍来总结我们已经看到的一种有吸引力的方法来创建仅使用2D数据(图像)的人脸解锁算法,它依赖于神经网络在高维向量空间中对裁剪的人脸进行编码,其中相似的人脸彼此靠近。但是,我不知道该模型是如何训练的,并且可能很容易混淆(即使该算法在我的实验中运行良好)。如果在没有数据增强的情况下训练模型会怎样?然后,也许只是翻转同一个人可能会破坏底层表示。更强大的训练例程将是无监督的(类似于BYOL),它在很大程度上依赖于数据扩充。