728x90
반응형
가중치의 초깃값
- 신경망 학습에서 특히 중요한 것이 가중치의 초깃값
초깃값 0으로 할시
- 오버피팅을 억제해 범용 성능을 높이는 테크닉인 가중치 감소(weight decay) 기법
가중치 감소(weight decay)
- 가중치 매개변수의 값이 작아지도록 학습하는 방법
- 가중치 값을 작게 해서 오버피팅이 일어나지 않게 하는 방법
가중치 초깃값 0 설정
- 매우 나쁜 아이디어
- 가중치 초깃값 0으로 할시 학습이 올바르게 이루어지지 않는다.
- 가중치를 균일한 값으로 설정해서는 안된다.
- 오차역전파법에서 모든 가중치의 값이 똑같이 갱신되기 때문이다.
- 순전파 때 입력층 가중치 0이기 때문에 두 번째 층의 뉴런에 모두 같은 값이 전달된다. 모든 뉴런에 같은 값이 입력된다는 것은 역전파 때 두 번째 층의 가중치가 모두 똑같이 갱신된다는 말이 된다.
은닉층의 활성화값 분포
- 은닉층의 활성화값(활성화 함수의 출력 데이터)*의 분포를 관찰하면 중요한 정보를 얻을 수 있다.
# coding: utf-8
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def ReLU(x):
return np.maximum(0, x)
def tanh(x):
return np.tanh(x)
input_data = np.random.randn(1000, 100) # 1000개의 데이터
node_num = 100 # 각 은닉층의 노드(뉴런) 수
hidden_layer_size = 5 # 은닉층이 5개
activations = {} # 이곳에 활성화 결과를 저장
x = input_data
for i in range(hidden_layer_size):
if i != 0:
x = activations[i-1]
# 초깃값을 다양하게 바꿔가며 실험해보자!
w = np.random.randn(node_num, node_num) * 1
#w = np.random.randn(node_num, node_num) * 0.01
#w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)
#w = np.random.randn(node_num, node_num) * np.sqrt(2.0 / node_num)
a = np.dot(x, w)
# 활성화 함수도 바꿔가며 실험해보자!
z = sigmoid(a)
#z = ReLU(a)
#z = tanh(a)
activations[i] = z
# 히스토그램 그리기
for i, a in activations.items():
plt.subplot(1, len(activations), i+1)
plt.title(str(i+1) + "-layer")
if i != 0: plt.yticks([], [])
# plt.xlim(0.1, 1)
# plt.ylim(0, 7000)
plt.hist(a.flatten(), 30, range=(0,1))
plt.show()
- 시그모이드 함수는 출력이 0에 가까워지거나 또는 1에 가까워지면 그 미분은 0에 다가간다. 그래서 데이터가 0과 1에 치우쳐 분포하게 되면 역전파의 기울기 값이 점점 작아지다가 사라진다.
- 이것이 기울기 소실(gradient vanishing)이라 알려진 문제다.
가중치 초기값 설정 부분 변경
w = np.random.randn(node_num, node_num) * 0.01
- 0.5 부근에 집중
- 0,1 치우치진 않았으므로 기울기 소실 문제는 일어나지 않았지만, 활성화값들이 치우쳤다는 것은 표현력 관점에서 큰 문제가 있는 것이다.
- 다수의 뉴런이 거의 같은 값을 출력하고 있으니 뉴런을 여러 개 둔 의미가 없어진다는 뜻이다.
- 뉴런 100개가 거의 같은 값을 출력 시 뉴런 1개짜리와 별반 다를게 없다는 의미
사비에르 글로로트(Xavier Glorot)와 오슈아 벤지오(Yoshua Bengio)의 논문에서 권장하는 가중치 초기값 - Xavier 초기값 사용
- Xavier 초기값 사용시 앞 층에 노드가 많을수록 대상 노드의 초기값으로 설정하는 가중치가 좁게 퍼진다.
w = np.random.randn(node_num, node_num) * np.sqrt(1.0 / node_num)
ReLU 사용시 가중치 초기값
- Xavier 초기값은 활성화 함수가 선형인 것을 전제로 이끈 결과다.
- sigmoid 함수와 tanh함수는 좌우 대칭이라 중앙 부근이 선형인 함수라고 볼 수 있다.
- ReLU이용시 ReLU에 특화된 초깃값 이용하라고 권장
- 카이밍 히(Kaiming He)의 이름을 따 He 초깃값
- H2 초깃값은 앞 계층의 노드가 n개일 때, 표준편차가 루트2/n인 정규분포 사용
- std=0.01은 매우 작은 값이다. 신경망에 아주 작은 데이터가 흐른다는 것은 역전파 때 가중치의 기울기 역시 작아진다는 뜻이다.
- Xavier 초깃값 결과는 층이 깊어지면서 치우침이 조금씩 커진다. - '기울기 소실'문제 일으킴
- He 초깃값은 모든 층에서 균일하게 분포, 분포가 균일하므로 역전파때도 적절한 값이 나올 것으로 기대할 수 있다.
MNIST 데이터셋으로 가중치 초깃값 비교
# coding: utf-8
import os
import sys
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
import matplotlib.pyplot as plt
from mnist import load_mnist
from util import smooth_curve
from multi_layer_net import MultiLayerNet
from optimizer import SGD
# 0. MNIST 데이터 읽기==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000
# 1. 실험용 설정==========
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] = []
# 2. 훈련 시작==========
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)
if i % 100 == 0:
print("===========" + "iteration:" + str(i) + "===========")
for key in weight_init_types.keys():
loss = networks[key].loss(x_batch, t_batch)
print(key + ":" + str(loss))
# 3. 그래프 그리기==========
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.ylim(0, 2.5)
plt.legend()
plt.show()
출처 : 밑바닥부터 시작하는 딥러닝
https://www.hanbit.co.kr/store/books/look.php?p_code=B8475831198
728x90
반응형
최근댓글