본문 바로가기
컴퓨터비전(CV)

7. OpenCV6

by 곽정우 2024. 7. 14.

1. Clasification

  • 분류는 기계 학습과 통계학에서 시스템에서 일련의 특성을 기반으로 미리 정의된 여러 범주 또는 클래스 중 하나에 주어진 입력을 할당하도록 훈련되는 과정
  • 입력 기능과 클래스 레이블 사이의 학습된 관계를 기반으로 샘플의 클래스 레이블을 예측하는 것
  • Binary Classification
    • 이진 분류: 데이터 요소를 두 클래스 중 하나로 분류
    • 질병 vs 질병이 아님
  • Multiclass Classification
    • 다중 클래스 분류: 데이터 요소를 여러 클래스 중 하나로 분류
    • 고양이, 강아지, 코끼리 ...
  • Muti-label Classification
    • 다중 레이블 분류: 단일 데이터 요소가 여러 클래스에 속할 수 있음
    • 강아지 - 포유동일, 길들어진 동물, 잡식

 

2. Clasification 모델의 변천사

3. Clasification 실습

!pip install matplotlib
!pip install torch
!pip install torchvision
!pip install opencv-python
!pip install interact
import os
import cv2
import copy
import matplotlib.pyplot as plt
import torch
import warnings
warnings.filterwarnings("ignore")
from ipywidgets import interact
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, models
from torch import nn
# data_dir = "Covid19-dataset/train"
# sub_dir: Normal, Covid, Viral Pneumonia

def list_image_file(data_dir, sub_dir):
    image_format = ["jpeg", "jpg", "png"]
    image_files = []
    image_dir = os.path.join(data_dir, sub_dir) # Covid19-dataset/train/Normal
    for file_path in os.listdir(image_dir):
        if file_path.split(".")[-1] in image_format:
            image_files.append(os.path.join(sub_dir, file_path))
    return image_files
data_dir = "Covid19-dataset/train"
normals_list = list_image_file(data_dir, "Normal")
covids_list = list_image_file(data_dir, "Covid")
pneumonia_list = list_image_file(data_dir, "Viral Pneumonia")
print(len(normals_list))
print(len(covids_list))
print(len(pneumonia_list))

def get_RGB_image(data_dir, file_name):
    image_file = os.path.join(data_dir, file_name)
    image = cv2.imread(image_file)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    return image
min_num_files = min(len(normals_list), len(covids_list), len(pneumonia_list))
min_num_files

@interact(index=(0, min_num_files-1))
def show_samples(index=0):
    normal_image = get_RGB_image(data_dir, normals_list[index])
    covid_image = get_RGB_image(data_dir, covids_list[index])
    pneumonia_image = get_RGB_image(data_dir, pneumonia_list[index])

    plt.figure(figsize=(12, 8))

    plt.subplot(131)
    plt.title("Nomal")
    plt.imshow(normal_image)

    plt.subplot(132)
    plt.title("Covid")
    plt.imshow(covid_image)

    plt.subplot(133)
    plt.title("pneumonia")
    plt.imshow(pneumonia_image)

    plt.tight_layout()

train_data_dir = "Covid19-dataset/train/"
class_list = ["Normal", "Covid", "Viral Pneumonia"]
class Chest_dataset(Dataset):
    def __init__(self, data_dir, transform=None):
        self.data_dir = data_dir
        normals = list_image_file(data_dir, "Normal")
        covids = list_image_file(data_dir, "Covid")
        pneumonias = list_image_file(data_dir, "Viral Pneumonia")
        self.files_path = normals + covids + pneumonias
        self.transform = transform

    def __len__(self):
        return len(self.files_path)

    def __getitem__(self, index):
        image_file = os.path.join(self.data_dir, self.files_path[index])
        image = cv2.imread(image_file)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        target = class_list.index(self.files_path[index].split(os.sep)[-2])

        return {"image":image, "target": target}
dset = Chest_dataset(train_data_dir)
len(dset) # 70+70+111

dset[100]

index = 100
plt.title(class_list[dset[index]["target"]])
plt.imshow(dset[index]["image"])

dset[100]["target"]

transformer = transforms.Compose([
    transforms.ToTensor(),
    transforms.Resize((224, 224)),
    transforms.Normalize(mean=[0.5, 0.5, 0.5], std = [0.5, 0.5, 0.5])
])
class Chest_dataset(Dataset):
    def __init__(self, data_dir, transform=None):
        self.data_dir = data_dir
        normals = list_image_file(data_dir, "Normal")
        covids = list_image_file(data_dir, "Covid")
        pneumonias = list_image_file(data_dir, "Viral Pneumonia")
        self.files_path = normals + covids + pneumonias
        self.transform = transform

    def __len__(self):
        return len(self.files_path)

    def __getitem__(self, index):
        image_file = os.path.join(self.data_dir, self.files_path[index])
        image = cv2.imread(image_file)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        target = class_list.index(self.files_path[index].split(os.sep)[-2])
        if self.transform:
            image = self.transform(image)
            target = torch.Tensor([target]).long()

        return {"image":image, "target": target}
train_dset = Chest_dataset(train_data_dir, transformer)
index = 100
image = train_dset[index]["image"]
label = train_dset[index]["target"]
print(image.shape, label)

def build_dataloader(train_data_dir, val_data_dir):
    dataloaders = {}
    train_dset = Chest_dataset(train_data_dir, transformer)
    dataloaders["train"] = DataLoader(train_dset, batch_size=4, shuffle=True, drop_last=True) #drop_last=True 마지막에 갯수가 남으면 True(버려라)

    val_dset = Chest_dataset(val_data_dir, transformer)
    dataloaders["val"] = DataLoader(val_dset, batch_size=1, shuffle=False, drop_last=False)
    return dataloaders
train_data_dir = "./Covid19-dataset/train/"
val_data_dir = "./Covid19-dataset/test/"
dataloaders = build_dataloader(train_data_dir, val_data_dir)
for i, d in enumerate(dataloaders["train"]):
    print(i, d)
    if i == 0:
        break

d["image"].shape

d["target"].shape

4. VGG19(Classification) 모델 불러오기

  • VGG는 Visual Geometry Group의 약자
  • 다중 레이어가 있는 표준 심층 CNN 아키텍처

 

model = models.vgg19(pretrained=True)
model

model = build_vgg19_based_model(device_name="cpu")
model
loss_func = nn.CrossEntropyLoss(reduction='mean')
@torch.no_grad()
def get_accuracy(image, target, model):
    batch_size = image.shape[0]
    prediction = model(image)
    _, pred_label = torch.max(prediction, dim=1)
    is_correct = (pred_label == target)
    return is_correct.cpu().numpy().sum() / batch_size
def train_one_epoch(dataloaders, model, optimizer, loss_func, device):
    losses = {}
    accuracies = {}

    for tv in ['train', 'val']:
        running_loss = 0.0
        running_correct = 0

        if tv == 'train':
            model.train()
        else:   
            model.eval()

        for index, batch in enumerate(dataloaders[tv]):
            image = batch['image'].to(device)
            target = batch['target'].squeeze(dim=1).to(device)

            with torch.set_grad_enabled(tv == 'train'):
                prediction = model(image)
                loss = loss_func(prediction, target)

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

            running_loss += loss.item()
            running_correct += get_accuracy(image, target, model)

            if tv == 'train':
                if index % 10 == 0:
                    print(f"{index}/{len(dataloaders['train'])} - Running loss: {loss.item()}")
                    
        losses[tv] = running_loss / len(dataloaders[tv])
        accuracies[tv] = running_correct / len(dataloaders[tv])

    return losses, accuracies
def save_best_model(model_state, model_name, save_dir="./trained_model"):
    os.makedirs(save_dir, exist_ok=True)
    torch.save(model_state, os.path.join(save_dir, model_name))
device = torch.device("cpu")

train_data_dir = "./Covid19-dataset/train/"
val_data_dir = "./Covid19-dataset/test/"
dataloaders = build_dataloader(train_data_dir, val_data_dir)
model = build_vgg19_based_model(device_name=device)
loss_func = nn.CrossEntropyLoss(reduction="mean")
optimizer = torch.optim.SGD(model.parameters(), lr=1E-3, momentum=0.9)
num_epochs = 10
best_acc = 0.0
train_loss, train_accuracy = [], []
val_loss, val_accuracy = [], []

for epoch in range(num_epochs):
    losses, accuracies = train_one_epoch(dataloaders, model, optimizer, loss_func, device)
    
    train_loss.append(losses['train'])
    val_loss.append(losses['val'])
    
    train_accuracy.append(accuracies['train'])
    val_accuracy.append(accuracies['val'])
    
    print(f"{epoch+1}/{num_epochs} - Train_Loss:{losses['train']}, Val_Loss:{losses['val']}")
    print(f"{epoch+1}/{num_epochs} - Train_Accuracies:{accuracies['train']}, Val_Accuracies:{accuracies['val']}")
    
    if(epoch > 3) and (accuracies['val'] > best_acc):
          best_acc = accuracies['val']
          best_model = copy.deepcopy(model.state_dict())
          save_best_model(best_model, f'model_{epoch+1:02d}.pth')
        
print(f'Best Accuracy: {best_acc}')

plt.figure(figsize=(6, 5))
plt.subplot(211)
plt.plot(train_loss, label='train')
plt.plot(val_loss, label='val')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.grid('on')
plt.legend()
plt.subplot(212)
plt.plot(train_accuracy, label='train')
plt.plot(val_accuracy, label='val')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.grid('on')
plt.legend()
plt.tight_layout()

  • vgg19 모델을 다시 로드
  • 학습된 pth 파일을 적용
  • Covid19-dataset/test 파일로 분류
  • interact에 예측된 label을 표기
def preprocess_image(image):
    transformer = transforms.Compose([
        transforms.ToTensor(),
        transforms.Resize((224, 224)),  
        transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])    
    ])
    tensor_image = transformer(image)
    tensor_image = tensor_image.unsqueeze(0) 
    return tensor_image
def model_predict(image, model):
    tensor_image = preprocess_image(image)
    prediction = model(tensor_image)
    
    _, pred_label = torch.max(prediction.detach(), dim=1) 
    print('prediction.detach(): ',prediction.detach())
    print('pred_label: ',pred_label)
    pred_label = pred_label.squeeze(0)
    return pred_label.item()
ckpt = torch.load('./trained_model/model_07.pth')
model = build_vgg19_based_model()
model.load_state_dict(ckpt)
model.eval()

data_dir = './Covid19-dataset/test/'
test_normals_list = list_image_file(data_dir, 'Normal')
test_covids_list = list_image_file(data_dir, 'Covid')
test_pneumonias_list = list_image_file(data_dir, 'Viral Pneumonia')

class_list = ['Normal', 'Covid', 'Viral Pneumonia']
min_num_files = min(len(test_normals_list), len(test_covids_list), len(test_pneumonias_list))

@interact(index=(0, min_num_files-1))
def show_samples(index=0):
    normal_image = get_RGB_image(data_dir, test_normals_list[index])
    covid_image = get_RGB_image(data_dir, test_covids_list[index])
    pneumonia_image = get_RGB_image(data_dir, test_pneumonias_list[index])

    prediction_1 = model_predict(normal_image, model)
    prediction_2 = model_predict(covid_image, model)
    prediction_3 = model_predict(pneumonia_image, model)
    
    plt.figure(figsize=(12,8))

    plt.subplot(131)
    plt.title(f'Normal, Pred: {class_list[prediction_1]}')
    plt.imshow(normal_image)
    
    plt.subplot(132)
    plt.title(f'Covid, Pred: {class_list[prediction_2]}')
    plt.imshow(covid_image)
    
    plt.subplot(133)
    plt.title(f'Pneumonia, Pred: {class_list[prediction_3]}')
    plt.imshow(pneumonia_image)
    plt.tight_layout()

 

'컴퓨터비전(CV)' 카테고리의 다른 글

1. YOLO  (0) 2024.07.14
8. OpenCV7  (0) 2024.07.14
6. Open CV5  (0) 2024.07.14
5. OpenCV4  (1) 2024.07.08
4. Open CV3  (0) 2024.07.08