본문 바로가기

딥러닝/신규 모델&기술 설명

[DeepLearning] GPU-Net을 활용한 이미지 분류_1

320x100
국내에는 번역본이 많이 보이질 않아서 
pytorch문서와 NVIDIA 발 논문의 직접 해석을 진행했습니다.
꽤 최근 모델이었던 것 같습니다.



이번 시간에는 요즘 정말 핫한 그래픽 카드 전문 기업인 NVIDIA에서 밝혀낸 GPU-Net모델을
official하게는 아니고 잠깐 소개하는 시간을 가져보겠습니다. pytorch 공식 문서에서 본 내용으로
테스트를 진행하던 중 꽤 흥미로운 결과값을 보이는 이미지들이 있어서 그 부분도 같이 가져왔습니다.

✅ 주의
※ <GPU-Net: Lightweight U-Net with more diverse features>의 내용을 따르나, 논문 해석상의
오류나 의역이 존재할 수 있습니다.




먼저, GPU net은 쉽게 말하자면 CNN(Convolution Neural Network)에서 이미지 분류와 정확도에
특출난 성능을 보이는 신규 모델로, 현재까지는 특정 영역(추론)에서 정점을 찍고 있다고 볼 수 있을 정도로 최적화된 모델입니다.

NVIDIA가 GPU 계열에서는 독보적인 기술력을 갖고 있다는 점, 모두 알고 계실 겁니다.
그래서 딥러닝의 이미지 분야에서 사용되는 GPU 기술력을 더 원활히 사용할 수 있었을 것이죠.

기본적으로 nvidia가 갖고 있는 NAS 시스템을 사용하며, EfficientNet의 변형인 EfficientNetX와 ResNet 계열의 모델보다도
추론 정확도가 높은 것을 보이고 있습니다. 분당 EfficientNetX보다 2배 빠른 속도를 기록하며
낮은 loss와 신속성까지 잡은 모델이라고 할 수 있습니다. 이외에도 IRB(Inverted Residual Block)이나
어텐션 등 활발히 연구가 진행했던 기법들을 최대한 사용하고 있습니다.

자, 그렇다면 NAS 시스템이란 무엇이냐

NAS (Neural Architecture Search)



이 시스템도 정말 어마어마한 시스템입니다.

서버 네트워크에서 쓰이는 NAS(Network Attached Storage)와 다른 시스템이라는 것을 알아두셔야 합니다.


최근 연구에서, 연구진들은 검색 영역(search space), 검색 알고리즘(search algorithm), 검증 기법(evaluation method)를 한꺼번에 담는 프레임워크를 개발합니다. 검색 영역, 검색 알고리즘, 검증 기법을 자동으로 업데이트 하는 것이죠.
이를 병렬 NAS 시스템이라고 명명합니다. (EfficientNet의 개발에서 많은 영감을 받았다고 합니다)

검색 영역에서 신경망 자원자를 받아 평가하고, 그 결과는 다시 검색 영역에 영향을 줍니다.


그러면 검색 영역에서 제안된 영역은 지연시간(latency)동안 분류되고, 블랙박스 옵티마이저라는
기법(black box optimiser)을 통해 반복적으로 계속 탐지합니다.


그러고나서 분산 검색 프레임워크를 통해 병렬식으로 처리합니다.

여기에서 또 처음 제시되는 기법이 나타납니다. 바로 IRB인데요?
IRB는 Inverted Residual Block으로, Residual block의 응용입니다.


몇 년전 진행된 모바일넷의 연구에 의하면, 채널 사이즈를 확장하는 것이
신경망의 용량과 표현력을 높이는데 도움이 된다는 점을 증명했습니다.
- 본 논문에서는 확장 비율이 내부 채널의 크기도 제어한다고 설명하고 있습니다.


이 IRB의 기본적인 목표는 합성곱을 하기 위해 채널 사이즈를 확장시켜주는 것입니다.
(이때의 합성곱 크기는 1x1입니다. )

형태 자체는 과거 Conv2d와 ConvTranspose2d의 관계처럼 역으로 진행된다고 보면 좋을 것 같습니다.

이제 개발진들은 신경망과 검색 영역의 표현으로 넘어갑니다.
검색영역에서 가져온 신경망 샘플을 일종의 Int 벡터형태로 인코딩합니다.

그리고 추론 대기시간(Inference Latency)로 신경망들을 계층화하구요.
분산 NAS 시스템 하에서 학습모델에게 보상을 쥐워주며 (검증 정확도) 모델의 성능을 높이기
위한 하이퍼 패러미터를 검색 영역에서 진행합니다. 이 부분은 강화 학습과 똑같네요.


이 세가지가 GPU-Net의 성능을 높이는 중요한 축입니다. 특히 분산 NAS는 논문에서
거의 한 페이지가 넘어갈 때마다 나올 정도로 자주 강조되고 있습니다.
NAS 시스템 하에서 샘플링을 통해 추론 대기시간 범위에 있는 네트워크를 검색 영역으로 사용합니다.

정리된 검색 영역을 서버에 올리기 위한 알고리즘에 통합(Integrate)하구요, 서버와 클라이언트는 데이터를 교환합니다.
클라이언트는 그럼 네트워크에 올릴 수 있거나 최적의 검증 정확도일 경우 서버에 요청하개 되고,
검색 알고리즘은 이 정보를 활용해서 다음 네트워크에 올라갈 후보를 제안할 수 있습니다.

지난 과거 모델과 비교했을 때, 이 모델은 SOTA pareto 프론티어를 향상시킴으로서
정확도와 추론 대기시간을 모두 향상시키는 효과를 얻었습니다.

이것이 바로 GPU-Net의 초기 형태 구조입니다.
복잡한 과정에 비해서 구조 자체는 심플합니다.

이제 실제로 구현하고 테스트한 부분을 보겠습니다.


validators matplotlib 프로그램과 timm이라는 프로그램을 설치합니다.
두 프로그램 모두 이미지 전처리 및 시각화에 사용되는 것입니다.

!pip install validators matplotlib -q
!pip install timm==0.5.4 -q


필수 라이브러리 로드합니다.

import torch
from PIL import Image
import torchvision.transforms as transforms
import numpy as np
import json
import requests
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings('ignore')
%matplotlib inline


역시 GPU 기업에서 진행해서 그런지, GPU 성능도 확인시켜 줍니다.

# 내 cpu에 있는 gpu성능을 보여줌
if torch.cuda.is_available():
    device = torch.device("cuda") 
    !nvidia-smi
else:
    device = torch.device("cpu")

print(f'Using {device} for inference')
Mon Feb 13 12:54:45 2023       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.47.03    Driver Version: 510.47.03    CUDA Version: 11.6     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Tesla T4            Off  | 00000000:00:04.0 Off |                    0 |
| N/A   66C    P0    32W /  70W |      3MiB / 15360MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
Using cuda for inference




기본적으로 IMAGENET 데이터세트에서 사전 훈련된 NVIDIA GPUNet-0 모델을 로드합니다.
GPUNet-0에서 아래에 나열된 다음 모델 중 하나로 기본 사전 훈련된 모델 로딩을 전환할 수 있습니다.

GPUNet-0
GPUNet-1
GPUNet-2
GPUNet-P0
GPUNet-P1
GPUNet-D1
GPUNet-D2

아래로 갈수록 고성능의 모델입니다. 앞서 실험해본 결과 단순한 이미지 분류에서는 굉장한 차이점을
가지진 않았네요. GPUNet-0 계열의 경우 -0의 변형으로 -1버전은 레이어 한개 추가, -2버전은 두개를 추가해서 정확도를 높혔습니다.
GPUNet-P 계열은 위 -0 모델을 정제한 모델로, 대기시간은 동일하지만 정확도가 높습니다. P0은 -0버전을 차용했고, P1은 -1버전을 사용했습니다.
GPUNet-D계열은 모든 라인중에서 가장 높은 정확도를 기록한 모델입니다. GPUNet-D2가 가장 탁월하다고 보면 되겠습니다.

실험 시작
GPUNet-0 : 속도 빠름. 생명체를 위주로 잘 맞춘다. 객체가 없는 Landscape은 판단이 어려움


nvidia에서 미리 훈련한 모델을 로드합니다.

model_type = "GPUNet-0" # 위에서 하나 선택 (자유)
precision = "fp64" # fps 32, fps  64중에서 하나를 선택 (GPU의 32 or 64비트를 말하는 것 같습니다)

# 로드
gpunet = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub', 'nvidia_gpunet', pretrained=True, model_type=model_type, model_math=precision)
utils = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub', 'nvidia_convnets_processing_utils')
print("GPU NET 다운로드를 진행중입니다.... \n 10초 가량의 시간이 걸릴 수 있습니다.")

# GPUnet을 gpu에 저장
gpunet.to(device)

# 신경망 모델 확인
gpunet.eval()
 10초 가량의 시간이 걸릴 수 있습니다.
GPUNet(
  (network): Sequential(
    (head: 2): prologue_i3_o32_s2_swish
    (stage: 1 layer3): conv_k3_i32_o32_s1_relu
    (stage: 1 layer4): conv_k3_i32_o32_s1_relu
    (stage: 2 layer5): er_k3_e5_i32_o32_s2_relu_se_False
    (stage: 2 layer6): er_k3_e5_i32_o32_s1_relu_se_False
    (stage: 3 layer7): er_k3_e5_i32_o64_s2_relu_se_False
    (stage: 3 layer8): er_k3_e5_i64_o64_s1_relu_se_False
    (stage: 3 layer9): er_k3_e5_i64_o64_s1_relu_se_False
    (stage: 4 layer10): irb_k3_e5_i64_o256_s2_swish_se_False
    (stage: 4 layer11): irb_k3_e5_i256_o256_s1_swish_se_False
    (stage: 4 layer12): irb_k3_e5_i256_o256_s1_swish_se_False
    (stage: 6 layer13): irb_k3_e5_i256_o704_s2_relu_se_True
    (stage: 6 layer14): irb_k3_e5_i704_o704_s1_relu_se_True
    ( layer15): epilogue_i704_o1280_s1_relu
  )
)


모델의 구조는 위와 같이 생겼습니다.

추론할 데이터 준비


이미지 추론을 위해 각종 이미지 샘플을 준비했습니다.

이미지 개체

  • 순서 : 비생물체, 생물체, 인간, 풍경, 추상화 이미지, 상상의 동물(개체)

# uris = 인터넷 웹 이미지에서 링크 복사해서 사용
uris = ['https://cdn.pixabay.com/photo/2017/06/07/10/53/pizza-2380025_1280.jpg',
        'https://cdn.pixabay.com/photo/2019/07/23/13/51/shepherd-dog-4357790_1280.jpg',
        'https://cdn.pixabay.com/photo/2020/01/23/16/42/embrace-4788167_1280.jpg',
        'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
        'https://images.pexels.com/photos/1676530/pexels-photo-1676530.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2',
        'https://media.wired.com/photos/615204854a9e495923621ef1/master/pass/Games-Diablo_LordOfTerror_2D_Desktop.jpg'
        ]

# batch크기 : uris에서 지원
batch = torch.cat(
    [utils.prepare_input_from_uri(uri) for uri in uris]
).to(device)

if precision == "fp16":
    batch = batch.half()
    
print("추론을 진행중입니다....")



전체적으로 저작권 없는 pixabay, pexels의 샘플입니다.
이 모델이 아무런 형태나 객체가 없는 추상화는 어떻게 생각할지 궁금해서 추상화도 불러와봤습니다.

uris # 이미지 확인
# 5번째 이미지 : steve johnson 님의 추상화 작품입니다. (pexels)

['https://cdn.pixabay.com/photo/2017/06/07/10/53/pizza-2380025_1280.jpg',
 'https://cdn.pixabay.com/photo/2019/07/23/13/51/shepherd-dog-4357790_1280.jpg',
 'https://cdn.pixabay.com/photo/2020/01/23/16/42/embrace-4788167_1280.jpg',
 'https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823_1280.jpg',
 'https://images.pexels.com/photos/1676530/pexels-photo-1676530.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2',
 'https://media.wired.com/photos/615204854a9e495923621ef1/master/pass/Games-Diablo_LordOfTerror_2D_Desktop.jpg']

추론 실행

pick_n_best(predictions=output, n=N) 헬퍼 함수를 사용하여 모델에 따라 가장 가능성이 높은 N개의 가설을 선택합니다.

첫번째는 텍스트를 기반으로 출력합니다.

# 텍스트 추론
with torch.no_grad():
    output = torch.nn.functional.softmax(gpunet(batch), dim=1)
    
results = utils.pick_n_best(predictions=output, n=5)
Downloading Imagenet Classes names.
Downloading finished.
sample 0: [('pizza, pizza pie', '94.5%'), ('pomegranate', '0.2%'), ('pretzel', '0.2%'), ('trifle', '0.2%'), ('wooden spoon', '0.1%')]
sample 1: [('German shepherd, German shepherd dog, German police dog, alsatian', '71.4%'), ('malinois', '8.6%'), ('Australian terrier', '1.0%'), ('Leonberg', '0.7%'), ('kelpie', '0.5%')]
sample 2: [('whistle', '15.8%'), ('bulletproof vest', '5.2%'), ('flute, transverse flute', '2.7%'), ('accordion, piano accordion, squeeze box', '2.6%'), ('wig', '2.4%')]
sample 3: [('valley, vale', '50.6%'), ('lakeside, lakeshore', '4.5%'), ('maze, labyrinth', '2.6%'), ('groom, bridegroom', '1.5%'), ('park bench', '1.3%')]
sample 4: [('padlock', '6.4%'), ('chainlink fence', '6.0%'), ('mailbox, letter box', '4.1%'), ('switch, electric switch, electrical switch', '4.0%'), ('gas pump, gasoline pump, petrol pump, island dispenser', '2.5%')]
sample 5: [('crayfish, crawfish, crawdad, crawdaddy', '29.9%'), ('American lobster, Northern lobster, Maine lobster, Homarus americanus', '20.0%'), ('triceratops', '18.0%'), ('spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish', '10.1%'), ('walking stick, walkingstick, stick insect', '0.9%')]


이미지 출력 결과물입니다.

for uri, result in zip(uris, results):
    img = Image.open(requests.get(uri, stream=True).raw)
    img.thumbnail((256,256), Image.ANTIALIAS)
    plt.axis('off')
    plt.imshow(img)
    plt.show()
    
    print(result)


무생물 개체 - 피자입니다.

[('pizza, pizza pie', '94.5%'), ('pomegranate', '0.2%'), ('pretzel', '0.2%'), ('trifle', '0.2%'), ('wooden spoon', '0.1%')]


생물 개체 - 져먼 쉐퍼드 입니다.
이 추론이 갖가지 품종들을 모두 가져오면서 상당히 인상깊은데요. 다음 시간에는 이부분을 더 공략할 예정입니다.

[('German shepherd, German shepherd dog, German police dog, alsatian', '71.4%'), ('malinois', '8.6%'), ('Australian terrier', '1.0%'), ('Leonberg', '0.7%'), ('kelpie', '0.5%')]


whistle 즉 휘파람이 가장 높았습니다. 입술을 내밀어서 그런 것일까요.
방탄조끼도 보입니다.

[('whistle', '15.8%'), ('bulletproof vest', '5.2%'), ('flute, transverse flute', '2.7%'), ('accordion, piano accordion, squeeze box', '2.6%'), ('wig', '2.4%')]


valley와 lakeside가 보입니다. 아예 벗어난 것은 아니지만 상당히 일반화된 추론입니다.

[('valley, vale', '50.6%'), ('lakeside, lakeshore', '4.5%'), ('maze, labyrinth', '2.6%'), ('groom, bridegroom', '1.5%'), ('park bench', '1.3%')]


독특하게도 padlock (자물쇠)를 들고 왔습니다.
chainlink fence라는 울타리로 보는 해석도 존재합니다만 모두 수치가 10%도 넘기진 못합니다.

[('padlock', '6.4%'), ('chainlink fence', '6.0%'), ('mailbox, letter box', '4.1%'), ('switch, electric switch, electrical switch', '4.0%'), ('gas pump, gasoline pump, petrol pump, island dispenser', '2.5%')]


이 이미지 추론은 필자가 추가적으로 실험을 진행하면서 계속 같게 나온 추론입니다.

[('crayfish, crawfish, crawdad, crawdaddy', '29.9%'), ('American lobster, Northern lobster, Maine lobster, Homarus americanus', '20.0%'), ('triceratops', '18.0%'), ('spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish', '10.1%'), ('walking stick, walkingstick, stick insect', '0.9%')]



crayfish이란

American Lobster이란

crayfish는 일종의 민물가재로, 서양에서는 굉장히 크기가 큰 종으로도 소개됩니다. american lobster는
우리가 보통 일컫는 '랍스타'로, 큰 집게발이 특징입니다.

상상의 생물인 악마는 모델이 딱히 추론하지 못한 것으로 보입니다.
큰 손톱을 가진 발, 붉은색 색상, 갑각류와 같은 경화된 피부, 큰 뿔, 구부러진 척추 등이 가재와 유사하다는 판단을 내린것 같습니다.
실제로 모든 형태의 상상의 생물은 거의 판단을 못했습니다.

피카츄나 외계인으로 실험했을 경우에도, 전혀 관련없는 추론을 나타낼 때도 있었습니다.

반대로, 생물의 경우에는 정말 압도적인 추론능력을 보여주었습니다.
다음 시간에는 이 지점에서 모델을 착안하여 강아지와 고양이 품종을 맞추는 테스트를 진행하려 합니다.

Reference

본 게시물은 2022년 1월 7일 EESS(Electrical Enginerring and Systems Science)에 투고된
GPU-Net 연구 논문의 내용을 따릅니다.

[GPU-Net: Lightweight U-Net with more diverse features, Heng Yu, Di Fan, Weihu Song], Fri, 7 Jan 2022

pytorch의 원본 게시물은 아래와 같습니다.

GPUNet | PyTorch

PyTorch

An open source machine learning framework that accelerates the path from research prototyping to production deployment.

pytorch.org

728x90