본문 바로가기

Deep Learning

[Deep Learning] 220809 학습일기

 

밑바닥부터 시작하는 딥러닝 - YES24

직접 구현하고 움직여보며 익히는 가장 쉬운 딥러닝 입문서 이 책은 라이브러리나 프레임워크에 의존하지 않고, 딥러닝의 핵심을 ‘밑바닥부터’ 직접 만들어보며 즐겁게 배울 수 있는 본격 딥

www.yes24.com

 

1.

기계학습 문제는 분류와 회귀로 나뉜다.

 

  • 분류: 데이터가 어느 class에 속하느냐는 문제

     ex) 인물의 성별을 분류하는 문제

 

  • 회귀: 입력 데이터에서 (연속적인) 수치를 예측하는 문제

    ex) 사진 속 인물의 몸무게를 예측하는 문제

 

 

 

2.

소프트 맥스 함수는 다음과 같다.

 

import numpy as np
a = np.array([0.3,2.9,4.0])
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y= exp_a/sum_exp_a

print(exp_a)
print(sum_exp_a)
print(y)

<출력층>

[ 1.34985881 18.17414537 54.59815003]
74.1221542101633
[0.01821127 0.24519181 0.73659691]

 

 

소프트맥스 함수를 파이썬 함수로 정리하면

import numpy as np
def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a/ sum_exp_a

    return y

a = np.array([0.3,2.9,4.0])
print(softmax(a))

<출력층>

[0.01821127 0.24519181 0.73659691]

 

 

 

3.

소프트맥스 함수에 숫자가 큰 원소들이 포함된 배열을 집어넣어보자.

import numpy as np
a = np.array([1010,1000,990])
print(np.exp(a)/np.sum(np.exp(a)))

그러면 출력값이 아래와 같이 나온다.

RuntimeWarning: overflow encountered in exp
  print(np.exp(a)/np.sum(np.exp(a)))
c:\Users\tina0\Desktop\python 실습들\Deep Learning-밑시딥\3.5 출력층 설계하기.py:30: RuntimeWarning: invalid value encountered in true_divide
  print(np.exp(a)/np.sum(np.exp(a)))
[nan nan nan]

nan은 not a number의 약자이다.

숫자가 너무 크다는 것이다.

자연상수 e의 10제곱만 해도 20,000이 넘고, e의 100승은 0이 40개가 넘는 큰 값이다.

근데 여기 배열에 넣은 것과 같이 e의 1000 제곱을 파이썬에서 계산하면 무한대를 뜻하는 inf가 되어 돌아온다.

이런 큰 값끼리 나눗셈을 하면 결과 수치가 불안정해진다.

 

컴퓨터는 수(number)를 4byte나 8byte 같이 크기가 유한한 데이터로 다룬다. 다시 말해 표현할 수 있는 수의 범위가 한정되어 너무 큰 값은 표현할 수 없다. 이것을 Overflow라고 한다. Overflow는 컴퓨터로 수치를 계산할 때 주의해야 한다.

Stack Overflow라는 사이트에서 overflow라는 말을 접한 적이 있다. 이 말이 이런 뜻이었구만..

 

이 문제를 해결하려면 소프트 맥스 함수 구현을 개선해야한다. 이때 수학이 사용된다.

위의 식의 변형을 통해 알 수 있는 것은

소프트 맥스 함수의 지수함수를 계산할 때 어떤 정수를 더하거나 빼도 결과는 바뀌지 않는다는 것이다.

여기서 C'에는 오버플로를 막을 목적으로 입력 신호 중 최댓값을 이용하는 것이 일반적이다.

저렇게 변형할 생각을 한 것이 참 대단한 것 같다.

 

C'에 입력 신호중 최댓값을 이용하여 원래 배열에서 빼면

import numpy as np
a = np.array([1010,1000,990])
c = np.max(a)
print(np.exp(a-c)/np.sum(np.exp(a-c)))

<출력값>

[9.99954600e-01 4.53978686e-05 2.06106005e-09]

이렇게 잘 출력이 되는 것을 볼 수 있다.

 

 

그리고 개선된 식을 바탕으로 소프트맥스 함수를 다시 구현하면

import numpy as np
def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a-c)
    sum_exp_a = np.sum(exp_a)
    y= exp_a/sum_exp_a
    
    return y

a = np.array([0.3,2.9,4.0])
y = softmax(a)

print(y)
print(np.sum(y))

<출력값>

[0.01821127 0.24519181 0.73659691]
1.0

소프트 맥스 함수의 출력은 0부터 1.0까지의 실수이다.

 

 

그리고 소프트맥스 함수의 출력의 총합은 1이다.

why?

소프트 맥스 함수는 위와 같이 생겼다.

여기서 n은 출력층의 뉴런 수이고, yk는 그 중 k번째 출력을 의미하므로 k는 1이상 n이하의 자연수이다.

따라서 소프트맥스 함수의 출력을 모두 더하면

이렇게 된다.

따라서 소프트맥스 함수의 출력의 총합은 1이다.

출력 총합이 1이 된다는 점은 소프트맥스 함수의 중요한 성질이다.

이 성질 덕분에 소프트맥스 함수의 출력을 '확률'로 해석할 수 있다.

 

 

아까

import numpy as np
def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a-c)
    sum_exp_a = np.sum(exp_a)
    y= exp_a/sum_exp_a
    
    return y

a = np.array([0.3,2.9,4.0])
y = softmax(a)

print(y)
print(np.sum(y))

<출력값>

[0.01821127 0.24519181 0.73659691]
1.0

여기에서도

y[0]의 확률은 0.018(1.8%), y[1]의 확률은 0.245(24.5%), y[2]의 확률은 0.737(73.7%)로 해석할 수 있다.

이 결과 확률들로부터 "2번째 원소의 확률이 가장 높으니, 답은 2번째 클래스다"라고 할 수 있다.

혹은 "74%의 확률로 2번째 클래스, 25%의 확률로 1번째 클래스, 1%의 확률로 0번째 클래스다"와 같이 확률적인 결론도 낼 수 있다. 

즉, 소프트맥스 함수를 이용함으로써 문제를 확률적(통계적)으로 대응할 수 있다.

 

소프트맥스 함수를 적용해도 각 원소의 대소 관계는 변하지 않는다.

당연하다. 모든 원소에 동일한 sum_exp(a)가 나눠지고, exp 함수는 단조증가 함수이기 때문이다.

 

신경망을 이용한 분류에서는 일반적으로 가장 큰 출력을 내는 뉴런에 해당하는 클래스로만 인식한다. 그리고 소프트맥스 함수를 적용해도 출력이 가장 큰 뉴런의 위치는 변하지 않기에 신경망으로 분류할 때는 출력층의 소프트맥스 함수를 생략해도 된다. 현업에서도 지수 함수 계산에 드는 자원 낭비를 줄이고자 출력층의 소프트맥스 함수는 생략한다고 한다.

 

 

 4.

기계학습의 문제 풀이는 학습추론의 단계를 거친다.

학습 단계에서 모델을 학습하고,

추론 단계에서는 학습한 모델을 바탕으로 미지의 데이터에 대한 추론을 한다.

 

신경망을 학습시킬 때는 출력층에서 소프트맥스 함수를 사용한다.

그러나 위에서도 말했듯 추론 단계에서는 소프트맥스 함수를 생략하는 것이 일반적이다.

 

 

 

 

'Deep Learning' 카테고리의 다른 글

[Deep Learning] 220810 학습일기  (0) 2022.08.10
[Deep Learning] 220808 학습일기  (0) 2022.08.08
[Deep Learning] 220806 학습일기  (0) 2022.08.08
[Deep Learning] 220805 학습일기  (0) 2022.08.05
[Deep Learning] 220803 학습일기  (0) 2022.08.03