앎을 경계하기

Machine Learning/Reinforcement Learning

차근차근 Spinning Up 톺아보기 4 - Part 3: Intro to Policy Optimization

양갱맨 2019. 11. 7. 20:42

Part 3: Intro to Policy Optimization

Simplest Policy Gradient 유도

확률적이고 파라미터화된 정책인 $$\pi_{\theta}$$ 의 경우를 다룬다.

우리의 목표$$J(\pi_{\theta})$$는 기대 누적 보상(expected return)을 최대화하는 것이다.


위의 식의 경우, 우리는 finite-horizon undiscounted return, 즉 무한한 timestep을 거치면서 보상에 대한 discount가 없는 Reward의 합을 받게 된다. 그러나 infinite-horizon discounted return을 위한 목표함수식도 거의 동일하다.

gradient ascent를 사용해서 policy를 최적화한다.


gradient descent가 아니라 ascent를 하는 이유는 목표함수이기 때문이다. reward를 최대화하는 것을 목표로하는 함수이기때문에 최대화를 시키기위해 ascent를 하는 것이다.

이것을 반대로 -를 붙이면 gradient descent를 하면 된다.


위 식이 바로 policy의 성능을 gradient한 것으로 이것을 policy gradient라고한다.

policy를 최적화하는 알고리즘을 policy gradient algorithms이라고한다.

Vanilla Policy gradient(가장 기본적인 PG), TRPO, PPO 등 여러가지 알고리즘들이 있다.

이 PG 알고리즘을 사용하려면 수치적으로 계산할 수 있는 policy gradient에 대한 식이 필요하다.

이것은 두가지 단계를 포함한다.

  1. expected value의 형태로써 나타나는 정책 성능의 분석적 gradient를 도출하는 것.
  2. 유한한 개수의 agent와 환경 간 상호작용 단계로부터 받은 데이터로 계산될 수 있는 expected value를 추정하는 샘플 추정을 형성하는 것.

gradient 계산을 위한 몇가지 유용한 사실들에 대해서 설명함.

  1. Trajectory의 확률

    • $$\pi_{\theta}$$로부터 받을 수 있는 action이 주어질 때 하나의 trajectory의 확률은 다음과 같다.

 

위 식을 설명하면 초기 state는 $$\rho_0(s_0)$$로부터 얻을 수 있다.

그리고 그 뒤 policy를 따라 state에서 action을 하면서 transition probability와 곱해진 것이 바로 policy의 파라미터인 theta가 주어질 때 그 Trajectory가 나올 확률인 것이다.

2. Log-Derivative Trick

log 형태로 유도하는 미분 트릭이다. x에 대한 log x의 미분은 1/x이다.
체인룰을 사용해서 정리하면 다음과 같이 정리할 수 있다.


3. Trajectory의 log-확률

하나의 trajectory의 log-prob은 다음처럼 표현가능하다

log니까 각 확률에 log취하고 곱을 합으로 바꿔주는 것.

 

4. 환경 함수들의 Gradients

환경은 $$\theta$$에 의존하지 않는다. 따라서 initail state prob, transition prob, Reward function은 전부 0이 된다.

 

5. Trajectory의 Grad-Log-Prob

하나의 Trajectory에 대한 log-prob의 gradient는 다음과 같다.

지워지는 term들은 theta와 독립적인 functions이기 때문이다.

앞서 설명한 것들을 적용하여 Policy Gradient 과정을 나열해보면 아래와 같다.

 

 

expectation은 샘플들의 평균으로 추정할 수 있다는 것을 의미한다.

예를 들어 D라는 trajectory들의 집합이 있다.
$$
D = {\tau_i}_{i=1,...,N}
$$
각 trajectory들은 policy를 사용해서 환경이 주는 action을 따라서 얻을 수 있다.

policy gradient는 다음과 같이 추정될 수 있다.


|D|는 D에 있는 trajectory들의 수이다.

위에서 말한 것과 같이 Expectation이 샘플들의 평균으로 나타날 수 있음을 확인하였다.

마지막 표현은 우리가 원하는 가장 간단한 계산 가능한 표현이다.


위 식을 계산할 수 있는 방식으로 정책을 표현했다고 가정하고 trajectory 샘플들을 모으기 위해서 환경에서 정책을 따를 수 있다면 우리는 policy gradient를 계산하고 업데이트 단계를 수행할 수 있다.

Simplest Policy Gradient 구현

Tensorflow 환경에서 구현됨.

Policy network 구성

# make core of policy network
obs_ph = tf.placeholder(shape=(None, obs_dim), dtype=tf.float32)
logits = mlp(obs_ph, sizes=hidden_sizes+[n_acts])

# make action selection op (outputs int actions, sampled from policy)
actions = tf.squeeze(tf.multinomial(logits=logits,num_samples=1), axis=1)

logits은 log-prob과 actions들의 확률을 구성하기위해 사용하는 tensor이다.

actions는 logits으로부터 액션을 샘플링한 tensor이다.

Loss function 구성

# make loss function whose gradient, for the right data, is policy gradient
weights_ph = tf.placeholder(shape=(None,), dtype=tf.float32)
act_ph = tf.placeholder(shape=(None,), dtype=tf.int32)
action_masks = tf.one_hot(act_ph, n_acts)
log_probs = tf.reduce_sum(action_masks * tf.nn.log_softmax(logits), axis=1)
loss = -tf.reduce_mean(weights_ph * log_probs)

올바른 데이터가 사용된다면 loss의 기울기가 곧 정책의 기울기가 된다.

올바른 데이터라는 것은 현재 정책에 따라서 움직이는 동안 수집된 (state, action, weight)튜플을 의미한다.

state-action 쌍의 weight는 episode로부터 반환된다.

여기서 알고가야할 것은,

loss function이 일반적으로 지도학습에서 사용하는 loss function이 아니다.

표준 손실함수와 크게 2가지 차이점이 있다.

  1. data 분포가 parameter들에 의존한다.

    loss function은 대개 최적화를 하기위해서 파라미터에 독립적인 고정된 데이터 분포로 정의된다. 그러나 여기서는 최근 policy에서 샘플링된 데이터에 대한 분포이다.

  2. 성능을 측정할 수 없다.

    loss function은 성능을 평하가는 지표로 사용되는데, PG에서 우리는 목적함수인 $$J(\pi_{\theta})$$를 최적화하는 것이 목표이다.

    loss function은 그냥 현재 파라미터에서 생성된 데이터를 사용해서 그 현재 파라미터를 평가할 때 성능을 평가하기 위해서 사용되는 것이다.

gradient descent를 한번 하고난 후에는 성능과 관련이 없어진다.

이 말은 주어진 데이터 배치에 맞춰서 loss function을 최소화한다고 해서 expected return이 나아질거라는 보장이 되지 않는다는 의미이다.

loss function을 음의 무한대로 보내면 policy performance가 떨어지게 될 것이다.

deep RL 연구원들은 이러한 결과를 보고서 데이터 배치에 대한 policy가 "overfitting 되었다."고 말하기도 한다.

설명으로는 맞지만 일반화 오류를 나타내는 건 아니기때문에 overfitting 말 그대로 받아들이면 안된다.

ML에서 일하는 사람들은 일반적으로 학습하는 동안에 loss function 값이 내려갈수록 잘된다라고 말하지만 policy gradient에서는 그렇지 않다. PG에서는 평균리턴을 고려해야한다. loss function은 의미가 없다.

log_probs tensor는 action mask를 만들고 이것을 사용해서 특정 log prob을 선택하도록 하는데,

이것은 categorical policies에서만 작동한다. 일반적으로 작동하는 것이 아니다.

학습의 한 에폭 실행

# for training policy
    def train_one_epoch():
        # make some empty lists for logging.
        batch_obs = []          # for observations
        batch_acts = []         # for actions
        batch_weights = []      # for R(tau) weighting in policy gradient
        batch_rets = []         # for measuring episode returns
        batch_lens = []         # for measuring episode lengths

        # reset episode-specific variables
        obs = env.reset()       # first obs comes from starting distribution
        done = False            # signal from environment that episode is over
        ep_rews = []            # list for rewards accrued throughout ep

        # render first episode of each epoch
        finished_rendering_this_epoch = False

        # collect experience by acting in the environment with current policy
        while True:

            # rendering
            if not(finished_rendering_this_epoch):
                env.render()

            # save obs
            batch_obs.append(obs.copy())

            # act in the environment
            act = sess.run(actions, {obs_ph: obs.reshape(1,-1)})[0]
            obs, rew, done, _ = env.step(act)

            # save action, reward
            batch_acts.append(act)
            ep_rews.append(rew)

            if done:
                # if episode is over, record info about episode
                ep_ret, ep_len = sum(ep_rews), len(ep_rews)
                batch_rets.append(ep_ret)
                batch_lens.append(ep_len)

                # the weight for each logprob(a|s) is R(tau)
                batch_weights += [ep_ret] * ep_len

                # reset episode-specific variables
                obs, done, ep_rews = env.reset(), False, []

                # won't render again this epoch
                finished_rendering_this_epoch = True

                # end experience loop if we have enough of it
                if len(batch_obs) > batch_size:
                    break

        # take a single policy gradient update step
        batch_loss, _ = sess.run([loss, train_op],
                                 feed_dict={
                                    obs_ph: np.array(batch_obs),
                                    act_ph: np.array(batch_acts),
                                    weights_ph: np.array(batch_weights)
                                 })
        return batch_loss, batch_rets, batch_lens

train_one_epoch()은 pg의 1번의 epoch을 수행한다.

  1. 경험을 쌓는 단계(L62-97), 에이전트는 최근 정책을 따라서 환경에서 몇 에피소드 동안 액션을 한다.

    그다음 2번 수행

  2. PG update 한번 실행 (L99-105).

    train_one_epoch()를 메인에서 여러번 호출한다.