#!/usr/bin/env python # coding: utf-8 # # Mathematical foundations of reinforcement learning # # > 그로킹 심층 강화학습 중 2장 내용인 "강화학습의 수학적 기초"에 대한 내용입니다. # # - hide: true # - toc: true # - badges: true # - comments: true # - author: Chanseok Kang # - categories: [Python, Reinforcement_Learning, Grokking_Deep_Reinforcement_Learning] # - permalink: /book/:title:output_ext # - search_exclude: false # > Note: 라이브러리 설치를 위해 아래의 패키지들을 설치해주기 바랍니다. # In[ ]: #collapse get_ipython().system('pip install tqdm numpy scikit-learn pyglet setuptools && !pip install gym asciinema pandas tabulate tornado==5.* PyBullet && !pip install git+https://github.com/pybox2d/pybox2d#egg=Box2D && !pip install git+https://github.com/mimoralea/gym-bandits#egg=gym-bandits && !pip install git+https://github.com/mimoralea/gym-walk#egg=gym-walk && !pip install git+https://github.com/mimoralea/gym-aima#egg=gym-aima && !pip install gym[atari]') # In[1]: import gym, gym_walk, gym_aima # ## MDPs # ### Bandit Walk # # - 결정적인 환경 (100%의 확률로 원하는 행동을 수행) # - 1개의 비종료 상태와, 2개의 종료 상태로 되어 있음 # - 보상은 "walk"의 가장 오른쪽 상태에 갔을때만 받음 # - 에피소드로 되어 있는 환경이며, 에이전트는 가장 왼쪽이나 오른쪽 셀에 갔을 때 종료됨 # - (한번 어떠한 행동을 취한 후에 종료됨) # - 에이전트는 상태 1에서 시작함. (walk의 중간입니다) T-1-T # - 행동: 왼쪽 (0) 또는 오른쪽 (1) # In[2]: P = { 0: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 0, 0.0, True)] }, 1: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 2, 1.0, True)] }, 2: { 0: [(1.0, 2, 0.0, True)], 1: [(1.0, 2, 0.0, True)] } } P # >Note: OpenAI Gym에 구현되어 있는 BanditWalk env를 사용할 수 있음 # In[3]: P = gym.make('BanditWalk-v0').env.P P # ### Bandit Slippery Walk (BSW) # # - 확률적인 환경 (80%의 확률로 행동이 성공하고, 20%의 확률로 되돌아감) # - 1개의 비종료 상태와, 2개의 종료 상태로 되어 있음 # - 보상은 "walk"의 가장 오른쪽 상태에 갔을때만 받음 # - 에피소드로 되어 있는 환경이며, 에이전트는 가장 왼쪽이나 오른쪽 셀에 갔을 때 종료됨 # - (한번 어떠한 행동을 취한 후에 종료됨) # - 에이전트는 상태 1에서 시작함 (walk의 중간입니다) T-1-T # - 행동: 왼쪽 (0) 또는 오른쪽 (1) # In[4]: P = { 0: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 0, 0.0, True)] }, 1: { 0: [(0.8, 0, 0.0, True), (0.2, 2, 1.0, True)], 1: [(0.8, 2, 1.0, True), (0.2, 0, 0.0, True)] }, 2: { 0: [(1.0, 2, 0.0, True)], 1: [(1.0, 2, 0.0, True)] } } P # > Note: OpenAI Gym에 구현되어 있는 BanditSlipperyWalk env를 사용할 수 있음 # In[5]: P = gym.make('BanditSlipperyWalk-v0').env.P P # ### Walk three # # - 결정적인 환경 # - 3개의 비종료 상태와 2개의 종료 상태를 가짐 # - 보상은 "walk"의 가장 오른쪽 상태에 갔을때만 받음 # - 에피소드로 되어 있는 환경이며, 에이전트는 가장 왼쪽이나 오른쪽 셀에 갔을 때 종료됨 # - 에이전트는 상태 2에서 시작함. (walk의 중간) T-1-2-3-T # - 행동: 왼쪽 (0) 또는 오른쪽 (1) # In[6]: P = { 0: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 0, 0.0, True)] }, 1: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 2, 0.0, False)] }, 2: { 0: [(1.0, 1, 0.0, False)], 1: [(1.0, 3, 0.0, False)] }, 3: { 0: [(1.0, 2, 0.0, False)], 1: [(1.0, 4, 1.0, True)] }, 4: { 0: [(1.0, 4, 0.0, True)], 1: [(1.0, 4, 0.0, True)] } } P # > Note: OpenAI Gym에 구현되어 있는 WalkThree env를 사용할 수 있습니다. # In[7]: P = gym.make('WalkThree-v0').env.P P # ### Slippery Walk Three # # - 확률적인 환경 (50%의 확률로 행동이 성공하고, 33.33%의 확률로 머물러있고 # - 16.66%의 확률로 되돌아감) # - 3개의 비종료 상태와 2개의 종료 상태를 가짐 # - 보상은 "walk"의 가장 오른쪽 상태에 갔을때만 받음 # - 에피소드로 되어 있는 환경이며, 에이전트는 가장 왼쪽이나 오른쪽 셀에 갔을 때 종료됨 # - 에이전트는 상태 2에서 시작함 (walk의 중간) T-1-2-3-T # - 행동: 왼쪽 (0) 또는 오른쪽 (1) # In[8]: P = { 0: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 0, 0.0, True)] }, 1: { 0: [(0.5000000000000001, 0, 0.0, True), (0.3333333333333333, 1, 0.0, False), (0.16666666666666666, 2, 0.0, False) ], 1: [(0.5000000000000001, 2, 0.0, False), (0.3333333333333333, 1, 0.0, False), (0.16666666666666666, 0, 0.0, True) ] }, 2: { 0: [(0.5000000000000001, 1, 0.0, False), (0.3333333333333333, 2, 0.0, False), (0.16666666666666666, 3, 0.0, False) ], 1: [(0.5000000000000001, 3, 0.0, False), (0.3333333333333333, 2, 0.0, False), (0.16666666666666666, 1, 0.0, False) ] }, 3: { 0: [(0.5000000000000001, 2, 0.0, False), (0.3333333333333333, 3, 0.0, False), (0.16666666666666666, 4, 1.0, True) ], 1: [(0.5000000000000001, 4, 1.0, True), (0.3333333333333333, 3, 0.0, False), (0.16666666666666666, 2, 0.0, False) ] }, 4: { 0: [(1.0, 4, 0.0, True)], 1: [(1.0, 4, 0.0, True)] } } P # > Note: OpenAI Gym에 구현되어 있는 SlipperyWalkThree env를 사용할 수 있습니다. # In[9]: P = gym.make('SlipperyWalkThree-v0').env.P P # ### Random Walk # # - 매우 확률적인 환경 (50%의 확률로 행동이 성공하고, 50%의 확률로 되돌아감) # - 5개의 비종료 상태와 2개의 종료 상태로 되어 있음 # - 보상은 "walk"의 가장 오른쪽 상태에 갔을때만 받음 # - 에피소드로 되어 있는 환경이며, 에이전트는 가장 왼쪽이나 오른쪽 셀에 갔을 때 종료됨 # - 에이전트는 상태 3에서 시작함 (walk의 중간) T-1-2-3-4-5-T # - 행동: 왼쪽 (0) 또는 오른쪽 (1)이나, 무작위로 동작하기 때문에 별 차이가 없음 # In[10]: P = { 0: { 0: [(1.0, 0, 0.0, True)], 1: [(1.0, 0, 0.0, True)] }, 1: { 0: [(0.5, 0, 0.0, True), (0.5, 2, 0.0, False)], 1: [(0.5, 2, 0.0, False), (0.5, 0, 0.0, True)] }, 2: { 0: [(0.5, 1, 0.0, False), (0.5, 3, 0.0, False)], 1: [(0.5, 3, 0.0, False), (0.5, 1, 0.0, False)] }, 3: { 0: [(0.5, 2, 0.0, False), (0.5, 4, 0.0, False)], 1: [(0.5, 4, 0.0, False), (0.5, 2, 0.0, False)] }, 4: { 0: [(0.5, 3, 0.0, False), (0.5, 5, 0.0, False)], 1: [(0.5, 5, 0.0, False), (0.5, 3, 0.0, False)] }, 5: { 0: [(0.5, 4, 0.0, False), (0.5, 6, 1.0, True)], 1: [(0.5, 6, 1.0, True), (0.5, 4, 0.0, False)] }, 6: { 0: [(1.0, 6, 0.0, True)], 1: [(1.0, 6, 0.0, True)] } } P # > Note: OpenAI Gym에 구현되어 있는 RandomWalk env를 사용할 수 있습니다. # In[11]: P = gym.make('RandomWalk-v0').env.P P # ### GridWorld (Russll and Norvig의 Artificial Intelligence - Modern Approach책 참고) # # - 확률적인 환경 (80%의 확률로 행동이 성공하고, 20% 확률씩 양 옆으로 이동함) # - 3x4 격자로 되어 있고, 12개의 상태(0-11)를 가짐 # - 시간당 -0.04 패널티를 가짐 # - 상태 3 (가장 오른쪽 구석)에 도달하면 +1 보상을 받음 # - 상태 7 (상태 3 아래)에 도달하면 -1 보상을 받음 # - 상태 5는 벽이고, 에이전트가 해당 셀로 들어갈 경우 다시 튕겨져 나옴 # - 에피소드로 된 환경이며, 에이전트가 상태 3이나 7에 도달할 때 종료됨 # - 에이전트는 상태 0 (가장 왼쪽 구석)에서 시작함 # - 행동: 왼쪽(0), 아래 (1), 오른쪽 (2), 위 (3) # In[12]: P = { 0: { 0: [(0.9, 0, -0.04, False), (0.1, 4, -0.04, False) ], 1: [(0.1, 0, -0.04, False), (0.8, 4, -0.04, False), (0.1, 1, -0.04, False)], 2: [(0.1, 4, -0.04, False), (0.8, 1, -0.04, False), (0.1, 0, -0.04, False)], 3: [(0.1, 1, -0.04, False), (0.8, 0, -0.04, False), (0.1, 0, -0.04, False)] }, 1: { 0: [(0.2, 1, -0.04, False), (0.8, 0, -0.04, False) ], 1: [(0.1, 0, -0.04, False), (0.8, 1, -0.04, False), (0.1, 2, -0.04, False)], 2: [(0.1, 1, -0.04, False), (0.8, 2, -0.04, False), (0.1, 1, -0.04, False)], 3: [(0.1, 2, -0.04, False), (0.8, 1, -0.04, False), (0.1, 0, -0.04, False)] }, 2: { 0: [(0.1, 2, -0.04, False), (0.8, 1, -0.04, False), (0.1, 6, -0.04, False) ], 1: [(0.1, 1, -0.04, False), (0.8, 6, -0.04, False), (0.1, 3, 0.96, True)], 2: [(0.1, 6, -0.04, False), (0.8, 3, 0.96, True), (0.1, 2, -0.04, False)], 3: [(0.1, 3, 0.96, True), (0.8, 2, -0.04, False), (0.1, 1, -0.04, False)] }, 3: { 0: [(1.0, 3, 0, True)], 1: [(1.0, 3, 0, True)], 2: [(1.0, 3, 0, True)], 3: [(1.0, 3, 0, True)] }, 4: { 0: [(0.1, 0, -0.04, False), (0.8, 4, -0.04, False), (0.1, 8, -0.04, False) ], 1: [(0.2, 4, -0.04, False), (0.8, 8, -0.04, False)], 2: [(0.1, 8, -0.04, False), (0.8, 4, -0.04, False), (0.1, 0, -0.04, False)], 3: [(0.2, 4, -0.04, False), (0.8, 0, -0.04, False)] }, 5: { 0: [(1.0, 5, 0, True)], 1: [(1.0, 5, 0, True)], 2: [(1.0, 5, 0, True)], 3: [(1.0, 5, 0, True)] }, 6: { 0: [(0.1, 2, -0.04, False), (0.8, 6, -0.04, False), (0.1, 10, -0.04, False) ], 1: [(0.1, 6, -0.04, False), (0.8, 10, -0.04, False), (0.1, 7, -1.04, True)], 2: [(0.1, 10, -0.04, False), (0.8, 7, -1.04, True), (0.1, 2, -0.04, False)], 3: [(0.1, 7, -1.04, True), (0.8, 2, -0.04, False), (0.1, 6, -0.04, False)] }, 7: { 0: [(1.0, 7, 0, True)], 1: [(1.0, 7, 0, True)], 2: [(1.0, 7, 0, True)], 3: [(1.0, 7, 0, True)] }, 8: { 0: [(0.1, 4, -0.04, False), (0.9, 8, -0.04, False) ], 1: [(0.9, 8, -0.04, False), (0.1, 9, -0.04, False)], 2: [(0.1, 8, -0.04, False), (0.8, 9, -0.04, False), (0.1, 4, -0.04, False)], 3: [(0.1, 9, -0.04, False), (0.8, 4, -0.04, False), (0.1, 8, -0.04, False)] }, 9: { 0: [(0.2, 9, -0.04, False), (0.8, 8, -0.04, False) ], 1: [(0.1, 8, -0.04, False), (0.8, 9, -0.04, False), (0.1, 10, -0.04, False)], 2: [(0.2, 9, -0.04, False), (0.8, 10, -0.04, False)], 3: [(0.1, 10, -0.04, False), (0.8, 9, -0.04, False), (0.1, 8, -0.04, False) ] }, 10: { 0: [(0.1, 6, -0.04, False), (0.8, 9, -0.04, False), (0.1, 10, -0.04, False) ], 1: [(0.1, 9, -0.04, False), (0.8, 10, -0.04, False), (0.1, 11, -0.04, False) ], 2: [(0.1, 10, -0.04, False), (0.8, 11, -0.04, False), (0.1, 6, -0.04, False) ], 3: [(0.1, 11, -0.04, False), (0.8, 6, -0.04, False), (0.1, 9, -0.04, False) ] }, 11: { 0: [(0.1, 7, -1.04, True), (0.8, 10, -0.04, False), (0.1, 11, -0.04, False) ], 1: [(0.1, 10, -0.04, False), (0.9, 11, -0.04, False) ], 2: [(0.9, 11, -0.04, False), (0.1, 7, -1.04, True)], 3: [(0.1, 11, -0.04, False), (0.8, 7, -1.04, True), (0.1, 10, -0.04, False) ] } } P # > Note: OpenAI Gym에서 RussellNorvigGridworld env를 사용할 수 있습니다. # In[13]: P = gym.make('RussellNorvigGridworld-v0').env.P P # ### Frozen Lake Gridworld # # - 매우 확률적인 환경 (33.33%의 확률로 행동이 성공하고, 33.33% 확률씩 양 옆으로 이동함) # - 4x4 격자로 되어 있고, 16개의 상태(0-15)를 가짐 # - 상태 15 (가장 아래 가장자리)에 도달했을 때 +1 보상을 받고 나머지는 보상을 받지 않음 # - 상태 5, 7, 11, 12는 구멍이고, 에이전트가 구멍에 들어가면 패널티 없이 종료됨 # - 상태 15는 목표점이며, 역시 에피소드가 종료됨 # - 에이전트는 상태 0 (가장 왼쪽 구석)에서 시작함 # - 행동: 왼쪽(0), 아래 (1), 오른쪽 (2), 위 (3) # In[14]: P = { 0: { 0: [(0.6666666666666666, 0, 0.0, False), (0.3333333333333333, 4, 0.0, False) ], 1: [(0.3333333333333333, 0, 0.0, False), (0.3333333333333333, 4, 0.0, False), (0.3333333333333333, 1, 0.0, False) ], 2: [(0.3333333333333333, 4, 0.0, False), (0.3333333333333333, 1, 0.0, False), (0.3333333333333333, 0, 0.0, False) ], 3: [(0.3333333333333333, 1, 0.0, False), (0.6666666666666666, 0, 0.0, False) ] }, 1: { 0: [(0.3333333333333333, 1, 0.0, False), (0.3333333333333333, 0, 0.0, False), (0.3333333333333333, 5, 0.0, True) ], 1: [(0.3333333333333333, 0, 0.0, False), (0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 2, 0.0, False) ], 2: [(0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 1, 0.0, False) ], 3: [(0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 1, 0.0, False), (0.3333333333333333, 0, 0.0, False) ] }, 2: { 0: [(0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 1, 0.0, False), (0.3333333333333333, 6, 0.0, False) ], 1: [(0.3333333333333333, 1, 0.0, False), (0.3333333333333333, 6, 0.0, False), (0.3333333333333333, 3, 0.0, False) ], 2: [(0.3333333333333333, 6, 0.0, False), (0.3333333333333333, 3, 0.0, False), (0.3333333333333333, 2, 0.0, False) ], 3: [(0.3333333333333333, 3, 0.0, False), (0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 1, 0.0, False) ] }, 3: { 0: [(0.3333333333333333, 3, 0.0, False), (0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 7, 0.0, True) ], 1: [(0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 7, 0.0, True), (0.3333333333333333, 3, 0.0, False) ], 2: [(0.3333333333333333, 7, 0.0, True), (0.6666666666666666, 3, 0.0, False) ], 3: [(0.6666666666666666, 3, 0.0, False), (0.3333333333333333, 2, 0.0, False) ] }, 4: { 0: [(0.3333333333333333, 0, 0.0, False), (0.3333333333333333, 4, 0.0, False), (0.3333333333333333, 8, 0.0, False) ], 1: [(0.3333333333333333, 4, 0.0, False), (0.3333333333333333, 8, 0.0, False), (0.3333333333333333, 5, 0.0, True) ], 2: [(0.3333333333333333, 8, 0.0, False), (0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 0, 0.0, False) ], 3: [(0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 0, 0.0, False), (0.3333333333333333, 4, 0.0, False) ] }, 5: { 0: [(1.0, 5, 0, True)], 1: [(1.0, 5, 0, True)], 2: [(1.0, 5, 0, True)], 3: [(1.0, 5, 0, True)] }, 6: { 0: [(0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 10, 0.0, False) ], 1: [(0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 7, 0.0, True) ], 2: [(0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 7, 0.0, True), (0.3333333333333333, 2, 0.0, False) ], 3: [(0.3333333333333333, 7, 0.0, True), (0.3333333333333333, 2, 0.0, False), (0.3333333333333333, 5, 0.0, True) ] }, 7: { 0: [(1.0, 7, 0, True)], 1: [(1.0, 7, 0, True)], 2: [(1.0, 7, 0, True)], 3: [(1.0, 7, 0, True)] }, 8: { 0: [(0.3333333333333333, 4, 0.0, False), (0.3333333333333333, 8, 0.0, False), (0.3333333333333333, 12, 0.0, True) ], 1: [(0.3333333333333333, 8, 0.0, False), (0.3333333333333333, 12, 0.0, True), (0.3333333333333333, 9, 0.0, False) ], 2: [(0.3333333333333333, 12, 0.0, True), (0.3333333333333333, 9, 0.0, False), (0.3333333333333333, 4, 0.0, False) ], 3: [(0.3333333333333333, 9, 0.0, False), (0.3333333333333333, 4, 0.0, False), (0.3333333333333333, 8, 0.0, False) ] }, 9: { 0: [(0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 8, 0.0, False), (0.3333333333333333, 13, 0.0, False) ], 1: [(0.3333333333333333, 8, 0.0, False), (0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 10, 0.0, False) ], 2: [(0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 5, 0.0, True) ], 3: [(0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 5, 0.0, True), (0.3333333333333333, 8, 0.0, False) ] }, 10: { 0: [(0.3333333333333333, 6, 0.0, False), (0.3333333333333333, 9, 0.0, False), (0.3333333333333333, 14, 0.0, False) ], 1: [(0.3333333333333333, 9, 0.0, False), (0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 11, 0.0, True) ], 2: [(0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 11, 0.0, True), (0.3333333333333333, 6, 0.0, False) ], 3: [(0.3333333333333333, 11, 0.0, True), (0.3333333333333333, 6, 0.0, False), (0.3333333333333333, 9, 0.0, False) ] }, 11: { 0: [(1.0, 11, 0, True)], 1: [(1.0, 11, 0, True)], 2: [(1.0, 11, 0, True)], 3: [(1.0, 11, 0, True)] }, 12: { 0: [(1.0, 12, 0, True)], 1: [(1.0, 12, 0, True)], 2: [(1.0, 12, 0, True)], 3: [(1.0, 12, 0, True)] }, 13: { 0: [(0.3333333333333333, 9, 0.0, False), (0.3333333333333333, 12, 0.0, True), (0.3333333333333333, 13, 0.0, False) ], 1: [(0.3333333333333333, 12, 0.0, True), (0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 14, 0.0, False) ], 2: [(0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 9, 0.0, False) ], 3: [(0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 9, 0.0, False), (0.3333333333333333, 12, 0.0, True) ] }, 14: { 0: [(0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 14, 0.0, False) ], 1: [(0.3333333333333333, 13, 0.0, False), (0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 15, 1.0, True) ], 2: [(0.3333333333333333, 14, 0.0, False), (0.3333333333333333, 15, 1.0, True), (0.3333333333333333, 10, 0.0, False) ], 3: [(0.3333333333333333, 15, 1.0, True), (0.3333333333333333, 10, 0.0, False), (0.3333333333333333, 13, 0.0, False) ] }, 15: { 0: [(1.0, 15, 0, True)], 1: [(1.0, 15, 0, True)], 2: [(1.0, 15, 0, True)], 3: [(1.0, 15, 0, True)] } } P # > Note: OpenAI gym의 FrozenLake env를 사용할 수 있습니다. # In[15]: P = gym.make('FrozenLake-v0').env.P P # ### FrozenLake8x8 # # - 참고로 MDP는 더 복잡하고 클 수 있습니다. # - 64개의 상태를 가지는 FrozenLake도 살펴보기 바랍니다. # In[16]: env = gym.make('FrozenLake8x8-v0') P = env.env.P P