智慧型控制 Intelligent Control

馬可夫決策過程與動態規劃

馬可夫決策過程 Markov Decision Process

強化學習的問題用馬可夫決策過程(MDP)描述,由五個部分組成:

「馬可夫」指下一個狀態只取決於現在的狀態與動作,與更早的歷史無關,這正是狀態空間模型中「狀態」的意義。代理人的策略 \(\pi(a \mid s)\) 決定在每個狀態做什麼動作,目標是讓報酬總和(return)的期望值最大:

$$G_t = r_{t+1} + \gamma r_{t+2} + \gamma^2 r_{t+3} + \cdots = \sum_{k=0}^{\infty} \gamma^k r_{t+k+1}$$

價值函數與 Bellman 方程式 Value Functions

狀態 s 的價值是從 s 出發、照策略 π 走下去的報酬總和期望值;動作價值 Q 則是先做動作 a、之後再照 π 走:

$$V^\pi(s) = \mathbb E_\pi\!\left[G_t \mid s_t = s\right],\qquad Q^\pi(s, a) = \mathbb E_\pi\!\left[G_t \mid s_t = s, a_t = a\right]$$

因為 \(G_t = r_{t+1} + \gamma G_{t+1}\),價值滿足遞迴關係,也就是 Bellman 方程式:

$$V^\pi(s) = \sum_a \pi(a \mid s) \sum_{s'} P(s' \mid s, a)\left[r + \gamma V^\pi(s')\right]$$

最佳策略的價值 \(V^*\) 滿足 Bellman 最佳方程式:每一步都選讓「立即報酬+折扣後的未來價值」最大的動作:

$$V^*(s) = \max_a \sum_{s'} P(s' \mid s, a)\left[r + \gamma V^*(s')\right],\qquad \pi^*(s) = \arg\max_a \sum_{s'} P(s' \mid s, a)\left[r + \gamma V^*(s')\right]$$

動態規劃:值迭代與策略迭代 Dynamic Programming

模型(P 與 r)已知時,可以直接解 Bellman 方程式:

範例:4×3 網格世界(Russell 與 Norvig《人工智慧:現代方法》的經典例子)。代理人從左下角出發,(3, 2) 是 +1 的出口、(3, 1) 是 −1 的出口,(1, 1) 是牆。動作會「滑」:往意圖方向的機率 0.8,往左右兩側各 0.1,撞牆留在原地。每走一步報酬 −0.04,γ = 1:

# 值迭代:4×3 網格世界(Russell & Norvig 的經典例子)
# 每走一步報酬 r,(3,2) 終點 +1、(3,1) 終點 −1,(1,1) 是牆;往意圖方向走的機率 0.8,往左右兩側各 0.1
import numpy as np

ACTS = {"↑": (0, 1), "→": (1, 0), "↓": (0, -1), "←": (-1, 0)}
WALL, TERM = (1, 1), {(3, 2): 1.0, (3, 1): -1.0}
STATES = [(x, y) for y in range(3) for x in range(4) if (x, y) != WALL]

def move(s, a):
    n = (s[0] + ACTS[a][0], s[1] + ACTS[a][1])
    return n if 0 <= n[0] < 4 and 0 <= n[1] < 3 and n != WALL else s      # 撞牆就留在原地

def q(V, s, a, r, gamma=1.0):
    names = list(ACTS); i = names.index(a)
    outcomes = [(a, 0.8), (names[(i - 1) % 4], 0.1), (names[(i + 1) % 4], 0.1)]
    return sum(p * (r + gamma * V[move(s, b)]) for b, p in outcomes)

def value_iteration(r):
    V = {s: TERM.get(s, 0.0) for s in STATES}
    for it in range(1, 1000):
        newV = {s: V[s] if s in TERM else max(q(V, s, a, r) for a in ACTS) for s in STATES}   # Bellman 最佳方程式
        delta = max(abs(newV[s] - V[s]) for s in STATES)
        V = newV
        if delta < 1e-10:
            break
    pi = {s: max(ACTS, key=lambda a: q(V, s, a, r)) for s in STATES if s not in TERM}
    return V, pi, it

for r in (-0.04, -2.0):
    V, pi, it = value_iteration(r)
    print(f"每步報酬 r = {r}:{it} 次迭代收斂")
    for y in (2, 1, 0):
        vals = "  ".join("  牆  " if (x, y) == WALL else f"{V[(x, y)]:6.3f}" for x in range(4))
        arrows = " ".join("■" if (x, y) == WALL else ("+1" if (x, y) == (3, 2) else "-1" if (x, y) == (3, 1) else pi[(x, y)]) for x in range(4))
        print(f"  {vals}    {arrows}")

⬇ 下載 value_iteration.py(Python 3+numpy)

實際執行的輸出:

每步報酬 r = -0.04:40 次迭代收斂
   0.812   0.868   0.918   1.000    → → → +1
   0.762    牆     0.660  -1.000    ↑ ■ ↑ -1
   0.705   0.655   0.611   0.388    ↑ ← ← ←
每步報酬 r = -2.0:35 次迭代收斂
  -7.043  -4.230  -1.730   1.000    → → → +1
  -9.543    牆    -3.570  -1.000    ↑ ■ → -1
  -10.815  -8.474  -5.974  -3.775    → → → ↑
每步報酬 −0.04↑0.705←0.655←0.611←0.388↑0.762↑0.660-1→0.812→0.868→0.918+1每步報酬 −2(每走一步代價很高)→-10.815→-8.474→-5.974↑-3.775↑-9.543→-3.570-1→-7.043→-4.230→-1.730+1黃色箭頭:最佳策略 下方數字:最佳價值 V*(γ = 1,往意圖方向 0.8、左右各 0.1)

每步報酬 −0.04 時,算出的價值與教科書的數值完全相同(0.812、0.868、0.918……0.388,verify_rl.py 核對)。注意 (2, 0) 往左走、(2, 1) 往上走:寧可繞遠路,也不冒 10% 的機率滑進 −1。若每步要付 −2,留在場上太貴,(2, 1) 乾脆直接跳進 −1 結束。策略迭代只要 5 輪就得到同樣的策略。值迭代的收斂與 γ 有關:γ = 1 要 40 次,γ = 0.9 只要 31 次(下圖左)。

自製動畫(依控制理論數值模擬)

Bellman 方程式與 LQR Bellman Equation and LQR

把同樣的想法用在連續狀態的線性系統 \(\mathbf x_{k+1} = \mathbf A\mathbf x_k + \mathbf B\mathbf u_k\),成本(負報酬)為 \(\sum_k (\mathbf x_k^{\mathsf T}\mathbf Q\mathbf x_k + \mathbf u_k^{\mathsf T}\mathbf R\mathbf u_k)\)。Bellman 方程式成為

$$V(\mathbf x) = \min_{\mathbf u}\left[\mathbf x^{\mathsf T}\mathbf Q\mathbf x + \mathbf u^{\mathsf T}\mathbf R\mathbf u + V(\mathbf A\mathbf x + \mathbf B\mathbf u)\right]$$

猜 \(V(\mathbf x) = \mathbf x^{\mathsf T}\mathbf P\mathbf x\),代入後對 \(\mathbf u\) 微分令為 0,得到最佳回授 \(\mathbf u = -\mathbf K\mathbf x\),而 \(\mathbf P\) 必須滿足

$$\mathbf K = (\mathbf R + \mathbf B^{\mathsf T}\mathbf P\mathbf B)^{-1}\mathbf B^{\mathsf T}\mathbf P\mathbf A,\qquad \mathbf P = \mathbf Q + \mathbf A^{\mathsf T}\mathbf P\mathbf A - \mathbf A^{\mathsf T}\mathbf P\mathbf B(\mathbf R + \mathbf B^{\mathsf T}\mathbf P\mathbf B)^{-1}\mathbf B^{\mathsf T}\mathbf P\mathbf A$$

這正是離散時間 LQR 的代數 Riccati 方程式。從 \(\mathbf P = 0\) 反覆套用右邊(也就是值迭代),就會收斂到 Riccati 方程式的解。以模糊控制章的 MCK 系統為例(取樣 0.1 秒):

# 用 Bellman 方程式(動態規劃)解 LQR:MCK 系統(m = 1、c = 1、k = 2,同模糊控制章)離散化後,
# 從 V = 0 開始反覆套用 Bellman 方程式,就是 Riccati 迭代,結果和 scipy 解離散代數 Riccati 方程式相同
import numpy as np
from scipy.linalg import expm, solve_discrete_are

dt = 0.1
Ac, Bc = np.array([[0., 1.], [-2., -1.]]), np.array([[0.], [1.]])
M = expm(np.block([[Ac, Bc], [np.zeros((1, 3))]]) * dt)                 # 零階保持離散化
A, B = M[:2, :2], M[:2, 2:]
Q, R = np.diag([10., 1.]), np.array([[0.1]])                           # 成本 Σ (xᵀQx + uᵀRu)

# V(x) = xᵀPx 代入 V(x) = min_u [xᵀQx + uᵀRu + V(Ax + Bu)],最小化 u 後得到 P 的更新式
P = np.zeros((2, 2))
for k in range(1, 201):
    K = np.linalg.solve(R + B.T @ P @ B, B.T @ P @ A)                   # 這一步的最佳回授 u = −Kx
    P_new = Q + A.T @ P @ (A - B @ K)
    if np.abs(P_new - P).max() < 1e-9 * np.abs(P_new).max():
        P = P_new
        break
    P = P_new
print(f"Bellman 迭代 {k} 次收斂,P =\n{P.round(4)}")
P_are = solve_discrete_are(A, B, Q, R)
print("與 solve_discrete_are 的最大差:", f"{np.abs(P - P_are).max():.1e}")
K = np.linalg.solve(R + B.T @ P @ B, B.T @ P @ A)
print("最佳回授增益 K =", K.round(4), ",閉迴路特徵值大小", np.abs(np.linalg.eigvals(A - B @ K)).round(4))

x = np.array([1.0, 0.0])                                               # 從位移 1、速度 0 出發
for t in range(30):
    x = (A - B @ K) @ x
x_open = np.linalg.matrix_power(A, 30) @ np.array([1.0, 0.0])
print(f"3 秒後 x = {x.round(4)}(不加控制時 x = {x_open.round(4)})")

⬇ 下載 lqr_bellman.py(Python 3+numpy+scipy)

實際執行的輸出:

Bellman 迭代 42 次收斂,P =
[[56.7106  8.2748]
 [ 8.2748  4.8288]]
與 solve_discrete_are 的最大差: 5.9e-08
最佳回授增益 K = [[6.2624 3.5862]] ,閉迴路特徵值大小 [0.7707 0.7707]
3 秒後 x = [-0.0001  0.0016](不加控制時 x = [-0.2131  0.2483])
010203040-10-8-6-4-20迭代次數最大變化量(log₁₀)γ = 1:40 次γ = 0.9:31 次02040600204060Bellman 迭代次數P₁₁Riccati 解 56.71MCK 系統的 LQR:從 P = 0 反覆套用 Bellman 方程式

所以 LQR 可以看成強化學習在「模型已知、線性、二次成本」時的特例,答案是解析的。當模型未知、系統非線性,或報酬不是二次式時,就需要下一頁不靠模型的學習方法。