boostcampaitech3 / final-project-level3-cv-18

final-project-level3-cv-18 created by GitHub Classroom
0 stars 4 forks source link

Pytorch Grad Cam 사용법 #4

Open GwonPyo opened 2 years ago

GwonPyo commented 2 years ago

아래 명령으로 pytorch-grad-cam을 설치합니다.

pip install grad-cam

제 경우 baseline 코드 아래에 실행하면 정상적으로 작동합니다. 혹시 에러 발생 시 알려주시면 감사하겠습니다:)

먼저 학습한 모델을 불러옵니다.

model = timm.create_model('swinv2_large_window12to24_192to384_22kft1k', pretrained=True).to(device)
in_features = model.head.in_features
model.head = nn.Sequential(
    nn.Linear(in_features, 5)
).to(device)

model.load_state_dict(torch.load('twin_v2_lr1e-4/model.pt'))
model.eval()

그리고 valid 이미지가 존재하는 파일에 접근해 이미지 파일들을 가져옵니다. valid_path 부분은 알맞게 바꿔주셔야 합니다.

valid_path = 'dataset/valid/JPEGImages'
file_list = os.listdir(valid_path)
image_list = []

for file in file_list:
    if '.jpg' in file:
        image_list.append(file)

마지막으로 아래 코드를 실행시켜주시면 됩니다.

from pytorch_grad_cam import GradCAM, ScoreCAM, GradCAMPlusPlus, AblationCAM, XGradCAM, EigenCAM, FullGrad
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
from pytorch_grad_cam.utils.image import show_cam_on_image, preprocess_image

def reshape_transform(tensor, height=12, width=12): # 아래 설명한 에러 발생 시 height와 width를 수정하시면 됩니다.
    result = tensor.reshape(tensor.size(0),
                            height, width, tensor.size(2))

    # Bring the channels to the first dimension,
    # like in CNNs.
    result = result.transpose(2, 3).transpose(1, 2)
    return result

target_layers = [model.layers[-1].blocks[-1].norm1] # 모델에 맞는 층으로 변경하셔야 합니다.

cam = GradCAM(model=model, 
            target_layers=target_layers, 
            reshape_transform=reshape_transform, 
            use_cuda=torch.cuda.is_available())

fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(20, 10))
rgb_img = cv2.imread(os.path.join(valid_path, image_list[10]), 1)[:, :, ::-1]
rgb_img = cv2.resize(rgb_img, (384, 384)) # 이미지 크기에 맞게 수정하셔야 합니다.
axs[0].imshow(rgb_img)
axs[0].axis('off')

rgb_img = np.float32(rgb_img) / 255

input_tensor = preprocess_image(rgb_img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])

grayscale_cam = cam(input_tensor=input_tensor,
                    targets=None,)

grayscale_cam = grayscale_cam[0, :]
cam_image = show_cam_on_image(rgb_img, grayscale_cam, use_rgb=True)

axs[1].imshow(cam_image)
axs[1].axis('off')
plt.show()

위 코드에서 바꿔야 할 부분은 target_layer리스트 안에 있는 model.layers[-1].blocks[-1].norm1 입니다. 저의 경우 해당 층을 입력하면 cam을 그려주지만 모델마다 입력해야 할 값이 다릅니다.

어떤 층을 사용해야 하는지는 위 링크에서 참고하시면 될 것 같습니다.

위 코드 실행 시 이미지 크기에 따라, target_layer의 위치에 따라 아래와 같은 에러가 발생할 수 있습니다.

이때는 target_layer의 채널 수(저의 경우 768입니다.)를 확인하시고 size(442368)에 나눠주시면 임의의 수에 대한 제곱수(ex) 24*24)가 나오게 됩니다. 이때 def reshape_transform(tensor, height=12, width=12): 부분의 height와 width를 알맞게 바꿔주시면 됩니다. (위 경우 24로 바꾸시면 됩니다.)

GradCam 이외에 다른 방식을 사용하시고 싶다면 cam = GradCAM 부분에서 GradCAM 부분을 바꿔주시면 됩니다. 단, 제 경우 EigenCAM, FullGrad는 작동 시 에러가 발생하며 ablationcam의 경우는 약간의 수정이 필요한 걸로 알고 있습니다.

YJ0522771 commented 2 years ago

efficientnet grad cam 참고 repo : https://github.com/yaleCat/Grad-CAM-pytorch