Policy, Q 和 V:到底該用哪個

ReinforcementLearning
Published

August 6, 2026

開場

【師】「今天要講的大概是 RL,Day 1 到 Day 10 的部分。我現在大概整理出一個脈絡,這個脈絡既不是照歷史的順序,也不是我心中最完美的走法。我心中比較完美的走法是這樣:RL 是一個很大的 setup,它有各種形態的問題,我們可以從最簡單的開始,提出方法一,某種方法可以簡單解決;接著遇到困難、某些情境卡住了,就提出方法二;方法二解了一些、但也有些解不出來,再提出方法三。所以今天我們可以一起,把這三、四個方法探索出來。好,開始吧,先來複習一下 RL 的 setting 是怎樣。」

RL setup

(manim: 環境↔︎代理人迴圈,s0→π→a0→env→s1,r1 一步步長出來)

【師】「你有一個 environment。一開始,你呼叫 environment.reset(),它就回傳第一個 observation 給你,就是圖上這個 s0。然後你根據這個 observation、用你的 policy π,算出一個 action a0,也就是這裡的 a0。」

【生】「所以 π 是一個 function 嗎?」

【師】「對,policy 就是一個 function,就是你要做出來的那個 function。你根據 s0 算出 a0,然後把 a0 丟給 environment,environment.step(a0),走一步。然後 environment 回傳給你五個東西:s1,下一個 observation;這個 action 的 reward,r1;是不是 terminate;是不是 truncate;還有一些其他 information。其他 information 其實不重要,可以想像它回傳四個東西。terminate 跟 truncate 這兩個是 boolean。所以最重要的,就是前面兩個:下一個 s1、跟第一步的 reward r1。」

【師】「這個 environment 還有一個性質先記著:它保證只跟上一個 state 有關。它可能有隨機性,但下一步只 depends on 前面那個 state,沒有藏起來的 hidden state。這叫 Markov,之後會用到。」

【生】「我有個小問題,為什麼叫 observation,不叫 state?」

【師】「嗯,s 感覺就是 state 嘛,你要叫它 state 也可以。不過嚴格講,你『觀察到』的不一定是環境的全部,所以我們叫它 observation。今天先當它們一樣,都寫 s。」

【師】「然後就是把 a1 再丟進去、以此類推,一直走下去。走的時候要判斷一下:if terminate or truncate,代表這個 environment 已經結束了,那我就要再呼叫一次 reset,它才會從頭開始玩。」

【師】「terminate 跟 truncate 差在哪?分成兩種結束方式。truncate 是,我不想讓它跑無窮迴圈,所以選在一個比較大的數字,比如最後給你走一千步,走滿就 truncate。terminate 是遊戲真的結束了。」

(footage: cartpole_random | slide 旁標:reward = 每撐一步 +1)

【師】「舉個例子。假設我要控制一台車,上面有一根桿子,我想控制這台車、讓桿子不要倒。桿子會因為重力往左或往右倒,但我可以把車往左拉、往右拉來平衡。這個情況下 reward 的設計,就是每一步加一分,直到結束;結束可能是桿子倒超過一個角度,或車子超出一個範圍,那就是 terminate;走滿一千步就是 truncate。所以在這個情況下,我最好要撐到 truncate 越好。」

(footage: frozenlake 迷宮圖 [manim 畫] | 旁標:每步 −1、到終點才停)

【師】「另外一種是走迷宮。我要從起點走到終點,中間有一些陷阱不能掉進去。這個情況我要越快越好,所以走到 truncate 反而不好。terminate 有可能是掉進洞裡、也有可能是走到終點,所以在 terminate 那一步,你還是會拿到一個 reward。」

【師】「reward 怎麼設計,你可以有不同做法:走到終點加一百分、平常每步零分;或每走一步扣一分、走到終點零分;或洞裡要不要扣分。這些都是不同的 reward 設計。不同設計,就自然對應出不同的最佳 policy。而這些 reward 設計,都是問題定義的一部分,都還在『問題的定義』裡面。」

(manim: maximize E[r1+r2+r3+…] 一項一項寫出)

【師】「那我們所謂 optimal 的 policy,就是要最大化 r1 加 r2 加 r3 這一系列 reward 的期望值。這就是我們的目標:找到一個 policy,最大化 reward 總和的期望值。」

(manim: 每項乘 γ^k,遠處變淡)

【師】「不過,這樣直接把 r1、r2 一直加下去,有可能會不收斂。如果這個遊戲可能永遠玩不完、一直加下去,總和可能加到無限大,那『最大化一個無限大的東西』根本沒有意義。所以我們不得不給每一項乘一個 γ、一個 decay 的比率,比如 γ 取 0.99:步數越多,γ 的 n 次方就越小、可以忽略,總和才會收斂成一個有限、有定義的數。加了 γ,數學上比較好分析,有些性質才成立。不過那些漂亮的收斂保證,是對最單純的情況才嚴格成立的,之後我們會再認真談收斂。」

【師】「所以在這個框架下,我們現在只要專注在一件事:把 policy π 做出來,讓 r1+r2+r3 這個 reward 總和越大越好。至於這個 reward 設計得好不好、能不能真的引導我們走到心中的最佳解,那是框架外的事,我們先不管。reward 跟 environment 都是給定的;environment 可以讓我們實驗很多很多次,我們就透過跟它互動,去把這個 π 學出來。」

【生】「那 environment 跟 reward 是誰給的?我們現在是專注在設計 action 的角色?」

【師】「對,你講得很好,確實是這樣。但未來某一刻,比如你真的要拿程式去玩瑪利歐,瑪利歐不會給你 reward,那你就要自己設計 reward。我們現在談的,是假設 reward 已經設計好,那 policy 要怎麼解出來。」

【生】「所以我們是設計 action 去解 π 嗎?」

【師】「不是,我們是設計 policy 這個函數,我們只在乎 policy。action 是 policy 的產物。」

【生】「喔,因為 action 是 policy 的 output。」

【師】「對。而且這個 π 也可以有隨機性,不一定要是決定性的策略。這句先記著,等一下會用到。」

把 π 做成一個網路

【師】「好,problem 這樣就定義清楚了。接下來的問題是:這個 π 到底長什麼樣、我們要怎麼把它做出來?」

【師】「先分一下情況:state 有 state space、observation 有 observation space、action 有 action space。有可能兩個都有限,那就比較簡單,我可以列一張表,把所有 state 對 action 的可能性列出來,這叫 tabular。也有可能 state 有無窮多種,比如超過 10 的 20 次方,對我們來說幾乎就是無窮多。」

【師】「今天要談的例子是:state 無窮多種,但 action 有限種。兩個都有限太簡單;state 無限、action 有限,稍微變難、又不至於太難。所以今天就專注在這一種。」

(manim: π=NN 吃 state,吐 1×4 向量;四格=上下左右)

【師】「所以我們的 π,把 action 想像成上下左右四種可能。你可以說 π 輸出 0、1、2、3 其中一個整數。但具體來說,我們設計上是把 π(s) 設計成這四個按鈕的一個 logits。」

【生】「logits 是什麼?」

【師】「logits 就是它的 log probability。比如機率是 0.1、0.2、0.7、0,這是一個機率分佈;轉成 logits,就是 log 0.1、log 0.2、log 0.7、跟一個趨近負無窮的數。」

【生】「那要把它 normalize、加起來等於一嗎?」

【師】「不太需要。因為取 log 之後它可以平移,同時加一、同時加十,完全沒差。所以它並沒有 normalize。之後你要把 logits 變回機率,那個叫 softmax:把這堆東西取 softmax,就變回一個機率分佈。這只是為了之後方便,讓大家知道我們在討論什麼,當然你也可以有別的設計。」

【師】「所以我們設計一個 policy π,output 一個 1×4 的向量,代表按上下左右的 logits。如果某個 state 一定要按上,那它這邊就很高、比如 10,其他很低、比如 -5、-3、-2,那就幾乎百分之百按上。」

【師】「因為 input 要無窮多種,所以我們就設計一個 function、output 一個 1×4 的向量,那 π 就假設是一個 neural network。不管你要多複雜、fully connected、幾層深,都不是重點。重點是,它要學什麼?」

為什麼不能用 supervised learning

【師】「最直覺的想法,是套 supervised learning。在 supervised 的框架下,我們已經給好你很多個 pair、s 跟 a 的 pair。我會告訴你:在這個 state 下正確答案的 action 是什麼;在另一個 state 下正確答案是什麼。」

【生】「喔,餵給正確答案。」

【師】「對。假設沒有唯一正確答案、是一個機率,那也得有一個相對正確的、比如 1、0、0、0(百分之百按上),它還是會被翻譯成一個向量。然後取這個 output 跟正確答案的 mean square error、或者 cross entropy 去學。」

【師】「但這邊是 reinforcement learning,這邊就是沒有一個正確答案可以學的問題。」

【生】「對,我只能一直探索 environment,一直走、一直走,從來沒有任何人告訴我正確的 a 是什麼。那我要怎麼套用 neural network 這一套?」

【師】「對。你剛剛講的就是重點:要 train 一個 network,我一定要『正確的 a 是什麼』,那個 network 才有辦法更新。但現在不是這樣。我們只有一直跟 environment 互動的機會,而 environment 只告訴我們每一步的 reward,永遠不會告訴我們正確的 action。」

【生】「那我這個 network 要怎麼 train?我的 loss 是什麼?reward 要怎麼被翻譯成『哪一步該加強』?」

【師】「對。而且更麻煩:比如你這一步走往上,你可能上、下、左都拿到一樣分數、沒有死,只有往右是死了。但其實往上、往下、往左,就真正的最佳解而言,可能走其中某一個方向才是好的。所以你走錯一步,它並不會立即反應在 reward 上。」

(slide: 順帶一提,這正是現在 LLM 的作法)

【師】「順帶一提,這件事跟現在的大語言模型有關。你看它好像很強、會寫詩,但它主體其實是 supervised learning:我們把人類大量的文本,拆成 next token prediction,叫神經網路學『下一個字要什麼』。甚至現在會思考、會寫程式的 AI,它還是在做 supervised learning,只是背後多了一層 reinforcement learning:先用 RL 探索、生出正確的推理過程跟程式,再用 supervised learning 把那條推理鏈背下來。先探索、有人告訴它『你這一步是好的』,然後把好的背下來。這個之後有機會再展開,先回到我們的問題。」

造一個評分器 V + 經驗池

【師】「既然沒有正確答案可以直接學,我們換個角度:與其學『正確的 action 是什麼』,不如先學會『評分』。所以我們再造一個 network,就是這個 V。」

(manim: 第二個網路 V,吃 s,吐一個數:從這步之後預期還能拿幾分)

【師】「它在 state sₜ 的時候,會預測一個 estimation:我預估從這一步之後、從 sₜ₊₁ 到最終局,我會拿到多少 reward。」

【師】「但這個 V 必須跟著某一個策略 π,它才有實質意義。因為我往後每一步,都要在某種策略的引導之下去走,不然這個期望值要怎麼算?所以 V 其實是一個 V^π:在目前這個 π 策略底下,我之後期望會拿到幾分。」

【生】「這個 π 是在 sₜ 這個狀態的 π 嗎?」

【師】「π 就是我上面那個 network,把 state 變成 action 的那個 policy,它 depend on input state。」

【生】「反正它們兩個都是 network。」

【師】「對,V 跟 π 是兩個獨立的 network,我現在手上有兩個 network。」

(footage: cartpole_random | manim: 玩一局 → 收集 (s,a,r,s’,done) → 丟進桶子 buffer)

【師】「然後我還要有一個 observation buffer、經驗池。我玩一局,譬如從 s0 開始,玩到不管是 terminate 還是 truncate。那我就有一大堆樣本,把每一步放進 buffer 裡面。放進去的每個元素,都是一個 5-tuple:我在哪個 state、做了什麼 action、拿到 reward 幾分、變成什麼 state、terminate 了沒。這五個。」

【師】「其實這些 sample 是有 correlation 的,因為上一個 state 就是下一個 state。但沒關係,我們就收集起來。走一回合,就拿到一大堆 sample。也可以玩十局,一起丟進一個 buffer,再開始學。」

【生】「這是我們的 training data 嗎?」

【師】「對。而這正是 reinforcement learning 跟其他所有 supervised learning 非常非常不一樣的地方:supervised 都是先把 data 給好、你去學一個 distribution;RL 是它自己一邊 sample、一邊解,它的 training data 是它自己生出來的。玩越多回、training data 越多、越準。」

【生】「等一下,我先整理一下:這要先有一個 policy、就是 random policy,用它生出這個 observation buffer,然後去 train 那兩個 network。就是先有 random 的 π,生出 buffer,然後我去 train V。不用 update π 嗎?」

【師】「要 update π。然後它再生成一個新 buffer、train 出新的 V、update π,一直無限循環,直到它收斂。」

【生】「對,就是這樣。I’m so smart.」

【師】(笑)「好。那怎麼 update V,還算明顯:跑完一局之後,你就有它真實的 return,也就是 sₜ 之後真實拿到的總分,我們叫 Gₜ。所以你就有這個 target、所謂的『正確答案』,V 要做的就是逼近它。更新 V 的 loss,就是 min square error:(Gₜ − V(sₜ)) 的平方。所以 V 可以越 train 越準,這是可預期的。」

用 V 讓 π 進步:advantage

【生】「等一下,這個 V 是跟著現在這個爛策略估出來的。我們還沒找到 optimal π,學這個爛 V 有什麼用?」

【師】「對,本身沒用。(笑)但我們可以拿這個 V 去幫助 π 進步。怎麼幫?我們看這個 Gₜ 減 V(sₜ)。」

(manim: Gₜ − V(sₜ);三種可能,第三條打星)

【師】「假設 Gₜ 大於 V(sₜ),是什麼意思?三種可能。第一,單純幸運,V 是期望值,這一輪 sample 到的 Gₜ 剛好比較高,sample 還是有 variance。第二,V 低估了、沒估準,但先不管。第三種才是重點:V 估的是平均,但這一步我已經走了 aₜ、也就是這一步走對了,所以讓 Gₜ 變得更高。」

【師】「比如在 π 這個策略下,在 sₜ 走 aₜ 的機率是 0.4。V 大概可以猜:我 0.4 的機率走這一步、0.3 走另一步、0.2 走另一步;但 Gₜ 是我『確實走在 0.4 那個框框裡面』、而且往後也確實走出了得到最高 reward 的路,所以 Gₜ 就會比 V 高。這代表這一步走對了。」

【生】「有道理。那所以我們應該提高這個 0.4?」

【師】「對,提高在這個 state 做這個 action 的機率。比如上下左右四格,他現在走上、發現 G 比 V 高,那他要做的就是把『上』那個機率提高。反過來如果是負的,就要降低這個機率。」

【生】「等一下,如果我們只是把『做過、結果好』的動作機率調高、壞的調低,那它怎麼會去試那些沒試過、但其實更好的動作?」

【師】「好問題,這叫 exploration、探索。答案其實藏在前面:π 吐的是機率、不是『一定選哪個』,所以它每一步都有機率 sample 到別的動作、包括沒試過的。正因為策略是隨機的,它才會去探索,這也是為什麼我們一開始不讓它太確定。」

【生】「所以『隨機』是故意的。」

【師】「對,這就是剛剛叫你先記著的那句。」

(manim: π(aₜ|sₜ) += α·(Gₜ − V);α=learning rate)

【師】「所以更新方向就是:把 π(在 sₜ 做 aₜ 的機率)加上 α 倍的 (Gₜ − V(sₜ))。α 就是 learning rate,一開始大步一點、後來小步一點。」

【生】「那為什麼要減 V?直接用 Gₜ 不行嗎?」

【師】「直覺是:減 V 是為了降低變異。Gₜ 抖得很厲害;你減掉『平均預期』V,剩下的就是『比平均好還是差』,這個數字乖很多、學起來穩很多。至於減 V 到底改不改變答案,最後我會用數學證給你看。」

(manim: 兩個問題 → log π → loss = −Σ(Gₜ−V)log π)

【師】「不過更新之前,這裡有兩個技術問題。第一,π 是 network 的 output,我們真正要動的是 network 參數。第二,π 在 0 到 1 之間,直接這樣加、加減會爆。所以我們改成加這個 log π。取完 log,0 到 1 之間的東西就變成任意實數,愛怎麼加都行。所以就是 log π 加上 α 倍的 (Gₜ − V)。寫成 loss,就是:loss = −Σ (Gₜ − V(sₜ)) log π(aₜ|sₜ)。」

【生】「為什麼取 log?而且為什麼剛好是 (Gₜ−V) 乘一次、不是三次方?為什麼是一比一?」

【師】「你問到關鍵。取 log 這一步是精確的,我到時候拿 log π 對 θ、network 參數做微分,剛好會掉出這個係數。但『乘一次』這件事,現在只是一個 heuristic、一個直覺;為什麼是一比一、不是平方,這一版還沒證明。你先把這個問號記住,這一整堂的高潮,就是最後回來把它解掉。」

【師】(嚴格分,這裡其實還要分 V(sₜ) 跟 V(sₜ, aₜ),後者就是 Q,我們以後會講到。這段先跳過。)

(manim: new algo 四步)

【師】「好,所以新的演算法:每跑一個 round,我們就獲得一大堆 5-tuple,丟進 buffer。然後更新 V,用 min square error。然後更新 π,用剛才推導的式子;這邊 V 雖然也是個 network,但我們把它固定起來、視為常數,所以這個 policy loss 不會去更新 V 的參數,只會更新 π。兩個 network 分開更新、一起進步。然後把 buffer 全部丟掉,回到第一步、拿新的 round,一直跑到收斂。」

【師】「這個方法,叫 REINFORCE + baseline,1992 年。那個被減掉的 V,就叫 baseline。記住這個年份。」

Bootstrap → Actor-Critic(A2C)

(slide: 痛點,Gₜ 要跑完一整局才算得出來)

【師】「REINFORCE 有個麻煩:Gₜ 你得跑完一整局才算得出來。」

【生】「那我們可不可以不要跑完一局,往後看 N 步就好?」

【師】「對,你又預言了下一個方法。這叫 bootstrap。」

(manim: Gₜ → rₜ + γ·V(sₜ₊₁),標 detach)

【師】「因為 Gₜ 其實等於 rₜ 加 γ 乘以 G_{t+1},而後面那一大串 G_{t+1},我們換成 V(sₜ₊₁)。所以把 Gₜ 換成 rₜ + γ·V(sₜ₊₁):一步是真實的 reward,剩下的用 V 估。這樣每一步就能更新,不用跑完整局。代價是不準度增加,你把後面真實的結果,換成一個 V 估計出來的結果。」

【生】「V(sₜ₊₁) 這一項……」

【師】「對,關鍵:這一項雖然也是 NN output,但這邊會被 detach、當成固定的。兩個 NN output 串在一起、相減、算出 loss,但這邊被 detach 了,所以 loss 只會傳到另一半邊。我們把它視為固定,才不會有『目標跟被更新的東西一起被更新』的問題。」

【師】「所以這個叫 A2C。」

【生】「A2C 是什麼縮寫?」

【師】「Advantage Actor-Critic。Advantage 就是剛剛那個 Gₜ 減 V。Actor 就是 π、負責動作;Critic 就是 V、負責評分。一個演、一個評。」

【生】「那 A3C 呢?」

【師】「A3C 前面多一個 A、Asynchronous、非同步,同時開很多個一起跑。後來發現非同步沒那麼重要,拿掉就變回 A2C。講一下年代:這名字是 2016 年前後的事,其實比等一下要講的 GAE 還晚;而 actor-critic 的想法,1980 年代就有了。所以你會發現,我們今天走的是好懂的順序,不是歷史的順序。」

GAE:一個旋鈕把兩端接起來

(manim: 光譜,左「看整局」REINFORCE、右「只看一步」A2C,中間旋鈕 λ)

【師】「那我們現在有兩端了:REINFORCE 是跑完全程、看整局;A2C 是只看一步。各有優缺點,那能不能把兩端接起來?接下來這個 Lambda decay,就是中間那顆旋鈕。λ 控制看幾步:一端是『看完全部』,另一端是『只看一步』,λ 在中間取平衡。」

【生】「λ 就是看幾步。這設計滿有道理的。」

【師】「對。所以我們把 rₜ + γV(sₜ₊₁) − V(sₜ) 這一坨,定義成 δₜ,只是符號簡化。那 value loss 就是 Σ δ²,policy loss 把 Gₜ 換成 δ。」

(manim: Âₜ = δₜ + γλ·Âₜ₊₁ 遞迴)

【師】「最後 δ 被換成 Advantage Â(數學上念 A hat)。Â 從最後一項往回算:Âₜ = δₜ 加上 γλ 乘以後面那一項。展開會發現它就是『往前看幾步』的加權,λ 的 K 次方乘看 K 步、λ 的 K+1 次方乘看 K+1 步,這樣加起來。」

【生】「可是那個 V 在哪?它還有 V 的估計嗎?」

【師】「V 藏在 δ 裡面,因為 δ 的定義裡就帶有 V。所以只是符號變簡單了,V 還是在裡面。」

(slide: GAE, Generalized Advantage Estimation, 2015)

【師】「所以我們現在已經迅速學完三個方法。這個叫 GAE,全名 Generalized Advantage Estimation,2015 年。E 就是 Estimation。它把 advantage 給 generalize 了。」

【師】「欸,你注意到年份了嗎?REINFORCE 是 1992,GAE 是 2015,中間隔了二十幾年。這中間,是 policy gradient 這條線的黑暗期:理論講得很美,但實際上 train 不起來、一上去就掉下來,大家一度不相信它。但同一段時間,另一條線、Q-learning,反而在發展、還做出了成績。所以不是整個 RL 都黑暗,是 policy gradient 這一脈卡住了。」

【生】「是因為 GPU 不夠強嗎?」

【師】「完全沒關係,這裡的 network 都超級小。是這套方法自己卡住,理論跟實作接不起來。」

Policy Gradient Theorem:把湊出來的 loss 證明成真

(slide: 回到那個問號,policy loss 是湊出來的吧?)

【師】「好,最後。還記得那個問號嗎?value loss 用 MSE 很合理,但 policy loss,是湊出來的吧?1992 年的 Policy Gradient Theorem 就在回答這件事。」

(manim: 整局 rollout 框成一個超大網路:s0→π_θ→a0→env→…→G0;π_θ 被 copy 很多遍)

【師】「我講一下架構。我們玩一個 round:從 initial state 開始,跑 π、做 action、進 environment、再跑 π,整個當成一個盒子,最後的 output 就是這些 return 的總和、就是 G0。那我們只要把 G0 定義成 loss(loss = −G0),把這整個當成一個超大神經網路;因為這個 π_θ 被 copy 了這麼多遍,那對 θ 求梯度,不就可以回來更新這一堆東西了嗎?大概是這個想法。」

(manim: 結論式 ∇_θ E[G0] = E[ Σ ∇ log π(aₜ|sₜ) · G ])

【師】「中間是一段漫長而複雜的計算,我不逼你跟每一步,那個你自己回去看筆記。我直接給你結論。因為 θ 是多變數,我們寫成這個倒三角形。」

【生】「那個倒三角形念什麼?我第一次看到。」

【師】「念 nabla,就是梯度符號。」

【師】「所以 ∇ E[G0],就等於:Σ ∇ log π(aₜ|sₜ) 乘上回報 G,的期望值。你仔細看,這個跟我們剛才那個 policy loss 是一樣的!就是 log π 乘上 G。它只是少減了一個 V。」

(slide: baseline 不變性,減任何跟 aₜ 無關的量,期望不變)

【師】「而這個減 V,後來事後發現,對這個期望完全沒有影響,所以我們可以減任何一個量,只要它跟 aₜ、跟這一步的 action 無關就好。而 V(sₜ) 剛好跟 aₜ 無關:那個時候它還不知道 a 要選什麼,它只是『從 sₜ 這個 state 往下的期望』,還沒選那一步。所以我們減掉這個 baseline,期望是一樣的。」

【師】「所以這個 loss 的 gradient,完全就跟『把 G 的期望值變大』那個方向一樣。1992 年,就恰好提出這個符合期望值的理論。所以回到你剛剛問的『為什麼要減 V』:現在你懂了,它不改變答案、不偏,但讓估計乖很多、低變異,是白拿的好處。」

(slide: ⚠️ 收斂要誠實)

【師】「這是一個有趣的歷史:那個公式先被猜出來、先被湊出來,然後才被證明是對的、才被證明它其實是『某個東西的微分』。其實現在大部分也走這條路,loss function 先被湊出來,然後大家才開始算:這個 loss 合不合理、到底是什麼東西的微分。」

【師】「但有一件事我要對你誠實。我一直沒回答:這個 V 跟 π 都可以更新,但它為什麼會收斂?為什麼一定會長到最好的答案?這個我沒回答。而且我們今天教的是神經網路版本,它其實不保證收斂到全世界最好的策略。這個之後再回答。」

【師】「所以先留一個疑問。」

【生】「等一下,我一直有個疑問:我們 sample 了整個 buffer、獲得 observation buffer,為什麼用完一次就丟掉?之前用 Gₜ 的版本,Gₜ 是用 π sample 的,π 一變就必須丟。但如果 loss 已經換成 bootstrap 的版本,那我 V 更新了、π 更新了,我是不是可以重複使用這些 sample?」

【師】(笑)「這個問題會讓做 RL 的人半夜睡不著。你摸到了一個超級重要的分水嶺。我們今天教的這些方法,全都叫 on-policy:資料必須來自『現在這個』policy,policy 一變、舊資料就對不上、只好丟。但你的直覺是對的:有另外一整個家族,叫 off-policy,就是想辦法重複利用舊資料,Q-learning、DQN、replay buffer 都住那邊。」

【師】「而且你注意到沒有,前面我埋過伏筆:V 如果連 action 一起吃、變成 V(s, a),那個就是 Q。所以 Q 這條線、跟 off-policy 這條線,就是我們下一堂的主角,也正好就是剛剛講『黑暗期時、另一條在發展的線』。」

【師】「好,大概今天就到這邊。謝謝你今天當我的學生,把該問的問題都問了。」

【生】「謝謝老師。」