---
# System prepended metadata

title: DRL 介紹

---

# DRL 介紹

### 簡介
&emsp;&emsp;本人主要依據[李弘毅老師的 DRL 課程](https://www.youtube.com/watch?v=z95ZYgPgXOY&list=PLJV_el3uVTsODxQFgzMzPLa16h6B8kWM_&index=1)，搭配其他網路上的資料與論文，撰寫出這篇 DRL 入門介紹。

## Reinforcement Learning (RL) 介紹
&emsp;&emsp;首先我們先來看最基本的 RL 架構。如下圖所示，一個 RL 架構包含 Agent (又稱 actor)、Environment、State (又稱 observation)、Reward 和 Action。我們考慮在時槽 $n$ 時，Agent 會根據上一個時間的 Reward $r[n-1]$ 和這個時間的 State $s[n]$ 來當作輸入，透過一個 Policy $\pi$ 來決定這個時間的 action $a[n]$，這個 policy $\pi$ 就是你要訓練的網路，假設目前網路訓練的參數為 $\theta$。而 environment 會根據 action $a[n]$ 來給出這個時間的 Reward $r[n]$ 並回傳給 Agent，environment 也會更新 State 成 $s[n+1]$。

![RL framework](https://hackmd.io/_uploads/rkN-Uzpqxg.png)



註: 為甚麼 state 又稱 observation? 有些人認為 state 是模型最真實的狀態，而我們用來訓練的資料只是我們從外界觀察到模型的變化過程，state 往往無法被觀察到或難以被定義出來，因此稱這個觀察為 observation。這裡提到很重要的一點：「observation 是我們從外界觀察到模型的變化過程」，因此你如何定義 observation 可以跟你的真實狀態越接近，那模型就越接近真實的模型。


&emsp;&emsp;我們稱一個互動過程為一個 episode，舉例可能是下一盤棋、玩一場遊戲等等。假設一個 episode 耗費的時間為 $N$，那 Agent 的目標就是要最大化

$$R=\sum^{N}_{n=1}r[n]$$

&emsp;&emsp;一個 trajectory $\tau$ 可以被定義為一段時間 $N$ 內的所有 state 跟 action，而我們可以定義產生這個 $\tau$ 的機率為

\begin{equation}
p_{\theta}(\tau)=p(s[1])\prod_{n=1}^{N}p_{\theta}(a[n]|s[n])p(s[n+1]|s[n],a[n])
\end{equation}

其中 $p_{\theta}(a[n]|s[n])$ 是 Agent 可以決定的 action，而 $p(s[n+1]|s[n],a[n])$ 是 environment 決定的 state。接著我們用 $R(\tau)=\sum^{N}_{n=1}r[n]$ 表示一個給定的 $\tau$ 的 reward，由於 $\tau$ 是一個隨機變數，因此 reward 也是一個隨機變數。因此我們要最大化的是 reward 的期望值:

$$\overline{R}_{\theta}=E_{\tau\sim p_{\theta}(\tau)}[R(\tau)]=\sum_{\tau}R(\tau)p_{\theta}(\tau)$$

那做法就是對 $\overline{R}_{\theta}$ 做 gradient 來求最大值 :

\begin{align*}
\nabla \overline{R}_{\theta} 
&= \sum_{\tau}R(\tau)\nabla p_{\theta}(\tau) \\
&= \sum_{\tau}R(\tau)p_{\theta}(\tau)\frac{\nabla p_{\theta}(\tau)}{p_{\theta}(\tau)}\\
&= \sum_{\tau}R(\tau)p_{\theta}(\tau)\nabla\log(p_{\theta}(\tau))\\
&= E_{\tau\sim p_{\theta}(\tau)}[R(\tau)\nabla\log(p_{\theta}(\tau))]\\
&\approx  \frac{1}{M}\sum^{M}_{m=1}R(\tau^m)\nabla\log(p_{\theta}(\tau^m))\\
&= \frac{1}{M}\sum^{M}_{m=1}\sum^{N_m}_{n=1}R(\tau^m)\nabla\log(p_{\theta}(a^m[n]|s^m[n]))
\end{align*} 

其中近似是因為我們沒辦法求出所有 $\tau$，因此用蒙地卡羅方法撒點來求出近似期望值，第六個等號是因為 $p(s[n+1]|s[n],a[n])$ 跟 $\theta$ 沒有關係，所以微分會不見。直觀概念就是若因這個 state 產生的 action 可以讓 reward 變大，那我們就要增加這個執行的機率。這邊要注意的是：「每個 $n$ 最終乘上的 weight 是這次 episode 的 reward，並不是當下時間的 reward。」

&emsp;&emsp;在實作上，有以下幾點可以注意：
1. 每次更新完 $\theta$ ，我們都會需要重新 sample 很多 trajectories。
2. 由於 reward 可能一直都是正的，因此我們在算 gradient 時可以把 reward 減掉一個 baseline $b$，有點像中間值的概念，讓 reward 可以有正有負，這樣可以避免有些 action 因為沒有被 sample 到，經過權重調整且正規化後，這個 action 反而被選到的機率被降低。整題來說可以改寫為

$$\nabla \overline{R}_{\theta}=\frac{1}{M}\sum^{M}_{m=1}\sum^{N_m}_{n=1}(R(\tau^m)-b)\nabla\log(p_{\theta}(a^m[n]|s^m[n])) $$

3. 由於當下的行動跟之前的行動應該是無關的，如果都乘上同一個 reward 其實不公平，因此比較公平的算法是當下的 action 應該乘上他發生的時間以後計算出來的 weight。此外，我們會在乘上一個 $\gamma$ 來代表這個這個 action 對未來步驟的影響力 (discount)，時間越久，這個影響力越小。具體來說可以寫成：

$$\nabla \overline{R}_{\theta}=\frac{1}{M}\sum^{M}_{m=1}\sum^{N_m}_{n=1}(\sum^{N_m}_{n'=n}\gamma^{n'-n}r^{m}_{n'}-b)\nabla\log(p_{\theta}(a^m[n]|s^m[n])) $$

其中 $A^{\theta}(s[n],a[n])=\sum^{N_m}_{n'=n}\gamma^{n'-n}r^{m}_{n'}-b$ 其實就是我們的 advantage function，代表在某一個 state 時，這個 action 相較其他的 action 有多好。(可以由 critic 評估)


## On policy v.s. Off policy

&emsp;&emsp;前面我們說到若要使用 DRL 的方法，為了避免計算期望值，我們必須要每次更新都 sample 一堆資料，這樣是耗時且浪費資源的。為此，科學家們想出一種 Off policy 的方法來解決此問題。而我們前面提到的其實是 On policy 的方法，這兩種方法的說明如下：
* On policy：要學習的 agent 自己跟環境的互動來學習。
* Off policy：要學習的 agent 透過觀察其他 agent 跟環境互動的來學習。

這種 Off policy 的方法令要學習的 agent 透過觀察其他 agent 跟環境的互動來學習。想當然耳我們會對更新公式做出一些修改，然而這些修改剛好解決了我們要在每個步驟取樣一堆點的問題，以下我會依序講解。

### Importance Sampling

&emsp;&emsp;首先，我們介紹 Importance Sampling，回想上一章講的：「我們要從某 $p$ 分布取樣，將取樣後的值帶入某個函數，並算出這個函數的期望值，但這個值算不出來，因此我們用蒙地卡羅撒點近似平均值。」但 Importance Sampling 告訴我們可以不用一定要從 $p$ 分布取樣，也可以從任意 $q$ 分布取樣，之後再乘上一個 weight 便會就會跟從 $p$ 取出來的點一樣。具體數學式如下：

$$
E_{\tau\sim p_{\theta}(\tau)}[R(\tau)]= \int R(\tau)p_{\theta}(\tau)d\tau=\int R(\tau)\frac{p_{\theta}(\tau)}{q_{\theta}(\tau)}q_{\theta}(\tau)d\tau=E_{\tau\sim q_{\theta}(\tau)}[R(\tau)\frac{p_{\theta}(\tau)}{q_{\theta}(\tau)}]
$$
其中可以看出 $\frac{p_{\theta}(\tau)}{q_{\theta}(\tau)}$ 便是要乘上的 weight。因此，我們的 gradient 更新公式便可以寫為：

$$
\nabla \overline{R}_{\theta}= E_{\tau\sim p_{\theta}(\tau)}[R(\tau)\nabla\log(p_{\theta}(\tau))]=E_{\tau\sim p_{\theta'}(\tau)}[\frac{p_{\theta}(\tau)}{p_{\theta'}(\tau)}R(\tau)\nabla\log(p_{\theta'}(\tau))]
$$
其中 $p_{\theta'}(\tau)$ 便是我們要取樣的分佈，只要在第一次做取樣就好。由於我們每個步驟都會更新 $\theta$，所以 weight $,\frac{p_{\theta}(\tau)}{p_{\theta'}},$ 絕對會變，也因此可以一直使用第一次取樣的資料來訓練。

&emsp;&emsp;接著再回到 Advantage 的形式，我們可以推導出：

\begin{align*}
\nabla \overline{R}_{\theta} 
&= E_{(s[n],a[n]\sim\pi_{\theta})}[\sum^{N_m}_{n=1}A^{\theta}(s[n],a[n])\nabla\log(p_{\theta}(a[n]|s[n])) \\
&= E_{(s[n],a[n]\sim\pi_{\theta'})}[\sum^{N_m}_{n=1}\frac{p_{\theta}(s[n],a[n])}{p_{\theta'}(s[n],a[n])}A^{\theta'}(s[n],a[n])\nabla\log(p_{\theta}(a[n]|s[n]))\\
&= E_{(s[n],a[n]\sim\pi_{\theta'})}[\sum^{N_m}_{n=1}\frac{p_{\theta}(a[n]|s[n])}{p_{\theta'}(a[n]|s[n])}\frac{p_{\theta}(s[n])}{p_{\theta'}(s[n])}A^{\theta'}(s[n],a[n])\nabla\log(p_{\theta}(a[n]|s[n]))\\
&= E_{(s[n],a[n]\sim\pi_{\theta'})}[\sum^{N_m}_{n=1}\frac{p_{\theta}(a[n]|s[n])}{p_{\theta'}(a[n]|s[n])}A^{\theta'}(s[n],a[n])\nabla\log(p_{\theta}(a[n]|s[n]))\\
\end{align*}

其中第四個等式是因為 $p_{\theta}(s[n])$ 跟 $p_{\theta'}(s[n])$ 可以視為一樣的分佈。此時我們便推導完 off policy 的 gradient 了，以下在做幾點說明：
1. 由微分式子我們可以在推回 objective function 為：
\begin{equation}
J^{\theta'}(\theta)=E_{(s[n],a[n]\sim\pi_{\theta'})}[\sum^{N_m}_{n=1}\frac{p_{\theta}(a[n]|s[n])}{p_{\theta'}(a[n]|s[n])}A^{\theta'}(s[n],a[n])]
\end{equation}
2. 雖然我們可以推導出 importance sampling 後的分佈的期望值與原分佈的期望值相同，但我們卻無法保證它們的變異數一樣。若變異數差太多，會造成機率分佈差太多，也就是訓練出來的模型跟原模型會不匹配。

### PPO

&emsp;&emsp;上一小節我們講到若被 importance sampling 的分佈與原分佈差太多，則訓練出來的模型跟原模型會不匹配。而 Proximal Policy Optimization (PPO) 演算法就是在處理這個問題。他在原目標函數中加了一個限制，使訓練出來的模型跟原模型不會差太多，具體數學如下：
\begin{equation}
J^{\theta'}_{PPO}(\theta)=J^{\theta'}(\theta)-\beta KL(\theta,\theta')
\end{equation}
其中 $KL(\theta,\theta')$ 其實也不太好算，因此之後還有延伸出一個 PPO2 演算法，不用算 $KL(\theta,\theta')$，更容易實作，有興趣可以去看李老師的影片。

## Q-Learning

&emsp;&emsp;一個不直接參與決定 action ，但會評價其他 agent 的 agent 我們稱為 critic，而被評價的 agent 我們可以稱為 actor。critic 會根據狀態 $s[n]$ 來給出這個 actor 使用的 policy $\pi$ 在時間 $n$ 之後的價值 $V^{\pi}(s[n])$。從定義上來看，他是一種 off policy。有一些方法可以用來設計 $\pi$ 的價值函數 $V^{\pi}(s[n])$ ，包含 Monte-Carlo (MC) 方法跟 Temporal-difference (TD) 方法。

&emsp;&emsp;MC 方法是先讓 actor 跟環境互動，產生一組 state 和他們對應的 cumulated reward，之後讓 $V^{\pi}(s[n])$ 網路去學習不同 state 和他們可以得到的分數，這樣就可以學出 Policy $\pi$，這個學法可以用回歸的方式學習。

&emsp;&emsp;TD 方法一樣是先讓 actor 跟環境互動，產生一組 state 和他們對應的 cumulated reward。之後讓 $V^{\pi}(s[n])$ 網路去學習輸入 $s[n]$ 跟 $s[n+1]$ 得到的分數會差 $r[n]=V^{\pi}(s[n])-V^{\pi}(s[n+1])$，這樣就可以學出 Policy $\pi$，這個學法可以用回歸的方式學習。

&emsp;&emsp;此外，我們介紹一種類似價值函數的 Q-function $Q^{\pi}(s[n],a[n])$，只不過它的輸入變成 state 跟 action。Q-function 的方法一樣是先讓 actor 跟環境互動，產生一組 state 、根據 $\pi$ 的對應 action 和他們對應的 cumulated reward。之後用類似 TD 的方式，讓 Q-function 網路去學習 $s[n]$ 跟 $a[n]$ 與 $s[n+1]$ 跟 $\pi(s[n+1])$ 之間的差 $r[n]=Q^{\pi}(s[n],a[n])-Q^{\pi}(s[n+1],\pi(s[n+1]))$，這樣就可以學出 Q-function。

&emsp;&emsp;總之，假設我們現在有一個 actor 擁有 policy $\pi$，讓其跟環境互動一下我們可以得到很多組狀態跟分數。我們將這些資料拿來訓練 Q-function $Q^{\pi}(s[n],a[n])$。接著我們在找出可以使 $Q^{\pi}(s[n],a[n])$ 在不同 state 最大化的 action，並將其拿來當作我們的新策略 $\pi'$，此策略可以保證 $V^{\pi'}(s[n])>V^{\pi}(s[n])$。接著在替換掉舊策略 $\pi$，然後再不斷重複便可以得到最佳策略。如下圖所示：

![Q-learning diagram.drawio](https://hackmd.io/_uploads/HkBkczpqll.png)


&emsp;&emsp;但實作上要注意的是，有可能我們在訓練 Q-function 時，有一些 state 跟 action 並沒有被使用到。為了更全面的試出所有可能的 action，我們在找 action 時不一定會根據 policy 來找，目前較普遍的有兩種做法，包括 Epsilon Greedy 跟 Boltzmann Exploartion：
1. Epsilon Greedy 的作法是設定一個 $1-\epsilon$ 當作選 policy 選的 action 的機率，反之則隨機選 action。通常我們會將 $\epsilon$ 隨時間遞減：

\begin{align}
a=
\begin{cases}
\underset{a}{argmax} Q(s,a), & (1-\epsilon)*100\%\\
0, & \text{otherwise}\\ 
\end{cases}
\end{align}

2. Boltzmann Exploartion 則是將所有某個 state 所有可能的 action 去做正歸化求出機率，接著隨機 sample 出 action。也就是 Q-value 越高就越有機會被 sample，但 Q-value 小也會有機會被 sample 到：

$$
P(a|s)=\frac{\exp(Q(s,a))}{\sum_a \exp(Q(s,a))}
$$

### Replay Buffer
&emsp;&emsp;通常我們會設一個 buffer 來收集資料，而 Q-function 在訓練的時候就一次從 buffer 裡面拿一個 batch 的資料量進來訓練。這邊講一個比較玄的事情，就是 buffer 內不一定都是要是 policy $\pi$ 跟環境互動過的結果，也可以是以前的 policy 跟環境互動的結果。雖然聽下來推翻了我們 Q-learning 講的所有東西，我們變成要找一個比未知的 policy 還要好的 policy $\pi'$，但理論跟模擬都可以證明這個新 policy $\pi'$ 一定比舊 policy $\pi$ 還要好。會這樣做的好處是可以增加多樣性，並且用 replay buffer 可以讓我們減少當下要跟環境互動的次數，主要的資料都是過去的經驗。演算法可以參考以下圖片：


![image](https://hackmd.io/_uploads/HkxoyPn9gx.png)

## Advantage Actor-Critic

&emsp;&emsp;在前幾章我們有講到：

$$\nabla \overline{R}_{\theta}=\frac{1}{M}\sum^{M}_{m=1}\sum^{N_m}_{n=1}(\sum^{N_m}_{n'=n}\gamma^{n'-n}r^{m}_{n'}-b)\nabla\log(p_{\theta}(a^m[n]|s^m[n])) $$

但由於模型的隨機性，我們的 $G^m[n]=\sum^{N_m}_{n'=n}\gamma^{n'-n}r^{m}_{n'}$ 是非常不穩定的。因此，結合上述所學，我們將 $G^m[n]$ 替換成 $E[G^m[n]]=Q^{\pi_{\theta}}(s^m[n],a^m[n])$。而上式的 b 我們就以 $V^{\pi_{\theta}}(s^m[n])$ 取代，因為 $V^{\pi_{\theta}}(s^m[n])$ 就是 $Q^{\pi_{\theta}}(s^m[n],a^m[n])$ 的期望值。我們令 $Q^{\pi_{\theta}}(s^m[n],a^m[n])=E[r^m[n]+V^{\pi_{\theta}}(s^m[n+1])]\approx r^m[n]+V^{\pi_{\theta}}(s^m[n+1])$，此時 $Q^{\pi_{\theta}}(s^m[n],a^m[n])$ 會因為 $r^m[n]$ 而有一點不穩定，但怎麼樣也比 $G^m[n]$ 的不穩定來的好。所以我們的 Advantage 可以寫為 
$$
A^{\theta}(s[n])=r^m[n]+V^{\pi_{\theta}}(s^m[n+1])-V^{\pi_{\theta}}(s^m[n])
$$
&emsp;&emsp;因此，Advantage Actor-Critic 的流程圖如下所示，只是將學習 Q-function 改成學習 V-function 而已。

![V-learning diagram](https://hackmd.io/_uploads/B1pSqzT5ge.png)


&emsp;&emsp;在做訓練 V-function 時有一個小技巧是「加一個提高輸出 entropy 的限制」，這個限制可以使得在 exploration 時更全面。


## 結語
&emsp;&emsp;這個網頁算是整理了 DRL 的基本介紹，但並沒有包含所有李宏毅老師授課的內容，有一些比較細節的，像是 Q-learning advanced tips (裡面有 DQN)、Q-learning continuous action、sparse reward (很難獲得 reward 怎麼辦) 跟 limitation learning 等等，大家有興趣可以在自行去觀看影片。
