1. 신경망 학습 절차
- 신경망에는 적응 가능한 가중치와 편향이 있다.
- 가중치와 편향을 훈련 데이터에 적응하도록 조정하는 과정을 학습이라고 한다.
- 신경망 학습은 다음과 같이 4단계로 수행한다.
- 미니배치
- 훈련 데이터 중 일부를 무작위로 가져온다.
- 이렇게 선별한 데이터를 미니배치라 하며, 미니배치의 손실 함수 값을 줄이는 것이 목표
- 기울기 산출
- 미니배치의 손실 함수 값을 줄이기 위해 각 가중치 매개변수의 기울기를 구한다.
- 기울기는 손실 함수의 값을 가장 작게 하는 방향을 제시한다.
- 매개변수 갱신
- 가중치 매개변수를 기울기 방향으로 아주 조금 갱신한다.
- 반복
- 1 ~ 3단계를 반복한다.
2. 2층 신경망 클래스 구현
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
# 가중치 초기화
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
return y
# x : 입력 데이터, t : 정답 레이블
def loss(self, x, t):
y = self.predict(x)
return cross_entropy_error(y, t)
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
# x : 입력 데이터, t : 정답 레이블
def numerical_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
grads = {}
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
TwoLayerNet 클래스의 변수
- params : 신경망의 매개변수를 보관하는 딕셔너리(인스턴스 변수)
- params['W1']은 1번째 층의 가중치
- parmas['b1']은 1번째 층의 편향
- grads : 기울기를 보관하는 딕셔너리(numerical_gradient() 메서드의 반환 값)
- grads['W1']은 1번째 층의 가중치의 기울기
- grads['b1']은 1번째 층의 편향의 기울기
- grads['W1']은 1번째 층의 가중치의 기울기
- params : 신경망의 매개변수를 보관하는 딕셔너리(인스턴스 변수)
TwoLayerNet 클래스가 사용하는 메서드
- predict(self, x) : 예측을 수행한다. 인수 x는 이미지 데이터
- loss(self, x, t) : 손실 함수의 값을 구한다. 인수 x는 이미지 데이터, t는 정답 레이블
- accuracy(self, x, t) : 정확도를 구한다.
- numerical_gradient(self, x, t) : 가중치 매개변수의 기울기를 구한다.
2.1. 미니배치 학습 구현
- TwoLayerNet 클래스와 MNIST 데이터셋을 사용하여 미니배치 학습을 수행해보자
from dataset.mnist import load_mnist # MNIST 데이터 불러오기 (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True) network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10) # 하이퍼파라미터 iters_num = 1000 # 반복 횟수를 적절히 설정한다. train_size = x_train.shape[0] batch_size = 100 # 미니배치 크기 learning_rate = 0.1 train_loss_list = [] for i in range(iters_num): # 미니배치 획득 batch_mask = np.random.choice(train_size, batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] # 기울기 계산 grad = network.numerical_gradient(x_batch, t_batch) # 매개변수 갱신 for key in ('W1', 'b1', 'W2', 'b2'): network.params[key] -= learning_rate * grad[key] # 학습 경과 기록 loss = network.loss(x_batch, t_batch) train_loss_list.append(loss)
- 위 코드에서는 미니배치 크기를 100으로 했다. 즉, 매번 60,000개의 훈련 데이터에서 임의의 100개 데이터를 추려낸다.
- 그 100개의 미니배치를 대상으로 확률적 경사 하강법을 수행해 매개변수를 갱신
- 경사법에 의한 갱신 횟수를 10,000번으로 설정하고, 갱신할 때 마다 훈련 데이터에 대한 손실 함수를 계산하고, 그 값을 배열에 추가한다.
import matplotlib.pyplot as plt
plt.plot(train_loss_list)
plt.xlabel('Iteration')
plt.ylabel('Loss')
plt.title('Training Loss over Iterations')
plt.show()
- 손실 함수의 변화를 그래프로 나타내보았다.
2.2. 시험 데이터로 평가하기
- 학습을 반복함을써 손실 함수의 값이 서서히 내려가는 것을 확인해보았다.
- 이때의 손실 함수의 값은 정확히는 '훈련 데이터의 미니배치에 대한 손실 함수'의 값이다.
- 훈련 데이터의 손실 함수 값이 작아지는 것은 신경망이 잘 학습하고 있다는 방증이지만, 이 결과만으로는 다른 데이터셋에도 비슷한 실력을 발휘할지는 확실하지 않다.
- 신경망 학습에서는 훈련 데이터 외의 데이터를 올바르게 인식하는지를 확인해야 한다.
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
# 하이퍼파라미터
iters_num = 1000 # 반복 횟수를 적절히 설정한다.
train_size = x_train.shape[0]
batch_size = 100 # 미니배치 크기
learning_rate = 0.1
train_loss_list = []
train_acc_list = []
test_acc_list = []
# 1에폭당 반복 수
iter_per_epoch = max(train_size / batch_size, 1)
for i in range(iters_num):
# 미니배치 획득
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 기울기 계산
grad = network.numerical_gradient(x_batch, t_batch)
# 매개변수 갱신
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
# 학습 경과 기록
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
# 1에폭당 정확도 계산
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
# 그래프 그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
- 위 코드에서는 1에폭마다 모든 훈련 데이터와 시험 데이터에 대한 정확도를 계산하고, 그 결과를 기록한다.
- 정확도를 1에폭마다 계산하는 이유는 for 문 안에서 매변 계산하기에는 시간이 오래 걸리고, 자주 기록할 필요도 없기 때문
- 그래프에서 훈련 데이터에 대한 정확도는 실선, 시험 데이터에 대한 정확도는 점선으로 그려보았다.
- 학습이 진행될수록 훈련 데이터와 시험 데이터 모두 정확도가 좋아지고 있다.
- 또, 두 정확도 사이에 차이가 없을을 알 수 있다.
- 다시 말해 이번 학습에서는 오버피팅이 일어나지 않았음을 알 수 있다.
3. 정리
- 머신러닝에서 사용하는 데이터셋은 훈련 데이터와 시험 데이터로 나눠 사용한다.
- 훈련 데이터로 학습한 모델의 범용 능력을 시험 데이터로 평가한다.
- 신경망 학습은 손실 함수를 지표로, 손실 함수의 값이 작아지는 방향으로 가중치 매개변수를 갱신한다.
- 가중치 매개변수를 진행할 때는 가중치 매개변수의 기울기를 이용하고, 기울어진 방향으로 가중치의 값을 갱신하는 작업을 반복한다.
- 아주 작은 값을 주었을 때의 차분으로 미분하는 것을 수치 미분이라고 한다.
- 수치 미분을 이용해 가중치 매개변수의 기울기를 구할 수 있다.
'TIL > 밑바닥부터 시작하는 딥러닝' 카테고리의 다른 글
계산그래프 신경망에 적용하기(ReLU, Sigmoid) (0) | 2024.06.28 |
---|---|
계산그래프 (0) | 2024.06.27 |
경사법 (1) | 2024.06.16 |
손실 함수 (1) | 2024.06.15 |
소프트맥스 함수 (0) | 2024.06.15 |