Closed eubinecto closed 3 years ago
한번 pre-trained bert로 시도를 해보자.
여전히 bias가 있긴하지만, 랭크에 유의미한 변화가 있긴 있다. 즉 다른 인풋을 넣으면 다른 인풋이 들어가는 것은 맞음.
그동안 dataloader에서 shuffle을 False로 두고 훈련을 해왔었다. 혹시 이게 문제인가? 데이터셋도 contiguous한 것을 고려해보면, 이것이 문제인 것일 수도 있다.
A red fruit | a yellow fruit | the fruit that monkeys love |
---|---|---|
배치 = 전체 훈련셋의 크기로 바꾸면 어떻게 될까? ( 5 * 8) = 40. 그러면 다양성은 100% 보장이 되는거니까.. 일단 한번 이렇게 시도를 해보자.
batch_size = 40, 즉 모든 트레이닝 셋을 하나의 배치로 그냥 다 넣어보았다. 그러면 각 단어별 데이터의 개수가 동일하니, 배치 속의 다양성은 이론적으로는 최대치.
A red fruit | A yellow fruit | The fruit that monkeys love |
---|---|---|
33272071758f1d90035d8a4b26c26359fd511301
def test_forward_dim(self):
# (N, 3, L) -> (N, K, |S|)
S_subword = self.mono_rd.forward(self.X)
self.assertEqual(S_subword.shape[0], self.X.shape[0])
self.assertEqual(S_subword.shape[1], self.mono_rd.hparams['k'])
self.assertEqual(S_subword.shape[2], self.S)
def test_S_word_dim(self):
# (N, 3, L) -> (N, K, |S|)
S_subword = self.mono_rd.forward(self.X)
# (N, K, |S|) -> (N, |V|)
S_word = self.mono_rd.S_word(S_subword)
self.assertEqual(S_word.shape[0], self.X.shape[0])
self.assertEqual(S_word.shape[1], self.V)
def test_training_step_dim(self):
# (N, 3, L) -> scalar
loss = self.mono_rd.training_step((self.X, self.y), 0)
self.assertEqual(len(loss.shape), 0) # should be a scalar
이렇게 dimension만 테스트를 하는 코드를 짜보았는데, 전부 패스한다.
일단, 로스 계산 로직에 큰 문제가 없다는 가정을 해야할 것 같다.
데이터를 더 수집해보았자, 각 과일에 해당하는 정의는 거기서 거기일 것. 그렇다면 그냥 torch.repeat 함수로 데이터를 단순복사해서 upsampling하는 것도 한가지 방법이다.
그런데 솔직히 이게 될까? 클래스 별 불균형이 있는 것도 아니고, 어차피 샘플의 개수만 늘리는 것으로는... 그냥 훈련시간만 길어지는 결과를 초래하는 것 아닐까?
일단 한번 해보자!
GPU를 사용해보려고 했는데, device에 옮기는 작업을 안해서 좀 애먹었다. 새로운 tensor를 만들때 마다, 반드시 X = X.cuda()를 해줘야 한다. 이 패턴 기억하자.
이렇게 그냥 샘플을 늘릴 수 있도록 추가했다.
그리고 cuda() 관련 오류도, 새로운 tensor를 만드는 경우 반드시 cuda()를 호출하는 식으로, 일단 핫픽스를 했다. infer를 할때도 모델을 cuda()로 옮겨야 한다. 3de9798f6656f5979e33823d80ceca286658b2bb
repeat 을 20으로 두고서 학습을 진행함. batch size는 여전히 40으로 고정.
A red fruit | a yellow fruit | The fruit that monkeys love |
---|---|---|
별 달라진 점이 없다.
배치 크기를 늘려보면 어떨까?
repeat = 20, batch = 100으로 해보았다.
크게 변하는 것은 없다. 어쩌면 이 랭크가. 최적의 순서인 것일수도 있다. 로스 함수가 단순히 모든 score를 더하는 것 뿐이니... 도대체 로스가 무엇을 기준으로 최적화되는 것인지 가늠이 가지가 않는다.
현재의 고정된 랭크가 최적의 순서라면, 이건 혹시 underfitting이 문제는 아닐까? 안그래도 eubinecto/learn#7 여기에서 loss가 1.6에서 머무르는 것이 마음에 들지가 않았는데. 그러면 learning rate를 낮추면 해결할수 있지 않을까?
lr: 0.001 -> 0.00001 로 줄여보자!
기존에는 1.59에 머무르던 loss가 (training loss), 이번에는 0.0459까지 내려갔다.
그렇게 얻게된 모델: data/ ├── fruit2def.tsv └── lightning_logs └── version_0 ├── checkpoints │ └── mono_epoch=11_train_loss=0.04.ckpt ├── events.out.tfevents.1624510963.eubinCloud.37272.0 └── hparams.yaml
결과: A red fruit | A yellow fruit | The fruit that monkeys love |
---|---|---|
해결했다아아아아아ㅏ
특히 세번째 쿼리가 흥미롭다. 데이터셋에 바나나에 대한 정의에 monkeys가 언급된 부분은 없었는데, 쿼리로 The fruit that monkeys love를 주니, 해당하는 단어가 바나나일 확률이 70%로 출력된다. 다시한번 반복해도, 똑같은 결과가 나온다 (model.eval()).
역시 기본기가 중요하다. 왜 learning rate를 낮출생각을 못했을까.
하지만 덕분에 별의별 삽질을 다하며 배운게 많다. eubinecto/learn#7 배치 속 다양성이 성능에 영향을 끼친다는 것을 배웠고, eubinecto/learn#7 출력의 차원을 테스트하는 것으로 로직을 간이 테스트할 수 있다는 것을 배웠고, eubinecto/learn#7 파이토치에서 gpu를 사용하기 위해서는 새로운 tensor를 instantiate할 때마다 tensor.cuda()로 gpu에 텐서를 옮겨야한 다는 것 을 배웠고, eubinecto/learn#7 입력에 관계없이 prediction이 거기서 거기라면 underfitting을 의심해야한다는 것도 배웠다. 1.60이 생각보다 큰 로스상태라는 것도 알게되었다.
closing the issue with 2837b67ca697d4c9941a929b3775e51300f18083
The Problem?
어떤 입력이 들어와도, 랭크가 동일하다... 첫번째, 세번째는 출력이 그냥 동일하다.
Analysis
어떤 인풋이 들어오던간에, 순서가 고정이다. 고정인 이유가 무엇인가? 일단, pineapple이 꼴찌인 것을 보면... 분명 데이터에서 무엇인가를 학습한 것은 맞다. 아마 문제는 둘로 나뉘지 않을까 싶다.