[딥러닝]2. 딥러닝 원리

1. 선형회귀(linear regression)

= 가장 훌륭한 예측선 긋기

1) 선형회귀의 정의

  • 독립변수 x를 사용해 종속변수 y의 움직임을 예측하고 설명하는 작업
    • 독립변수 : 독립적으로 변할 수 있는 값
    • 종속변수 : 독립변수에 의해 종속적으로 변하는 값
  • 종류
    1️⃣ 단순선형회귀(simple linear regression) : 독립변수 1개
    2️⃣ 다중선형회귀(multiple linear regression) : 독립변수 여러개

1-1. 가장 훌륭한 예측선

  • 직선의 기울기와 y 절편값을 정확하게 예측 ➡️ 최적의 a, b값 찾아내기
    • ex) y = ax 구하기
      X = { 2, 4, 6, 8 }
      Y = { 81, 93, 91, 97 }

1-2. 최소 제곱법(method of least squares)

  • 각 점의 좌표값과 함수값의 오차의 제곱의 합이 최소가 되는 경우의 선
    1️⃣ 기울기 a 구하기

    - 편차 : 각 값과 평균과의 차이
    - 즉, a = (x,y 편차의 곱의 합) / (x 편차 제곱의 합)

    • x 평균: (2 + 4 + 6 + 8) ÷ 4 = 5
    • y 평균: (81+ 93 + 91 + 97) ÷ 4 = 90.5

    ➡️ a = 2.3

2️⃣ y절편 b 구하기

  • 즉, y 평균에서 x평균에 기울기를 곱한 값을 빼면 됨
    ➡️ b = 90.5-(2.3 x 5) = 79

➡️ y = 2.3x + 79

1. 단순 반복문 이용

import numpy as np

x = [2,4,6,8]
y = [81, 93, 91, 97]

mx = np.mean(x)
my = np.mean(y)

divisor = sum([(i - mx)**2 for i in x])
# 분모

def top(x, mx, y, my):
    d = 0
    for i in range(len(x)):
        d += (x[i] - mx)*(y[i] - my)
    return d
    
dividend = top(x, mx, y, my)
# 분자

a = dividend/divsor
b = my - (mx * a)

print("분모:", divisor)
print("분자:", dividend)

print("기울기 a =", a)
print("y 절편 b =", b)
  • divisor = (x[0] - mx)^2 + ... + (x[3] - mx)^2
  • dividend = (x[0] - mx)(y[0]-my) + ... + (x[3] - mx)(y[3]-my)

2. ✅넘파이 배열 이용 시

x = np.array(x)
y = np.array(y)

divisor = ((x - x.mean()) ** 2).sum()
dividend = ((x - x.mean()) * (y - y.mean())).sum()

a = dividend/divisor
b = y.mean() - x.mean()*a

print("분모:", divisor)
print("분자:", dividend)

print("기울기 a =", a)
print("y 절편 b =", b)

y_pred = a*x + b
print("예측값 : ", y_pred)

import matplotlib.pyplot as plt
plt.rc('font', family='AppleGothic')
plt.scatter(x, y, label='실제값')
plt.scatter(x, y_pred, label='예측값')
plt.plot(x, y_pred, c='y')
plt.legend()
plt.show()

2) 평균 제곱 오차 (mean square error, MSE)

  • 1️⃣ 최소 제곱 오차 : 입력이 하나일 때 가장 훌륭한 예측선 찾기
  • 2️⃣ 평균 제곱 오차 : 입력이 여러 개일 때 가장 훌륭한 예측선을 찾아내기 위한 오차 평가 알고리즘
    • ✔️ 오차 = 실제값 - 예측값
    • 오차 합 = 각 오차값을 제곱하여 부호를 없앰
      • i : x가 나오는 순서
      • n : x의 총개수
      • x에 대응하는 실제 값에서 예측값을 빼줌
      • 여기서 평균값으로 나눠주면 평균제곱 오차임
  • ❗️선형 회귀 : 임의의 직선을 그어 평균 제곱 오차를 구하고 이 값을 최소화해주는 a, b값을 찾아감

2-1. 잘못 그은 선 바로잡기

  • 원리 : 임의의 직선을 그은 후 실측값과의 오차 구한 뒤(평균제곱오차법) 이전 임의의 직선과 비교하여 차츰 개선해 나감
    ex) 1️⃣ 임의의 직선 : y = 3x + 76

    2️⃣ 기울기를 너무 크게 잡았을 경우

    3️⃣ 기울기를 너무 작게 잡은 경우

1. 반복문 이용

fake = [3, 76] # 임의의 기울기와 y절편값
data = [[2, 81], [4, 93], [6, 91], [8, 97]]
x = [i[0] for i in data]
y = [i[1] for i in data]

def predict(x): # y = ax + b
    return x*fake[0] + fake[1]

def mse(y_hat, y): #mse 함수
    return ((y_hat-y)**2).mean()
    
def mse_val(predict_result, y):#예측값과 실제값을 mse 함수에 대입
    return mse(np.array(predict_result), np.array(y))

pr= []

for i in range(len(x)):#모든 값에 대하여
    pr.append(predict(x[i])) #결과값에 실제 데이터에 대한 예측값 삽입
    print("공부시간 = %.f, 실제 점수 = %.f, 예측 점수 = %.f" % (x[i], y[i], predict(x[i])))
    
print("mse 최종값: " + str(mse_val(pr, y)))

  • 오차가 11임.

2. ✅넘파이 배열 이용 시

x = [2,4,6,8]
y = [81, 93, 91, 97]

X = np.array(x)
Y = np.array(y)
a, b = 3, 76

Y_pred = a*X + b
err = Y - Y_pred
MSE = (err**2).sum()/len(X)

plt.scatter(X,Y)
plt.scatter(X, Y_pred)
plt.plot(X, Y_pred)
plt.show()

2. 경사 하강법(gradient descent) : 오차수정

  • 오차를 비교하여 가장 작은 방향으로 이동
  • 기울기 a를 이동시켜 최솟값 m을 찾는 방법
    • 순간 기울기가 0인 점이 곧 최솟값 m이 됨
    • ➡️ 미분값이 0인 지점 찾기
      • 1️⃣ a1에서의 미분을 구한다
      • 2️⃣ 구해진 기울기의 반대 방향으로 얼마간 이동시킨 a2에서 미분
      • 3️⃣ 0이 될때까지 반복
      • 4️⃣ 값들은 점점 0으로 수렴하게 됨
  • 절편 b
    • 너무 크면 오차가 커짐
    • 너무 작아도 오차가 커짐
  • 최솟값을 구하려면 이차함수에서 미분해야함 ➡️ 평균제곱오차에서 나옴
    • MSE에 y = ax + b 대입
    • a에 대한 편미분
    • b에 대한 편미분

    • 연쇄법칙 : y = f(g(x)) ➡️ y' = f'(g(x))*g'(x)
    • a,b에 대해 편미분이므로 이를 제외한 값은 모두 상수취급하여 미분 시 사라짐
    • 시그마 편미분 = 편미분의 합
import pandas as pd

data = [[2, 81], [4, 93], [6, 91], [8, 97]]
x = [i[0] for i in data]
y = [i[1] for i in data]

plt.figure(figsize=(8,5))
plt.scatter(x,y)
plt.show()

X = np.array(x)
Y = np.array(y)

a, b = 0, 0 #기울기, y절편 초기화
lr = 0.01 # 학습률
ep = 2001 #에포크

for i in range(ep):
    y_pred = a * X + b
    err = Y - y_pred
    
    a_diff = -(2/len(X))*sum(X * err)
    b_diff = -(2/len(X))*sum(err)
    
    a = a - lr*a_diff
    b = b - lr*b_diff
    
    if i % 100 == 0:
        print("epoch=%.f, 기울기=%.04f, 절편=%.04f" % (i, a, b))
    
y_pred = a * X + b
plt.scatter(x,y)
plt.plot([min(X), max(X)],[min(Y), max(Y)])
plt.show()

✅넘파이 이용

X = np.array([2,4,6,8])
Y = np.array([81,93,91,97])

a, b = 0, 0 #기울기, y절편 초기화
lr = 0.01 # 학습률
ep = 2001 #에포크

for i in range(ep):
    y_pred = a * X + b
    err = Y - y_pred
    
    n = len(X)
    a_diff = -(2/n) * (X * err).sum()
    b_diff = -(2/n) * (err).sum()
    
    a -= lr*a_diff
    b -= lr*b_diff
    
    if i % 100 == 0:
        print("epoch=%.f, 기울기=%.04f, 절편=%.04f" % (i, a, b))
    
y_pred = a * X + b
plt.scatter(x,y)
plt.plot(X, y_pred)
plt.show()    

1) 학습률(learning rate)

  • 어느만큼 이동시킬지 나타내는 이동거리
    • 학습률을 너무 크게 잡으면 한 점으로 수렴하지 않고 발산함.
    • 인공지능에서 변화량(학습률) 결정하는 것은 중요함

2) 다중 선형 회귀

  • 독립변수의 수를 여러개 사용하여 선형 회귀 수행 ➡️ 더 정확한 예측을 위함.
data = [[2, 0, 81], [4, 4, 93], [6, 2, 91], [8, 3, 97]]
x1 = [i[0] for i in data]
x2 = [i[1] for i in data]
y = [i[2] for i in data]

from mpl_toolkits import mplot3d #3D 그래프
ax = plt.axes(projection='3d')
ax.set_xlabel('study_hours')
ax.set_ylabel('private_class')
ax.set_zlabel('Score')
ax.dist = 11
ax.scatter(x1, x2, y)
plt.show()

x1 = np.array(x1)
x2 = np.array(x2)
y = np.array(y)

a1, a2, b = 0,0,0

lr = 0.003
ep = 2001

for i in range(ep):
    y_pred = a1 * x1 + a2 * x2 + b
    err = y - y_pred
    
    a1_diff = -(2/len(x1))*sum(x1*err)
    a2_diff = -(2/len(x2))*sum(x2*err)
    b_diff = -(2/len(x1))*sum(err)
    
    a1 -= lr*a1_diff
    a2 -= lr*a2_diff
    b -= lr*b_diff
    # 학습률 만큼 빼주면서 학습 반복
    
    if i % 100 == 0:       # 100번 반복될 때마다 현재의 a1, a2, b 값 출력
        print("epoch=%.f, 기울기1=%.04f, 기울기2=%.04f, 절편=%.04f" % (i, a1, a2, b))


✅넘파이 이용

x1 = np.array([2,4,6,8])
x2 = np.array([0,4,2,3])
y = np.array([81,93,91,97])

a1, a2, b = 0,0,0

lr = 0.003
ep = 2001


for i in range(ep):
    y_pred = a1 * x1 + a2 * x2 + b
    err = y - y_pred
    
    a1_diff = -(2/len(x1))*(x1*err).sum()
    a2_diff = -(2/len(x2))*(x2*err).sum()
    b_diff = -(2/len(x1))*err.sum()
    
    a1 -= lr*a1_diff
    a2 -= lr*a2_diff
    b -= lr*b_diff
    
    if i % 100 == 0:       # 100번 반복될 때마다 현재의 a1, a2, b 값 출력
        print("epoch=%.f, 기울기1=%.04f, 기울기2=%.04f, 절편=%.04f" % (i, a1, a2, b))
y_pred = a1 * x1 + a2 * x2 + b
print('a1 : {}, a2 : {}, b : {}'.format(a1,a2,b))
print('y:', y)
print('y_pred : ', y_pred)
print('error : ', err)

3. 로지스틱 회귀(logistic regression)

  • 독립변수와 종속변수의 관계를 사용하여 참 거짓 예측하는 방법
  • 선형 회귀와 마찬가지로 적절한 선(S선)을 그려가는 과정

1) 시그모이드 함수

  • 결국 a, b를 구해야 함


    1️⃣ a : 기울기의 경사도
    ✔️a값이 크면 경사도가 가팔라지고 작으면 경사도가 완만

    ➡️ 기울기 a와 오차의 관계 : a가 작아질수록 오차는 무한대로 커지나 a가 커질 수록 오차는 줄어든다(오차가 없어지는 건 아님)

    2️⃣ b : 그래프의 좌우이동

    ➡️ b와 오차의 관계 : b값이 너무 작아지거나 커지면 오차도 급증

    * 오차공식

    경사하강법 이용

    • 시그모이드 함수 : y값이 0과 1 사이의 값 ➡️ 실제값이 1일 때 예측값이 0에 가까워질 수록 오차가 커짐.(역도 마찬가지)
    • ➡️ 로그함수 이용
      • 실제값이 1일 때, 0으로 갈수록 오차값이 커짐(-log h)
      • 실제값이 0일 때, 1로 갈수록 오차값이 커짐(-log (1-h))
      • 실제값 : y_data
      • 실제값 1이면 B 없어짐.
    ➡️ 오차 공식

코드

data = [[2, 0], [4, 0], [6, 0], [8, 1], [10, 1], [12, 1], [14, 1]]

x = [i[0] for i in data]
y = [i[1] for i in data]

plt.scatter(x, y)
plt.xlim(0, 15)
plt.ylim(-.1, 1.1)

a,b = 0,0
lr = 0.003

def sigmoid(x): # 시그모이드 함수
   return 1/(1+np.e**(-x))

for i in range(2001):
   for x, y in data:
       a_diff = x * (sigmoid(a*x + b) - y)
       b_diff = sigmoid(a*x + b) - y
       a = a - lr*a_diff
       b = b - lr*b_diff
       if i%1000 == 0:
           print("epoch=%.f, 기울기=%.04f, 절편=%.04f" % (i, a, b))

plt.scatter(x, y)
plt.xlim(0, 15)
plt.ylim(-.1, 1.1)  
x_range = (np.arange(0, 15, 0.1)) # 그래프로 나타낼 x 값의 범위 정하기
plt.plot(np.arange(0, 15, 0.1), np.array([sigmoid(a * x + b) for x in x_range]))
plt.show()

퍼셉트론에 이용

  • 입력값 : x1, x2
  • 가중치 : a1, a2
  • 출력값 y : 0 or 1

좋은 웹페이지 즐겨찾기