Q-learning 이랑 action-value function 값을 업데이트 해주면서 가장 나은 action을 취해주는 알고리즘이다. 예전 포스트 보면 Gridworld와 Frozenlake 에 적용한 알고리즘인 Q-Table을 작성하여 action을 취하는 이론을 정리할 것이다.


 action value function을 Q-Table로 작성하여 푸는 방법을 Tabular Methods라고 한다. 서튼 교수님 책에서는 이 Tabular Methods를 state 나 action이 작을때만 적용 가능 하다고 한다. 왜냐하면 각각의 state에 action마다 Q값을 넣어줘야 하기 때문이다. 그래서 실제 환경이나 실생활, 혹은 연속적인 환경에서는 적용을 할 수 없다.


 OpenAI Gym 에 있는 FrozenLake-v0 의 Environment 이다. agent가 있을 수 있는 state가 총 16개 밖에 되지 않고, action 또한 4개밖에 되지 않기 때문에 Q-table을 이용하여 학습을 할것이다.


 간단하게 FrozenLake Environment에 대해 설명하겠다. 

 agent, 즉 action을 당할 놈은 초록색에서 시작을 해서 저기있는 노란색 위치까지 가야한다. 중간에 파란색 부분은 빠지면 게임이 끝나버리는 구멍이라고 보면 된다. Environment에서는 action값을 입력해주면 그에 맞는 Next_state, reward, done, info를 리턴해준다. 여기서 Next_state는 action을 통해 움직여서 바뀐 state라고 보면 된다. reward는 그 action을 했을때 주는 보상값이고 done은 이 환경이 끝났는지 안끝났는지를 알려주는 boolean 값이다. info는 기타 추가 정보를 가져와준다. 여기서 done이 일어날 state는 각각의 파란색 구멍과 도착지점인 노란색 부분이다. 이 Env에서는 목표 지점이 아닌 곳으로 움직이면 reward를 0을 주고 목표지점에 도착하면 reward 1 을 준다.



 이제 움직이면서 학습을 해보자!

 agent가 움직일때는 먼저 어디로 가야 가장 reward를 높게 받을 수 있는지 판단을 해야한다. 그것이 Q-Learning의 핵심이다. 가장 reward를 많이 받을 수 있는 action을 취해야하는데, 이때 다음 state에서 가장 높게 받을 수 있는 reward 까지 생각을 해야하기때문에 Q 값을 업데이트 하려면 다음 상태의 Q값도 알아야 한다.

정리해보자면 

1. agent 는 state s에 있다.

2. agent가 action 를 했을 때, reward r을 받고 state s'로 움직인다.

3. 그러면 Q(s',a')도 존재 할 것이다

라고 가정을 해놓고 해야한다.


 이것으로 Q(s,a)를 표현하면 Q(s, a)= r + max Q(s',a') 이다. 이해 안가는 분들을 위해 다시 정리하자면

현재 상태에서 action a 의 Q값은 그 action a를 했을 때의 reward값과 다음 stats s'에서 가장 많이 받을 수 있는 Q값을 더해준다. 

역시 글보다는 그림이다. 위에 Q-table을 보자.


 agent의 위치, 각각의 state는 0~15로 표현하겠다.

아직 Q-table 이 하나도 업데이트 되지 않은 상황이라 agent는 현재 Q값을 통해 action을 구할 수 없다. 구할 수 없다기보다는 모두 Q값이 0으로 같기 때문에 agent 입장에서는 모두 다 가치가 같은 행동이다. 그렇기 때문에 값이 같을 때는 랜덤으로 여기저기 움직인다고 정책을 정하자.

(0)에 있는 agent가 오른쪽으로 움직여서 (1)로 갔다고 하자. 그러면 움직이면서  Q(s, a)= r + max Q(s',a') 이 식을 이용하여 Q값을 업데이트 해야한다. 그럼 Q(0,오른쪽 a) = 0 + 0 이다. 무슨말인지 이해가 안갈 수 있다. 


 첫번째 값 0은 action을 취했을 때 받는 reward r값이다. 위에 Environment 설명을 할때 목표지점을 제외한 모든 state에서는 0을 준다고 했기 때문에 0이고, 

 두번째 값0은 다음 state에서 가장 크게 받을 수 있는 reward 값이다. 하지만 여기서는 아직 하나도 Q-table이 업데이트 되지 않았기 때문에 Q(1,a)들의 값들은 모두 0이다. 그렇기 때문에 가장 큰 값은 0이 되는 것이고 결국 Q(0,오른쪽 a) = 0 + 0 이 되는 것이다.


여기까지 보면 대충 짐작이 갈 것이다. 아무리 움직여봤자 Q-table은 업데이트 되지 않는다. 단, 목표지점을 도착하기 전까지 말이다.


다음편에서는 목표지점에 도착했을때 비로소 어떻게 Q-table이 업데이트 되는지 알아볼 것이다.


저번 포스트에서는 절차지향형 코딩을 했지만


앞으로 여러개의 네트워크를 사용하는 DQN을 사용해야하기 때문에 객체지향형 코드로 바꿔봤다.


원래 내가 했던 코드대로 deque()대신 list를 사용했고 minibatch에서 스택을 사용하는 대신에 바로바로 값을 업데이트 하였다.



클래스를 사용하여 해야하는데 아직 객체지향에 익숙하지 않아서 그냥 절차지향식으로 코딩을 해버렸다.


위와 같은 알고리즘을 사용했다.


아마 그대로 알고리즘과 똑같이 보면 될거같다.


1. 리플레이를 저장할 수 있는 리플레이 메모리와 네트워크를 구성하고


2. state를 초기화하고 전처리를 해준다(이 코드에서 전처리는 state 값을 2차 배열로 만들어 주는 것이다)


3. 한 개의 에피소드를 시작하고 e-greedy 으로 랜덤하게 action을 선택하거나 Q-value 값(Weight를 이용한)으로 action을 선택하여 실행한다.


4. action을 통한 reward와 다음 state를 받는다.


5. 위 받은 값들(state, action, reward, next_state, done)을 메모리에 저장한다.


6. 저장된 메모리의 값들 중에 몇 개를 가져와서 미니배치로 학습을 한다.


7. 위 과정을 반복한다.


로 보면 된다.


Replay memory를 사용하는 이유는 Linear Regression을 하는데 있어서, 전체적인 값으로 학습을 못하고 근처에있는 값으로 학습이 되기때문에 전체적인 분포의 Linear Regression을 할 수 없다. 그래서 일정 step 만큼의 값을 저장해두었다가 랜덤으로 값을 뽑아내면 전체적인 값을 학습할 수 있다.



+ Recent posts