DQN을 돌려보기는 했지만, 사실 이게 제대로 작동하고 있는지에 대해서는 계속 의문이 들었습니다. 그래서 DQN이 제대로 작동하고 있는지를 확실히 파악해보자라는 생각에서 이번 포스팅을 작성하게 되었습니다.
저번에 어느 정도 학습이 되었다고 생각한 건 monkey investor에 비해서 대체로 높은 score를 기록했기 때문에 학습이 되었다고 생각했지만, 사실 그것만 가지고는 제대로 training 된 건지 알 수가 없었습니다. 따라서 보다 객관적으로 분석할 수 있는 방법이 필요했습니다.
Atari 게임들과 같이 score가 정확히 구해지는 Problem들과는 다르게, 저번에 만든 DQN을 Evaluate하는 데에는 여러 가지 어려움이 따릅니다.
가장 큰 문제점은, 바로 training이 되는 Problem인지 아닌지조차 알 수 없다는 것입니다. 일반적인 Problem의 경우 높은 score를 기록하면 training 완료, 낮은 score를 기록하면 training이 되지 않았다고 판단할 수 있습니다. 저는 Close Price만으로 구성할 수 있는 최선의 DQN을 기대했습니다. 그러나, score가 흥미로운 결과를 가져다주지 못했고, 따라서 지금의 DQN이 최선인지 아닌지, 코드 에러가 있었는지를 확인하기가 힘듭니다. 비단 Finance Data에만 국한되는 문제는 아니지만, Finance Data를 분석할 때면 항상 느끼는 어려움입니다.
또한 저번에 서술했던 것처럼 Environment class, 등등부터 해서 손으로 작성한 코드 길이도 길고 혼자 작업하는 거다 보니까 실수의 가능성이 높다는 문제점도 있더라구요.. (코딩을 아직 잘 못하나봅니다...하하ㅠ)
무튼! DQN이 제대로 작동하는지를 좀 확인하고 싶어서 이 포스팅을 쓰게 되었습니다.
결론적으로는 제대로 작동하지 않는 것 같아요. 한 번 이유를 확인해봅시다.
DQN을 training할 때 loss function을 다음과 같이 잡았습니다.
[ (Target Network의 output 값 * discount rate + reward) - Pred Network의 output 값 ]^2
으로 잡았습니다. 이렇게 training을 계속하게 되면, 결국 Pred Network는 현재 state에서의 action에 따른 기대 reward를 도출하는 방향으로 수렴해야 합니다. 간단하게 묘사해보자면
[30개 Close Price + money + position] -> NN ->
-> [Long의 expected reward / Hold의 expected reward / Short의 expected reward]
가 되겠네요. 그런고로, 제 NN은 reward를 그닥 많이 가져가지 못하기 때문에 어떤 state를 넣었을 때 기대되는 reward는 그와 유사해야 합니다. 한 번 살펴보죠.
NN의 output을 도출해보았더니 각각 100만이 넘네요. 이렇게 많이 벌었을리가 없는데 말이죠. 혹시나 해서 replaymemory에 있는 reward 값을 모두 더해보았습니다. memory size를 100만으로 두었는데, reward sum은 -434만입니다. 한 번의 trading당 기대 이익은 -4원 정도네요. 분명 history에 있는 experience를 대상으로 training을 시켰으니, 기대 reward는 0에 가까워야 정상인데 말입니다. 뿐만 아니라, 해당 주식을 하루에 한 번씩 매매하도록 설정해 놓았으니 reward의 크기는 해당 주식의 1주 가격에 영향을 매우 많이 받게 됩니다. 같은 금액만큼을 투자한 것이 아니라, 주식의 수량을 바탕으로 매매하도록 하였으니 아무래도 그렇겠죠. 그런데 2000원짜리 주식을 거래할 때랑 20만원짜리 주식을 거래할 때랑 기대되는 reward에는 큰 차이가 없습니다. 원래대로라면 100배가량 차이가 나야 마땅한데, 2배 정도밖에 차이가 나지 않는 걸 보면 확실히 문제가 있다는 생각이 들었습니다.
분명 오류가 있는데, 이 오류는 도대체 어디서 발생한 건지 알아보고자 몇 가지 실험을 하려고 합니다.
1. DQN 자체에 오류가 있을 경우
코드 오류라던지 알고리즘 실수를 했다던지 등의 이유로 DQN이 애초에 작동하지 않는 DQN일지도 모릅니다. 따라서 이 경우를 배제하기 위해 간단한 Data를 통해서 한 번 DQN의 작동 여부를 테스트해보겠습니다.
Data를 31개의 무작위 0~1까지의 float로 잡았습니다. 만약 31개의 합이 16보다 낮으면 short에 reward 1을 주고, long에 reward -1, hold에는 reward 0를 주겠습니다. 반대로 16보다 크면 long에 reward 1을 주고, short에 reward -1을 주겠습니다. 마지막에는 terminal을 넣어서 데이터에 포함시켜보겠습니다. 데이터를 10000개를 구성해서 그 데이터를 대상으로 한 번 training을 시켜보겠습니다.
위의 그림에서 sum은 제가 정한 규칙대로 31개의 합을 나타낸 것입니다. 16보다 낮으면 short를 해야 하므로 가장 앞의 것이 가장 reward가 높은 것이 맞고, 가장 뒤가 reward가 낮은 것이 맞습니다. 17.92~를 보면 반대로 마지막이 가장 높은 것을 볼 수 있습니다.
음 action의 경향성 자체는 맞는데 reward가 기대한 대로 나오지는 않네요. terminal까지 한참 남은 상황이라 기대 reward는 높아야 하는데 그렇지 않습니다. 아마 action의 선택을 random하게 설정해놔서 발생하는 문제인 것 같습니다. random하게 action을 취하기 때문에 미래의 에피소드를 겪으면서 더 reward를 얻어갈 수 없기 때문입니다. 따라서 action을 epsilon-greedy하게 선택하도록 바꿔서 다시 test를 해보도록 하겠습니다.
epsilon-greedy를 추가하고 나니 아까와는 다르게 올랐네요. 그런데 왜 16.11과 16.04에서는 short의 reward가 더 높게 나올까요? 제 추측으로는 아마 31개 random.random 대상으로 sum이 16보다 높은지 낮은지를 추렸기 때문에 실제로는 short를 하는 경우가 더 많이 등장할 것입니다. 따라서 아마 그런 이유 때문에 16~16.2내지 16.3정도까지는 short의 reward가 높게 나오는 게 맞는 것처럼 NN이 착각한 것 같습니다. 또 의문점은 60번의 모든 상황에서 제대로 행동했다면 60의 reward를 받는 게 맞을 텐데, 저기에서는 18정도밖에 획득하지 못했는가입니다. 이것도 제 추측이지만, epsilon-greedy하게 움직이는 과정 동안 random하게 움직인 data들이 memory안에 쌓였고, experience-replay하는 과정에 따라 memory에서 random하게 샘플을 추출할 때 그러한 data들도 같이 훈련되어서 혼선을 준 것 같습니다. 아마 16근방에서 short가 우세하게 나오는 error도 reward가 작게 나오는 데 영향을 줬을 테고, epsilon의 최저값 또한 0.1로 잡았기 때문에 그러한 영향도 분명히 있을 것 같습니다. training time을 늘려봐도 성능이 좋아지지는 않네요. 이건 좀 더 생각해봐야 겠습니다. 그리고 값이 이쁘게 나오려면 hold의 경우가 long과 short의 평균값 정도여야 하는데 오히려 그렇지도 않게 나오는 것 같습니다.
여기서 발생한 문제점을 해결하지 못하면 아마 뉴럴넷에 문제가 있을 확률이 높기 때문에, 조금 더 점검해봐야겠습니다. 음 뉴럴넷의 size를 한참 줄이고 트레이닝을 돌리고 있는데도 불구하고, 학습이 잘 되지 않는 모습을 보입니다. initial setting에 영향을 받는 듯 합니다.
DQN training에 대해서 조금 더 공부해봐야 할 것 같습니다.
내일 다시 끄적여보도록 할게요...
댓글 없음:
댓글 쓰기