[바닥부터 배우는 강화학습] - Chapter 9. 정책 기반 에이전트 1 (Policy Gradient)

방선생·어제

딥러닝과 정책 함수가 결합하면 강력한 정책 네트워크를 만들어 냅니다. 이번 챕터에서는 보상 및 밸류 네트워크를 이용해 직접적으로 정책 네트워크를 학습하는 방법에 대해 알아보겠습니다. 이는 수많은 최신 강화학습 알고리즘의 뿌리가 되는 방법론입니다.


9.1 Policy Gradient

  • 가치 기반 에이전트가 액션을 선택하는 방식은 결정론적(deterministic)
    • 즉, 모든 상태 s에 대해 각 상태에서 선택하는 액션이 변하지 않음
    • 학습이 끝나면 Q(s,a)의 값이 고정되기 때문임

  • 정책 기반 에이전트는 확률적 정책(stochastic policy)을 취할 수 있음
    • 정책 함수의 정의가 π(s,a)=P[as]\pi(s,a) = \mathbb{P}[a \mid s] 임으로 즉, 상태 s에서 할 수 있는 액션에 대한 확률 분포를 가리키기 때문임

  • 만약 액션 공간(action space)연속적(continuous)인 경우 즉, 0에서 1 사이의 모든 실수값이 액션으로 선택될 수 있는 상황일때
    • 가치 기반 에이전트가 작동하려면 모든 a[0,1]a \in [0,1]에 대해 Q(s,a)의 값을 최대로 하는 입력 a를 찾아야함 → 이 자체로 하나의 최적화 문제가 되기 때문에 연속적 액션 공간에서는 Q(s,a) 기반 에이전트가 작동하기 힘듬

    • 정책 기반 에이전트는 π(s)\pi(s)가 주어져 있다면 바로 액션을 뽑아줄 수 있기 때문에 문제없음

    • 또한 정책 기반 방법론이 가치 기반 방법론에 비해 환경에 숨겨진 정보가 있거나, 환경 자체가 변하는 경우에도 더 유연하게 대처할 수 있음

목적 함수 정하기

  • (정책 네트워크를 πθ(s,a)\pi_\theta(s,a)로, θ\theta는 정책 네트워크의 파라미터로 표현)

  • 목표는 환경에 πθ(s,a)\pi_\theta(s,a)로 움직이는 에이전트를 가져다 놓아 경험을 쌓게 하고, 그 경험으로부터 πθ(s,a)\pi_\theta(s,a)를 계속해서 강화하는 것임
    • πθ(s,a)\pi_\theta(s,a)를 업데이트 한다는 것은 결국 뉴럴넷의 파라미터를 업데이트 하는 것이니 그라디언트 디센트 방법론을 사용함 → 손실 함수를 정의 해야 사용 가능

πθ(s,a)\pi_\theta(s,a)의 손실 함수를 어떻게 정의하지...?

  • 손실 함수가 정의되어야 이를 줄이는 방향으로 파라미터를 업데이트있는데, 손실 함수를 정의하려면 먼저 정답지가 정의되어야 됨 (뉴럴넷의 예측값과 실제 정답 사이의 차이기 때문)

  • 정책 함수의 정답이란 것이 곧 최적 정책인데, 최적 정책를 알면 강화학습을 하는 이유가 없음
    • 즉, 손실 함수를 줄이는 방향이 아니라, 정책을 평가하는 기준을 세워서 그 값을 증가시키도록 하는 방향으로 그라디언트 업데이트를 함 → 그라디언트 어센트(gradient ascent)

  • 목표는 주어진 정책 네트워크 πθ(s,a)\pi_\theta(s,a)에 대해 이 정책이 얼마나 좋은 정책인지 평가하는 방법을 찾는 것 → 이때 평가 함수를 J(θ)J(\theta)라고 함
    • π\pi를 인풋으로 받아 점수를 리턴하는 함수이고, π\pi가 곧 θ\theta에 의해서 표현되기 때문에 θ\theta만 인풋으로 들어감
    • 이 함수를 알 수 있다면 이 함수의 값을 증가시키는 방향으로 그라디언트 어센트를 진행 할 수 있음

  • 하지만, π\pi가 고정되어도 에피소드마다 서로 다른 상태를 방문하고 서로 다른 보상를 받기 때문에 정책을 평가하기 위해서는 기대값 연산자가 필요함
    • J(θ)=Eπθ[trt]J(\theta)=\mathbb{E}_{\pi_\theta}\left[\sum_t r_t\right]
    • 보상의 합에 기댓값을 취한 것이 곧 J(θ)J(\theta)

  • 이는 시작하는 상태가 s0s_0로 항상 고정되어 있다면 s0s_0의 가치로 볼 수 있음
    • J(θ)=Eπθ[trt]=vπθ(s0)J(\theta)=\mathbb{E}_{\pi_\theta}[\sum_t r_t]=v_{\pi_\theta}(s_0)
    • 즉, J(θ)J(\theta)s0s_0의 밸류로 표현 가능함

  • 만약 시작하는 상태가 s0s_0로 고정된 것이 아니라 매번 다른 상태에서 출발한다고 가정할 경우, 시작 상태 s의 확률 분포 d(s)가 정의되어야함
    • J(θ)=sSd(s)vπθ(s)J(\theta)=\sum_{s\in S} d(s)\,v_{\pi_\theta}(s)
    • 모든 상태 s에 대하여 해당 상태에서 출발했을 때 얻을 가치를 해당 상태에서 출발할 확률과 곱하여 가중 합을 해준 것

  • θJ(θ)\nabla_\theta J(\theta)를 구하여 “θθ+αθJ(θ)\theta' \leftarrow \theta + \alpha * \nabla_\theta J(\theta)” 를 실행하면 J(θ)J(\theta')의 값은 J(θ)J(\theta)보다 증가하게 됨
    • 이 과정을 반복하면 최적 정책의 파라미터 θ\theta^*를 찾을 수 있음 → 이를 그라디언트 어센트라고함

    • 그라디언트 디센트가 손실 함수를 최소화하기 위해 그라디언트를 계산하여 그 반대 방향으로 파라미터를 업데이트 했다면, 그라디언트 어센트는 목적 함수를 최대화하기 위해 그라디언트를 계산하여 그라디언트 방향으로 파라미터를 업데이트함

1-Step MDP

  • 1-Step MDP : 한 스텝만 진행하고 바로 에피소드가 끝나는 MDP
    • 처음 상태 s0s_0에서 액션 a를 선택하고 보상 Rs,aR_{s,a}를 받고 끝나는 것
    • 처음 상태 s0s_0는 확률분포 d(s)를 통해 정해짐 → s0d(s)s_0 \sim d(s)

  • J(θ)=sSd(s)vπθ(s)=sSd(s)aAπθ(s,a)Rs,aJ(\theta)=\sum_{s\in S} d(s)\,v_{\pi_\theta}(s) =\sum_{s\in S} d(s)\sum_{a\in A}\pi_\theta(s,a)\,R_{s,a}
    • d(s) : 존재하는 모든 상태 s에 대해 s가 첫 상태가 될 확률
    • vπθ(s)v_{\pi_\theta}(s)는 s에서 모든 액션 a에 대해 a를 선택할 확률과 그 때 발생하는 보상을 곱해서 더해주면 됨

  • θJ(θ)=θsSd(s)aAπθ(s,a)Rs,a\nabla_\theta J(\theta)=\nabla_\theta \sum_{s\in S} d(s)\sum_{a\in A}\pi_\theta(s,a)\,R_{s,a}
    • 양변에 그라디언트 취한것
    • 하지만 Rs,aR_{s,a}를 모르기 때문에 계산할 수 없음 (사실 알아도 continuous action space라 못함)

  • 샘플 기반 방법론을 활용하여 계산 진행

    θJ(θ)=θsSd(s)aAπθ(s,a)Rs,a\nabla_\theta J(\theta) = \nabla_\theta \sum_{s\in S} d(s)\sum_{a\in A}\pi_\theta(s,a)\,R_{s,a}

    =sSd(s)aAθπθ(s,a)Rs,a= \sum_{s\in S} d(s)\sum_{a\in A}\nabla_\theta \pi_\theta(s,a)\,R_{s,a}

    =sSd(s)aAπθ(s,a)πθ(s,a)θπθ(s,a)Rs,a= \sum_{s\in S} d(s)\sum_{a\in A}\frac{\pi_\theta(s,a)}{\pi_\theta(s,a)}\,\nabla_\theta \pi_\theta(s,a)\,R_{s,a}

    =sSd(s)aAπθ(s,a)θπθ(s,a)πθ(s,a)Rs,a= \sum_{s\in S} d(s)\sum_{a\in A}\pi_\theta(s,a)\,\frac{\nabla_\theta \pi_\theta(s,a)}{\pi_\theta(s,a)}\,R_{s,a}

    =sSd(s)aAπθ(s,a)θlogπθ(s,a)Rs,a= \sum_{s\in S} d(s)\sum_{a\in A}\pi_\theta(s,a)\,\nabla_\theta \log \pi_\theta(s,a)\,R_{s,a}

    =Eπθ[θlogπθ(s,a)Rs,a]= \mathbb{E}_{\pi_\theta}[\nabla_\theta \log \pi_\theta(s,a)\,R_{s,a}]

  • 기대값 연산자 Eπθ\mathbb{E}_{\pi_\theta} 덕분에 “샘플 기반 방법론”을 활용해 계산 할 수 있음
    • πθ(s,a)\pi_\theta(s,a)에 대한 기댓값이기 때문에 πθ(s,a)\pi_\theta(s,a)로 움직이는 에이전트를 환경에 가져다 놓고, θlogπθ(s,a)Rs,a\nabla_\theta \log \pi_\theta(s,a) * R_{s,a}의 값을 여러 개 모으면 됨

  • θlogπθ(s,a)\nabla_\theta \log \pi_\theta(s,a)는 뉴럴넷의 그라디언트이기 때문에 쉽게 계산할 수 있으며, Rs,aR_{s,a}는 s에서 a를 선택하고 얻는 보상을 관측하기만 하면 됨
    • 상태전이마다 1개의 θlogπθ(s,a)Rs,a\nabla_\theta \log \pi_\theta(s,a) * R_{s,a} 값을 계산할 수 있고, 이 값을 모아서 평균을 내면, 그 평균이 곧 θJ(θ)\nabla_\theta J(\theta)와 같음

  • 이게 가능한 이유는 θlogπθ(s,a)Rs,a\nabla_\theta \log \pi_\theta(s,a)\,R_{s,a}을 기댓값 연산자 형태로 바꿨기 때문임
    • 수식 앞에 πθ(s,a)\sum \pi_\theta(s,a)가 곱해진 형태이기 때문
      • πθ(s,a)\sum \pi_\theta(s,a)가 곱해져 있으면 이는 곧 그 뒤에 나올 값에 πθ(s,a)\pi_\theta(s,a)만큼의 가중치를 곱해서 더해주라는 뜻이고, 이는 곧 기댓값 연산자 Eπθ\mathbb{E}_{\pi_\theta}의 정의이며, 이 부분이 policy gradient의 핵심임

일반적 MDP에서의 Policy Gradient

  • 1 step MDP : θJ(θ)=Eπθ[θlogπθ(s,a)Rs,a]\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}[\nabla_\theta \log \pi_\theta(s,a) * R_{s,a}]

  • MDP : θJ(θ)=Eπθ[θlogπθ(s,a)Qπθ(s,a)]\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}[\nabla_\theta \log \pi_\theta(s,a) * Q_{\pi_\theta}(s,a)] → “Policy Gradient Theorem”
  • Rs,aR_{s,a}Qπθ(s,a)Q_{\pi_\theta}(s,a)로 바뀜. s에서 a를 할 때 받는 보상 대신, s에서 a를 할 때 얻는 리턴의 기댓값으로 바꾼 것 → 한 스텝만 진행하고 MDP가 끝나는 것이 아닌 이후 여러 스텝이 존재하기 때문

  • 이 식을 Policy Gradient Theorem이라고 함
    • Policy gradient : 목적함수 J(θ)J(\theta)에 대한 그라디언트를 πθ(s,a)\pi_\theta(s,a)가 경험한 데이터를 기반으로 계산할 수 있게 해주는 방법론


9.2 REINFORCE 알고리즘

이론적 배경

  • θJ(θ)=Eπθ[θlogπθ(s,a)Gt]\nabla_\theta J(\theta)=\mathbb{E}_{\pi_\theta}[\nabla_\theta \log \pi_\theta(s,a) * G_t]
    • 기존 수식의 Qπθ(s,a)Q_{\pi_\theta}(s,a) 자리에 그 샘플의 리턴 GtG_t가 들어감
      • GtG_tQπθ(s,a)Q_{\pi_\theta}(s,a)의 정의 때문에 편향되지 않은 샘플임
      • Qπ(s,a)=E[Gtst=s,at=a]Q_\pi(s,a)=\mathbb{E}[G_t \mid s_t=s, a_t=a]이기 때문에, GtG_t의 샘플을 여러 개 모아서 평균을 내면 그 식이 실제 Qπθ(s,a)Q_{\pi_\theta}(s,a)에 근사해지기 때문

REINFORCE pseudo code

  1. πθ(s,a)\pi_\theta(s,a)의 파라미터 θ\theta를 랜덤으로 초기화

  2. 다음(A~C)을 반복
    • A. 에이전트의 상태를 초기화: ss0s \leftarrow s_0

    • B. πθ\pi_\theta를 이용하여 에피소드 끝까지 진행, {s0,a0,r0,s1,a1,r1,,sT,aT,rT}\{s_0, a_0, r_0, s_1, a_1, r_1, \ldots, s_T, a_T, r_T\}을 얻음

    • C. t=0Tt = 0 \sim T에 대해 다음을 반복
      • Gti=tTriγitG_t \leftarrow \sum_{i=t}^{T} r_i * \gamma^{i-t}
      • θθ+αθlogπθ(st,at)Gt\theta \leftarrow \theta + \alpha * \nabla_\theta \log \pi_\theta(s_t, a_t) * G_t
  • πθ\pi_\theta로 에피소드 하나에 해당하는 데이터를 얻고, 해당 데이터로 θ\theta를 업데이트하고, 업데이트된 πθ\pi_\theta를 이용해 또 다음 에피소드의 경험을 얻고, 그 데이터로 또 강화하고, 이 과정을 계속해서 반복

  • θlogπθ(s,a)Gt\nabla_\theta \log \pi_\theta(s,a) * G_t
    • 리턴이 음수일 경우, 그 리턴을 반환하는 액션의 확률은 감소시키도록 업데이트됨

    • 만약 양수만 존재할 경우, 더 큰 값을 더 크게 업데이트 함 → πθ(s,a)\pi_{\theta}(s,a)의 아웃풋은 확률이기 때문에 값을 모두 더하면 1인데 즉, 리턴이 더 좋았던 쪽의 액션이 더 많이 강화되어 더 확률이 올라감

Q : θlogπθ(s,a)\nabla_\theta \log \pi_\theta(s,a) 대신 θπθ(s,a)\nabla_\theta \pi_\theta(s,a)를 사용해도 될까요?

  • θJ(θ)Eπθ[θπθ(s,a)Gt]\nabla_\theta J(\theta) \ne \mathbb{E}_{\pi_\theta}[\nabla_\theta \pi_\theta(s,a) * G_t]이기 때문에 안됨

    • 아까 말한 샘플 기반 방법론 기반 변환 수식을 보면

      θJ(θ)=sSd(s)aAθπθ(s,a)Rs,a\nabla_\theta J(\theta) = \sum_{s\in S} d(s)\sum_{a\in A}\nabla_\theta \pi_\theta(s,a)\,R_{s,a}
      θJ(θ)sSd(s)aAπθ(s,a)θπθ(s,a)Rs,a\nabla_\theta J(\theta) \ne \sum_{s\in S} d(s)\sum_{a\in A}\pi_\theta(s,a)\,\nabla_\theta \pi_\theta(s,a)\,R_{s,a}

    • 임으로 사실 그냥 다른 식임


REINFORCE 구현

  • θJ(θ)Gtθlogπθ(st,at)\nabla_\theta J(\theta) \approx G_t * \nabla_\theta \log \pi_\theta(s_t, a_t)
    • 데이터를 이용하여 계산해야 하는 gradient 식
    • 식은 GtG_t라는 상수에 logπθ(st,at)\log \pi_\theta(s_t, a_t)의 그라디언트가 곱해져있지만, 파이토치나 텐서플로같은 라이브러리는 미분된 형태의 수식을 사용하지 않음

  • DQN에서 구현할 땐 아래처럼 θL(θ)\nabla_\theta L(\theta)에 대한 수식이 아니라 L(θ)L(\theta)에 대한 수식을 사용함
    • L(θ)=(r+γmaxaQθ(s,a)Qθ(s,a))2L(\theta)=(r+\gamma \max_{a'} Q_\theta(s',a')-Q_\theta(s,a))^2
    • θL(θ)(r+γmaxaQθ(s,a)Qθ(s,a))θQθ(s,a)\nabla_\theta L(\theta)\approx-\left(r+\gamma \max_{a'} Q_\theta(s',a')-Q_\theta(s,a)\right)\nabla_\theta Q_\theta(s,a)

  • Gtlogπθ(st,at)G_t * \log \pi_\theta(s_t, a_t)
    • θ\theta에 대한 항이 πθ(st,at)\pi_\theta(s_t,a_t)뿐이기 때문에 그냥 θ\nabla_\theta 연산자를 지워버리면 L(θ)L(\theta)가 됨

  • 라이브러리의 optimizer는 손실 함수를 자동으로 minimize하는 방향으로 업데이트 하지만 REINFORCE 알고리즘은 gradient ascent를 사용하기 때문에 maximize하는 방향으로 업데이트 해야함
    • Gtlogπθ(st,at)-G_t * \log \pi_\theta(s_t, a_t)
      • 즉, 위 값을 minimize하는 것은 곧 Gtlogπθ(st,at)G_t * \log \pi_\theta(s_t,a_t)를 maximize하는 것







profile
AI & Robotics

0개의 댓글