발표자: 김정민
실습은 코드도 길고 첨부할 이미지도 많아서 따로 게시물을 작성하였습니다.
코드는 깃허브에서 가져왔고 중간 중간에 조금씩 수정은 하였습니다.
코랩을 이용하였기 때문에 드라이브에 마운트하여 파일을 이용하면 됩니다.
우선 깃허브에 있는 데이터셋으로 이용할 파일을 다운받아주고 코랩라이브러리에 저장해줍니다.
파일에는 각종 이미지가 담겨져 있습니다. 물론 주피터를 사용하신다면 본인 내장 드라이브 주소를 입력하시면 됩니다.
/content/drive/My Drive/Colab Notebooks/training
위에 보이는 것이 주소입니다. 후에 언급할것입니다.
<코드>
#각종 라이브러리를 임포트 해줍시다.
%matplotlib inline
import torchvision
import torchvision.datasets as dset
import torchvision.transforms as transforms
from torch.utils.data import DataLoader,Dataset
import matplotlib.pyplot as plt
import torchvision.utils
import numpy as np
import random
from PIL import Image
import torch
from torch.autograd import Variable
import PIL.ImageOps
import torch.nn as nn
from torch import optim
import torch.nn.functional as F
import os
#각종 사용할 함수를 세팅합니다.
def imshow(img,text=None,should_save=False):
npimg = img.numpy()
plt.axis("off")
if text:
plt.text(75, 8, text, style='italic',fontweight='bold',
bbox={'facecolor':'white', 'alpha':0.8, 'pad':10})
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
def show_plot(iteration,loss):
plt.plot(iteration,loss)
plt.show()
#Configuration Class를 정의합시다.
#구글 코랩에 '드라이브 마운트'하면 드라이브에 저장되어있는 파일을 불러서 사용가능합니다.
#참고로 코랩에 연결할 때 마다 마운트를 해줘야 불러올 수 있습니다.
드라이브 마운트를 누르면 코드가 나오는데 실행 절차를 밟으면 된다.
class Config():
training_dir = "/content/drive/My Drive/Colab Notebooks/training"
testing_dir = "/content/drive/My Drive/Colab Notebooks/testing"
train_batch_size = 64
train_number_epochs = 100
#커스텀 데이터셋을 정의합시다.
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:
while True:
#keep looping till a different class image is found
img1_tuple = random.choice(self.imageFolderDataset.imgs)
if img0_tuple[1] !=img1_tuple[1]:
break
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)
#앞서서 정의한 사용자 데이터셋을 불러옵시다.
folder_dataset = dset.ImageFolder(root=Config.training_dir)
siamese_dataset = SiameseNetworkDataset(imageFolderDataset=folder_dataset,
transform=transforms.Compose([transforms.Resize((100,100)),
transforms.ToTensor()
])
,should_invert=False)
#데이터의 일부를 보여보도록 하겠습니다.
vis_dataloader = DataLoader(siamese_dataset,
shuffle=True,
num_workers=8,
batch_size=8)
dataiter = iter(vis_dataloader)
example_batch = next(dataiter)
concatenated = torch.cat((example_batch[0],example_batch[1]),0)
imshow(torchvision.utils.make_grid(concatenated))
print(example_batch[2].numpy())
#컨볼루션 계층을 정의합니다.
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.ReflectionPad2d(1),
nn.Conv2d(4, 8, kernel_size=3),
nn.ReLU(inplace=True),
nn.BatchNorm2d(8),
nn.ReflectionPad2d(1),
nn.Conv2d(8, 8, kernel_size=3),
nn.ReLU(inplace=True),
nn.BatchNorm2d(8),
)
self.fc1 = nn.Sequential(
nn.Linear(8*100*100, 500),
nn.ReLU(inplace=True),
nn.Linear(500, 500),
nn.ReLU(inplace=True),
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
#Loss 함수를 정의합니다.
class ContrastiveLoss(torch.nn.Module):
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, keepdim = True)
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
# 본격적으로 트레인을 시켜보도록 합시다.
#앞서서 진행했던 실습처럼 옵티마이저와 에포크등을 설정합니다.
train_dataloader = DataLoader(siamese_dataset,
shuffle=True,
num_workers=8,
batch_size=Config.train_batch_size)
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 = img0.cuda(), img1.cuda() , label.cuda()
optimizer.zero_grad()
output1,output2 = net(img0,img1)
loss_contrastive = criterion(output1,output2,label)
loss_contrastive.backward()
optimizer.step()
if i %10 == 0 :
print("Epoch number {}\n Current loss {}\n".format(epoch,loss_contrastive.item()))
iteration_number +=10
counter.append(iteration_number)
loss_history.append(loss_contrastive.item())
show_plot(counter,loss_history)
# 실제 이미지와 테스트 해보겠습니다.
folder_dataset_test = dset.ImageFolder(root=Config.testing_dir)
siamese_dataset = SiameseNetworkDataset(imageFolderDataset=folder_dataset_test,
transform=transforms.Compose([transforms.Resize((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)
imshow(torchvision.utils.make_grid(concatenated),'Dissimilarity: {:.2f}'.format(euclidean_distance.item()))
참조 깃허브
https://github.com/harveyslash/Facial-Similarity-with-Siamese-Networks-in-Pytorch
데이터 셋 파일
'3.5기(200104~) > 출석체크 팀' 카테고리의 다른 글
Colab에서 tensorflow ObjectDetection API를 이용해서 Object Detection을 trasnfer learning 해보자. (0) | 2020.03.21 |
---|---|
DeepFace 논문 간단 리뷰:Closing the Gap to Human-Level Performance in Face Verificat (0) | 2020.03.10 |
face_recognition을 이용한 real time 얼굴 인식 (0) | 2020.03.08 |
샴 네트워크(Siamese Network),삼중항 손실 (Triplet loss) (0) | 2020.03.06 |
딥러닝을 이용한 출석관리 계획 (0) | 2020.03.05 |