Artificial intelligence, AI/Pytorch

[PyTorch] 열화상 감지 파일만들기

engine 2021. 4. 20. 15:59

열화상이 베이스로 자리 잡은 요즘 시대를 맞이해

 

vgg16 모델과 이 두 가지 코드를 참조하여 thermal face을 만들 것이다.

 

처음에는 tensorflow로 만들었는데 Tuning 하기 좋은 Torch로 변동해서 만들어봤다.

github.com/pytorch/vision/blob/master/torchvision/models/vgg.py

 

pytorch/vision

Datasets, Transforms and Models specific to Computer Vision - pytorch/vision

github.com

 

github.com/raguilar-f/Thermal-Face-Recognition-Using-Convolutional-Neural-Networks-and-Transfer-Learning

 

raguilar-f/Thermal-Face-Recognition-Using-Convolutional-Neural-Networks-and-Transfer-Learning

In this project, I propose a thermal face recognition method that, for the first time in the state-of-the-art, utilizes transfer learning. - raguilar-f/Thermal-Face-Recognition-Using-Convolutional-...

github.com

간략하게 요약 작성했다.

from __future__ import print_function, division
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torchvision import datasets,transforms
import time
import os

import copy
from tensorboardX import SummaryWriter
import datetime
from pre.utils import load_state_dict_from_url

from typing import Union, List, Dict, Any, cast

data_transforms = {
    'train': transforms.Compose([
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
    ]),
    'val': transforms.Compose([
        transforms.ToTensor(),
    ]),
}

data_dir = '/home/Documents/train_val'
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=32, shuffle=True, num_workers=4)
              for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classes

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
    since = time.time()
    patience = 20
    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']:

            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)

                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
            if phase == 'train':
                scheduler.step()

            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())

        writer.add_scalar('Loss', epoch_loss,epoch)
        writer.add_scalar('Accuracy', epoch_acc, epoch)

    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

__all__ = [
    'vgg19',
]

model_urls = {
    'vgg19_bn': 'https://download.pytorch.org/models/vgg19_bn-c79401a0.pth',
}

class VGG(nn.Module):

    def __init__(
        self,
        features: nn.Module,
        num_classes: int = 2,
        init_weights: bool = True
    ) -> None:
        super(VGG, self).__init__()
        self.features = features
        self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
        self.classifier = nn.Sequential(
            nn.Linear(512 * 1 * 1, 1024),
            nn.Linear(1024, num_classes),
        )
        if init_weights:
            self._initialize_weights()

    def forward(self, x: torch.Tensor) -> torch.Tensor: #실행하는
        x = self.features(x)
        x = self.classifier(x)
        return x

    def _initialize_weights(self) -> None:
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)

def make_layers(cfg: List[Union[str, int]], batch_norm: bool = False) -> nn.Sequential:
    layers: List[nn.Module] = []
    return nn.Sequential(*layers)

cfgs: Dict[str, List[Union[str, int]]] = {
    'A': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}

def _vgg(arch: str, cfg: str, batch_norm: bool, pretrained: bool, progress: bool, **kwargs: Any) -> VGG:
        model.load_state_dict(state_dict)
    return model

# tensorboard
save_time = f'{datetime.datetime.now().strftime("%Y%m%d-%H%M%S")}'

model_ft = vgg16_bn()
model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.Adam(model_ft.parameters(), lr=0.001)
#tensorboard --logdir=./

exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
writer = SummaryWriter('thermalface_vgg19_bn')
model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=128)
save_path = "thermalface_vgg19_bn.pth"
torch.save(model_ft.state_dict(), save_path)
writer.close()

'''
Epoch 0/127
----------
train Loss: 0.1183 Acc: 0.9557
val Loss: 0.1464 Acc: 0.9767
Epoch 1/127
----------
train Loss: 0.1013 Acc: 0.9677
val Loss: 0.0160 Acc: 0.9939
Epoch 2/127
----------
train Loss: 0.0638 Acc: 0.9792
val Loss: 0.0131 Acc: 0.9965


'''

 

처음부터  loss, accuracy 값이 뛰어나 의아했지만, 다행히 잘 돌아가는 모델이었다.

조금 더 다듬어서 다시 코드 업데이트할 예정이다.