본문 바로가기
AI/컴퓨터 비전

15. YOLO v8을 이용한 폐질환 분류

by 사라리24 2024. 8. 7.



🟠. 폐암데이터 세트를 가지고  yolo v8 을 통해 암환자 찾기

 

 

The IQ-OTH/NCCD lung cancer dataset

Lung Cancer CT Scans from Iraqi hospitals: Normal, Benign, and Malignant Cases

www.kaggle.com

 

 

 

import 


       
        import os
        import random
        import shutil
        import cv2
        import glob
        import yaml
        import matplotlib.pyplot as plt
        import ultralytics
        from tqdm import tqdm
        from PIL import Image
        from ultralytics import YOLO


 


 랜덤 시드 설정


       
      random.seed(2024)


 

 

 

데이터 받아오기


       

    ! kaggle datasets download -d hamdallak/the-iqothnccd-lung-cancer-dataset



 

 

 

  압축풀기


       

      ! unzip -q '/content/the-iqothnccd-lung-cancer-dataset.zip'



 

 

  data 폴더 만들어 주고 세개의 폴더 넣기



 

 

폴더 정리


       
        # 폴더 경로 설정
        data_root = '/content/The IQ-OTHNCCD lung cancer dataset'
        file_root = f'{data_root}/data'
        project_name = 'lung_cancer'

        # 정리할 디렉토리 정의
        train_file_root = f'{data_root}/{project_name}'
        train_root = f'{data_root}/{project_name}/train'
        valid_root = f'{data_root}/{project_name}/valid'
        test_root = f'{data_root}/{project_name}/test'


 
 

 

 

file_root 디렉토리 내의 모든 폴더 이름 확인


       

        # 3종류의 클래스 디렉토리를 data 안으로 넣어줌
        # file_root 에 있는 모든 디렉토리와 파일을 리스트로 만듦
        cls_list = os.listdir(file_root)
        cls_list


['Malignant cases', 'Bengin cases', 'Normal cases']

 

 

[ train_root ],  [ valid_root ],  [ test_root] 라는 세 개의 폴더 생성   
     그 내부에 cls_list의 각 클래스 폴더를 생성


       
        for folder in [train_root, valid_root, test_root]:
            if not os.path.exists(folder):
                os.makedirs(folder)
            for cls in cls_list:
                cls_folder = f'{folder}/{cls}'
                if not os.path.exists(cls_folder):
                    os.makedirs(cls_folder)

 



 

 

[ file_root ]내의 클래스별 서브디렉토리에서 파일을 랜덤하게 섞기 
     이를 학습(training), 검증(validation), 테스트(test) 세트로 나누는 작업


       

        for cls in cls_list:
            file_list = os.listdir(f'{file_root}/{cls}')
            random.shuffle(file_list)
            test_ratio = 0.1
            num_file = len(file_list)
            test_list = file_list[:int(num_file * test_ratio)]
            valid_list = file_list[int(num_file * test_ratio):int(num_file * test_ratio)*2]
            train_list = file_list[int(num_file * test_ratio)*2:]
            print(test_list)
            print(valid_list)
            print(train_list)

            for i in test_list:
                shutil.copyfile(f'{file_root}/{cls}/{i}', f'{test_root}/{cls}/{i}')
               
            for i in valid_list:
                shutil.copyfile(f'{file_root}/{cls}/{i}', f'{valid_root}/{cls}/{i}')  

            for i in train_list:
                shutil.copyfile(f'{file_root}/{cls}/{i}', f'{train_root}/{cls}/{i}')  









 

 

[ test_root  ] 내의 모든 파일을 가져와서 랜덤하게 섞기


       
        test_file_list = glob.glob(f'{test_root}/*/*')
        random.shuffle(test_file_list)
        test_file_list


 

 

◼ [ test_root ]  첫 10개의 이미지를 시각화 


       

      plt.figure(figsize=(20, 10))
      for i in range(10):
          test_img_path = os.path.join(test_root, test_file_list[i])
          ori_img = Image.open(test_img_path).convert('RGB')
          plt.subplot(2, 5, (i+1))
          plt.title(test_file_list[i].split('/')[-2])
          plt.imshow(ori_img)
         
      plt.show()    



 

 

데이터셋의 루트 디렉토리를 지정하기


       
      project_root ='/content/The IQ-OTHNCCD lung cancer dataset/lung_cancer'


 

 

  [ project_root  ]  내에 < data.yaml >이라는 YAML 파일을 생성하여, 데이터셋의 구조와 관련된 정보를 저장


       
        data = dict()

        data['train'] = train_root
        data['val'] = valid_root
        data['test'] = test_root
        data['nc'] = len(cls_list)
        data['names'] = cls_list

        with open(f'{project_root}/data.yaml', 'w') as f:
            yaml.dump(data, f)

 

 

ultralytics 설치


       
      ! pip install ultralytics


 

ultralytics 버전체크


       
          import ultralytics
          from ultralytics import YOLO

          ultralytics.checks()


 

 

  경로이동


       
        %cd /content/The IQ-OTHNCCD lung cancer dataset/lung_cancer


/content/The IQ-OTHNCCD lung cancer dataset/lung_cancer

 

 

모델 불러오기


       

      model = YOLO('yolov8n-cls.pt')


 

 

  학습하기


      
        results = model.train(data=f'{data_root}/{project_name}', epochs=50, batch=8, device='cpu', name='lung_cancer_s')





 

결과 폴더 지정


       

      result_folder = f'{project_root}/runs/classify/lung_cancer_s'



 

YOLO  모델을 로드하고, best.pt라는 이름의 사전 훈련된 가중치 파일을 사용하여 해당 모델을 초기화


       
        model = YOLO(f'{result_folder}/weights/best.pt')
        model



 

  YOLO 모델의 val() 메서드를 사용하여 검증 또는 테스트 데이터셋에 대한 평가를 수행하고, 평가 지표를 반환


       
      metrics = model.val(split='test')
      metrics


 

 

모델의 성능 평가 지표인 top1과 top5 정확도를 출력


       
        print('top1 accuracy: ', metrics.top1)
        print('top5 accuracy: ', metrics.top5)


top1 accuracy:  0.9908257126808167
top5 accuracy:  1.0
  • 정확도 정의:
    • Top-1 정확도: 모델이 예측한 가장 높은 확률의 클래스가 실제 클래스와 일치할 확률.
    • Top-5 정확도: 실제 클래스가 모델의 상위 5개 예측 클래스 중 하나에 포함될 확률.

 

 

추가 import 

      

        import numpy as np
        import torch
        from torchvision import transforms


 

 

이미지 데이터 전처리를 위한 변환(transform) 작업


       
      IMG_SIZE = (512, 512)
      test_data_transform = transforms.Compose([
          transforms.Resize(IMG_SIZE),
          transforms.ToTensor(),
      ])


 

 

이미지 파일을 열고, 지정된 전처리 변환을 적용한 후, PyTorch 텐서로 변환하여 모델 입력으로 준비하기


       
        img = Image.open(test_file_list[0]).convert('RGB')
        img_src = test_data_transform(img)
        print(img_src.shape)
        x_tensor = img_src.unsqueeze(0)
        print(x_tensor.shape)


 
torch.Size([3, 512, 512])
torch.Size([1, 3, 512, 512])
  • 이미지 열기 및 변환:
    • Image.open(test_file_list[0]): test_file_list의 첫 번째 이미지 파일 경로를 사용하여 이미지를 엽니다.
    • .convert('RGB'): 이미지를 RGB 모드로 변환합니다. 이는 이미지가 3채널(RGB) 색상 모드를 갖도록 보장합니다.
  • 이미지 전처리:
    • test_data_transform(img): 앞서 설정한 test_data_transform 변환을 적용하여 이미지를 전처리합니다. 이 변환은 이미지의 크기를 조정하고 텐서로 변환합니다. 결과는 PyTorch 텐서입니다.
  • 전처리된 이미지의 형태 출력:
    • img_src.shape: 전처리된 이미지 텐서의 형태를 출력합니다. 일반적으로 (채널 수, 높이, 너비) 형태를 가집니다. 예를 들어, torch.Size([3, 512, 512])는 3개의 채널(정상적으로 RGB 이미지)과 512x512 픽셀 크기의 이미지 텐서를 나타냅니다.
  • 배치 차원 추가:
    • img_src.unsqueeze(0): 텐서에 배치 차원(batch dimension)을 추가합니다. unsqueeze(0)은 텐서의 첫 번째 차원에 새로운 차원을 추가하여 (1, 채널 수, 높이, 너비) 형태를 만듭니다. 이는 모델이 배치 단위로 데이터를 처리할 때 유용합니다.
  • 배치 차원이 추가된 텐서의 형태 출력:
    • x_tensor.shape: 배치 차원이 추가된 텐서의 형태를 출력합니다. 예를 들어, torch.Size([1, 3, 512, 512])는 배치 크기가 1인 텐서로, 1개의 이미지(3 채널, 512x512 크기)가 포함된 것을 나타냅니다.

 

 

모델에 이미지를 입력하여 예측 결과를 얻기


       
        result = model(x_tensor)[0]

 
0: 512x512 Bengin cases 0.58, Normal cases 0.42, Malignant cases 0.00, 224.8ms
Speed: 0.0ms preprocess, 224.8ms inference, 7.2ms postprocess per image at shape (1, 3, 512, 512)

model(x_tensor): 모델을 호출하여 x_tensor 텐서에 대해 예측을 수행합니다. x_tensor는 모델의 입력으로 사용되는 이미지 텐서입니다. 모델의 forward 메서드가 호출되어 예측 결과를 반환합니다.



 

 

모델의 예측 결과를 사용하여
입력 이미지의 실제 클래스(ground truth)와 모델이 예측한 클래스(및 그 확률)를 출력


       

        gt = test_file_list[0].split('/')[-2]
        pt = model.names[torch.argmax(result.probs.data).item()]
        print(gt)
        print(pt)



  • Ground Truth 클래스 추출:
    • test_file_list[0]: 테스트 데이터 리스트에서 첫 번째 이미지의 파일 경로를 가져옵니다.
    • .split('/')[-2]: 파일 경로를 '/'를 기준으로 나누고, 마지막에서 두 번째 요소를 선택합니다. 이는 일반적으로 클래스 이름이 있는 디렉토리 이름입니다. 예를 들어, 파일 경로가 /path/to/test/class_name/image.jpg인 경우, class_name이 추출됩니다.
  • 모델의 예측 클래스 추출:
    • result.probs.data: 모델의 예측 확률 또는 로짓(logits) 값입니다. result 객체가 반환한 확률 값 또는 로짓을 포함하는 텐서입니다. (객체 탐지 모델에서는 확률 대신 바운딩 박스와 같은 다른 정보일 수 있습니다.)
    • torch.argmax(result.probs.data): 예측 확률 텐서에서 가장 높은 확률의 인덱스를 찾습니다. 이 인덱스는 모델이 예측한 클래스의 인덱스를 나타냅니다.
    • .item(): torch.argmax의 결과는 PyTorch 텐서입니다. .item()을 호출하여 텐서에서 스칼라 값을 추출합니다.
    • model.names[...]: 모델의 클래스 이름 목록에서 예측 클래스의 이름을 추출합니다. model.names는 클래스 이름의 리스트를 포함하고 있어야 합니다.
  • 결과 출력:
    • print(gt): 실제 클래스 이름(ground truth)을 출력합니다.
    • print(pt): 모델이 예측한 클래스 이름을 출력합니다.

 

1개의 이미지 시각화 : 실제 클래스(ground truth)와 모델의 예측 클래스(predicted class)를 제목으로 표시


       
        plt.figure(figsize=(3, 3))
        plt.title(f'GT: {gt}, Predict: {pt}')
        plt.imshow(np.array(img))
        plt.show()


 

5개의 이미지 예측결과


       
      plt.figure(figsize=(20,5))

      for idx in range(5):
          img = Image.open(test_file_list[idx]).convert('RGB')
          img_src = test_data_transform(img)
          x_tensor = img_src.unsqueeze(0)
          result = model.predict(x_tensor)[0]
          gt = test_file_list[0].split('/')[-2]
          pt = model.names[torch.argmax(result.probs.data).item()]
          plt.subplot(1, 5, (idx+1))
          plt.title(f'GT:{gt}, Predict:{pt}')
          plt.imshow(img)

      plt.show()


 

 

 

@. 과제 : 안전장비 착용 감지 확인하기

데이터셋 : https://www.kaggle.com/datasets/andrewmvd/hard-hat-detection/data

 

 

 

'AI > 컴퓨터 비전' 카테고리의 다른 글

17. YOLO v8을 이용한 이상행동 탐지  (0) 2024.08.12
16. YOLO v8를 활용한 안전모 탐지  (0) 2024.08.08
14. YOLO | 객체탐지  (0) 2024.08.06
@. 과제  (0) 2024.08.05
13. Faster R-CNN | 객체 탐지  (0) 2024.07.25