코딩일지/Machine Learning

실전 머신러닝 적용 3주차 정리

야언 2022. 10. 12. 19:24

이번주 배울 것

  • 딥러닝이란?
  • 딥러닝의 주요 개념과 기법

 

딥러닝이란?

 

출처: https://neocarus.tistory.com/entry/딥러닝의-필요성

  • 우리가 지금까지 배운 선형회귀와 논리회귀는 모두 1차 함수를 이용해서 문제를 풀었는데요, 자연계에는 직선으로 설명할 수 없는 문제들이 훨씬 많습니다. (뒤에 배울 XOR 문제처럼요!)
  • 이런 복잡한 문제들을 풀기 위해 선형회귀를 여러번 반복해보았어요.

  • 하지만 선형회귀를 여러번 반복한다고해서 비선형(선형이 아닌 것)이 되는 것은 아니었지요.

  • 그래서 선형회귀 사이에 비선형의 무엇인가를 넣어야 한다고 생각했어요.

이렇게 층(Layer)을 여러개 쌓기 시작했고 이 모델은 정말 잘 동작했지요. 층을 깊게(Deep) 쌓는다고 해서 딥러닝이라고 불리게 되었습니다!

 

딥러닝의 다른 단어 표현
1. 딥러닝(Deep learning)
2. Deep neural networks
3. Multilayer Perceptron(MLP)

 

딥러닝의 주요 개념과 기법

  • 배치 사이즈와 에폭
  • 활성화 함수
  • 과적합과 과소적합
  • 데이터 증강
  • 드랍아웃
  • 앙상블
  • 학습률 조정

 

 

딥러닝의 역사

 

XOR 문제

딥러닝의 태동을 불러온 XOR 문제에 대해 알아봅시다!
  • 기존의 머신러닝은 AND, OR 문제로부터 시작해요.

출처: https://donghwa96.tistory.com/11

  • 위와 같은 문제를 풀기위해서는 직선 하나만 있으면 되는데 그 직선은 논리회귀로 쉽게 만들 수 있었죠.

  • 이 수식을 아래와 같이 그림으로 나타낼 수 있습니다. 이런 모양을 Perceptron(퍼셉트론)이라고 불렀어요.

  • w0, w1, w2 의 값만 잘 지정해주면 우리가 원하는 출력을 계산할 수 있었기 때문에 사람들은 흥분하기 시작했어요. AND, OR 문제를 잘 조합하면 생각하는 기계를 만들 수 있겠다! 전 인류가 흥분의 도가니에 빠지게 됩니다. 실제로 1958년 뉴욕타임즈에는 아래와 같은 기사가 실렸어요.

출처: http://www.parvez-ahammad.org/blog/category/ai

  • 그런데 선형회귀로는 AND, OR 문제는 잘 풀었지만 XOR 문제는 풀지 못했죠.

출처: https://extsdd.tistory.com/217

  • Perceptron을 여러개 붙인 Multilayer Perceptrons (MLP)라는 개념을 도입해서 문제를 풀어보려고 했습니다.

출처: https://towardsdatascience.com/convolutional-neural-networks-an-introduction-tensorflow-eager-api-7e99614a2879

  • 많은 사람들이 MLP로 XOR 문제를 풀기 위해 도전했지만 Marvin Minsky는 한 개의 perceptron으로는 XOR를 풀 수 없고, MLP를 써야하는데 각각의 weight과 bias를 학습시키는 데 너무 많은 계산이 필요하므로 당시 기술로는 불가능하다고 주장했습니다.

  • 그래서 많은 사람들이 이 문제를 포기하게 되고 딥러닝(=MLP, Neural networks)의 발전은 짧게는 10년, 길게는 20년 정도 후퇴하게 됩니다.

 

Backpropagation (역전파)

딥러닝의 발전을 가져온 아이디어인 역전파에 대해 알아봅시다!
  • 계속되어온 딥러닝의 침체기는 1974년에 발표된 Paul Werbos(폴)이라는 사람의 박사 논문 덕분에 끝이 나게 됩니다.
  • 폴은 다음과 같이 주장했습니다.

출처: https://developer.nvidia.com/blog/inference-next-step-gpu-accelerated-deep-learning/

  1. 우리는 W(weight)와 b(bias)를 이용해서 주어진 입력을 가지고 출력을 만들어 낼 수 있다.
  2. 그런데 MLP가 만들어낸 출력이 정답값과 다를 경우 W와 b를 조절해야한다.
  3. 그것을 조절하는 가장 좋은 방법은 출력에서 Error(오차)를 발견하여 뒤에서 앞으로 점차 조절하는 방법이 필요하다.
  • 이 알고리즘은 관심받지 못하다가 1986년에 Hinton 교수가 똑같은 방법을 독자적으로 발표하면서 알려지게 되었죠.
  • 이렇게 해서 XOR 문제는 MLP를 풀 수 있게 되어 해결될 수 있었고 그 핵심방법은 바로 역전파 알고리즘의 발견이었습니다.

출처: https://www.youtube.com/watch?v=kNPGXgzxoHw

 

 

Deep Neural Networks 구성 방법

 

Layer(층) 쌓기

앞서 나온 것처럼 딥러닝 네트워크(MLP)는 여러 층을 쌓아 구성합니다.
이번 파트에서는 보편적으로 층을 쌓는 방법을 배워봅시다!
  • 딥러닝에서 네트워크의 구조는 크게 3가지로 나누어집니다.
    • Input layer(입력층): 네트워크의 입력 부분입니다. 우리가 학습시키고 싶은 x 값입니다.
    • Output layer(출력층): 네트워크의 출력 부분입니다. 우리가 예측한 값, 즉 y 값입니다.
    • Hidden layers(은닉층): 입력층과 출력층을 제외한 중간층입니다.

출처: https://www.kdnuggets.com/2016/10/deep-learning-key-terms-explained.html

  • 풀어야하는 문제에 따라 입력층과 출력층의 모양은 정해져 있고, 따라서 우리가 신경써야할 부분은 은닉층입니다. 은닉층은 완전연결 계층 (Fully connected layer = Dense layer)으로 이루어져 있지요.
  • 기본적인 뉴럴 네트워크(Deep neural networks)에서는 보통 은닉층에 중간 부분을 넓게 만드는 경우가 많습니다. 예를 들면 보편적으로 아래와 같이 노드의 개수가 점점 늘어나다가 줄어드는 방식으로 구성합니다:
    • 입력층의 노드 개수 4개
    • 첫 번째 은닉층 노드 개수 8개
    • 두 번째 은닉층 노드 개수 16개
    • 세 번째 은닉층 노드개수 8개
    • 출력층 노드개수 3개
  • 곧 배우는 활성화 함수를 어디다가 넣어야하는지도 중요합니다. 보편적인 경우 모든 은닉층 바로 뒤에 위치합니다.

 

네트워크의 Width(너비)와 Depth(깊이)

  • 만약 우리가 수많은 시간을 투자하여 완성한 적당한 연산량을 가진, 적당한 정확도의 딥러닝 모델이 있다고 가정합시다. 그 모델은 Baseline model(베이스라인 모델)이라고 보편적으로 지칭합니다. 예를 들어 우리가 만든 베이스라인 모델의 크기는 다음과 같습니다:
    • 입력층: 4
    • 첫 번째 은닉층: 8
    • 두 번째 은닉층: 4
    • 출력층: 1
  • 우리는 이 베이스라인 모델을 가지고 여러가지 실험(튜닝)을 해볼 수 있는데요. 가장 간단하게 성능을 테스트할 수 있는 방법이 바로 모델의 너비와 깊이를 가지고 테스트하는 것입니다.

 

실무에서는 네트워크의 너비와 깊이를 바꾸면서 실험을 많이 합니다.
그만큼 시간도 많이 들고 지루한 작업입니다.
다음 파트에서 배울 과적합과 과소적합을 피하기위해서는 꼭 필요한 노가다입니다.

 

 

 

딥러닝의 주요 개념

 

Batch size, Epoch (배치 사이즈, 에폭)

 

모델을 학습시키는 데 쓰이는 '단위'

 

batch와 iteration

  • 만약 우리가 10,000,000개의 데이터셋을 가지고 있다고 가정합시다. 10,000,000개의 데이터셋을 한꺼번에 메모리에 올리고 학습시키려면 엄청난 용량을 가진 메모리가 필요하고 그 메모리를 사는데 (메모리가 없다면 개발하는데) 천문학적인 비용이 들 것입니다.
  • 따라서 우리는 이 데이터셋을 작은 단위로 쪼개서 학습을 시키는데 쪼개는 단위를 배치(Batch)라고 부릅니다. 예를 들어서 1,000만개의 데이터셋을 1,000개 씩으로 쪼개어 10,000번을 반복하는 것이죠. 이 반복하는 과정을 Iteration(이터레이션)이라고 부릅니다.

epoch

  • 보통 머신러닝에서는 똑같은 데이터셋을 가지고 반복 학습을 하게되는데요, 이 과정은 우리가 수능시험을 대비해서 모의고사 문제를 여러번 풀어보는 과정하고 비슷합니다. 만약 100번 반복 학습을 한다면 100 epochs(에폭)을 반복한다고 말해요.
  • batch를 몇 개로 나눠놓았냐에 상관 없이 전체 데이터셋을 한 번 돌 때 한 epoch이 끝납니다.

 

따라서 1천만개의 데이터셋을 1천개 단위의 배치로 쪼개면, 1만개의 배치가 되고, 이 1만개의 배치를 100에폭을 돈다고 하면 1만 * 100 = 100만번의 이터레이션을 도는 것이 됩니다!

출처: https://www.mauriciopoppe.com/notes/computer-science/artificial-intelligence/machine-learning/glossary/

 

 

Activation functions (활성화 함수)

  • 우리가 앞서 배운 MLP의 연결 구조를 여러개의 뉴런이 연결된 모습과 비슷하다고 가정하고 생각해봅시다!

  • 수많은 뉴런들은 서로 서로 빠짐없이 연결되어 있습니다. 그런데 뉴런들은 전기 신호의 크기가 특정 임계치(Threshold)를 넘어야만 다음 뉴런으로 신호를 전달하도록 설계되어 있습니다. 연구자들은 뉴런의 신호전달 체계를 흉내내는 함수를 수학적으로 만들었는데, 전기 신호의 임계치를 넘어야 다음 뉴런이 활성화 한다고해서 활성화 함수라고 부릅니다.
  • 활성화 함수는 비선형 함수여야 합니다. 위에서 딥러닝은 비선형 함수를 사용한다고 했었죠? 비선형 함수의 대표적인 예가 바로 시그모이드 함수입니다. 따라서 비선형 함수 자리에 시그모이드를 넣으면 이렇게 되겠네요.

  • 이런 비선형의 활성화 함수를 사용하여 다음 뉴런을 활성화 시킬지를 결정할 수 있어요. 다시 한번 시그모이드 함수를 볼까요.

  • 시그모이드 함수는 x가 -6보다 작을 때는 0에 가까운 값을 출력으로 내보내서 비활성 상태를 만듭니다. 반대로 x가 6보다 클때는 1에 가까운 값을 출력으로 내보내서 활성 상태로 만들죠.
  • 이런 활성화 함수는 여러가지 종류가 있는데요. 그래프로 보면 아래와 같습니다.

Reference https://medium.com/@shrutijadon10104776/survey-on-activation-functions-for-deep-learning-9689331ba092

  • 딥러닝에서 가장 많이 보편적으로 쓰이는 활성화함수는 단연 ReLU(렐루) 입니다. 왜냐하면 다른 활성화 함수에 비해 학습이 빠르고, 연산 비용이 적고, 구현이 간단하기 때문입니다.
대부분 딥러닝 모델을 설계할 때는 ReLU를 기본적으로 많이 쓰고,
여러 활성화 함수를 교체하는 노가다를 거쳐 최종적으로 정확도를 높이는 작업을 동반합니다.
이러한 노가다의 과정을 모델 튜닝이라고 부릅니다.

 

 

Overfitting, Underfitting (과적합, 과소적합)

 

  • 딥러닝 모델을 설계/튜징하고 학습시키다 보면 가끔씩 Training loss는 점점 낮아지는데 Validation loss가 높아지는 시점이 있습니다. 그래프로 표시하면 아래와 같은 현상이죠.

출처: https://vitalflux.com/overfitting-underfitting-concepts-interview-questions/

  • 이런 현상을 과적합 현상이라고 합니다. 우리가 풀어야하는 문제의 난이도에 비해 모델의 복잡도(Complexity)가 클 경우 가장 많이 발생하는 현상이죠. 시험에 빗대어 얘기하면 모의고사의 정답 번호를 달달외워서 모의고사는 100점을 받는데, 실제로 수능시험을 보면 틀리는 문제가 더 많아지는 현상과 비슷합니다.
  • 반대로 우리가 풀어야하는 문제의 난이도에 비해 모델의 복잡도가 낮을 경우 문제를 제대로 풀지 못하는 현상을 과소적합이라고 합니다.
  • 따라서 우리는 적당한 복잡도를 가진 모델을 찾아야 하고 수십번의 튜닝 과정을 거쳐 최적합(Best fit)의 모델을 찾아야합니다.
딥러닝 모델을 학습시키다보면 보통 과소적합보다는 과적합때문에 골치를 썩는 경우가 많습니다.
과적합을 해결하는 방법에는 여러가지 방법이 있지만
대표적인 방법으로는 데이터를 더 모으기, Data augmenation, Dropout 등이 있습니다.

 

 

 

딥러닝의 주요 스킬

 

Data augmentation (데이터 증강기법)

 

과적합을 해결할 가장 좋은 방법은 데이터의 개수를 늘리는 방법입니다. 하지만 실무에서는 데이터가 넘쳐나기는 커녕 부족한 경우가 매우 많습니다. 부족한 데이터를 보충하기위해 우리는 데이터 증강기법이란느 꼼수아닌 꼼수를 사용합니다. 데이터 증강기법은 이미지 처리 분야의 딥러닝에서 주로 사용하는 기법입니다. 데이터 증강기법은 아래 한 장의 이미지로 설명이 가능합니다.

출처: https://www.mygreatlearning.com/blog/understanding-data-augmentation/

원본 이미지 한 장을 여러가지 방법으로 복사를 합니다. 사람의 눈으로 보았을 때 위의 어떤 사진을 보아도 사자인 것처럼 딥러닝 모델도 똑같이 보도록 학습시킵니다. 이 방법을 통해 더욱 강건한 딥러닝 모델을 만들 수 있죠.

데이터 증강기법은 반드시 정해진 방법들을 사용해야 하는 것이 아닙니다.
데이터가 부족할 때 이미 있는 데이터 사용하여 증강시키는 개념으로
여러분들의 방법을 사용해서 증강 방법을 새로 만들어 낼 수 있습니다.

 

Dropout (드랍아웃)

 

과적합을 해결할 수 있는 가장 간단한 방법으로는 Dropout이 있습니다. Dropout은 단어에서도 의미를 유추할 수 있듯이 각 노드들이 이어진 선을 빼서 없애버린다는 의미가 있습니다.

출처: https://www.researchgate.net/figure/Dropout-Strategy-a-A-standard-neural-network-b-Applying-dropout-to-the-neural_fig3_340700034

오른쪽 그림처럼 각 노드의 연결을 끊어버리는 작업을 하는데, 각 배치마다 랜덤한 노드를 끊어버립니다. 즉 다음 노드로 전달할 때 랜덤하게 출력을 0으로 만들어버리는 것과 같습니다.

"사공이 많으면 배가 산으로 간다"라는 속담처럼 과적합이 발생했을 때 적당한 노드들을 탈락시켜서 더 좋은 효과를 낼 수 있습니다.

출처: https://www.youtube.com/watch?v=_JB0AO7QxSA

위와 같이 전문가들이 너무 많다고 가정합시다. 귀만 판단하는 전문가, 꼬리만 판단하는 전문가 등등 너무 많은 전문가(노드)들이 있다면, 이들 중 일부만 사용해도 충분히 결과를 낼 수 있습니다. 오히려 이들 중에서 충분할 만큼의 전문가만 선출해서 반복적으로 결과를 낸다면, 오히려 균형 잡힌 훌륭한 결과가 나올 가능성이 높죠.

Dropout은 과적합 발생시 생각보다 좋은 효과를 냅니다. (그리고 사용하기도 정말 간단하죠)
실무에서 과적합이 발생한다면 꼭 한 번 사용해보세요!

 

 

Ensemble (앙상블)

 

앙상블 기법은 컴퓨팅 파워만 충분하다면 가장 시도해보기 쉬운 방법입니다. 여러개의 딥러닝 모델을 만들어 각각 학습시킨 후 각각의 모델에서 나온 출력을 기반으로 투표를 하는 방법이죠. 앞에서 설명했던 랜덤 포레스트의 기법과 비슷합니다.

출처: https://towardsdatascience.com/neural-networks-ensemble-33f33bea7df3

앙상블 또한 개념적으로 이해하는 것이 중요한데 여러개의 모델에서 나온 출력에서 다수결로 투표(Majority voting)를 하는 방법도 있고, 평균값을 구하는 방법도 있고, 마지막에 결정하는 레이어를 붙이는 경우 등 다양한 방법으로 응용이 가능합니다.

앙상블을 사용할 경우 최소 2% 이상의 성능 향상 효과를 볼 수 있다고 알려져 있습니다.

 

 

Learning rate decay (Learning rate schedules)

 

Learning rate decay 기법은 실무에서도 자주 쓰는 기법으로 Local minimum에 빠르게 도달하고 싶을 때 사용합니다.

출처: https://www.deeplearningwizard.com/deep_learning/boosting_models_pytorch/lr_scheduling/

위 사진에서보면 왼쪽 그림은 학습의 앞부분에서는 큰 폭으로 건너뛰고 뒷부분으로 갈 수록 점점 조금씩 움직여서 효율적으로 Local minimum을 찾는 모습입니다. 오른쪽 그림은 Learning rate를 고정시켰을 때의 모습이지요.

또한 Learning rate decay 기법을 사용하면 Local minimum을 효과적으로 찾도록 도와줍니다. 아래 그림을 보면 Learning rate가 줄어들때마다 Error 값이 한 번씩 큰 폭으로 떨어지는 현상을 보입니다. 이렇게 하면 Local minimum을 찾기 쉽겠죠?!

출처: https://neurohive.io/en/popular-networks/resnet/

Keras에서는 tf.keras.callbacks.LearningRateScheduler() 와
tf.keras.callbacks.ReduceLROnPlateau() 를 사용하여 학습중 Learning rate를 조절합니다.
https://keras.io/api/callbacks/learning_rate_scheduler/
https://keras.io/api/callbacks/reduce_lr_on_plateau

 

 

 

XOR 실습

 

필요한 패키지 임포트하기

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam, SGD

XOR 데이터셋 만들기

x_data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.float32)
y_data = np.array([[0], [1], [1], [0]], dtype=np.float32)

이진논리회귀로 풀어보기

model = Sequential([
  Dense(1, activation='sigmoid')
])

model.compile(loss='binary_crossentropy', optimizer=SGD(lr=0.1))

model.fit(x_data, y_data, epochs=1000, verbose=0)

y_pred = model.predict(x_data)

딥러닝(MLP)로 풀어보기

model = Sequential([
  Dense(8, activation='relu'),
  Dense(1, activation='sigmoid'),
])

model.compile(loss='binary_crossentropy', optimizer=SGD(lr=0.1))

model.fit(x_data, y_data, epochs=1000, verbose=0)

y_pred = model.predict(x_data)

Keras Functional API 써보기

import numpy as np
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, Input
from tensorflow.keras.optimizers import Adam, SGD
input = Input(shape=(2,))
hidden = Dense(8, activation='relu')(input)
output = Dense(1, activation='sigmoid')(hidden)

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

model.compile(loss='binary_crossentropy', optimizer=SGD(lr=0.1))

model.summary()
model.fit(x_data, y_data, epochs=1000, verbose=0)

y_pred = model.predict(x_data)

 

 

 

딥러닝 실습

 

  • 데이터셋 다운로드
  • 필요한 패키지 임포트하기
  • 데이터셋 로드하기
  • 라벨 분포 확인하기
  • 전처리하기
    • 입력과 출력 나누기
    • 데이터 미리보기
    • one-hot 인코딩하기
    • 일반화하기
  • 네트워크 구성하기   *딥러닝에서 추가되는 부분
input = Input(shape=(784,))
hidden = Dense(1024, activation='relu')(input)
hidden = Dense(512, activation='relu')(hidden)
hidden = Dense(256, activation='relu')(hidden)
output = Dense(24, activation='softmax')(hidden)

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

model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.001), metrics=['acc'])
  • 모델 학습시키기