쉽게 배우는 경사하강 학습법

쉽게 배우는 경사하강 학습법

지도 학습 vs 비지도 학습

사람의 지도학습

머신러닝의 지도학습

학습 매개변수

손실 함수

  • 어떤 손실 함수를 사용하느냐에 따라서 학습이 어떻게 이루어질 것인지, 그리고 학습을 할 때 정답의 형태를 결정하기 때문에 손실 함수는 중요하다!

알고리즘 학습을 달리 말하면

  • Traning Data를 Model에 입력해 우리가 학습시키고자 하는 Trainable Parameters를 얻게 되는데 Trainable Parameters들을 inputs으로 보고 outputs을 학습결과인 Loss Function으로 생각하면, 알고리즘 학습은 입력을 바꿔가면서, 출력값이 점점 작아지게 하는 것이라고 볼 수 있다.

최적화 이론과 알고리즘 학습

  • 결국 알고리즘 학습은 입력을 바꿔가면서, 출력값이 점점 작아지게 하는 것이라는 관점에서 최적화 이론의 목표와 동일하다는 사실을 알 수 있다.

경사 하강 학습법

무차별 대입법(Brute-Force)

  • 무차별 대입법은 범위를 알아야하고 범위를 안다해도 step을 촘촘히 조사해야 하므로 계산 복잡도가 높다. 적게 대입해 보고 답을 찾을 수 있는 방법을 생각하다 최적화 알고리즘이 발전 하게 되었다.

경사하강법(Gradient Descent)

경사하강법(Gradient Descent)

학습률의 선택 00

학습률의 선택 01

학습률의 선택 02

Convex Function

Non-convex Function

최적화 이론과 수학적 표현

최적화 이론(Optimization Theory)

분석적 vs 수치적 방법

  • 수치적 방법의 대표적인 방법이 경사하강법이다.

Global vs local solution

딥러닝과 최적화 이론

심화 경사 하강 학습법

  • 경사하강 학습법의 단점들을 극복한 알고리즘에 대해서 알아보자.

Non_convex Finction

Local Minimum

Saddle Point

  • 경사하강법은 안장점에서 기울기가 0이 되므로 벗어나지 못하게 되는 문제점이 있다.

Momentum

  • 이동 벡터가 이전 기울기에 영향을 받도록 하는 방법 이전의 속도에 영향을 받는 방법이라고 할 수 있다.

  • 장점 : Local minimum과 noise에 대처 가능

  • 단점 : 경사하강법은 단순히$x_{t-1}$이동벡터($v_{t}$)를 추가로 사용하므로, 경사 하강법 대비 2배의 메모리를 사용

AdaGrad

  • 변수별로 learning rate가 달라지게 조절한다. 예를 들어서 $x=[x_{1}, x_{2}, x_{3},…,x_{n}]$이 존재할때 어떤 변수는 기울기를 크게 가져가고 어떤 변수는 기울기를 작게 가져갈 경우 처음에 기울기를 크게 가져가지 못한다면 local minimum에 빠지기 쉬운 문제점이 있다. 이런 문제점을 해결하고자 변수별로 learning rate를 다르게 가져가는 알고리즘인 Ada Grad 탄생된 것이다.

  • 장점 : $g_{t}$가 누적되어 커진 것은 학습이 그만큼 많이 된 것이므로 학습이 많이 변수는 학습율을 감소시켜, 다른 변수들이 잘 학습되도록 한다.

  • 단점 : $g_{t}$ 가 계속해서 커져서 학습이 오래 진행되면 learning rate가 0ㅇ에 가까워지므로 더이상 학습이 이루어지지 않는 단점이 있다.

RMSProp

  • gradient의 크기를 제곱한 벡터(gradient벡터의 L2-norm)를 누적합을 해서 적게 학습되는 변수들을 더 학습시켜 주도록했지만 epoch나 batchsize등 반복 시키는 parameter의 value가 높아질수록 오래 진행되어 누적합이 커지게 되면 더 이상 학습이 되지 않는 문제점을 개선한 방법이다. 위의 식에서 $\gamma$값은 0~1값을 갖게 되며, 이 값을 통해 이전의 gradient 누적합을 감소시키는 효과를 주면서 새로운 gradient의 값을 쫓아갈 수 있도록 개선하였다. 그러므로, 변수 간의 상대적인 학습율 차이는 유지하면서$g_{t}$가 무한정 커지지 않아 학습을 오래 할 수 있다.

Adam

  • RMSprop과 Momentum의 장점을 결합한 알고리즘이다. 대부분의 코드에 이 Adam optimization을 사용한다.

경사 하강법을 이용한 얕은 신경망 학습

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 경사 하강법을 이용한 얕은 신경망 학습
import tensorflow as tf
import numpy as np

## 하이퍼 파라미터 설정
epochs = 1000

## 네트워크 구조 정의
### 얕은 신경망
#### 입력 계층 : 2, 은닉 계층 : 128 (Sigmoid activation), 출력 계층 : 10 (Softmax activation)

# keras의 모듈을 상속해서 Model을 구현
class MyModel(tf.keras.Model):
def __init__(self):
# 상속을 한 경우에는 상속을 한 상위 class를 initialize하는 것을 잊어버리지 말자!
super(MyModel, self).__init__()
# 아래의 input_dim을 적어줄 필요는 없다. 실제 데이터가 들어올때 정의 되기 떄문이다.
self.d1 = tf.keras.layers.Dense(128, input_dim=2, activation="sigmoid")
self.d2 = tf.keras.layers.Dense(10, input_dim=128, activation="softmax")


# Model이 실제 call이 될때 입력에서 출력으로 어떻게 연결이 될 것인지를 정의
def call(self, x, training=None, mask=None):
x = self.d1(x)
return self.d2(x)

## 학습 루프 정의
@tf.function
# tensorflow의 Auto Graph를 통해 쉽게 구현가능하다.
# function 내의 python 문법으로 입력된 모든 tensor 연산들을 tf.function에 의해서
# 최적화된다.
def train_step(model, inputs, labels, loss_object, optimizer, train_loss, train_metric):
# Gradient를 계산하기위한
with tf.GradientTape() as tape:
predictions = model(inputs)
loss = loss_object(labels, predictions)
# loss를 model의 trainable_variables(W,b)로 각각 미분해서 gradient를 구한것.
# loss는 scalar이고, model.trainable_variables는 벡터이므로 결과 또한 벡터가 될 것이다.
gradients = tape.gradient(loss, model.trainable_variables)

# 각 gradient와 trainable_variables들이 optimizer로 학습
optimizer.apply_gradients(zip(gradients, model.trainable_variables))

# loss를 종합
train_loss(loss)

# matric
train_metric(labels, predictions)

## 데이터셋 생성, 전처리
np.random.seed(0)

pts = []
labels = []

center_pts = np.random.uniform(-8.0, 8.0, size=(10, 2))
for label, center_pt in enumerate(center_pts):
for _ in range(100):
pts.append(center_pt + np.random.randn(*center_pt.shape))
labels.append(label)

# GPU를 사용하게 된다면 위의 MyModel class에서 initialize 할때
# Layer에 따로 dtype을 지정하지 않으면 float32로 설정되므로 동일하게 해주기 위해 type 재설정
pts = np.stack(pts, axis=0).astype(np.float32)

# 이미 integer이므로 바꿀 필요가 없음.
labels = np.stack(labels, axis=0)

# 위에서 만든 데이터를 train data set으로 변형
# train_ds는 iterable한 object가 된다.
# 1000개를 섞어 batch_size를 32개로 해서 구성해준다.
train_ds = tf.data.Dataset.from_tensor_slices((pts, labels)).shuffle(1000).batch(32)

print(pts.shape)
print(labels.shape)

## 모델 생성
model = MyModel()

## 손실 함수 및 최적화 알고리즘 설정
### CrossEntropy, Adam Optimizer
loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()

## 평가 지표 설정
### Accuracy
train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

## 학습 루프
for epoch in range(epochs):

#위에서 batch_size를 32로 했으므로 한번 실행시 32개씩 나옴.
for x, label in train_ds:
train_step(model, x, label, loss_object, optimizer, train_loss, train_accuracy)

template = 'Epoch {}, Loss: {}, Accuracy: {}'
print(template.format(epoch+1, train_loss.result(), train_accuracy.result()*100))

## 데이터셋 및 학습 파라미터 저장
# 압축해서 여러개의 Numpy Object들을 저장할 수 있다.
np.savez_compressed('ch2_dataset.npz', inputs=pts, labels=labels)

W_h, b_h = model.d1.get_weights()
W_o, b_o = model.d2.get_weights()

# weight는 tensorflow에서 사용하고 있는 convention이랑
# shallowNN을 구현할 때 사용했던 convention이 좀 다르다.
W_h = np.transpose(W_h)
W_o = np.transpose(W_o)

np.savez_compressed('ch2_parameters.npz', W_h=W_h, b_h=b_h, W_o=W_o, b_o=b_o)