신경망의 특징은 데이터를 보고 학습할 수 있다는 것으로, 데이터에서 학습한다는 것은 가중치 매개변수의 값을 데이터를 보고 자동으로 결정한다는 뜻이다.
기계학습은 데이터에서 답을 찾고 패턴을 발견하는 등으로 데이터가 생명이다. 데이터가 이끄는 접근 방식으로 사람 중심 접근에서 벗어날 수 있게 된다.
사람과 달리 기계학습은 사람의 개입을 최소화하고 수집한 데이터로부터 패턴을 찾으려 시도한다. 게다가 신경망과 딥러닝은 기존 기계학습에서 사용하던 방법보다 사람의 개입을 더욱 배제할 수 있게 해주는 특징을 지녔다.
이미지에서 '특징(feature)을 추출하고 그 특징의 패턴을 기계학습 기술로 학습을 할 때, '특징'은 여전히 '사람'이 설계하는 것임에 주의해야 한다. 다시 말해 문제에 적합한 특징을 쓰지 않으면(설계 하지 않으면) 좀 처럼 좋은 결과를 얻을 수 없다는 뜻이다.
신경망의 이점은 모든 문제를 같은 맥락에서 풀 수 있다는 것이다. 주어진 데이터를 온전히 학습하고 주어진 문제의 패턴을 발견하려 시도한다. 즉 신경망은 모든 문제를 주어진 데이터 그대로를 입력 데이터로 활용해 'end-to-end'로 학습할 수 있다.
종단간 기계학습(end-to-end machine learning)에서 종단간은 '처음부터 끝까지'라는 의미로, 데이터 입력에서 목표한 결과까지 사람의 개입 없이 얻는다는 뜻이다.
기계학습에서 데이터를 취급할 때 주의할 점은 훈련 데이터와 시험 데이터를 나눠 학습과 실험(평가)을 수행하는 것이다. 시험 데이터를 사용하여 앞서 훈련한 모델의 실력을 평가하는 것이다.
이렇게 데이터를 나누는 것은 범용적으로 사용할 수 있는 모델을 설계하기 위함이다. 아직 보지 못한 데이터(훈련 데이터에 포함되지 않은 데이터)로도 문제를 올바르게 풀어내는 능력이 있어야 한다. 이 범용 능력을 획득하는 것이 기계학습의 최종 목표이다.
데이터셋 하나로만 매개변수의 학습과 평가를 수행하면 올바른 평가가 될 수 없다. 수중의 데이터셋은 제대로 맞히더라도 다른 데이터셋에는 엉망인 일도 벌어진다. 하나의 데이터셋에만 지나치게 최적화된 상태를 '과적합'(overfitting)이라고 하며, 이 과적합 피하기는 기계학습의 중요한 과제 중 하나다.
신경망 학습에서는 현재의 상태를 '하나의 지표'로 표현한다. 그리고 그 지표를 가장 좋게 만들어주는 가중치 매개변수의 값을 탐색한다. '하나의 지표'를 기준으로 최적의 매개변수 값을 탐색하는데, 이 지표를 '손실 함수(loss function)이라 한다.
y는 신경망의 출력(신경망이 추정한 값), t는 정답 레이블, k는 데이터의 차원의 수를 나타낸다.
실제 예로 확인해보자.
def sum_squares_error(y, t):
return 0.5 * np.sum((y - t)**2)
# index 2 정답
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# ex1
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
sum_squares_error(np.array(y), np.array(t))
>
0.09750000000000003
# ex2
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
sum_squares_error(np.array(y), np.array(t))
>
0.5975
예와 같이 정답은 '2'로 첫번째 예에서는 약 10%로 두번째 예에서는 60%로, 첫 번째 예의 손실 함수 쪽 출력이 작으며 정답 레이블과의 오차도 작다. 즉 오차제곱합 기준으로는 첫 번째 추정 결과가 오차가 더 작으니 정답에 더 가까울 것이라 판단할 수 있다.
log는 밑이 e인 자연로그, y는 신경망의 출력, t는 정답 레이블로 정답에 해당하는 인덱스의 원소만 1이고 나머지는 0(원-핫 인코딩)
def cross_entropy_error(y, t):
delta = 1e-7
return -np.sum(t * np.log(y + delta))
# index 2 정답
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
# 예1
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t))
>
0.510825457099338
# 예2
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t))
>
2.302584092994546
delta값을 더한 이유는, np.log() 함수에 0을 입력하면 마이너스 무한대가 되기에, 아주 작은 값을 더하여 0이 되지 않도록(마이너스 무한대가 되지 않도록) 한 것이다.
정답일 경우 첫 번째 예의 오차는 0.51이고 두 번째 예의 오차는 2.3으로, 결과(오차 값)가 '더 작은' 첫 번째 추정이 정답일 가능성이 높다고 판한한다.
예로 MNIST 데이터셋은 훈련 데이터가 60,000개로 모든 데이터를 대상으로 손실 함수의 합을 구하려면 시간이 오래 걸린다. 더 나아가 빅데이터 수준이 되면 그 수는 수백만에서 수천만도 넘는 거대한 값이 된다.
이 많은 데이터를 대상으로 일일이 손실 함수를 계산하는 것은 현실적이지 않을 수 있다. 그래서 데이터 일부를 추려 전체의 '근사치'로 이용할 수 있는데, 신경망 한습 시 훈련 데이터로부터 일부만 골라 학습을 수행한다. 이 일부를 미니배치(mini_batch)라고 한다.
예로 MNIST 60,000장 중에서 100장을 임의로 뽑아서 100장만을 사용하여 학습을 한다.
from tensorflow import keras
mnist = keras.datasets.mnist
(train_x, train_y), (test_x, test_y) = mnist.load_data()
train_x.shape, train_y.shape, test_x.shape, test_y.shape
>
((60000, 28, 28), (60000,), (10000, 28, 28), (10000,))
훈련 데이터는 28*28 데이터가 6만장이고, 정답 레이블은 해당하는 숫자가 6만개인 데이터다.
이중에서 무작위로 100장만 빼내서 사용해보자.
train_size = train_x.shape[0]
batch_size = 100
batch_mask = np.random.choice(train_size, batch_size)
batch_x = train_x[batch_mask]
batch_y = train_y[batch_mask]
신경망 학습에서 최적의 매개변수(가중치와 평향)를 탐색할 때 손실 함수의 값을 가능한 한 작게 하는 매개변수 값을 찾는다. 이때 매개변수의 기울기를 계산하고 그 기울기 값을 단서로 매개변수의 값을 서서히 갱신하는 과정을 반복한다.
매개변수의 손실 함수의 기울기란 '가중치 매개변수의 값을 아주 조금 변화시켰을 때, 손실 함수가 어떻게 변하나'라는 것이다. 만약 이 미분 값이 음수면 그 가중치 매개변수를 양의 방향으로 변화시켜 손실 함수의 값을 줄일 수 있다. 그러나 기울기 값이 0이면 가중치 매개변수를 어느 쪽으로 움직여도 손실 함수의 값은 줄어들지 않게 되어 가중치 매개변수의 갱신은 멈추게 된다.
'정확도'를 지표로 삼아서는 안 되는 이유는 바로 기울기(미분) 값이 대부분의 장소에서 0이 되어 매개변수를 갱신할 수 없기 때문이다.
정확도는 매개변수의 미소한 변화에는 거의 반응을 보이지 않고, 반응이 있더라도 그 값이 불연속적으로 갑자기 변화한다. 이는 활성화 함수로 '계단 함수'를 쓰지 않고 시그모이드 함수를 쓰는 이유와도 들어맞는다.
계단 함수는 한순간만 변화를 일으키지만, 시그모이드 함수의 미분(접선)은 출력이 연속적으로 변하고 곡선의 기울기도 연속적으로 변한다. 즉 시그모이드 함수의 미분은 어느 정소라도 0이 되지는 않는다.
이는 신경망 학습에서 중요한 성질로, 기울기가 0이 되지 않는 덕분에 신경망이 올바르게 학습할 수 있는 것이다.
미분은 '특정 순간'의 변화량을 나타낸다. 즉 미분은 특정 순간 기울기다.
미분하는 계산을 파이썬으로 구현해보자.
def numerical_diff(f, x):
h = 1e-50
return (f(x + h) - f(x)) / h
여기에서 2가지 문제가 있다.
먼저 h를 0에 최대한 가까운 값으로 하기 위해 '1e-50값을 지정하였으나 반올림 오차로 인해 0.0이라는 값을 가지게 된다. 보통은 h값으로 10에 -4승을 이용한다.
두번째는 f의 차분과 관련되어 있다. 특정 순간의 값은 0을 가지지 않기에, 특정 순간의 기울기가 아닌 x+h, x 사이의 기울기다. 그래서 특정 순간에서 (x-h)와 (x+h)일 때의 f 차분을 계산하는 방식을 쓰기도 한다. x를 중심으로 그 전후의 차분을 계산한다는 의미에서 중심 차분 혹은 중앙 차분이라 한다.
def numerical_diff(f, x):
h = 1e-4
return (f(x + h) - f(x - h)) / (2 * h)
변수가 여럿인 함수에 대한 미분을 편미분이라고 한다.
f(x0, x1) = x0^2, x1^2
위 식을 파이썬으로 표현하면 다음과 같다.
def function_2(x):
return x[0]**2 + x[1]**2
f(x0, x1)을 미분하려면 x0와 x1 중 어느 변수에 대한 미분인 것인지 구별해야 한다.
x0은 3, x1은 4일 때, x0과 x1의 편미분을 파이썬으로 표현하면 다음과 같다.
# x0 편미분
def function_1(x0):
return x0 * x0 + 4.0 ** 2.0
numerical_diff(function_1, 3.0)
>
6.00000000000378
# x1 편미분
def function_2(x1):
return 3.0 ** 2.0 + x1 * x1
numerical_diff(function_2, 4.0)
>
7.999999999999119
편미분은 변수가 하나인 미분과 마찬가지로 특정 장소의 기울기를 구한다. 목표 변수 하나에 초점을 맞추고 다른 변수의 값은 고정을 한다.
편미분에서는 x0와 x1을 따로 계산한 반면, 동시에, 한 번에 모든 변수의 편미분을 벡터로 정리한 것을 기울기(gradient)라고 한다.
아래와 같이 기울기는 방향을 가진 벡터(화살표)로 그려진다. 기울기는 함수의 '가장 낮은 장소(최소값)'을 가리키고 있다. 엄밀히 말해서 반드시 가장 낮은 장소를 가리키는 것이 아닌, 각 지점에서의 낮아지는 방향을 가리킨다.
기울기가 가리키는 쪽은 각 장소에서 함수의 출력 값을 가장 크게 줄이는 방향이다.
기계학습에서 최적의 매개변수(가중치와 편향)을 학습 시에 찾아야 한다. 그래서 기울기를 이용하여 함수의 최솟값(가능한 가장 작은 값)을 찾으려는 것이 경사법이다.
주의할 점은 각 지점에서 함수의 값을 낮추는 방안을 제시하는 지표가 기울기라는 것이다. 그러나 기울기가 가리키는 곳에 정말 함수의 최솟값이 있는지, 그 방향이 나아가야 할 방향인지는 보장할 수 없다.
기울어진 방향이 꼭 최솟값은 아니나, 그 방향으로 가야 함수의 값을 줄일 수 있다. 그래서 최솟값이 되는 장소를 찾는 문제에서는 기울기를 단서로 나아갈 방향을 제시하게 된다.
경사법은 현 위치에서 기울어진 방향으로 일정 거리만큼(learning rate) 이동한다. 이동한 곳에서 다시 기울기를 구하고 또 기울어진 방향으로 나아가기를 반복한다. 이렇게 해서 함수의 값을 점차 줄이는 것이 경사법(gradient method)이다.
이동을 할 때 얼마만큼 이동을 해야하는지, 즉 매개변수를 갱신할 때 갱신하는 양을 학습률(learning rate)이라고 한다. 이 값이 너무 크거나(값이 매우 불안정하게 튄다) 너무 작으면(국소적인 지역에 빠져 학습 진행이 안 된다) '좋은 장소(최솟값)'을 찾아갈 수가 없다.
학습률 같은 매개변수를 하이퍼파라미터(hyper parameter, 초매개변수)라고 하며, 사람이 직접 설정해야 한다. 이 하이퍼파라미터들은 여러 후보 값 중에서 시험을 통해 가장 잘 학습하는 값을 찾는 과정을 거친다.
신경망 학습에서도 기울기를 구하는데, 여기서 기울기는 가중치 매개변수에 대한 손실 함수의 기울기다.
형상이 2x3, 가중치가 W, 손실 함수 L인 신경망이 있다. 여기에서 가중치를 변경했을 때 손실 함수 L이 얼마나 변했는지 나타내는 경사(경사의 형상은 2x3인 W와 같다)를 구할 수 있는데, 그 값들은 양수 혹은 음수로 되어 있다. 여기에서 음수는 양의 방향으로 양수는 음의 방향으로 갱신하고 값이 클 수록 갱신되는 데에 크게 기여하게 된다.
신경망에는 적응 가능한 가중치와 편향이 있고, 이 가중치와 편향을 훈련 데이터에 적응하도록 조정하는 과정을 '학습'이라고 한다. 보통 다음과 같이 4단계를 거친다.
tip. 확률적 경사 하강법(SGD : stochastic gradient descent) : 데이터를 미니배치로 무작위로 선정하기에 확률적 경사 하강법이라고 부른다.