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


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를 주지 않아도 해결할 수 있다고 하셨는데.

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





+ Recent posts