본문 바로가기

spartacodingclub/개발보고서

가장 쉽게 배우는 머신러닝 4주차

https://spartacodingclub.kr/

 

 

*스파르타 클럽 강의 4주차(끝)를 듣고 난 개인적인 후기*

더보기

전에도 말했던 내용이지만 다른 강의는 몰라도 이 '가장 쉽게 배우는 머신러닝'은 '실무' 중심의 강의로, 다른 전공자, 혹은 코딩을 처음 배우는 사람에게는 쉽지 않은 과목일 것이다.

 

실제로 학생들에게는 공무전이라는 실무에 바로 적용할 수 있는 코드와 정보들을 제공받을 수 있는 좋은 수업이라고 생각한다.

 

 

*강의 내용*

 

신경망 구조란?

신경망을 구성하는 방법은 정말 여러가지가 있다.

그중 가장 많이 쓰이는 것에는 합성곱 신경망CNN, 순환 신경망RNN, 생성적 적대 신경망GAN이 있다.

 

전이학습이란?

이미 학습된 모델을 비슷한 문제를 푸는 데에 다시 사용하는 것을 전이학습이라고 한다.

더 적은 데이터로 더 빠르고 정확하게 학습시킬 수 있다.

 

합성곱 신경망Convolutional Neural Networks은?

합성곱Convolution은 예전부터 컴퓨터 비전CV 분야에서 많이 쓰이는 이미지 처리 방식으로 계산하는 방식은 입력 데이터와 필터의 각각의 요소를 서로 곱한 후 다 더하면 출력값이 된다.

출처: https://ce-notepad.tistory.com/14

위와 같은 그림을 예로 들면, 입력 데이터의 제일 왼쪽 윗부분부터 3*3 형태의 또따른 정사각형을 만들어, 이를 필터와 곱셈 시킨 뒤 모든 수를 더하는 계산 방식을 이용한다.

위의 그림을 이용해 설명해 본다면, 입력 데이터에서

왼쪽 윗부분인 3*3 부분을 필터와 곱한다.

(1*2) (2*0) (3*1)

(0*0) (1*1) (2*2)

(3*1) (0*0) (1*2)

그리고 이 곱한 값들을 전부 더해 출력값의 제일 왼쪽 윗부분에 놓는다.

딥러닝 연구원들은 이 합성곱을 어떻게 해야 딥러닝에 활용할 수 있을지에 대해 고민하던 중, 1988년 Yann LeCun 교수가 엄청난 논문을 발표하게 된다.

바로, 합성곱을 이용한 신경망 디자인을 발표한 것이다. 르쿤 교수님은 이 신경망을 CNN이라 명칭했고, 이미지 처리에서 엄청난 성능을 보이는 것을 증명해냈다.

이 CNN의 발견 이후 딥러닝의 전성기가 시작되었다고 볼 수 있다.

 

필터Filter, 스트라이드Stride, 패딩Padding이란?

출처: https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1

위와 같이 5*5 크기의 입력이 주어졌을 때, 3*3짜리 필터를 사용해 합성곱을 하게 되면 3*3 크기의 특성맵Feature map을 뽑아낼 수 있다.

필터Filter 또는 커넬Kernel은 한 칸씩 오른쪽으로 움직이며 합성곱 연산을 하게 되는데, 이때 이동하는 간격을 스트라이드Stride라고 한다.

즉, 위의 있는 그림에서의 스트라이드는 1이다.

그러나 이러한 연산을 하게 되면 특성맵의 크기가 줄어든다. 이를 방지하게 위해 패딩Padding 또는 마진Margin을 줘, 스트라이드가 1일 때 입력값과 특성맵의 크기를 같게 만들 수 있다.

지금까지의 것들은 전부 1개의 필터를 사용해 연산했지만 여러 개의 필터를 사용하면 합성곱 신경망의 성능을 높일 수 있다.

출처: https://stackoverflow.com/questions/42883547/intuitive-understanding-of-1d-2d-and-3d-convolutions-in-convolutional-neural-n

이 그림과 같은 합성곱 신경망이 있다면, 입력 이미지 크기는 (10, 10, 3)이고, 필터의 크기는 (4, 4, 3), 개수는 2이다. 그리고 출력값인 특성맵의 크기는 (10, 10, 2)를 가지게 된다.

특성맵의 크기에서 마지막 숫자, 즉 채널은 필터의 개수와 관련 있다.

 

CNN의 구성은?

출처: https://teknoloji.org/cnn-convolutional-neural-networks-nedir/

CNN은 합성곱 계층Convolution과 완전연결 계층Dense layer을 함께 사용한다. 합성곱 계층, 활성화 함수, 풀링을 반복하며 점점 작아지지만 핵심적인 특성들을 뽑아 낸다.

여기에서 풀링 계층Pooling layer은 특성맵의 중요 부분을 추출해 저장하는 역할을 한다.

Max Pooling은 특성맵에서 가장 큰 값들을 추출한다.

Average Pooling은 특성맵에서 평균값을 추출한다.

활성화와 풀링을 두 번 반복하고 나면 완전연결 계층으로 이동해야 하는데, 특성맵은 2차원이고 완전연결 계층은 1차원이므로 연산이 불가능하다.

따라서 평탄화 계층Flatten layer을 사용해 2차원을 1차원으로 펼치는 작업을 한다.

 

YOLO(You Only Look Once)는 정확도가 높은 물체 인식 CV 알고리즘이다.

Segmentation은 각각의 오브젝트를 픽셀 단위로 분리하는 이미지 분할 방식이다.

LiDAR을 이용해 객체를 인식하는 방식은 자율주행에 사용된다.

Pose Detection은 사람을 detect하고, 인체의 각 부분의 위치를 파악해 자세를 인식할 수 있다. 저스트 댄스는 이것을 응용해 만든 게임이다.

Super Resolution은 이미지의 feature를 인식한 후 고화질 영상으로 추론하는, 즉 화질 개선에 사용되는 방식이다.

Style Transfer은 이미지에 다양한 화풍을 입힐 수 있게 이미지의 각 요소를 인식하는 방식이다.

Colorization은 사진 색을 복원하는 데 사용된다.

 

AlexNet(2012)은 의미있는 선능을 낸 첫 번째 합성곱 신경망이고, Dropout과 Image augmentation 기법을 효과적으로 사용해 딥러닝에 많은 기여를 했다.

VGGNet(2014)은 큰 특징은 없지만 파라미터의 개수가 많고, 모델의 깊은 것으로 잘 알려져 있다.

GoogLeNet, Inception V3(2015)은 한 가지 필터를 적용한 합성곱 계층을 단순히 깊게 쌓는 방법도 있지만, 하나의 계층에 다양한 종류의 필터와 풀링을 도입함으로써 개별 계층을 두텁게 확장시킬 수 있다는 창조적인 아이디어를 통해 인셉션 모듈Inception module을 제안했다.

 

순환 신경망Recurrent Neural Network은?

RNN은 은닉층이 순차적으로 연결돼 순환구조를 이루는 인공 신경망의 한 종류이다. 음성, 문자 등 순차적으로 등장하는 데이터 처리에 적합한 모델로 알려져 있다.

소설을 지어내는 인공지능, 주식이나 암호화폐의 시세를 예측하는 것에 사용되는 다양한 모델을 만들 수 있다.

 

생성적 적대 신경망Generative Adversarial Network은?

GAN은 적대Adversarial 관계에 있는 두 가지 모델을 동시에 사용해 학습시키는 분야이다.

예를 들어 생성 모델과 판별 모델을 각각 위조 지폐범, 경찰로 정했을 때, 생성 모델은 계속해서 위조 지폐를 만들어내고, 판별 모델은 데이터셋과 생성 모델이 만들어낸 위조 지폐 사이에서 진짜 지폐를 판별해내는 학습을 하게 된다.

서로가 서로를 발전시켜주는 이 모델은 딥페이크DeepFake와 같은 가장 핫한 분야를 담당하고 있다.

 

 

*실습*

캐글 데이터셋을 가지고 와 전이학습 실습

(https://colab.research.google.com/drive/1Hz_1bOPFglQGWrXc9wAogdDwIM5IFsNU?usp=sharing)

 

import os
os.environ['KAGGLE_USERNAME'] = 'username' # username
os.environ['KAGGLE_KEY'] = 'key' # key

!kaggle datasets download -d puneet6060/intel-image-classification
!unzip -q intel-image-classification.zip

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPooling2D, Flatten, Dropout
# Conv2D는 Conv 연산을 위해, MaxPooling은 maxpooling을 위해, Flatten은 2차원을 1차원으로 편집하기 위해

from tensorflow.keras.optimizers import Adam, SGD
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder

 

!unzip에서 -q는 많은 데이터셋을 저장할 때 출력이 너무 길게 뜰 것을 고려해 출력을 하지 않겠다고 하는 옵션이다.

train_datagen = ImageDataGenerator(
  rescale=1./255, # 일반화
  rotation_range=10, # 랜덤하게 이미지를 회전 (단위: 도, 0-180)
  zoom_range=0.1, # 랜덤하게 이미지 확대 (%)
  width_shift_range=0.1,  # 랜덤하게 이미지를 수평으로 이동 (%)
  height_shift_range=0.1,  # 랜덤하게 이미지를 수직으로 이동 (%)
  horizontal_flip=True # 랜덤하게 이미지를 수평으로 뒤집기
)
# 3주차에서 했던 것처럼

test_datagen = ImageDataGenerator(
  rescale=1./255 # 일반화
)

train_gen = train_datagen.flow_from_directory(
  'seg_train/seg_train',  # 현재 데이터셋에서 가지고 올 데이터
  target_size=(224, 224), # (height, width)
  batch_size=32,
  seed=2021,
  class_mode='categorical',
  shuffle=True # 데이터 순서를 섞는다 섞을수록 성능 향상에 도움이 된다고 한다.
)

test_gen = test_datagen.flow_from_directory(
  'seg_test/seg_test',
  target_size=(224, 224), # (height, width)
  batch_size=32,
  seed=2021,
  class_mode='categorical',
  shuffle=False #테스트 데이터이기 때문에 False
)

 

preview_batch = train_gen.__getitem__(0)
#모델에 데이터를 넣어준다.

preview_imgs, preview_labels = preview_batch

plt.title(str(preview_labels[0]))
plt.imshow(preview_imgs[0])

 

from tensorflow.keras.applications import ResNet50
# 이 실습에서는 ResNet50을 이용한다

input = Input(shape=(224, 224, 3))

base_model = ResNet50(weights='imagenet', include_top=False, input_tensor=input, pooling='max')
# 우리가 변형해줄 출력데이터 빼고 베이스 모델에 넣는다

x = base_model.output
x = Dropout(rate=0.25)(x)
x = Dense(256, activation='relu')(x)
output = Dense(6, activation='softmax')(x)

model = Model(inputs=base_model.input, outputs=output)

model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.001), metrics=['acc'])

model.summary()

 

from tensorflow.keras.callbacks import ModelCheckpoint
# 모델을 저장했다 사용할 수 있게 Callback 사용

history = model.fit(
    train_gen,
    validation_data=test_gen, # 검증 데이터를 넣어주면 한 epoch이 끝날때마다 자동으로 검증
    epochs=20, # epochs 복수형으로 쓰기!
    callbacks=[
      ModelCheckpoint('model.h5', monitor='val_acc', verbose=1, save_best_only=True)
    ] # h5에 모델 저장, berbose=1은 제일 높은 것 하나를 저장한다는 의미
)

from tensorflow.keras.models import load_model
# 모델 가지고 오기

model = load_model('model.h5')

print('Model loaded!')

test_imgs, test_labels = test_gen.__getitem__(100)
# 백 번째 가져오기(숫자 바꿔가면서 해볼 수 있다.)

y_pred = model.predict(test_imgs)

classes = dict((v, k) for k, v in test_gen.class_indices.items())

fig, axes = plt.subplots(4, 8, figsize=(20, 12))

for img, test_label, pred_label, ax in zip(test_imgs, test_labels, y_pred, axes.flatten()):
  test_label = classes[np.argmax(test_label)]
  pred_label = classes[np.argmax(pred_label)]
  #argmax는 원핫인코딩 한 걸 반대로 바꿔주는 역할을 한다

  ax.set_title('GT:%s\nPR:%s' % (test_label, pred_label))
  ax.imshow(img)