孿生網路如何識別面部相似度?這有一篇PyTorch實例教程
GIF/1.7M
原文來源:hackernoon
作者:Harshvardhan Gupta
「機器人圈」編譯:嗯~阿童木呀
這是兩篇文章的第二篇,為了更系統地了解與掌握該教程,在閱讀本文之前,建議最好通讀機器人圈的前一篇文章。
在前一篇文章中,我們討論了小樣本數據旨在解決的主要問題類別,以及孿生網路之所以能夠成為解決這個問題優良選擇的原因。首先,我們來重溫一個特殊的損失函數,它能夠在數據對中計算兩個的圖像相似度。我們現在將在PyTorch中實施我們之前所討論的全部內容。
你可以在本文末尾查看完整的代碼鏈接
架構
我們將使用的是標準卷積神經網路(CNN)架構,在每個卷積層之後使用批量歸一化,然後dropout。
代碼片段:孿生網路架構:
class SiameseNetwork(nn.Module):
def __init__(self):
super(SiameseNetwork, self).__init__()
self.cnn1 = nn.Sequential(
nn.ReflectionPad2d(1),
nn.Conv2d(1, 4, kernel_size=3),
nn.ReLU(inplace=True),
nn.BatchNorm2d(4),
nn.Dropout2d(p=.2),
nn.ReflectionPad2d(1),
nn.Conv2d(4, 8, kernel_size=3),
nn.ReLU(inplace=True),
nn.BatchNorm2d(8),
nn.Dropout2d(p=.2),
nn.ReflectionPad2d(1),
nn.Conv2d(8, 8, kernel_size=3),
nn.ReLU(inplace=True),
nn.BatchNorm2d(8),
nn.Dropout2d(p=.2),
)
self.fc1 = nn.Sequential(
nn.Linear(8*100*100, 500),
nn.ReLU(inplace=True),
nn.Linear(500, 500),
nn.Linear(500, 5)
)
def forward_once(self, x):
output = self.cnn1(x)
output = output.view(output.size()[0], -1)
output = self.fc1(output)
return output
def forward(self, input1, input2):
output1 = self.forward_once(input1)
output2 = self.forward_once(input2)
return output1, output2
其實這個網路並沒有什麼特別之處,它可以接收一個100px * 100px的輸入,並且在卷積層之後具有3個完全連接的層。
在上篇文章中,我展示了一對網路是如何處理數據對中的每個圖像的。但在這篇文章中,只有一個網路。因為兩個網路的權重是相同的,所以我們使用一個模型並連續地給它提供兩個圖像。之後,我們使用兩個圖像來計算損失值,然後再返回傳播。這樣可以節省大量的內存,絕對不會影響其他指標(如精確度)。
對比損失
我們將對比損失定義為
等式1.0
我們將Dw(也就歐氏距離)定義為:
等式1.1
Gw是我們網路的一個圖像的輸出。
PyTorch中的對比損失看起來是這樣的:
代碼片段:默認邊際價值為2的對比損失:
class ContrastiveLoss(torch.nn.Module):
"""
Contrastive loss function.
Based on: http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf
"""
def __init__(self, margin=2.0):
super(ContrastiveLoss, self).__init__()
self.margin = margin
def forward(self, output1, output2, label):
euclidean_distance = F.pairwise_distance(output1, output2)
loss_contrastive = torch.mean((1-label) * torch.pow(euclidean_distance, 2) +
(label) * torch.pow(torch.clamp(self.margin - euclidean_distance, min=0.0), 2))
return loss_contrastive
數據集
在上一篇文章中,我想使用MNIST,但有些讀者建議我使用我在同篇文章中所討論的面部相似性樣本。因此,我決定從MNIST / OmniGlot切換到AT&T面部數據集。
數據集包含40名測試對象的不同角度的圖像。我從訓練中挑選出3名測試對象的圖像,以測試我們的模型。
不同類的樣本圖像
一名測試對象的所有樣本圖像
數據載入
我們的架構需要一個輸入對,以及標籤(類似/不相似)。因此,我創建了自己的自定義數據載入器來完成這項工作。它使用圖像文件夾從文件夾中讀取圖像。這意味著你可以將其用於任何你所希望的數據集中。
代碼段:該數據集生成一對圖像和相似性標籤。如果圖像來自同一個類,標籤將為0,否則為1:
class SiameseNetworkDataset(Dataset):
def __init__(self,imageFolderDataset,transform=None,should_invert=True):
self.imageFolderDataset = imageFolderDataset
self.transform = transform
self.should_invert = should_invert
def __getitem__(self,index):
img0_tuple = random.choice(self.imageFolderDataset.imgs)
#we need to make sure approx 50% of images are in the same class
should_get_same_class = random.randint(0,1)
if should_get_same_class:
while True:
#keep looping till the same class image is found
img1_tuple = random.choice(self.imageFolderDataset.imgs)
if img0_tuple[1]==img1_tuple[1]:
break
else:
img1_tuple = random.choice(self.imageFolderDataset.imgs)
img0 = Image.open(img0_tuple[0])
img1 = Image.open(img1_tuple[0])
img0 = img0.convert("L")
img1 = img1.convert("L")
if self.should_invert:
img0 = PIL.ImageOps.invert(img0)
img1 = PIL.ImageOps.invert(img1)
if self.transform is not None:
img0 = self.transform(img0)
img1 = self.transform(img1)
return img0, img1 , torch.from_numpy(np.array([int(img1_tuple[1]!=img0_tuple[1])],dtype=np.float32))
def __len__(self):
return len(self.imageFolderDataset.imgs)
孿生網路數據集生成一對圖像,以及它們的相似性標籤(如果為真,則為0,否則為1)。 為了防止不平衡,我將保證幾乎一半的圖像是同一個類的,而另一半則不是。
訓練孿生網路
孿生網路的訓練過程如下:
1.通過網路傳遞圖像對的第一張圖像。
2.通過網路傳遞圖像對的第二張圖像。
3.使用1和2中的輸出來計算損失。
4.返回傳播損失計算梯度
5.使用優化器更新權重。我們將用Adam來進行演示:
代碼片段:訓練孿生網路:
net = SiameseNetwork().cuda()
criterion = ContrastiveLoss()
optimizer = optim.Adam(net.parameters(),lr = 0.0005 )
counter = []
loss_history = []
iteration_number= 0
for epoch in range(0,Config.train_number_epochs):
for i, data in enumerate(train_dataloader,0):
img0, img1 , label = data
img0, img1 , label = Variable(img0).cuda(), Variable(img1).cuda() , Variable(label).cuda()
output1,output2 = net(img0,img1)
optimizer.zero_grad()
loss_contrastive = criterion(output1,output2,label)
loss_contrastive.backward()
optimizer.step()
if i %10 == 0 :
print("Epoch number {}
Current loss {}
".format(epoch,loss_contrastive.data[0]))
iteration_number +=10
counter.append(iteration_number)
loss_history.append(loss_contrastive.data[0])
show_plot(counter,loss_history)
網路使用Adam,以0.0005的學習率進行了100次的迭代訓練。隨著時間的變化,損失曲線如下所示:
隨時間變化的損失值曲線,x軸代表迭代次數
測試網路
我們從訓練中抽取了3個測試對象,用於評估我們的模型性能。
為了計算相似度,我們只是計算Dw(公式1.1)。其中距離直接對應於圖像對之間的不相似度。Dw的高值表示較高的不相似度。
代碼片段:通過計算模型輸出之間的距離來評估模型:
folder_dataset_test = dset.ImageFolder(root=Config.testing_dir)
siamese_dataset = SiameseNetworkDataset(imageFolderDataset=folder_dataset_test,
transform=transforms.Compose([transforms.Scale((100,100)),
transforms.ToTensor()
])
,should_invert=False)
test_dataloader = DataLoader(siamese_dataset,num_workers=6,batch_size=1,shuffle=True)
dataiter = iter(test_dataloader)
x0,_,_ = next(dataiter)
for i in range(10):
_,x1,label2 = next(dataiter)
concatenated = torch.cat((x0,x1),0)
output1,output2 = net(Variable(x0).cuda(),Variable(x1).cuda())
euclidean_distance = F.pairwise_distance(output1, output2)
模型的一些輸出,較低的值表示相似度較高,較高的值表示相似度較低。
果然,實驗結果相當不錯。網路能夠做到從圖像中分辨出同一個人,即使這些圖像是從不同角度拍攝的。與此同時,該網路在辨別不同的圖像方面也做得非常好。
結論
我們討論並實施了用一個孿生網路從面部圖像對中進行面部識別的實驗。當某個特定面部的訓練樣本很少(或只有一個)時,使用這個辦法是非常有效的。我們使用一個有辨別性的損失函數來訓練神經網路。
點擊此處獲取該教程的完整代碼
※蘋果發布首篇基於GAN的文章,可提升合成圖像的真實感
※機器人闖蕩娛樂圈,「粉絲收割機」如何煉成?
※谷歌Keras之父「連發兩文」全面解析深度學習的局限性與未來
※孿生網路實現小數據學習!看神經網路如何找出兩張圖片的相似點
※ResNet有多大威力?最近又有了哪些變體?一文弄清
TAG:機器人圈 |
※iPhone Face ID與其他人臉識別技術有什麼不一樣?
※如何用Python實現類FaceID的人臉識別?
※如何用 Python 和深度神經網路識別圖像?
※iPhone X「人臉識別」有漏洞,蘋果這份內部文件透露了真相
※Vivo的屏下指紋一定比iPhone X人臉識別更管用?
※在opencv+python中目標識別的同時,怎麼樣調用單目攝像頭實現測距呢?
※外媒調查哪種指紋識別最受歡迎,結果卻是vivo NEX對標iPhone X
※iPhone X 人臉識別有漏洞,蘋果這份內部文件透露了真相
※因各種技術問題,警方丟棄亞馬遜人臉識別產品 Rekognition API
※iPhone X面部識別「認錯人」 用戶:我們不一樣
※安卓首例 它的面部識別竟讓iPhone X自愧不如
※iPhone X Plus:可橫屏使用面部識別,尺寸比 iPhone X 略大
※我還是不相信iPhoneSE2會是劉海屏+面部識別!原因太多
※如何用 OpenCV、Python 和深度學習實現面部識別?
※TensorFlow 實踐之手寫體數字識別!
※iPhone X人臉識別出錯!情侶竟能互相解鎖
※對 Facebook 的面部識別功能,外國人為什麼怨念這麼深?
※三重生物識別,這手機比iPhone X還安全
※如何利用TensorFlow.js部署簡單的AI版「你畫我猜」圖像識別應用
※榮耀FlyPods Pro評測 骨聲紋識別有多厲害?