sung kim 교수님 말대로 hole에 빠졌을때 -1 인 reward를 주지 않는 방향으로 생각해봤다.


아예 처음부터 싹 지우고 Q-Learning 알고리즘 그대로 이용해서 작성해보기로 했다.


(이번에는 미끄러짐 옵션도 켜둔 상태로)



이런 알고리즘이다.


진짜 이 알고리즘 그대로 구현한 코드가 이것이다.


이대로 모니터링을 하고 레코드를 하여 openAI gym에 업로드 하였다.


물론 미끄러짐 옵션 때문인지 성능이 오락가락 했지만


나름 상위권의 점수로 기록되었다.


https://gym.openai.com/envs/FrozenLake-v0


ps. 저기 나와있는 episode 35 짜리는 미끄러짐 옵션을 꺼뒀을때 레코드 한것이다.

강화학습 예제를 실제로 테스트 해보기 위해서


openai gym이라는 사이트에서 제공하는 Environment 를 이용하여 


agent의 움직임에 따라서 Q-table 를 작성하는 코드를 짜봤다.



보통의 Grid world의 게임에서는 


 start

 

 

 

 

 

 

 

Goal! 


Map이 이런식으로 start 지점에서 상/하/좌/우 로 움직여 goal 지점으로 가는 것이다.


그런데 openAI gym에 있는 Frozen lake는 미끄러짐 옵션과 hole(구멍에 빠져 죽는) 옵션이 있다.



여기서 미끄러짐 옵션을 일단 꺼두고, hole 만 있는 상태에서 코드를 작성 해봤다. 


Environment 에 나와있는 Map은 이런식으로 생겼다


"4x4": [
"SFFF",
"FHFH",
"FFFH",
"HFFG"




처음에 기본적인 Q-table 업데이트 방법에 따라서




이 식을 적용해준다.


for i in range(num_episodes):
# Reset environment and get first new observation
s = env.reset()
rAll = 0
d = False
j = 0
# The Q-Table learning algorithm
while j < 250:
j+=1
if j==1 :
a= np.random.randint(4)
else :
# Choose an action by greedily (with noise) picking from Q table
a = np.argmax(Q[s,:] + np.random.randn(1,env.action_space.n)/i)
#print( np.random.randn(1,env.action_space.n)*(1./(i+1)))
# Get new state and reward from environment
s1,r,d,_ = env.step(a)

# Get negative reward every step
if r== 0 :
r= -0.01

# Update Q-Table with new knowledge
Q[s, a] += lr * (r + y * np.max(Q[s1, :]) - Q[s, a])
rAll += r
sList.append(s)
s = s1
if (d == True) :
if r==1 :
print(sList)
sList=[]
rList.append(rAll)
print("Episode {} finished after {} timesteps with r={}. Running score: {}".format(i,j,rAll,np.mean(rList)))

break


원래 FrozenLake environment에는 스텝마다 negative reward 가 없어서 내가 코드에 따로 추가했다.


스텝마다 negative reward를 넣어준 이유는

학습을 하면서 이 agent가 한 범위를 왔다갔다 하다가 Goal 지점을 도착하나, 

agent가 최단 거리로 Goal를 도착하나 최종 reward는 같기 때문에

agent는 Goal 지점까지 오기전까지(Goal에 도착한다고 가정했을때) 얼마나 긴 시간이 걸릴지 모른다.

그래서 이것을 방지하기 위해 step마다 negative reward를 준다.


이렇게 작성을 하고 실행을 해보니




Episode 9472 finished after 6 timesteps with r=0.95. Running score: 0.6945846088884197

[0, 4, 8, 9, 13, 14]

Episode 9473 finished after 6 timesteps with r=0.95. Running score: 0.694611568503272

[0, 0, 4, 8, 9, 13, 14]

Episode 9474 finished after 7 timesteps with r=0.94. Running score: 0.6946374670184695

[0, 4, 8, 9, 13, 14]

Episode 9475 finished after 6 timesteps with r=0.95. Running score: 0.6946644153651329

[0, 0, 4, 8, 9, 13, 14]


이라는 값이 나온다. 최대한 최단거리로 가려고(실제로 최단거리는 6) 

그리고 7이 나오는 이유는 start 지점에서 우/하 방향으로 밖에 움직여지지 않는데,

상/좌 로 움직일때는 제자리 걸음을 하게 된다. 이때 생기는 step이다. 


혹시나 하고 몇번 돌려봤는데....


이런 말도 안되는 결과값이 나올 때가 있다.(대부분 이 결과값이다. 위의 결과값은 어쩌다 한번씩 나오는...)



Episode 271 finished after 2 timesteps with r=-0.02. Running score: -0.024852941176470588

Episode 272 finished after 3 timesteps with r=-0.03. Running score: -0.02487179487179487

Episode 273 finished after 3 timesteps with r=-0.03. Running score: -0.024890510948905112

Episode 274 finished after 2 timesteps with r=-0.02. Running score: -0.024872727272727272

Episode 275 finished after 2 timesteps with r=-0.02. Running score: -0.024855072463768113


이런 결과값을 내뱉고 있다...


이 agent 놈이 그냥 계속 홀에 빠져 죽는 것이다.


어떻게 된건지 궁금해서 이때 작성된 Q-table을 확인해보니


이 agent는 랜덤하게 움직일때 한번도 Goal 지점에 도착해본적이 없어서 positive reward를 받아 보지 못한 agent 였다.


그래서 자기는 나름대로 최대의 이득을 보겠다고 가장 빠른 시간내에 죽어버리기로 결심을 한것이다.

괜히 알지도 못하는 길 돌아다니다가 step negative reward를 받느니 차라리 빨리 자살을 하는게 났다고 학습이 된것이다.

(헬조선에 사는 사람같은 학습을 하게 된것이다.)



무엇이 문제일까 생각해보다가 이놈이 hole에 빠져서 죽어버리는것이 무섭지 않게 생각해서 이렇게 됬다고 판단.


그래서 hole에 들어가서 죽었을때, 큰 negative reward(= -1)를 주었다. 


그랬더니 가끔씩은 빠져죽거나, 최단거리로 가거나 한다.

(위에 첫 스타트 부분때 랜덤하게 가는 부분을 지워서 무조건 제자리 걸음 하는것을 멈춤.

아니면 이 게임에 한해서 첫 시작은 우/하 방향으로만 가게 조건을 잡아둘수도 있음.)





무엇이 문제일까 생각을 해봤더니 아마 discount factor를 수정해보면 어떨까 싶어서(코드 초기에는 0.99를 주었다.)


점점 줄여나가다보니 0.5 쯤부터 안정적으로 최단거리로만 가는 agent 학습이 된다!!!!(이것도 완벽하지 않았다.)



또 다른 방법을 생각해보다가 초반 탐색 범위를 늘리게 된다면 더욱 Goal 지점에 다다를수 있게 되고 


a = np.argmax(Q[s,:] + np.random.randn(1,env.action_space.n)*(1./(i+1)))


이와 같은 코드에서 


a = np.argmax(Q[s,:] + np.random.randn(1,env.action_space.n)*(10./(i+1)))

이렇게 바꿔주게 되면 초반에는 더 랜덤하게 돌아다니므로 Q-table을 더 안정적으로 update 할 수 있게 된다.


이렇게 하니 discount factor 또 한 0.99로 해두어도 아주 잘 학습이 된다.



Episode 37 finished after 13 timesteps with r=-0.65. Running score: -0.30131578947368426

[0, 0, 4, 8, 8, 8, 4, 8, 9, 10, 14]

Episode 38 finished after 11 timesteps with r=0.5. Running score: -0.28076923076923077

[0, 0, 0, 1]

Episode 39 finished after 4 timesteps with r=-0.2. Running score: -0.27875000000000005

[0, 0, 4, 8, 9, 10, 14]

Episode 40 finished after 7 timesteps with r=0.7. Running score: -0.25487804878048786

[0, 4, 8, 9, 13, 9, 10, 14]

Episode 41 finished after 8 timesteps with r=0.65. Running score: -0.2333333333333334

[0, 0, 0, 4, 8, 9, 10, 14]

Episode 42 finished after 8 timesteps with r=0.65. Running score: -0.21279069767441866

[0, 4, 8, 9, 10, 14]

Episode 43 finished after 6 timesteps with r=0.75. Running score: -0.19090909090909094

[0, 4, 8, 9, 10, 14]

Episode 44 finished after 6 timesteps with r=0.75. Running score: -0.17000000000000004



위와 같이 초반에 랜덤하게 왔다 갔다 하다가 한번 Goal 지점에 도달하고 나서부터는


Episode 52 finished after 6 timesteps with r=0.75. Running score: -0.03113207547169812

[0, 4, 8, 9, 10, 14]

Episode 53 finished after 6 timesteps with r=0.75. Running score: -0.016666666666666673

[0, 4, 8, 9, 10, 14]

Episode 54 finished after 6 timesteps with r=0.75. Running score: -0.0027272727272727336

[0, 4, 8, 9, 10, 14]

Episode 55 finished after 6 timesteps with r=0.75. Running score: 0.010714285714285699

[0, 4, 8, 9, 10, 14]

Episode 56 finished after 6 timesteps with r=0.75. Running score: 0.023684210526315776

[0, 4, 8, 9, 10, 14]


안정적으로 최단거리를 가기 시작했다.


여기까지는 내가 env에서 따로 주지않는 negative reward를 주어서 학습 시킨 코드이다.


페이스북 AI Korea 그룹에서 이 예제를 질문했을때,

홍콩 과기대 sung kim 교수님께서 negative reward를 주지 않아도 해결할 수 있다고 하셨는데.

이 것에 대해서도 다시 한번 생각해 봐야겠다.






Value Function

State-value function

agent가 state 1에 있다고 가정을 하자. 거기서부터 쭉 action을 취해가면서 이동할 것이고, 그에 따라서 reward를 받는 것들을 기억할 것이다. 끝이 있는 episode 라고 가정했을 때 episode가 끝났을 때 state 1에서부터 받았던 reward를 discount factor를 적용해 다 더할 수 있다. 

Return에 대한 식은 위와 같고, 이 return의 expectation이 state-value function이다. 그리고 이것은 아래와 같이 표현한다.

[State=s 일때, return의 기대값]

즉, 어떤 상태 S의 가치이다. 그렇다면 value function을 어떻게 구할 것인가? agent 가 다음으로 갈 수 있는 state들의 가치를 보고서 높은 가치의 state로 이동하게 되는데, 어떻게하면 효율적이고 정확한 value function을 구할 지가 중요한 문제가 된다. 예를들어 주사위를 던지듯이 계속 던지면서 expectation을 구할 수 있을 것이다. 하지만 거의 무한번을 던져야 true expectation값을 알 수 있듯이 value function 또한 무한 try 해봐야 알 수 있을 것이다. 


 전에 알아봤던 Policy에 대해서도 생각을 해보자. 위에는 전혀 policy에 대한 고려가 되지 않았다. 만약 agent 가 어떤 행동정책을 한다고 가정해보자. Random으로 움직일 때와 비교를 해보면, 각 state들은 완전히 다른 경험을 하게 될것이다. 각 policy마다 value function이 달라질수 있으므로, 그 value function을 최대로 하는 policy를 찾을 수 있을 것이다. policy에 대한 value function은 다음과 같다.


[state=s 이고 policy=π 일 때, return의 기대값]


Action-value function

MDP에서 action이란 무엇인지에 대해 정의를 했다. action이란 어떤 state에서 할 수 있는 행동들을 말하는데, 보통 모든 state에서 가능한 행동은 모두 같다. 위에서 정의를 내린 value function에 대해서 생각을 해보면, state의 가치라는 것은 그 state에서 어떤 action을 했는지에 따라 달라지는 reward들에 대한 정보를 포함하고 있다. 또한 agent 입장에서 다음 행동을 다음으로 가능한 state들의 value function으로 판단하는데, 그러려면 다음 state들의 대한 정보를 모두 다 알아야하고 그 state로 가려면 어떻게 해야하는 지도 알아야한다.

따라서 state에 대한 value function말고 action에 대한 value function을 구할 수 있는데 그것이 바로 action value function이다. action value function을 이용하면 state value function과는 달리 어떤 행동을 할지 action value function의 값을 보고 판단하면 되기 때문에, 다음 state들의 value function을 알고 어떤 행동을 했을 때 거기에 가게 될 확률을 알아야하는 일도 없어진다. action-value function에 대한 정의는 다음과 같다.


[state=s, action=a, policy=π 일 때, return의 기대값]


어떤 state s에서 action a를 취할 경우의 받을 return에 대한 기대값으로서 어떤 행동을 했을 때 얼마나 좋을 것인가에 대한 값이다. 위에서 언급한 이유로 앞으로 value function은 action-value function을 사용할 것이다. Action-value function은 다른말로 Q-value로서 q-learning이나 deep q-network같은 곳에서 사용되는 q라는 것을 의미한다.




+ Recent posts