아래 링크가 시작입니다~
2020/02/06 - [분류 전체보기] - 책(밑바닥부터 시작하는 딥러닝 2)
1.4.1 스파이럴 데이터셋
- spiral: 나선형의 데이터
# import 방식
from google.colab import drive
drive.mount('/content/gdrive')
# %cd Drive/ # 이 부분엔 현재 경로 넣기
from dataset import spiral
import matplotlib.pyplot as plt
x, t = spiral.load_data()
print('x', x.shape) # (300, 2)
print('t', t.shape) # (300, 3)
# 데이터점 플롯
N = 100
CLS_NUM = 3
markers = ['o', 'x', '^']
for i in range(CLS_NUM):
plt.scatter(x[i*N:(i+1)*N, 0], x[i*N:(i+1)*N, 1], s=40, marker=markers[i])
plt.show()
- x가 입력데이터이고, t가 정답 레이블입니다. 참고로 t는 원핫 벡터입니다.
x (300, 2)
t (300, 3)
- 위 그림처럼 입력은 2차원 데이터이고, 분류할 클래스 수는 3개가 있습니다.
- 보다시피 직선만으로는 클래스를 분리 할수 없으므로 비선형 분리를 학습해야합니다.
1.4.2 신경망 구현
- 은닉층이 하나인 신경망 구현
import sys
import numpy as np
from common.layers import Affine, Sigmoid, SoftmaxWithLoss
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size):
I, H, O = input_size, hidden_size, output_size
# 가중치와 편향 초기화
W1 = 0.01 * np.random.randn(I, H)
b1 = np.zeros(H)
W2 = 0.01 * np.random.randn(H, O)
b2 = np.zeros(O)
# 계층 생성
self.layers = [
Affine(W1, b1),
Sigmoid(),
Affine(W2, b2)
]
self.loss_layer = SoftmaxWithLoss()
# 모든 가중치와 기울기를 리스트에 모은다.
self.params, self.grads = [], []
for layer in self.layers:
self.params += layer.params
self.grads += layer.grads
- 위 코드 중 __init__(초기화)메서드는 3개의 인수를 받습니다.
-
input_size : 입력층의 뉴런 수
-
hidden_size : 은닉층의 뉴런 수
-
output_size : 출력층의 뉴런 수
- 우선 편향을 영벡터(zero vector)로 초기화합니다. : np.zeros( )
- 가중치는 작은 무작위 값으로 초기화 합니다. : 0.01 * np.random.randn( )
└ 가중치를 작은 무작위 값으로 설정시 학습이 잘 진행될 가능성이 커집니다.
- 필요한 계층을 생성해 인스턴스 변수인 layers 리스트에 모아둡니다.
- 이 모델에서 사용하는 매개변수들고 기울기들을 하나로 모읍니다.
▶ Softma with loss 계층은 다른 계층과 다르게 취급하여, layers리스트가 아닌 loss_layer 인스턴스 변수에 별도로 저장합니다.
- TwoLayerNet에 3개의 메서드를 구현해 넣습니다.
-
추론을 수행 : predict( )
-
순전파 담당 : forward( )
-
역전파 담당 : backward( )
def predict(self, x):
for layer in self.layers:
x = layer.forward(x)
return x
def forward(self, x, t):
score = self.predict(x)
loss = self.loss_layer.forward(score, t)
return loss
def backward(self, dout=1):
dout = self.loss_layer.backward(dout)
for layer in reversed(self.layers):
dout = layer.backward(dout)
return dout
- 신경망에서 사용하는 처리 블록들을 '계층' 단위로 미리 구현해놨으므로 forward( )화 backward( )를
적절하게 호출만 하면 됩니다.
1.4.3 학습용 코드
import sys
sys.path.append('..') # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
from common.optimizer import SGD
from dataset import spiral
import matplotlib.pyplot as plt
from two_layer_net import TwoLayerNet
# 하이퍼파라미터 설정
max_epoch = 300
batch_size = 30
hidden_size = 10
learning_rate = 1.0
# 데이터 읽기, 모델과 옵티마이저 생성
x, t = spiral.load_data()
model = TwoLayerNet(input_size=2, hidden_size=hidden_size, output_size=3)
optimizer = SGD(lr=learning_rate)
# 학습에 사용하는 변수
data_size = len(x)
max_iters = data_size // batch_size
total_loss = 0
loss_count = 0
loss_list = []
for epoch in range(max_epoch):
# 데이터 뒤섞기
idx = np.random.permutation(data_size)
x = x[idx]
t = t[idx]
for iters in range(max_iters):
batch_x = x[iters*batch_size:(iters+1)*batch_size]
batch_t = t[iters*batch_size:(iters+1)*batch_size]
# 기울기를 구해 매개변수 갱신
loss = model.forward(batch_x, batch_t)
model.backward()
optimizer.update(model.params, model.grads)
total_loss += loss
loss_count += 1
# 정기적으로 학습 경과 출력
if (iters+1) % 10 == 0:
avg_loss = total_loss / loss_count
print('| 에폭 %d | 반복 %d / %d | 손실 %.2f'
% (epoch + 1, iters + 1, max_iters, avg_loss))
loss_list.append(avg_loss)
total_loss, loss_count = 0, 0
- 우선 하이퍼파라미터(hyperparameter)를 설정합니다.
-
학습하는 에폭 수 : max_epoch
-
미니배치 크기 : batch_size
-
은닉층의 뉴런 수 : hidden_size
-
학습률 : learning_rate
- 데이터를 읽어 들이고, 신경망(모델)과 옵티마이저를 생성합니다.
└ 이미 신경망을 TwoLayerNet 클래스로, optimizer를 SGD클래스로 구현해놨습니다.
▶ 에폭(epoch)은 학습 단위입니다.
- 학습은 미니 배치 방식으로 진행되며 데이터를 무작위로 선택합니다.
- 에폭단위로 데이터를 뒤섞고, 뒤섞은 데이터 중 앞에서부터 순서대로 뽑아냅니다.
└ 데이터 뒤섞기 : np.random.permutation( )메서드
- 기울기를 구해 매개변수를 갱신합니다.
- 정기적으로 학습 결과를 출력합니다.
# 학습 결과 플롯
plt.plot(np.arange(len(loss_list)), loss_list, label='train')
plt.xlabel('반복 (x10)')
plt.ylabel('손실')
plt.show()
- 손실이 줄어드는 것을 그래프에서 볼수 있습니다.
- 학습 후 신경망이 어떻게 영역을 분리했는지를 시각화해 봅니다.(이를 결정경계 라고 합니다.)
# 경계 영역 플롯
h = 0.001
x_min, x_max = x[:, 0].min() - .1, x[:, 0].max() + .1
y_min, y_max = x[:, 1].min() - .1, x[:, 1].max() + .1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
X = np.c_[xx.ravel(), yy.ravel()]
score = model.predict(X)
predict_cls = np.argmax(score, axis=1)
Z = predict_cls.reshape(xx.shape)
plt.contourf(xx, yy, Z)
plt.axis('off')
# 데이터점 플롯
x, t = spiral.load_data()
N = 100
CLS_NUM = 3
markers = ['o', 'x', '^']
for i in range(CLS_NUM):
plt.scatter(x[i*N:(i+1)*N, 0], x[i*N:(i+1)*N, 1], s=40, marker=markers[i])
plt.show()
위 그림에서 보듯 학습된 신경망은 '나선형' 패턴을 올바르게 파악했음을 알 수 있습니다.
1.4.4 Trainer 클래스
- Trainer클래스 : 학습을 수행하는 역할
Trainer클래스는 trainer.py에 학습용 코드를 맡겼습니다.
Trainer 클래스의 초기화 메서드는 신경망(모델)과 옵티마이저를 인수로 받습니다.
model = TwoLayerNet(...)
optimizer = SGD(lr=1.0)
trainer = Trainer(model, optimizer)
Trainer 클래스의 fit( ) 메서드가 받는 인수: '(=XX)'는 기본값을 뜻함
인수 | 설명 |
x | 입력 데이터 |
t | 정답 레이블 |
max_epoch(=10) | 학습을 수행하는 에폭 수 |
batch_size(=32) | 미니배치 크기 |
eval_interval(=20) | 결과(평균 손실 등)를 출력하는 간격 |
eval_interval=20으로 설정하면, 20번째 반복마다 손실의 평균을 구해 화면에 출력한다. | |
max_grad(=None) | 기울기 최대 노름norm |
기울기 노름이 이 값을 넘어서면 기울기를 줄인다. (이를 기울기 클리핑이라 한다.) |
Trainer 클래스는 plot( )메서드도 제공합니다. 이 메서드는 fit( )에서 기록한 손실을 그래프로 그려줍니다.
import sys
sys.path.append('..') # 부모 디렉터리의 파일을 가져올 수 있도록 설정
from common.optimizer import SGD
from common.trainer import Trainer
from dataset import spiral
from two_layer_net import TwoLayerNet
# 하이퍼파라미터 설정
max_epoch = 300
batch_size = 30
hidden_size = 10
learning_rate = 1.0
x, t = spiral.load_data()
model = TwoLayerNet(input_size=2, hidden_size=hidden_size, output_size=3)
optimizer = SGD(lr=learning_rate)
trainer = Trainer(model, optimizer)
trainer.fit(x, t, max_epoch, batch_size, eval_interval=10)
trainer.plot()
학습용 코드를 Trainer 클래스에 맡겼기 때문에 코드가 깔끔해질 수 있습니다.
1.5 계산 고속화
신경망에서는 얼마나 빠르게 계산 하느냐가 매우 중요한 주제이므로 신경망 고속화에 도움 되는
'비트 정밀도'와 'GPU'에 관해 나와있습니다.
1.5.1 비트정밀도
* numpy의 부동소수점 수는 기본적으로 64 비트데이터 타입을 사용합니다.
import numpy as np
a = np.random.randn(3)
a.dtype
위 코드로 확인 할 수 있습니다.
* numpy에서는 추론과 학습을 32비트 부동소수점 수로도 문제없이 수행 할 수 있습니다.
이에 신경망 계산 시 데이터를 전송하는 '버스 대역폭'이 병목이 되는 경우도 있어서 데이터 타입을 작게하고 계산
속도 측면에서도 빠르기 때문에 32비트 부동소수점 수를 이 책에서는 우선으로 사용합니다.
b = np.random.randn(3).astype(np.float32)
c = np.random.randn(3).astype('f')
b.dtype, c.dtype
→ (dtype('float32'), dtype('float32'))
위 코드로 부동소수점을 변경할 수 있습니다.
'Deep learning > Computer vision(영상처리)' 카테고리의 다른 글
책(밑바닥부터 시작하는 딥러닝 2) 4 (0) | 2020.02.13 |
---|---|
BoW(이미지관련) (0) | 2020.02.12 |
GAN(이론) (0) | 2020.02.12 |
책(밑바닥부터 시작하는 딥러닝 2) 3 (0) | 2020.02.11 |
책(밑바닥부터 시작하는 딥러닝 2) (0) | 2020.02.06 |