티스토리 뷰
신경망 학습에서 가중치 설정은 중요합니다. 가중치를 엉뚱한 값으로 잡는 순간 학습은 훈련데이터에만 맞는 오버피팅이 일어날 것입니다.
가중치 감소 기법은 가중치 매개변수의 값이 작아지도록 학습하는 방법입니다. 가중치 값을 작아지도록 설정하여 오버피팅을 방지합니다.
가중치를 모든 층에서 같은 값으로 잡는다면, 오차역전파법에서 모든 가중치 값이 똑같은 값으로 전달됩니다. 예를 들어, 2층 신경망에서 1층의 가중치가 모두 같은 값이라면, 1층의 입력값에 상관없이 2층에 가중치가 같은 값이 전달됩니다.
이를 막기 위하여 가중치는 층마다 랜덤한 값으로 골라야하며, 이 가중치는 정규분포 N(0,1)에 적당한 표준편차를 고르면 됩니다. 이를 이용하여 각 층의 활성화 함수 값이 고르게 분포되어야합니다.
잘 알려진 가중치 초기값 설정은 다음과 같습니다. (모범 사례)
1. 활성화 함수가 sigmoid, tanh일 때 => Xavier 초기값 : 표준편차가 1/(n**0.5) 인 정규분포로 가중치 초기화 (n: 직전 층의 노드 수)
2. 활성화 함수가 ReLU일 때 => HE 초기값 : 표준편차가 2/(n**0.5) 인 정규분포로 가중치 초기화 (n: 직전 층의 노드 수)
for i in range(hidden_layer_size):
if i!=0:
x = activations[i-1]
# w = np.random.randn(node_num, node_num) * 0.01 # 표준편차 0.01
# w = np.random.randn(node_num, node_num) * (1 / np.sqrt(node_num)) # Xavier 초기값, 표준편차 = sqrt(앞 층 노드)
w = np.random.randn(node_num, node_num) * (2 / np.sqrt(node_num)) # HE 초기값, ReLU일 때 적합
a = np.dot(x, w)
# z = sigmoid(a)
# z = tanh(a)
z = ReLU(a)
activations[i] = z
MNIST 데이터셋을 이용해 가중치 초기값을 어떻게 설정하는지에 따라 매개변수의 손실함수 값이 어떻게 변하는지 알아보겠습니다. 손실함수 값을 최소화하는 것이 목표입니다.
층별 노드가 100개, 은닉층이 4개인 신경망으로 구성하고, 활성화함수는 ReLU를 사용하겠습니다. 그리고 매개변수 최적화는 SGD를 이용하였습니다.
import os, sys
sys.path.append(os.pardir)
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.util import smooth_curve
from common.multi_layer_net import MultiLayerNet
from common.optimizer import SGD
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000
weight_init_types = {'std=0.01':0.01, 'Xavier':'sigmoid', 'He':'relu'}
optimizer = SGD(lr=0.01)
networks = {}
train_loss = {}
for key, weight_type in weight_init_types.items():
networks[key] = MultiLayerNet(input_size=784, hidden_size_list=[100,100,100,100],
output_size=10, weight_init_std=weight_type)
train_loss[key] = []
for i in range(max_iterations):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
for key in weight_init_types.keys():
grads = networks[key].gradient(x_batch, t_batch)
optimizer.update(networks[key].params, grads)
loss = networks[key].loss(x_batch, t_batch)
train_loss[key].append(loss)
markers = {'std=0.01':'o', 'Xavier':'s', 'He':'D'}
x = np.arange(max_iterations)
for key in weight_init_types.keys():
plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.legend()
plt.show()
보다시피 std=0.01 (표준편차 0.01)로 잡은 경우 거의 손실함수 값이 감소되지 않고, ReLU를 활성화함수로 사용하였으므로, HE 초기값이 가장 좋은 손실함수의 최소화를 나타내는 것을 알 수 있습니다.