밑바닥부터 시작하는 딥러닝 - seq2seq(2)
seq2seq 클래스
이어서 seq2seq 클래스를 구현할 것이다. 이 클래스가 하는 일은 Encoder 클래스와 Decoder 클래스를 연결하고, Time Softmax with Loss 계층을 이용해 손실을 계산하는 것이다.
class seq2seq(BaseModel):
def __init__(self, vocab_size, wordvec_size, hidden_size):
V, D, H = vocab_size, wordvec_size, hidden_size
self.encoder = Encoder(V, D, H)
self.decoder = Decoder(V, D, H)
self.softmax = TimeSoftmaxWithLoss()
self.params = self.encoder.params + self.decoder.params
self.grads = self.encoder.grads + self.decoder.grads
def forward(self, xs, ts):
decoder_xs, decoder_ts = ts[:, :-1], ts[:, 1:]
h = self.encoder.forward(xs)
score = self.decoder.forward(decoder_xs, h)
loss = self.softmax.forward(score, decoder_ts)
return loss
def backward(self, dout = 1):
dout = self.softmax.backward(dout)
dh = self.decoder.backward(dout)
dout = self.encoder.backward(dh)
return dout
def generate(self, xs, start_id, sample_size):
h = self.encoder.forward(xs)
sampled = self.decoder.generate(h, start_id, sample_size)
return sampled
이것이 seq2seq 클래스이다. Encoder 클래스와 Decoder 클래스는 이미 구현되어 있기 때문에 그 기능들을 연결하기만 하면 된다.
seq2seq 평가
Trainer 클래스를 사용해 이 규칙대로 작업을 수행할 것이다. 또한, 매 에폭마다 seq2seq가 테스트 데이터를 풀게 하여 학습 중간중간 정답률을 측정하고자 할 것이다.
그럼 학습 코드를 살펴보자.
# 데이터셋 읽기
(x_train, t_train), (x_test, t_test) = sequence.load_data('addition.txt')
char_to_id, id_to_char = sequence.get_vocab()
# 하이퍼파라미터 설정
vocab_size = len(char_to_id)
wordvec_size = 16
hidden_size = 128
batch_size = 128
max_epoch = 25
max_grad = 1.0
# 모델 / 옵티마이저 / 트레이너 생성
model = seq2seq(vocab_size, wordvec_size, hidden_size)
optimizer = Adam()
trainer = Trainer(model, optimizer)
acc_list = []
for epoch in range(max_epoch):
trainer.fit(x_train, t_train, max_epoch = 1,
batch_size = batch_size, max_grad = max_grad)
correct_num = 0
for i in range(len(x_test)):
question, correct = x_test[[i]], t_test[[i]]
verbose = i < 10
correct_num += eval_seq2seq(model, question, correct,
id_to_char, verbose)
acc = float(correct_num) / len(x_test)
acc_list.append(acc)
print('검증 정확도 %.3f%%' % (acc * 100))
# 그래프 그리기
x = np.arange(len(acc_list))
plt.plot(x, acc_list, marker='o')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.ylim(0, 1.0)
plt.show()
학습이 진행됨에 따라 에폭마다의 정답률을 그린 그래프이다. 이 결과를 보면 seq2seq는 초기에는 정답을 잘 맞히지 못했다. 그러나 학습을 거듭할수록 조금씩 정답에 가까워지면서, 몇 개씩은 맞히기 시작한다.
25에폭에서 중단했지만, 정답률은 약 10% 정도였다. 그래프의 성장 추이를 보면, 학습을 더 거듭하면 더 정확해질 여지가 있어 보인다.
seq2seq 개선
이번에는 학습 속도를 개선해볼 것이다. 총 2가지를 알아볼 예정인데 첫 번째 방법은 입력 데이터 반전(Reverse)이다.
이 트릭을 사용하면 많은 경우 학습 진행이 빨라져, 결과적으로 최종 정확도도 좋아진다고 한다.
그러면 코드를 살펴보자.
x_train, x_test = x_train[:, ::-1], x_test[:, ::-1]
데이터셋을 반전시키기만 하고 학습을 시키면 된다.
입력 데이터를 반전시킨 것만으로 정답률이 약 50%까지 올랐다. 물론, 데이터를 반전시키는 효과는 어떤 문제를 다루느냐에 따라 다르지만, 대부분의 경우 더 좋은 결과로 이어진다.
그렇다면 왜 입력 데이터를 반전시키는 것만으로 학습의 진행이 빨라지고 정확도가 향상되는 걸까?
직관적으로는 기울기 전파가 원활해지기 때문이라고 생각한다.
'딥러닝' 카테고리의 다른 글
밑바닥부터 시작하는 딥러닝 - 어텐션(1) (0) | 2021.11.10 |
---|---|
밑바닥부터 시작하는 딥러닝 - seq2seq(3) (0) | 2021.11.09 |
밑바닥부터 시작하는 딥러닝 - seq2seq(1) (0) | 2021.11.04 |
밑바닥부터 시작하는 딥러닝 - RNN을 사용한 문장 생성 (0) | 2021.11.03 |
밑바닥부터 시작하는 딥러닝 - 게이트가 추가된 RNN(4) (0) | 2021.11.02 |