딥러닝 개요

김민석·2022년 4월 28일
0

딥러닝 : 머신러닝의 일종으로 신경망의 층을 깊게 쌓아 데이터를 학습하는 방식

1. 퍼셉트론

1) 퍼셉트론
다수의 입력망에서 하나의 결과를 내는 인공신경망

입력값에는 가중치(중요할 수록 큰 수)가 곱해져 임계치를 넘으면 1 아니면 0을 출력으로 내놓는다. 이를 계단 함수라고 한다.

가중치과 더불어 편향 bb가 더해져 임계치를 만들어내며
가중치와 편향은 최적의 값을 찾아야하는 변수

활성화 함수를 계단 함수에서 시그모이드로 변경하면 로지스틱 회귀와 동일하다.

2) 단층 퍼셉트론(Single-Layer Perceptron)

단층은 입력을 받는 단계, 출력하는 단계 두 단계로 이뤄지며 각 단계는 층(Layer)라 부른다.

AND 게이트(x1,x2모두 1일 때 y = 1)를 위한 매개변수 값을 가진 단층 퍼셉트론으이 식을 파이썬 코드로 구현

def AND_gate(x1, x2):
    w1 = 0.5
    w2 = 0.5
    b = -0.7
    result = x1*w1 + x2*w2 + b
    if result <= 0:
        return 0
    else:
        return 1
AND_gate(0, 0), AND_gate(0, 1), AND_gate(1, 0), AND_gate(1, 1)
(0, 0, 0, 1)

두 개의 입력값이 1인 경우에만 0, 아닌 경우 1인 NAND 게이트는

def NAND_gate(x1, x2):
    w1 = -0.5
    w2 = -0.5
    b = 0.7
    result = x1*w1 + x2*w2 + b
    if result <= 0:
        return 0
    else:
        return 1
NAND_gate(0, 0), NAND_gate(0, 1), NAND_gate(1, 0), NAND_gate(1, 1)
(1, 1, 1, 0)

이외에도 다양한 가중치와 편향 값이 존재할 것

두 입력이 모두 0인 경우 0, 아니면 1인 OR 게이트

def OR_gate(x1, x2):
    w1 = 0.6
    w2 = 0.6
    b = -0.5
    result = x1*w1 + x2*w2 + b
    if result <= 0:
        return 0
    else:
        return 1
OR_gate(0, 0), OR_gate(0, 1), OR_gate(1, 0), OR_gate(1, 1)
(0, 1, 1, 1)
  • XOR 게이트는 단층 퍼셉트론으로 구현할 수 없다.
    XOR 게이트는 입력값 두 개가 서로 다른 값을 갖고 있을 때 1을 출력, 서로 같은 값은 가지면 0이 되는 게이트.

이때는 위 코드에 어떤 값을 넣어도 구현이 불가능

https://wikidocs.net/images/page/24958/andgraphgate.PNG![](https://velog.velcdn.com/images/dkdlwlswk/post/b401c6ee-d38e-4c84-a17b-bc30ecc18d3f/image.png)

해결은 다층 퍼셉트론

3) 다층 퍼셉트론(Multi-Layer Perceptron, MLP)

다층 퍼셉트론은 은닉층이 존재, 입력층과 출력층 사이.

은닉층을 활용하면 XOR 함수가 가능하다.

def XOR_gate(x1, x2):
    #둘 다 같을 때 1
    y1 = NAND_gate(x1, x2)
    #둘 다 아닌 경우만 0
    y2 = OR_gate(x1, x2)
    #둘이 다른 값을 가질 때 1
    return AND_gate(y1, y2)

이런 은닉층이 2개 이상인 신경망을 심층 신경망(DNN)이라고 합니다.
머신러닝에서는 훈련, 학습 단계를 통해 위에서 구한 가중치와 편향을 직접 구하도록 자동화 시킵니다.
이때 학습 시키는 인공 신경망이 심층 신경망일 때 이를 딥 러닝(Deep Learning)이라고 합니다.

2. 인공 신경망

1) 피드 포워드 신경망(Feed-Forward Neural Network, FFNN)

다층 퍼셉트론이 입력층에서 출력층 방향으로 연산이 전개되는 신경망

RNN의 경우 은닉층의 출력값을 출력층으로 보내면서 은닉층의 입력으로 사용되기도 한다.

2) 전결합층(Fully-connected layer, FC, Dense layer)

어떤 층의 모든 뉴련이 이전 층의 모든 뉴련과 연결되어 있는 층ㅇ을 전결합층, 또는 완전 연결층이라고 한다.
동일한 의미로 밀집층 이라고도 하는데 케라스에서는 Dense()로 구현한다.

3) 활성화 함수(Activation Function)
은닉층, 출력층의 뉴런에서 출력값을 결정하는 함수를 활성화 함수라고 하며, 계단 함수는 이의 일종

(1) 비선형 함수
활성화 함수는 비선형 함수여야한다. 은닉층을 추가항였을 때 선형함수를 활성화 함수로 사용하면 은닉층을 사용하는 의미가 사라지기 때문이다.
활성화 함수가 f(x)=wxf(x) = wx라고 가정하면, 은닉층을 추가했을 때
y(x)=f(f(f(x)))y(x) = f(f(f(x)))가 되버리며 이는 y(x)=kxy(x) = kx와 같기 때문.

활성화 함수가 존재하지 않는 선형 함수 층을 사용하기는 한다.

주로 사용되는 활성화 함수는 다음과 같다.

(2) 계단 함수

def step(x):
    return np.array(x > 0, dtype=np.int)
x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = step(x)
plt.title('Step Function')
plt.plot(x,y)
plt.show()

(3) 시그모이드와 기울기 소실
인공 신경망의 학습 과정 : 입력에 대한 순전파 연산, 연산에 따른 손실 함수, 이 손실에 미분을 통해 기울기를 구하고, 이를 통해 출력층에서 입력층 방향으로 가중치와 편향을 업데이트 하는 역전파를 수행한다. 이 과정에서 경사 하강법을 사용.

시그모이드의 문제는 미분에서 기울기를 구할 때 극단 값으로 가면서 기울기가 0에 가까워지는데, 이때 역전파 과정에서 기울기가 잘 전달되지 않으며 기울기 소실 문제가 발생한다.

https://wikidocs.net/images/page/60683/시그모이드함수2.PNG![](https://velog.velcdn.com/images/dkdlwlswk/post/02912019-9a31-4f28-87fc-c1daeedc256e/image.png)

이 때문에 시그모이드는 주로 이진 분류를 위해 출력층에서 사용된다.

(4) 하이퍼볼릭탄젠트 함수(Hyperbolic tangent function)
tanh은 입력값을 -1~1의 값으로 변환

x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = np.tanh(x)

plt.plot(x, y)
plt.plot([0,0],[1.0,-1.0], ':')
plt.axhline(y=0, color='orange', linestyle='--')
plt.title('Tanh Function')
plt.show()


시그모이드처럼 양 끝 값에 가면서 미분값이 0에 가까운 문제는 있지만 0을 중심으로하여 미분시 최대값이 1로 나오며 시그모이드 함수의 미분 최대값인 0.25보다 크다. 즉 전반적으로 시그모이드 보다 크게 값이 나온다.

(5) 렐루 함수(ReLU)
가장 인기 있는 함수로 수식은 $f(x) = max(0,x)

def relu(x):
    return np.maximum(0, x)

x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)

plt.plot(x, y)
plt.plot([0,0],[5.0,0.0], ':')
plt.title('Relu Function')
plt.show()

렐루 함수는 음수일 때 0, 양수일 때는 입력값 그대로 반환.
0 이상의 입력값에서는 미분이 항상 1
입력값이 음수이면 미분이 0 -> 이 경우 뉴런이 다시 회생하기 어렵고 이 문제는 죽은 렐루(dying ReLU)라고 한다.

(6) 리키 렐루 (Leaky ReLU)

죽은 렐루를 보완하기 위해 등장한 변형 함수로
입력값이 음수일 때 0이 아니라 0.001과 같은 매우 작은 수를 반환
수식은 f(x)=max(ax,x)f(x) = max(ax, x) 이고 aa는 하이퍼파라미터로 Leaky(새는)정도를 결정하며 일반적으론 0.01의 값

a = 0.1

def leaky_relu(x):
    return np.maximum(a*x, x)

x = np.arange(-5.0, 5.0, 0.1)
y = leaky_relu(x)

plt.plot(x, y)
plt.plot([0,0],[5.0,0.0], ':')
plt.title('Leaky ReLU Function')
plt.show()

(7) 소프트맥스 함수(Softmax Function)

시그모이드가 이진 분류 문제에 사용된다면 소프트 맥스는 세 가지 이상의 선택지 중 하나를 고르는 다중 클래스 분류

x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = np.exp(x) / np.sum(np.exp(x))

plt.plot(x, y)
plt.title('Softmax Function')
plt.show()

  1. 행렬곱으로 이해하는 신경망

입력층에서 출력층으로 연산을 진행하는 과정은 순전파(Forward Propagation)라고 한다. 이를 행렬의 곱으로 이해하고, 학습 가능한 매개변수 가중치 ww와 편향bb의 개수를 추정하는 방법.

(1) 순전파

입력값은 여러 층을 지나 출력층으로 향해 예측값을 내놓는다.
이런 과정을 순전파라고 한다.

(2) 행렬곱으로 이해하기

입력 차원 3, 출력 차원 2인 인공 신경망의 구현은

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()

# 3개의 입력과 2개의 출력
model.add(Dense(2, input_dim=3, activation='softmax'))

케라스에서 .summary()를 사용ㅇ하면 매개변수를 확인할 수 있다.

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 2)                 8         
=================================================================
Total params: 8
Trainable params: 8
Non-trainable params: 0
_________________________________________________________________

8개의 매개변수가 나온 과정을 확인

입력 차원 3, 출력 차원 2
입력층의 뉴런이 3개, 출력층의 뉴런이 2개
가중치는 w의 개수 6개이며
편항은 2개
총 8개의 매개변수이다.

h1=x1w1+x2w2+x3w3+b1h_{1} = x_{1}w_{1} + x_{2}w_{2} + x_{3}w_{3} + b_{1}
h2=x1w4+x2w5+x3w6+b2h_{2} = x_{1}w_{4} + x_{2}w_{5} + x_{3}w_{6} + b_{2}
[y1,y2]=softmax([h1,h2])[y_{1}, y_{2}] = softmax([h_{1}, h_{2}])

X=[x1,x2,x3]X=[x_{1}, x_{2}, x_{3}]라고 명명하자

이때 위 식은
Y=XW+BY = XW + B이다.

(3) 병렬 연산 이해


샘플 4개를 처리한다고 할 때

여전히 매개 변수는 8개이다. 이렇게 다수의 샘플을 동시 처리하는 것을 배치 연산이라고 한다.

(4) 다층 퍼셉트론의 순전파 이해하기

위 인공 신경망을 케라스로 구현하면

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()

# 4개의 입력과 8개의 출력
model.add(Dense(8, input_dim=4, activation='relu'))

# 이어서 8개의 출력
model.add(Dense(8, activation='relu'))

# 이어서 3개의 출력
model.add(Dense(3, activation='softmax'))

코드 주석에서 () 괄호 안의 값은 각 층에서의 뉴런의 수이며 케라스를 통해 간단하게 딥러닝 모델을 구현할 수 있다.

행렬의 크기를 추정해보자

입력층 : 4개의 입력과 8개의 출력
은닉층1 : 8개의 입력과 8개의 출력
은닉층2 : 8개의 입력과 3개의 출력
출력층 : 3개의 입력과 3개의 출력

(a) 입력층 -> 은닉층 1
Xm × n×Wn × j+Bm × j=Ym × jX_{m\ \text{×}\ n} × W_{n\ \text{×}\ j} + B_{m\ \text{×}\ j} = Y_{m\ \text{×}\ j}
X1 × 4×Wn × j+Bm × j=Y1 × 8X_{1\ \text{×}\ 4} × W_{n\ \text{×}\ j} + B_{m\ \text{×}\ j} = Y_{1\ \text{×}\ 8}
X1 × 4×W4 × j+Bm × j=Y1 × 8X_{1\ \text{×}\ 4} × W_{4\ \text{×}\ j} + B_{m\ \text{×}\ j} = Y_{1\ \text{×}\ 8}
X1 × 4×W4 × j+B1 × 8=Y1 × 8X_{1\ \text{×}\ 4} × W_{4\ \text{×}\ j} + B_{1\ \text{×}\ 8} = Y_{1\ \text{×}\ 8}
X1 × 4×W4 × 8+B1 × 8=Y1 × 8X_{1\ \text{×}\ 4} × W_{4\ \text{×}\ 8} + B_{1\ \text{×}\ 8} = Y_{1\ \text{×}\ 8}

(b) 은닉층 1 -> 은닉층 2

X1 × 8×W8 × 8+B1 × 8=Y1 × 8X_{1\ \text{×}\ 8} × W_{8\ \text{×}\ 8} + B_{1\ \text{×}\ 8} = Y_{1\ \text{×}\ 8}

(c) 은닉층 2 -> 은닉층 3
X1 × 8×W8 × 3+B1 × 3=Y1 × 3X_{1\ \text{×}\ 8} × W_{8\ \text{×}\ 3} + B_{1\ \text{×}\ 3} = Y_{1\ \text{×}\ 3}

  1. 딥 러닝의 학습 방법

1) 손실 함수 (Loss Function)

예측값과 실제값의 차이를 수치화해주는 함수이다.
회귀에서는 평균 제곱 오차, 분류에서는 크로스 엔트로피를 주로 사용한다.
손실 함수의 값을 최소화 하는 두 개의 매개변수 w,bw,b를 찾는 것이 딥 러닝의 학습과정이므로 손실 함수 선정은 매우 중요하다.

(1) MSE(Mean Squared Error, MSE)

model.compile(optimizer='adam', loss='mse', metrics=['mse'])

이렇게 사용할 수도 있다.

model.compile(optimizer='adam', loss=tf.keras.losses.MeanSquaredError(), metrics=['mse'])

(2) 이진 크로스 엔트로피(Binary Cross-Entropy)

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc'])
model.compile(loss=tf.keras.losses.BinaryCrossentropy(), optimizer='adam', metrics=['acc'])

(3) 카테고리칼 크로스 엔트로피(Categorical Cross-Entropy)
범주형 교차 엔트로피라 불리기도 한다.
출력층에서 소프트맥스 함수를 사용하는 다중 클래스 분류일 경우 사용.

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
#or
model.compile(loss=tf.keras.losses.CategoricalCrossentropy(), optimizer='adam', metrics=['acc'])

원-핫 인코딩 과정을 생략하고, 정수값을 가진 레이블에 대해 다중 클래스 분류를 한다면 'sparse_categorical_crossentropy'

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['acc'])
#or
model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(), optimizer='adam', metrics=['acc'])

(4) 이외에 손실함수

https://www.tensorflow.org/api_docs/python/tf/keras/losses에서 확인해볼 수 있다.

위에선 adam을 옵티마이저로 사용했다.

2) 배치 크기에 따른 경사 하강법

손실 함수를 줄여나갈 때 어떤 옵티마이저를 사용하냐에 따라 달라지는데 Batch에 대한 이해가 필요하다.
배치는 매개 변수의 값을 조정하기 위해 사용하는 데이터의 양을 말한다.

(1) 배치 겨사 하강법(Batch Gradient Descent)

배치 경사 하강법은 가장 기본적인 경사 하강법.
옵티마이저 중 하나로 오차를 구할 때 전체 데이터를 고려한다.
딥 러닝에서는 전체 데이터에 대한 한 번의 훈련 횟수를 1 에코프라고 하며 배치 경사 하강법은 한 번의 에포크에 모든 매개변수 업데이트를 단 한 번 수행한다. 전체 데이터를 사용하므로 시간에 오래 걸리며 메모리를 크게 요구.

model.fit(X_train, y_train, batch_size=len(X_train))

(2) 배치 크기가 1인 확률적 경사 하강법(Stochastic Gradient Descent, SGD)

이는 랜덤으로 선택한 하나의 데이터에 대해서만 계산, 더 적은 데이터를 사용하므로 빠르게 계산 가능하다.


정확도가 낮을 수 있고, 매개 변수의 변경 폭이 불안정 하지만 메모리 요구가 적다는 장점이 있다.

model.fit(X_train, y_train, batch_size=1)

(3) 미니 배치 경사 하강법(Mini-Batch Gradient Descent)

배치 크기를 지정해 매개 변수의 값을 조정하는 경사 하강법.
전체 데이터보다 빠르며 SGD보다 안정적이라는 장점

model.fit(X_train, y_train, batch_size=128)

위처럼 사이즈를 지정할 수 있고, 사이즈 지정ㅇ이 없다면 기본 32로 설정된다.
보통 2의 n 제곱에 해당하는 숫자를 선택

3) 옵티마이저(Optimizer)

(1) 모멘텀(Momentum)
관성이라는 물리학 법칙을 응용, 경사하강법에서 계산된 접선의 기울기에 한 시점 전의 접선의 기울기 값을 일정한 비율만큼 반영.

tf.keras.optimizers.SGD(lr=0.01, momentum=0.9)

(2) 아다그라드 (Adagrad)
모든 매개 변수에 동일한 학습률을 적용하는 것은 비효율적이다.
따라서 서로 다른 학습률을 적용시키는 방법

tf.keras.optimizers.Adagrad(lr=0.01, epsilon=1e-6)

(3) 알엠에스프롭(RMSprop)
아다그라드의 경우 학습이 진행되며 학습률이 떨어지는 단점이 존재, 이를 다른 수식으로 대체해 개선

tf.keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=1e-06)

(4) 아담(Adam)
알엠에스프롭과 모멘텀 두 가지를 합친 듯한 방법, 방향과 학습률 두 가지를 모두 잡기 위한 방법.

tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)

(5) 사용 방법
각 옵티마이저 인스턴스는 compile의 optimizer에서 호출합니다. 예를 들어 아담(adam)은 다음과 같이 코드를 작성합니다.

adam = tf.keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
model.compile(loss='categorical_crossentropy', optimizer=adam, metrics=['acc'])

단순하게는

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])

4) 에포크와 배치 크기와 이터레이션

(1) 에포크 (Epoch)
전체 데이터에 대해 순전파,역전파가 끝난 상태

(2) 배치 크기(Batch Size)
몇 개의 데이터 단위로 매개 변수를 업데이트 하는지
기계가 오차를 계산하고 옵티마이저가 매개 변수를 업데이트하는 시점

(3) 이터레이션 Or 스텝
한 번의 에포크를 끝내기 위해 필요한 배치의 수
전체 데이터가 2000일 때 배치 크기를 200으로 한다면 이터레이션의 수는 10.

출처 : https://wikidocs.net/24958

profile
데이터 사이언스를 공부하는 커피쟁이

0개의 댓글