강화학습
몬테카를로법으로 정책 평가
정지홍
2024. 12. 7. 20:28
몬테카를로법으로 정책 평가
- 몬테카를로법으로 가치 함수를 추정할 것 임.
즉, 정책 pi가 주어졌을때, 이 정책의 가치함수를 몬테카를로법으로 계산할거임


- 위의 식은 가치 함수를 몬테카를로법으로 계산한 것 이다.
- 위의 식을 수행하기 위해서 agent는 정책pi에 따라서 실제 action을 하도록한다.
이렇게 하여 얻은 수익G가 sample data이며, 이러한 sample data를 모아서 평균을 구한다. 이것이 몬테카를로법이다.
- 위의 식을 수행하기 위해서 agent는 정책pi에 따라서 실제 action을 하도록한다.
- 상태 s에서 시작해서 얻은 수익을 G로 표기함. i번째 얻은 수익을 G(i)로 표기한다.
그래서 몬테카를로법으로 계산하기 위해서는 episode를 n번 수행하여 얻은 sample data의 평균을 구하면 된다. - 몬테카를로법을 이용한 것은 일회성 과제에서만 사용가능...
- why?
- 지속적인 과제에는 수익의 sample data가 확정되지 않기 때문이다.
- why?
- ex)
- agent가 총 3번의 action을 수행하였으며 얻은 보상이 1,0,2인 경우, G(1)=1+0+2=3이다.
(할인률을 1로 가정하였음)
2번째는 0,0,1,1의 보상을 얻었으며, G(2)=0+0+1+1=2이다. - ==> 해당 시점에서 가치 함수 V(s)는 2.5이다. ( 3+2/2 = 2.5 )
- 위와 같이 실제로 행동을 하여, 수익의 평균을 구하며 가치함수를 근사하는 것이 가능하다.
( 시도 횟수를 늘릴수록, 정확도는 높아짐)
- agent가 총 3번의 action을 수행하였으며 얻은 보상이 1,0,2인 경우, G(1)=1+0+2=3이다.
- 각각의 state에 대해서 가치 함수를 구하면 비효율적이다...
- 예시로 state가 A,B,C의 3가지가 있다고 하자... 그러면 아래와 같이 각각 구해야한다.
- state에 따라서 A->B->C로 전이함을 전재로 하자...
- 예시로 state가 A,B,C의 3가지가 있다고 하자... 그러면 아래와 같이 각각 구해야한다.

- 위의 식을 개선해보면 아래와 같다.

import numpy as np
from collections import defaultdict
class GridWorld:
def __init__( self ):
self.action_space = [ 0, 1, 2 , 3 ] # 행동 할 수 있는 가지 수
self.action_meaning = { 0:'UP' , 1:'DOWN' , 2:'LEFT' , 3:'RIGHT' } # 위에서 정의한 행동 번호가 의미 하는 바
self.reward_map = np.array( # 게임 맵
[ [ 0 , 0 , 0 , 1.0 ] ,
[ 0 , None , 0 , -1.0 ] ,
[ 0 , 0 , 0 , 0 ] ] )
self.goal_state = ( 0 , 3 ) # 목표 지점
self.wall_state = ( 1 , 1 ) # 벽 지점
self.start_state = ( 2 , 0 ) # 시작 지점
self.agent_state = self.start_state # 에이전트 초기 상태
@property # 맵의 행 갯수
def height( self ):
return len( self.reward_map )
@property # 맵의 컬럼 갯수
def width( self ):
return len( self.reward_map[0] )
@property # 맵의 쉐잎
def shape( self ):
return self.reward_map.shape
def actions( self ): # 행동할수 있는 범위
return self.action_space
def states( self ):
for h in range ( self.height):
for w in range ( self.width):
yield ( h , w ) # yield가 있는 라인은 함수를 호출한 쪽으로 프로그램의 제어를 넘겨줌을 의미
# yield는 return과 다르게 함수 종료가 아니라 일지중지이다. 그래서 다음에 함수 실행시 이전 상태를 기억하고 이어서 호출이 가능
def next_state( self , state , action ):
action_move_map = [ ( -1 , 0 ) , ( 1, 0 ) , ( 0 , -1 ) , ( 0 , 1 ) ]
move = action_move_map[ action ]
next_state = ( state[0] + move[0] , state[1] + move[1] ) # 위치 이동에 대해서 계산을 수행
ny , nx = next_state
if nx < 0 or nx >= self.width or ny < 0 or ny >= self.height: # agent가 맵을 벗어나려는 경우
next_state = state
elif next_state == self.wall_state: # 벽에 부딪히는 경우
next_state = state
return next_state
def reward( self , state , action , next_state ):
return self.reward_map[ next_state ]
def reset( self ):
self.agent_state = self.start_state
return self.agent_state
def step( self , action ):
state = self.agent_state
next_state = self.next_state( state , action ) # 전달받은 action으로 다음 state를 구함.
reward = self.reward( state , action , next_state )# 위ㅣ치를 이동하였을때 보상을 구함
done = ( next_state == self.goal_state ) # goal에 도달하였는지 확인
self.agent_state = next_state # 다음 위치를 저장
return next_state , reward , done
class RandomAgent:
def __init__( self ):
self.gamma = 0.9
self.action_size = 4
random_actions = { 0:0.25 , 1:0.25 , 2:0.25 , 3:0.25 }
self.pi = defaultdict( lambda: random_actions ) # 정책을 상하좌우 각각 0.25확률로 초기화 시킨다.
self.V = defaultdict( lambda: 0 )
self.cnts = defaultdict( lambda: 0 )
self.memory = []
def get_action( self , state ): # 현재 상태(위치)를 입력받습니다.
action_probabilities = self.pi[ state ] # 현재 위치에 대해서 정책을 가져옵니다.
actions = list( action_probabilities.keys() ) # 정책 상하좌우의 키값인 0,1,2,3을 가져옵니다.
probabilities = list( action_probabilities.values() )# 정책의 확률값을 가져옵니다.
return np.random.choice( actions , p=probabilities ) # probabilites의 확률에 따라서 actions중 하나를 뽑음
def add( self , state , action , reward ):
data = ( state , action , reward )
self.memory.append( data )
def reset( self ):
self.memory.clear()
def eval( self ):
G = 0
for data in reversed( self.memory ):
state , action , reward = data
print(data)
print("---------------")
G = self.gamma * G + reward
self.cnts[ state ] += 1
self.V[ state ] += ( G-self.V[state] ) / self.cnts[ state ]
