본문 바로가기

파이썬 & 머신러닝과 딥러닝

16일차 - 딥러닝의 역사, 퍼셉트론, 다층 퍼셉트론, 역전파 알고리즘 상세, 활성화 함수 및 원리

https://bit.ly/20240201_YU_AI

 

(복습)

 

딥러닝을 “잘” 이해하려면 딥러닝의 가장 말단에서 이루어지는 기본적인 두 가지 계산원리를 알아야함

• 선형 회귀 & 로지스틱 회귀 (시그노이드)

 

선형 회귀 (Linear Regression)란?

•   ‘x값이 변하면 y값도 변한다‘라는 정의에서 

  • 독립 변수: 독립적으로 변할 수 있는 값, 즉 x 
  • 종속변수: 독립 변수에 따라 종속적으로 변하는 값, 즉 y 

 

•  선형 회귀: 독립변수 x를 사용하여 종속 변수 y의 움직임을 예측하고 설명하는 작업을 의미

 

•  직선의 방정식: f(x) = mx+b 

-> 선형 회귀는 입력 데이터를 가장 잘 설명하는 기울기(m)와 절편 값(b) 을 찾는 문제이다 

 

• 선형 회귀의 기본식: f(x) = Wx+b

  • 기울기 -> 가중치
  • 절편 -> 바이어스

-> 문제를 설명할 수 있는 적합한 weight와 바이어스 찾는 것이 목적

 

 

Loss Function (손실 함수)

•  직선과 데이터 사이의 간격을 제곱하여 합한 값을 손실 함수(loss function)

또는 비용 함수(cost function)라고 한다.

•  평균 제곱 오차 (Mean Squared Error, MSE)

 

손실 함수 최소화 방법 : 경사 하강법(gradient descent method)

-> 기울기가 0이 되는 부분 찾기

 

 

학습률 (Learning Rate)

•  어느 만큼 이동시킬지를 결정

•  학습률의 값을 적절히 바꾸면서 최적의 학습률을 찾는 것은 매우 중요한 최적화 과정 중 하나임

 

 

단순 선형 회귀 vs 다중 선형 회귀

▶ 단순 선형 회귀 (simple linear regression)

• 하나의 x값 만으로도 y값을 설명할 수 있을 때

• 즉, 학습에 사용하는 특성이 하나일때

 

▶  다중 선형 회귀 (Multiple linear regression)

• X값이 여러 개 필요할 때

• 즉, 학습에 사용하는 특성이 여러개일때

 

 

로지스틱 회귀

•  직선으로 해결하기에는 적절하지 않은 경우도 있음

•  예: 점수가 아니라 오직 합격과 불합격만 발표되는 시험

•  점들의 특성을 정확하게 담아내려면 직선이 아닌 S자 형태를 사용해야함

•  로지스틱 회귀는 선형 회귀와 마찬가지로 적절한 선을 그려가는 과정 

•  단, 직선이 아니라 참(1)과 거짓(0) 사이를 구분하는 S자 형태의 선을 그 려주는 작업

 

 

시그모이드 (Sigmoid) 함수

S자 형태로 그래프가 그려지는 함수

 

빙어 예제

𝑧 = 𝑎 × 무게 + 𝑏 × 길이 + 𝑐 × 대각선 + 𝑑 × 높이 + 𝑒 × 두께 + f

 

 

확률적 경사하강법 (Stochastic Gradient Descent: SGD)

•  확률적 경사 하강법 : 하나의 샘플이 주어지면 오차를 계산하여서 바로 가중치를 변경하는 방법이다.

•  배치 학습(batch learning): 모든 샘플을 모두 보여준 후에 개별 샘플의 그래디언트를 전부 더해서 이것을 바탕으로 모델의 가중치를 변경하는 방법이다.

  온라인 학습과 배치 학습의 중간에 있는 방법이 미니 배치(mini batch) 이다.

  이 방법에서는 훈련 데이터를 작은 배치들로 분리시켜서 하나의 배치가 끝날 때마다 학습을 수행하는 방법이다.

  1 < size(미니 배치) < size(훈련 데이터)

  에포크 : 데이터의 배치사이즈와 데이터 셋과 관계가 있음

 


 

인공 신경망

신호를 받아 누적해서 임계치를 넘어가면 신호를 보내는 뉴런 네트워크가 연결되어 있다.

 

퍼셉트론 (perceptron)

•  퍼셉트론(perceptron)은 1957년에 로젠블라트(Frank Rosenblatt)가 고안한 인공 신경망이다.

•  뉴런에서는 입력 신호의 가중치 합이 어떤 임계값 이상인 경우에만

뉴런이 활성화되어서 1을 출력한다. 그렇지 않으면 0을 출력한다.

(출력이 또 다른 뉴런의 입력으로 전달하여 사슬처럼 연결,

입력은 증폭때문에 값이 곱해져서(weight) 들어옴)

 

-> 얼마만큼 증폭 시키고 값을 곱하고 뺄 지 weight를 정하는 것이 목적

 

w : weight

b : bias


 

로지스틱 회귀에서 퍼셉트론으로 

입력 값을 통해 출력 값을 구하는 함수는 다음과 같이 정의될 수 있음

 

입력 값 : 우리가 가진 값 x1 x2

y를 구하려면 a1, a2, b (weight)가 필요함 

 

-> 1, 0으로 판단할 수 있는 weight를 찾는 것이 목적


 

퍼셉트론은 논리 연산을 학습할 수 있을까?

논리 연산자 AND 학습 과정

 

 

→  학습이라고 부르려면 신경망이 스스로 가중치를 자동으로 설정해주는 알고리즘이 필요

→  퍼셉트론에서도 학습 알고리즘이 존재

 

출력이 잘못 나오면 입력이 1인 연결선의 가중치를 출력 오차에 비례하여 변경

새로운 가중치 = 기존 가중치 + 학습률 x 출력 오차

 

예) 두개의 입력과 bias에 대한 초기 가중치가 0, 0, 0이인 상황에서

x1, x2에 0과 0이 입력되고 bias는 항상 1이 입력된다고 가정했을 때, y는 1이 됨

따라서 가중치 업데이트 수행 됨 (입력이 1인 것은 bias만 있으므로 bias에 대한 가중치가 업데이트!)

출력 오차 = 0 – 1 (0이 나와야 하는데 1이 나왔으므로)

 

  0이 나와야하는데 1이 나왔으니 가중치가 작아져야해서 -0.1을 곱해야함

바이어스 가중치가 -0.1로 바껴야함

 

따라서, 새로운 bias의 가중치 = 기존 bias 가중치 + 학습률 * (0-1) = 0 + 0.1 *(-1) = -0.1

 

 

-> 학습률이 크면 값이 자주 바뀜

결국 반복을 통해 weight를 찾아내는 것이다.


 

퍼셉트론 구현 실습

 

# 학습데이터 셋
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 0, 0, 1]

# 가중치와 바이어스 초기값
weights = [0.0, 0.0]
bias = 0.0

l_rate = 0.1 # 학습률
n_epoch = 5 # 에포크 횟수
weights = train_weights(X, y, l_rate, n_epoch)

print("\n\n 학습완료")
print(weights, bias)


# 학습 알고리즘
def train_weights(X, y, l_rate, n_epoch):
  global weights
  global bias

  for epoch in range(n_epoch):
    sum_error = 0.0
    for row, target in zip(X, y):
      actual = calculate(row)
      error = target - actual
      bias = bias + l_rate * error
      sum_error += error ** 2

      for i in range(2):
        weights[i] = weights[i] + l_rate * error * row[i]
      print(weights, bias)

    print("에포크 번호 = %d, 학습률 = %.3f, 오류 = %.3f" % (epoch, l_rate, sum_error))
  return weights

 # 뉴론의 출력 계산 함수
def calculate(input):
  global weights
  global bias
  activation = bias # 바이어스
  for i in range(2): # 입력신호 총합 계산
    activation += weights[i] * input[i]
  if activation >= 0.0: # 스텝 활성화 함수
    return 1.0
  else:
    return 0.0

 

 

-> global weights, global bias : 전역함수
 -> calculate의 결과값을 actual로 뽑아냄
-> target값은 0001이 들어있고 결론은 손실 함수
-> 현재까지 구해진 weights * input으로 누적합 구해서 activation에 누적

activation에 누적된 결과값이 0보다 크다면 1을 리턴 아니면 0을 리턴

-> actual :현재 weight가 적용된 실제값

 


 

sklearn으로 퍼셉트론 실습 (AND)

from sklearn.linear_model import Perceptron

# 학습 데이터 셋
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 0, 0, 1] # AND

# 퍼셉트론을 생성 tol은 종료 조건
clf = Perceptron(tol = 1e-3, random_state = 0)

# 학습 수행
clf.fit(X, y)

# 테스트 수행
print(clf.predict(X))

 

 

-> tol=1e-3 : 얼마만큼 오차를 허용할 지

 


XOR도 잘 될까?

from sklearn.linear_model import Perceptron

# 학습 데이터 셋
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 1, 1, 0] # XOR

# 퍼셉트론을 생성 tol은 종료 조건
clf = Perceptron(tol = 1e-3, random_state = 0)

# 학습 수행
clf.fit(X, y)

# 테스트 수행
print(clf.predict(X))

-> [0, 1, 1, 0] 이 안나온 모습

퍼셉트론은 XOR을 학습할 수 없다.


XOR 학습 문제

에포크 횟수를 100으로 수동으로 지정하기

매 에포크마다 결과 확인 가능

 

# XOR 연산 학습 데이터셋
X = [[0,0], [0,1], [1,0], [1,1]]
y = [0, 1, 1, 0]

weights = [0.0, 0.0]
bias = 0.0

l_rate = 0.1 # 학습률
n_epoch = 100 # 에포크 횟수
weights = train_weights(X, y, l_rate, n_epoch)
print(weights, bias)

 

 

-> 100번 돌려도 아직 오류가 나오는 모습

 

AND 연산은 0001


 

선형 분류 가능 문제

 

패턴 인식 측면에서 보면 퍼셉트론은 직선을 이용하여

입력 패턴을 분류 하는 선형 분류자(linear classifier)의 일종이라고 말할 수 있다.

 

 

 


 

AI의 빙하기

 

Minsky와 Papert는 1969년에 발간된 책 “Perceptrons”에서

1개의 레이어(layer, 계층)으로 구성된 퍼셉트론은

XOR 문제를 학습할 수 없다는 것을 수학적으로 논리적으로 증명

-> 싱글 레이어 퍼셉트론은 힘들지만 다층 퍼셉트론(multilayer perceptron: MLP) 으론 가능하지만

할 수 있는 사람은 없을거라 말함

 

 


 

MLP

 

다층 퍼셉트론(multilayer perceptron: MLP)

: 입력층과 출력층 사이에 은닉층(hidden layer)을 가지고 있는 신경망

 


 

신경망의 부흥

 

1980년대 중반에 Rumelhart와 Hinton 등은 다층 퍼셉트론을 위한 학습 알고리즘을 재발견하심


 

역전파 학습 알고리즘

 

-> 역전파 알고리즘은 입력이 주어지면 순방향으로 계산하여 출력을 계산 한 후에

실제 출력과 우리가 원하는 출력 간의 오차를 계산한다. 

-> 이 오차를 역방향으로 전파하면서 오차를 줄이는 방향으로 가중치를 변경한다.

(역으로 미분해가면서 찾아가는 방식)

 


 

제 2의 빙하기

 

 

-> 시그모이드를 미분해서 나온 결과값을 역으로 곱해나가는 과정

입력쪽으로 갈수록 결국 값이 작아질 수 밖에 없다.

-> weight가 유지되어 효과가 사라진다.

 


 

Breakthrough

 

-> 현재까지도 렐루 함수 많이 사용

 


 

인공신경망 구현을 위한 라이브러리

다양한 라이브러리와 사전학습된 알고리즘들을 포함

Keras 프레임워크 사용하여 실습

 

Keras 라이브러리

  Tensorflow 위에 구현된 Python 기반의 라이브러리

• 배우기 쉽고 확장 가능

• 성능이 떨어지고, 대규모 프로젝트에는 미흡

 


 

로지스틱 회귀로 이미지 분류 실습

 

패션 MNIST 데이터 셋  

MNIST : Modified NIST 에서 배포한 이미지셋

 

 

데이터 확인

 

-> train_target에는 정답값 출력 → 정수값으로 출력되는 모습


 

로지스틱 회귀로 아이템 분류 (with SGD)

 

 

-> 255로 나누는 이유 : 0~1 사이 값으로 정규화

-> reshape(-1, 28*28) : SGDClassifier는 샘플 기준 2차원 입력을 다루지 못해 각 샘플을 1차원으로 변경

-> loss = 'log' : 로지스틱 회귀

-> max_iter = 5 : 에포크 수

 

 

패션 MNIST에 적용

z_티셔츠 = (w1 x 픽셀1) + (w2 x 픽셀2) + … + (w784 x 픽셀784) + b

z_바지 = (w1’ x 픽셀1) + (w2’ x 픽셀2) + … + (w784’ x 픽셀784) + b

 

 

-> 우리는 방금 “가장 기본적인“ 인공신경망을 만들어 보았음


 

인공신경망으로 모델 만들기 with keras 실습

 

데이터 준비


 

레이어 만들기

 

-> 10개의 뉴런으로 이뤄진 하나의 레이어가 만들어짐

 

Dense( 뉴런의 개수 10, activation = 'softmax', input_shape (입력의 크기))

-> input_shape (입력의 크기) : 레이어로 들어오는 특성의 개수

 

출력으로 나갈 땐 softmax를 거쳐 다중분류로 나간다.

(다중분류라 softmax 사용, 이진분류면 sigmoid)

 

첫번째 이미지를 펼친 배열 -> 입력층 (data input, 784개 뉴런) -> 출력층 (10개 뉴런)

-> 1: n (밀집층, fully connected layer)

 

-> 우리가 만든 신경망 모델 객체 model

-> Sequential : 차곡차곡 레이어를 쌓는다 (신경망 모델 객체 만들기)


 

모델 설정

 

-> 컴파일에서는 손실 함수를 지정

 

-> sparse_categorical_crossentropy : 손실함수

 

-> 손실함수가 이진분류냐 다중분류냐에 따라 사용하는 함수가 바뀜

  • 이진분류 -> loss: “binary_crossentropy”
  • 다중분류 -> loss: “(sparse_)categorical_crossentropy”

-> metrics = 'accuracy': loss가 기본적으로 출력되는데 accuracy(정확도)도 같이 출력하는 옵션


 

학습하기

 


 

검증 데이터로 평가

 

-> 원하는 데이터를 넣어서 평가 점수 보기

-> 처음보는 데이터에 대한 loss률과 accurancy 확인 가능

 


구글의 플레이 그라운드

 

 

 

 

 


사진 출처 : 혼자 공부하는 머신러닝 + 딥러닝 강의자료