본문 바로가기
혼공학습단 머신러닝+딥러닝

[6주차] 딥러닝은 어떻게 이미지를 분류하는가?

by 알래스카코코넛 2024. 2. 8.
반응형

Ch.7-1 인공신경망 

 갤럭시를 사용하는 분들은 갤러리 앱을 켜서 돋보기 버튼을 눌러보세요. 아마 처음 보는 분도 계시겠지만, 갤러리 앱이 알아서 사람 얼굴을 인식한 후 그 사람마다 따로 폴더를 만들어 놓았습니다. 신기하죠? 제가 아이폰 유저가 아니라서 아이폰도 되는지는 잘 모르겠습니다. 

제 폰에는 박명수씨가 23장 있네요.

 

 모든 사진마다 '이 사진은 박명수씨 사진입니다!'라고 표시를 해 둔 것도 아닌데, 상당히 높은 정확도로 이미지 분류를 잘 해놓았습니다. 이제 짤을 찾을 때 더 편하게 찾을 수 있을 것 같습니다. 이처럼 딥러닝을 통한 이미지 인식은 의외로 생활 전반에 숨어있습니다. 이번 챕터에서는 저번 주차에 이어 딥러닝을 이용한 이미지 분류를 더 정리해보도록 하겠습니다. 특히, 딥러닝의 알파이자 오메가라고 할 수 있는 인공신경망을 배워보겠습니다.

 인공신경망_간단ver입니다. 이미지들의 배열이 있고, 이 이미지 각각의 픽셀별 정보를 입력받는데 이 층을 입력층(input layer)이라고 합니다. 입력층 = 픽셀값 자체라고 봐도 무방합니다. 달리 뭔가 계산도 일어나지 않습니다. 

 

 이 입력층에 가중치를 부여해서 계산을 거친 후 예측된 클래스를 출력층(output layer)이라고 합니다. 사실 인공신경망에 대한 간단ver는 이미지의 픽셀에 가중치를 부여해서 클래스를 분류하는구나!가 끝입니다. 이건 전문ver이 아니니까 쉽게쉽게 넘어가겠습니다. 이번 챕터는 바로 코드를 보면서 실습해보도록 하겠습니다. 사실 이론에 바삭한 것도 좋지만 코드를 사용할 줄 알면 어느정도 프로젝트를 있어보이게 완료할 수 있습니다. 

 

이번에는 실습 데이터로 keras의 패션 아이템 이미지 데이터셋을 사용하였습니다. keras가 뭔가요? Tensorflow라는 딥러닝 라이브러리에 포함된 고수준 API입니다. 잘 감이 안오시면 sklearn처럼 머신러닝의 어려움을 덜어줄 구세주구나 라고만 하셔도 괜찮습니다. 사실 기존에 가지고 있는 이미지를 사용하려 했는데, 아쉽게도 박명수씨가 폰에 23장밖에 없습니다. 이번 딥러닝 실습은 GPU를 사용하니, Colab에서 런타임 유형을 GPU로 변경하는것도 잊지 맙시다.

 

딥러닝은 보통 GPU를 사용합니다. GPU는 벡터와 행렬 연산에 최적화되어 있기 때문에, 인공 신경망이 작동하기 용이하기 때문입니다. 음? 그럼 CPU는 갖다 버리고 항상 GPU로 사용하면 안돼요?라고 하실 수 있습니다. 그러나 GPU가 만능인 것은 아닙니다. 특히 Colab의 무료버전 GPU는 더욱 그렇습니다. 지금 단계에서는 상관 없지만, 약간 복잡한 코드를 작동하면 시스템 RAM을 모두 사용해서 GPU가 터질 수도 있거든요. 만약 AI쪽을 전공하시면 한 번쯤은 GPU를 터트려보실겁니다. 물론 저도 저번 학기에 시원하게 터트리고 머리를 싸매면서 코드를 고쳤던 기억이 있습니다. 

추억의 세션 터트리기!

 

 저러면 어떻게 하냐고요? GPU 누수를 최대한 막기 위해  각 train dataloader, evaluation dataloader의 iteration loop 내부 마지막에서 torch.cuda.empty_cache() 를 같이 넣어서 돌려주면 코드를 적거나, train dataloader, evaluation dataloader의 iteration loop 내부 마지막에서 gc.collect()를 넣어주거나... 근데 우리가 지금 알 사항은 아닙니다. 굳이 알 필요도 없으니 무서워하지 않으셔도 됩니다. 주인장의 추억 회상 코너였습니다. 그냥 아! GPU가 만능은 아니구나!만 아시면 됩니다. 

 

사족이 길었습니다. 이제 진짜 패션 아이템 이미지 분류 코드를 살펴보겠습니다. 

이번 인공 신경망 모델 코드 순서는 다음과 같습니다.

  1.  데이터셋 불러오기
  2. 인공신경망 모델 만들기
  3. 만든 인공신경망 모델을 이용해서 이미지 분류하기 

먼저 데이터셋을 불러오겠습니다. 

import tensorflow as tf  #딥러닝을 위한 tensorflow 라이브러리 불러오기 
from tensorflow import keras  #데이터셋 마련을 위한 keras 라이브러리 불러오기 

tf.keras.utils.set_random_seed(42)  #랜덤 시드 고정 
tf.config.experimental.enable_op_determinism()

(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()

 

import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 10, figsize=(10,10))
for i in range(10):
    axs[i].imshow(train_input[i], cmap='gray_r')
    axs[i].axis('off')
plt.show()

 

데이터셋이 예쁘게 다운로드되었습니다. 

 

2. 인공신경망 모델 만들기 

from sklearn.model_selection import train_test_split

train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)
    
print(train_scaled.shape, train_target.shape)
#(48000, 784) (48000,) - 입력의 크기가 784구나! (중요)
    
dense = keras.layers.Dense(10, activation='softmax', input_shape=(784,))  #층 만들기, 784(입력의 크기)가 여기 사용됨 
model = keras.Sequential(dense)  #인공 신경망 모델 'model' 만들기

 

3. 만든 인공신경망 모델을 이용하여 이미지 분류하기

model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') #세부 설정 
model.fit(train_scaled, train_target, epochs=5)   #fit()은 모델을 훈련시킨다. 
#epoch(에폭, 반복횟수: 5) 

''' 이렇게 출력됩니다:
Epoch 1/5
1500/1500 [==============================] - 6s 3ms/step - loss: 0.6069 - accuracy: 0.7947
Epoch 2/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.4742 - accuracy: 0.8382
Epoch 3/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.4508 - accuracy: 0.8474
Epoch 4/5
1500/1500 [==============================] - 4s 3ms/step - loss: 0.4367 - accuracy: 0.8527
Epoch 5/5
1500/1500 [==============================] - 3s 2ms/step - loss: 0.4280 - accuracy: 0.8555
<keras.src.callbacks.History at 0x7e83cf5cbdf0>
'''
model.evaluate(val_scaled, val_target)

 

정확도가 0.846정도로 꽤 좋습니다. 

 

Ch.7-2 심층신경망

이름이 점점 멋있어지고 있습니다. 그렇지만 쫄 필요는 없습니다. 심층 신경망이란, 인공신경망 속에서 층이 많이 추가된 것 뿐이니까요! 

이게 아까 보았던 인공 신경망의 기본 이미지입니다. 여기서 입력층과 출력층 사이, 또 다른 층을 추가하면 이게 심층 신경망입니다. 또, 이렇게 입력층과 출력층 사이에 있는 층을 은닉층(hidden layer)이라고 합니다. 

 

 

우리의 친절한 ChatGPT는 심층 신경망을 또 그려야 하는 주인장의 고충을 덜어줬습니다. 고마워요 GPT!

심층 신경망 이미지 처리완료!

 

 보통 층마다 활성화 함수가 붙어 있습니다. 활성화 함수란, 특성에 적용할 함수라고 생각하시면 편합니다. 더 쉽게 생각하면 특성에 붙는 가중치입니다. 출력층에서는 분류의 종류에 따라 이진분류는 시그모이드(sigmoid) 함수, 다중 분류는 소프트맥스(softmax) 함수를 주로 사용합니다. 그러나 은닉층은 활성화 함수를 더 다양하게 사용하며, 대표적으로는 시그모이드 함수나 렐루(ReLU) 함수를 사용합니다.

출처: software workshop

왼쪽이 시그모이드, 오른쪽이 렐루 함수입니다. 시그모이드 함수는 0과 1로 결과값을 표시할 수 있지만, x가 극단으로 갈 경우 그래프가 누워있기 때문에 출력이 올바르지 못할 수 있습니다. 이러한 단점을 극복하기 위하여 렐루 함수가 개발되었습니다. 렐루 함수는 x가 음수면 출력이 0, 양수면 y=x에 따라 그 값을 출력합니다. 

 

 신경망은 하이퍼파라미터가 특히 많습니다. 하이퍼파라미터를 어떻게 선택하느냐에 따라 결과가 천차만별이 되기도 하니, 잘 알아두면 좋습니다. 점점 내용이 어려워지니까 드립이 줄고 학술적 내용만 추가되고 있습니다. 지루함과 뒤로가기를 방지하기 위해 틈틈히 드립을 잘 끼워보겠습니다.

 

 하이퍼파라미터 중 '옵티마이저'라는 중요한 녀석이 있습니다. 신경망의 가중치과 절편을 학습하기 위한 방법으로, SGD, 네스테로프 모멘텀, RMSprop, Adam 등이 있습니다. 사실 결론만 말씀드리면 Adam이 많이 사용됩니다. 저희 교수님도 모르면 그냥 Adam 쓰라고 하셨습니다. 뻥 아님. 이제 여러분 머리에는 '옵티마이저 모르겠으면 Adam 쓰는구나!'만 남겠군요.하지만 정리를 안하고 가면 나머지 친구들이 섭섭해할 것 같습니다. 간략히 정리해주도록 합시다.

 

Adagrad - learning_rate가 매개변수, 기본값은 0.001
- 그레디언트 제곱을 누적한 값으로 학습률을 나눈다
- initial_accumulator_value 매개변수, 기본값은 0.1
RMSprop - learning_rate가 매개변수, 기본값은 0.001
- Adagrad처럼 그레디언트 제곱을 누적한 값으로 학습률을 나누나 지수감소 사용
- rho 매개변수에서 감소 비율 지정, 기본값은 0.9
SGD - 기본 경사 하강법 옵티마이저 클래스
- learning_rate 매개변수, 기본값은 0.01
- momentum 매개변수에 0 이상의 값을 지정하면 모멘텀 최적화 수행
- nesterov 매개변수를 True로 지정하면 네스테로프 모멘텀 최적화 수행 
Adam - learning_rate가 매개변수, 기본값은 0.001
- 모멘텀 최적화의 그레이디언트 지수 감소 평균 조절 매개변수 beta_1, 기본값은 0.9
- RMSprop의 그레디언트 제곱 지수 감소 평균 조절 매개변수 beta_2, 기본값은 0.999

 

 사실 코드도 보고싶은데 이번 코드는 진짜 깁니다. 장난 아니고 진짜로 길어요. 따라서 책으로 필기해가면서 보시는 걸 추천합니다. 

 Ch.7-3 신경망 모델 훈련

이번 챕터는 인공신경망 파트에서 오? 조금 더 성능이 개선되면 좋겠는데? 싶을 때 사용하는 스킬입니다. 

 

1. 드롭아웃(dropout) 

은닉층에 있는 일부 뉴런을 끄면 어떻게 될까요? 해당 뉴런의 활성화 함수를 통과하지 않기 때문에, 해당 부분만큼 가중치가 생기지 않을 것입니다. 즉, 덜 세부적인 출력이 생길 것입니다. 따라서 드롭아웃(dropout)이란 일부 뉴런을 끄는 것으로(삭제가 아님), 과대적합을 막는 하나의 방법입니다.

 

2. 콜 백(Call back)

 만약 epoch이 100인데, 30번 테스트한 이후 유의미한 성능 향상이 일어나지 않으면 더 이상 할 필요가 있을까요? 없습니다. 그런데 우리의 불쌍한 GPU는 아직도 타고 있습니다. 운이 나쁘면 성능이 더 개선되지는 않는데, GPU는 터져서 기껏 딥러닝 시킨 모델이 작동하지 않을 수 있습니다. 이런 상황을 방지하기 위해, 더 이상 성능 향상이 일어나지 않으면 일찍 종류하는 방법을 조기종료(Early Stopping)라고 합니다. 

 이처럼 훈련 과정 중간에 조기종료 등 특정한 작업을 수행하는 것을 콜 백(Call back)이라고 합니다. 조기종료도 콜 백의 일종입니다. 콜백 덕분에 소중한 컴퓨터 자원의 낭비를 막을 수 있습니다. 

 

마지막 미션입니다. 이번 혼공학습단 11기도 끝이네요. 확실히 머신러닝+딥러닝은 C때보다 조금 어렵긴 했는데, 그래도 한번 쫙 훑어볼 수 있어서 좋았습니다. 다음주 정말 마지막 회고록으로 돌아오겠습니다! 

반응형