PyTorch를 사용하여 얼굴을 인식하도록 얼굴 인식 분류기를 미세 조정

GAN으로 적대적 공격을 사용하여 안면 인식 시스템을 속입니다.

이것은 GAN과의 적대적 공격을 사용하여 안면 인식 시스템을 속이는 것에 대해 제가 쓰고있는 시리즈의 일부입니다.

그러나 안면 인식 분류기를 속이기 전에 속임수로 분류해야합니다. 저는 개인적으로 제 얼굴을 알아볼 수있는 것을 만들고 싶습니다. 신경망을 처음부터 훈련하는 대신 사전 훈련 된 네트워크로 시작한 다음 내 얼굴을 인식하도록 미세 조정할 수 있습니다. 대규모 얼굴 데이터베이스에서 이미 훈련 된 모델 가중치로 시작한 다음 일부를 업데이트하여 수행하려는 새로운 작업을 반영 할 수 있으므로 미세 조정은 매우 유용합니다. 이 가중치는 이미 얼굴을 인식하는 방법을 이해하고 있지만 유일한 차이점은 내 얼굴을 모른다는 것입니다. 따라서이 사전 훈련 된 모델이 내 얼굴을 배우도록하는 것은 모델 가중치에 이미 작업을 수행하는 데 필요한 많은 정보가 포함되어 있기 때문에 훈련하기가 훨씬 쉽습니다.

디렉토리 구조

project
│   README.md
│   AGN.ipynb  
│
└───data
│   │   files_sample.csv
│   └───eyeglasses
│   │
│   └───test_me
│       └───train
|           └───Adrien_Brody
|           ...
|           └───Michael_Chaykowsky
|           ...
|           └───Venus_Williams
│       └───val
|           └───Adrien_Brody
|           ...
|           └───Michael_Chaykowsky
|           ...
|           └───Venus_Williams
│   
└───models
│   │   inception_resnet_v1.py
│   │   mtcnn.py
│   └───utils

└───models
│   │   inception_resnet_v1.py
│   │   mtcnn.py
│   └───utils

모델의 각 레이어 가중치에는 또는 requires_grad로 설정할 수있는 라는 속성 이 있습니다 . 훈련 루프에서 실행하면 이러한 가중치가 업데이트되고 여기에는 예측을 수행하는 데 필요한 모든 정보가 포함됩니다. 네트워크를 미세 조정이 때 우리는 동결 설정에 따라 지난 길쌈 블록을 통해 층까지 모두 에 속성을 하고 만 남아있는 레이어에 가중치를 업데이트 - 직관적으로 인식하는 데 필요한 기본 수준의 정보를 포함하는 것으로 이전 레이어를 상상할 수있는 얼굴 속성 및 기본 수준 특성을 사용하여 다른 얼굴 (광산)을 포함하도록 최종 레이어를 업데이트하는 동안 모든 성능을 유지합니다.TrueFalseloss.backward()requires_gradFalse

모든 train디렉토리에는 각 개인의 11 개 또는 12 개의 이미지가 있으며 모든 val디렉토리에는 각 개인의 4 개 또는 5 개의 이미지가 있습니다. Michael_Chaykowsky다양한 포즈, 조명, 각도를 사용한 내 얼굴 디렉토리입니다. 이러한 이미지를 수집하기 위해 다양한 공간에서 표준 iPhone으로 비디오를 촬영 한 다음이 비디오를 이미지로 변환하고 각각의 MTCNN을 사용하여 얼굴 정렬 및 적절한 크기 (160 x 160 픽셀)로 자르기를 수행했습니다.

수입품

from torch import nn, optim, as_tensor
from torch.utils.data import Dataset, DataLoader
import torch.nn.functional as F
from torch.optim import lr_scheduler
from torch.nn.init import *
from torchvision import transforms, utils, datasets, models
from models.inception_resnet_v1 import InceptionResnetV1
import cv2
from PIL import Image
from pdb import set_trace
import time
import copy
from pathlib import Path
import os
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from skimage import io, transform
from tqdm import trange, tqdm
import csv
import glob
import dlib
import pandas as pd
import numpy as np

from IPython.display import Video
Video("data/IMG_2411.MOV", width=200, height=350)
Video of me rotating my face

vidcap = cv2.VideoCapture('IMG_2411.MOV')
success,image = vidcap.read()
count = 0
success = True
while success:
    cv2.imwrite(f"./Michael_Chaykowsky/Michael_Chaykowsky_{
                  format(count, '04d') }.png", image)
    success,image = vidcap.read()
    print('Read a new frame: ', success)
    count += 1

%%!
for szFile in ./Michael_Chaykowsky/*.png
do 
    magick mogrify -rotate 90 ./Michael_Chaykowsky/"$(basename "$szFile")" ; 
done

Autocrop에는 얼굴 이미지의 크기를 조정하고 얼굴 비율을 지정할 수있는 멋진 기능이 있습니다. 전체 MTCNN 방법 ( prefferred )을 수행하는 경우이를 무시할 수 있지만 그렇지 않은 경우이를 수행하는 것이 훨씬 더 쉽습니다.

! autocrop -i ./me_orig/Michael_Chaykowsky -o ./me/Michael_Chaykowsky160 -w 720 -H 720 --facePercent 80

! pip install scipy==1.1.0

이제 David Sandberg의 Facenet Tensorflow 구현align_dataset_mtcnn.py스크립트를 사용하여이를 얼굴 이미지 디렉토리에 적용 할 수 있습니다.

%%!
for N in {1..4}; do \
python ~/Adversarial/data/align/align_dataset_mtcnn.py \ # tensorflow script
~/Adversarial/data/me/ \ # current directory
~/Adversarial/data/me160/ \ # new directory
--image_size 160 \
--margin 32 \
--random_order \
--gpu_memory_fraction 0.25 \
& done

데이터로드

데이터를로드 할 때 훈련을 개선하기 위해 이미지에 무작위 변환을 수행합니다. 다른 변환을 시도 할 수 있으며 다음과 같은 다양한 변환을 시도 할 수 있습니다.

랜덤 컬러 지터
무작위 회전 +/- 5도
무작위 수평 뒤집기

여기서는 임의의 수평 뒤집기를 사용합니다. 이러한 모든 변환은 모델을보다 일반화하고 과적 합을 방지합니다.

data_transforms = {
    'train': transforms.Compose([
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}
data_dir = 'data/test_me'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
                                          data_transforms[x])
                  for x in ['train', 'val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x],
                                              batch_size=8, 
                                             shuffle=True)
              for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train','val']}
class_names = image_datasets['train'].classes
class_names

['Adrien_Brody','Alejandro_Toledo','Angelina_Jolie','Arnold_Schwarzenegger','Carlos_Moya','Charles_Moose','James_Blake','Jennifer_Lopez','Michael_Chaykowsky','Roh_Moo-hyun','Venus_Williams']

def imshow(inp, title=None):
    """Imshow for Tensor."""
    inp = inp.numpy().transpose((1, 2, 0))
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    inp = std * inp + mean
    inp = np.clip(inp, 0, 1)
    plt.imshow(inp)
    if title is not None:
        plt.title(title)
    plt.pause(0.001)  # pause a bit so that plots are updated
# Get a batch of training data
inputs, classes = next(iter(dataloaders['train']))
# Make a grid from batch
out = utils.make_grid(inputs)
imshow(out, title=[class_names[x] for x in classes])

from models.inception_resnet_v1 import InceptionResnetV1
print('Running on device: {}'.format(device))
model_ft = InceptionResnetV1(pretrained='vggface2', classify=False, num_classes = len(class_names))

이전에 마지막 conv 블록을 통해 동결 될 것이라고 언급했습니다. 그것이 어디에 있는지 -n, -n-1, ...찾기 위해 우리는 블록을 찾을 때까지 사용하여이 목록을 반복 할 수 있습니다 .

list(model_ft.children())[-6:]

출력 [2] :

[Block8(
   (branch0): BasicConv2d(
     (conv): Conv2d(1792, 192, kernel_size=(1, 1), stride=(1, 1), bias=False)
     (bn): BatchNorm2d(192, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
     (relu): ReLU()
   )
   (branch1): Sequential(
     (0): BasicConv2d(
       (conv): Conv2d(1792, 192, kernel_size=(1, 1), stride=(1, 1), bias=False)
       (bn): BatchNorm2d(192, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
       (relu): ReLU()
     )
     (1): BasicConv2d(
       (conv): Conv2d(192, 192, kernel_size=(1, 3), stride=(1, 1), padding=(0, 1), bias=False)
       (bn): BatchNorm2d(192, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
       (relu): ReLU()
     )
     (2): BasicConv2d(
       (conv): Conv2d(192, 192, kernel_size=(3, 1), stride=(1, 1), padding=(1, 0), bias=False)
       (bn): BatchNorm2d(192, eps=0.001, momentum=0.1, affine=True, track_running_stats=True)
       (relu): ReLU()
     )
   )
   (conv2d): Conv2d(384, 1792, kernel_size=(1, 1), stride=(1, 1))
 ),
 AdaptiveAvgPool2d(output_size=1),
 Linear(in_features=1792, out_features=512, bias=False),
 BatchNorm1d(512, eps=0.001, momentum=0.1, affine=True, track_running_stats=True),
 Linear(in_features=512, out_features=8631, bias=True),
 Softmax(dim=1)]

layer_list = list(model_ft.children())[-5:] # all final layers
layer_list

[AdaptiveAvgPool2d(output_size=1),
 Linear(in_features=1792, out_features=512, bias=False),
 BatchNorm1d(512, eps=0.001, momentum=0.1, affine=True, track_running_stats=True),
 Linear(in_features=512, out_features=8631, bias=True),
 Softmax(dim=1)]

model_ft = nn.Sequential(*list(model_ft.children())[:-5])

for param in model_ft.parameters():
    param.requires_grad = False

이 선형 계층은 Linear(in_features=1792, out_features=512, bias=False)실제로 두 개의 사용자 정의 클래스를 작성해야합니다. 이 클래스를 보면 완전히 명확하지는 않지만 데이터 입력 / 출력을 보면 계층 내에 Flatten 및 Normalize 클래스가 있음을 알 수 있습니다. 레이어 에서 재구성 이유에 대해 resnet 구현확인하십시오last_linear .

class Flatten(nn.Module):
    def __init__(self):
        super(Flatten, self).__init__()
        
    def forward(self, x):
        x = x.view(x.size(0), -1)
        return x
class normalize(nn.Module):
    def __init__(self):
        super(normalize, self).__init__()
        
    def forward(self, x):
        x = F.normalize(x, p=2, dim=1)
        return x

model_ft.avgpool_1a = nn.AdaptiveAvgPool2d(output_size=1)
model_ft.last_linear = nn.Sequential(
    Flatten(),
    nn.Linear(in_features=1792, out_features=512, bias=False),
    normalize()
)
model_ft.logits = nn.Linear(layer_list[3].in_features, len(class_names))
model_ft.softmax = nn.Softmax(dim=1)
model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()
# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=1e-2, momentum=0.9)
# Decay LR by a factor of *gamma* every *step_size* epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

def train_model(model, criterion, optimizer, scheduler,
                num_epochs=25):
    since = time.time()
    FT_losses = []
    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0
for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch, num_epochs - 1))
        print('-' * 10)
# Each epoch has a training and validation phase
        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()  # Set model to training mode
            else:
                model.eval()   # Set model to evaluate mode
running_loss = 0.0
            running_corrects = 0
# Iterate over data.
            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)
# zero the parameter gradients
                optimizer.zero_grad()
# forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)
# backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()
                        scheduler.step()
                
                FT_losses.append(loss.item())
                # statistics
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() /
                         dataset_sizes[phase]
print('{} Loss: {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))
# deep copy the model
            if phase == 'val' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())
time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Acc: {:4f}'.format(best_acc))
# load best model weights
    model.load_state_dict(best_model_wts)
    return model, FT_losses

model_ft, FT_losses = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=500)
plt.figure(figsize=(10,5))
plt.title("FRT Loss During Training")
plt.plot(FT_losses, label="FT loss")
plt.xlabel("iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()

GAN을 사용한 적대적 공격을 사용하여이 분류기를 속이는 방법을 설명하는이 시리즈에서 더 많은 것을 주목하십시오.

Suggested posts

AI는 물리학이 자연의 법칙을 연구하는 것처럼 지능의 법칙을 연구합니다.

AI는 물리학이 자연의 법칙을 연구하는 것처럼 지능의 법칙을 연구합니다.

AI에 대한보다 정확한 정의는 그 역할과 영향을 더 잘 이해할 수있게합니다. AI에 대한 많은 정의가 있습니다. 누가 추가로 필요합니까? 나는 우리가 생각한다 : 현재의 정의는 인공 지능을 잘못 구성함으로써 많은 혼란을 야기한다.

머신 러닝으로 음악 앱 이탈 예측 : Sparkify 프로젝트

머신 러닝으로 음악 앱 이탈 예측 : Sparkify 프로젝트

이 프로젝트에서는 Udacity Data Scientist 트랙 졸업 프로젝트 인 음악 앱 Sparkify의 이탈 모델링에 대해 설명합니다. 이 프로젝트의 코드는 내 githıb 계정에서 찾을 수 있습니다 : https : // github.

Related posts

Spotify의 마법 성분 : 기계 학습

Spotify의 마법 성분 : 기계 학습

면책 조항 :이 기사는 Spotify와 관련이 없으며 Spotify 및 현재 관련이 없을 수있는 과거 구조에 대한 확인되지 않은 정보로 구성 될 수 있습니다. 음악은 표현의 한 형태, 예술의 형태, 전체적인 문화 활동입니다.

2021 년 2 월에 읽을 4 가지 딥 러닝 논문

2021 년 2 월에 읽을 4 가지 딥 러닝 논문

신경 과학에서 자동 분화, 신경망 이론 및 신경 과정의 과소 적합에 이르기까지 현재 추구되고있는 다양한 딥 러닝 연구 흐름에 대한 더 나은 개요를 얻고 싶으십니까? 합리적으로 통과하기에는 열려있는 arXiv 탭이 너무 많습니까? 전체 동영상을 볼 시간이 너무 적습니까? 논문의 핵심 아이디어와 개념에 대한 간략한 요약 만 있다면. 그런 다음 '머신-러닝-콜라주'시리즈를 소개하게되어 기쁩니다.

내부의 관심 네트워크 그래프

수학에서 NumPy까지 단계별 가이드

내부의 관심 네트워크 그래프

그래프 신경망 (GNN)은 그래프 데이터에서 학습 할 수있는 표준 도구 상자로 등장했습니다. GNN은 콘텐츠 추천 또는 신약 발견과 같은 다양한 분야에서 영향이 큰 문제를 개선 할 수 있습니다.

분할에 대한 고정 2 부 : Python으로 이미지 분할을 수행하는 방법

분할에 대한 고정 2 부 : Python으로 이미지 분할을 수행하는 방법

안녕하세요! 이미지 분할에 대한이 짧은 시리즈의 첫 번째 부분을 읽지 않았다면 여기에서 읽으십시오. 이전 이야기에서 임계 값 및 색상 분할에 대해 논의 했으므로 2 부에서는 색도 분할과 이미지 차이에 중점을 둘 것입니다.