强化学习基础概念

强化学习领域的基础概念多,易混淆,记不清的话很容易对之后学习造成影响,因此本篇用来整理强化学习的基本概念。

基础概念

符号说明:
一般大写表示未观测到的数据,小写表示已经观测到的数据。

环境与状态

  • 状态 (state):
    公式里简记为 s,是一个关于这个环境状态的完整描述。

  • 观察 (observation):
    公式简记为 o,是对于一个状态的部分描述,可能会漏掉一些信息。

状态与观察的区别:
许多情况对于 agent 无法知道全部的状态,而是通过观察了解部分的状态。

  • 动作空间 (action spaces):
    所有有效动作的集合称之为动作空间。分为连续与离散的空间,如棋牌游戏的动作空间为离散的,控制类问题中动作空间大多为连续的。

  • 轨迹(trajectory) $\tau$:
    表示:$\tau = s_0,a_0,r_0,······,s_T,a_T,r_T$
    一个 episode 从开始到结束中每一步的状态,动作,奖励的序列。

  • 策略函数 (policy function):
    简记:$\pi$
    公式:$\pi(a|s)$
    是智能体用于决定下一步执行什么行动的规则默认为随机策略即随机抽样决定。是一个概率密度函数,即给定状态 S=s,做出动作 A=a 的概率密度。强化学习的主要目的即学习到这个策略函数。

  • 奖励 (reward):
    简记:r
    公式: $r_t = R(s_t, a_t, s_{t+1})$
    奖励一般根据做出的动作,但前的状态和下一步转移的状态决定,通常需要自己定义各种情况下给予的奖励值大小。

  • 回报 (return):
    简记为 U,表示未来的累计奖励。
    公式: $U_t = R_t + R_{t1} + R_{t2} + ··· + R_{end}$
    即从 t 时刻的奖励一直加到结束的奖励之和。$U_T$ 是一个随机变量,他依赖于未来所有的的动作和状态。

  • 折扣回报 (discounted return):
    $\gamma$ :折扣率一个超参数,$\gamma \in (0,1)$,作用是当前的奖励重要性更大,未来的奖励因为不确定性强从而权重更小。
    例如公式: $U_t = R_t + \gamma R_{t1} + \gamma^2 R_{t2} + ··· + \gamma^n R_{end}$
    即从 t 时刻的奖励一直加到结束的奖励之和。

  • 状态转移函数 (state transition function):
    公式: $p(s’|s,a) = P(S’=s’|S=s,A=a)$
    转态转移概率表示为(从某一状态时间 $t$ , $s_t$ 到另一状态时间 $t+1$ , $s_{t+1}$ 会发生什么),是由环境的自然法则确定的,并且只依赖于最近的行动 $a_t$。 状态转移可以是确定的也可以是随机的他由环境规则决定。

  • 预期收益 J:
    表示:$J(\pi)$
    公式:$J(\pi) = \int_\tau P(\tau|\pi)R(\tau) = \underset{\tau\thicksim\pi}{\Epsilon}[R(\tau)]$
    该公式的本质是求期望,强化学习的核心问题是最大化预期收益即期望的最大化。
    $\pi^* = \underset{\pi}{argmax}J(\pi)$,$\pi^*$是最优策略。

值函数 (value function):

这里的值指的是如果你从某一个状态或者状态行动对开始,一直按照某个策略运行下去最终获得的期望回报,它用于评估某个状态下做出的动作是好是坏。值函数有多种形式,下面进行举例。

$Q_{\pi}$ 动作值函数:

  • $Q_{\pi}(s_t,a_t) = E[U_t|S_t=s_t,A_t=a_t]$
    我们已经知道了当前动作的概率密度函数 $P = \pi(a|s)$ 和状态的概率密度函数 $P = p(s’|s,a)$ 。
    $U_t$ 看做是关于未来所有动作 a,和状态 s的函数。在求期望过程中最终只会剩下 $a_t, s_t$ 其他的都被积掉了。

$Q^*(s,a)$ 最优动作值函数:

  • $Q^*(s_t,a_t) = \displaystyle\max_{\pi}Q_\pi(s_t,a_t)$
    他是动作值函数 $Q_{\pi}(s,a)$ 的期望,其与策略函数无关,用于评估动作 a 的好坏。

$V_\pi(s)$ 状态值函数:

  • $V_\pi(s_t) = E_A[Q_\pi(s_t,A)] = \sum_a \pi(a|s_t) \cdot Q_\pi(s_t,a)$
    $V_\pi$ 的意义是在特定的策略 $\pi$ 下评估当前的状态好坏。
动作值与状态值对比
  1. 动作值函数 $Q_{\pi}(s,a)$ 函数逼近较复杂,学习一个良好的 $Q_{\pi}(s,a)$ 需要有足够多的数据覆盖所有的 $(s,a)$ 对。
  2. 状态值函数 $V_\pi(s)$ 需要数据合理分布于状态空间,在相同数据量的条件下 $V_\pi(s)$ 的估计值会好于 $Q_{\pi}(s,a)$
  3. $V_\pi(s)$ 缺点,如果状态的转换是随机的,执行同一个动作 a 会转换到不同的 状态 s ,那么智能体必须重复多次才能找到该动作对状态 s 的最佳估计。

该部分对强化学习中的算法作简要介绍,更加具体算法会在我之后的 blog 中加以介绍。 深度强化学习算法主要分为四类,基于策略、基于值、基于模型、组合算法。

策略梯度算法 (Policy Gradient/Reinforce)

策略梯度是一种基于策略的算法,该种算法的主要思想是不断强化造成好的结果的动作,使该动作的发生概率增加,导致不好结果的动作发生概率逐渐降低。

我们需要设计一个策略函数 $\pi(a|s;\theta)$ ($\theta$为网络参数)来得到该状态下动作概率,然而训练环境中状态数量往往是无法穷尽的,因此我们通常需要设计一个方法去估计策略函数, 比如使用线性函数,神经网络拟合(policy network)等。

算法核心公式如下:

策略梯度公式推导

这里有个核心点,通常使用时并不是直接用策略函数计算,而是用策略函数的期望。
而策略函数的期望我们通常使用蒙特卡洛抽样或随机抽样的结果来近似。

算法流程

技巧

自定义一个 policy network;
自定一个 agent;

for batch = 0,1,2,···,max do

  1. 游戏的每一帧输入当前状态 S,输出各个动作的概率 $\pi$;
  2. 采样动作,输入环境得到 reward;
  3. 收集动作概率;
  4. 收集每个动作的奖励;
  5. 奖励计算累加与衰减;
  6. loss = sum(-概率 * 奖励);
  7. 使用优化器进行反向传播更新参数;

基于值的算法 DQN

DQN 是一种基于值的算法,该算法的目的是拟合动作值函数的期望 $Q^*(s,a)$。
动作值函数含义是评价在某一状态 s 下,动作 a 的好坏。而在实际应用中环境的每个状态与每个动作往往是无法穷尽的,因此使用神经网络拟合 Q 值是一个不错的方法如同其名字一样 (Deep Q Network)。

算法与环境交互流程:

DQN计算流程

TD 算法实现 DQN

公式:
$Q(s_t,a_t;W) \approx r_t + \gamma \cdot Q(s_{t+1},a_{t+1};W)$

  • $Q(s_t,a_t;W)$ :网络在 t 时刻的期望,是对未来奖励总和的期望。
  • $r_t$ :是当前时刻真实的奖励。
  • $Q(s_{t+1},a_{t+1};W)$ :是网络在 t+1 时刻到结束奖励总和的估计。

TD公式

DQN求导

经验回放

经验回放(Experimen Replay):当 DQN(Deep Q Network)使用一个神经网络用于拟合一个值函数时,Q-learning 完成了从离散状态空间到连续状态空间的跨越。为了更好地使用这个叫 Q Network 的神经网络,我们需要用符合独立同分布(independent and identically distributed,i.i.d.)的数据分批次地训练它。
然而在强化学习中,Agent 与环境交互后产生的数据往往是存在时间关联的,不能直接用于训练 。因此,我们先把贝尔曼公式(Bellman Equation)需要的数据保存起来,当缓存中的数据足够多时,随机抽样得到的数据就能接近i.i.d.。

replay buffer

  • 写入:在每次与环境交互时保存 experience transition 一个元组 (state, action, reward, done, next state)
  • 抽样:使用 ReplayBuffer 内部的数据训练网络的时候,需要从中 random sample 出许多批次的数据用于随机梯度下降(Stochastic Gradient Descent)

案例代码:

更优雅的写法参考:
replay buffer https://github.com/Yonv1943/Python/blob/master/Demo_deep_learning/ReplayBufferComparison.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class ReplayBuffer:
    """Fixed-size buffer to store experience tuples."""

    def __init__(self, action_size, buffer_size, batch_size, seed):
        """Initialize a ReplayBuffer object.
        Params
        ======
            action_size (int): dimension of each action
            buffer_size (int): maximum size of buffer
            batch_size (int): size of each training batch
            seed (int): random seed
        """
        self.action_size = action_size
        self.memory = deque(maxlen=buffer_size)
        self.batch_size = batch_size
        self.experience = namedtuple("Experience", field_names=["state", "action", "reward", "next_state", "done"])
        self.seed = random.seed(seed)

    def add(self, state, action, reward, next_state, done):
        """Add a new experience to memory."""
        e = self.experience(state, action, reward, next_state, done)
        self.memory.append(e)

    def sample(self):
        """Randomly sample a batch of experiences from memory."""
        experiences = random.sample(self.memory, k=self.batch_size)

        states = torch.from_numpy(np.vstack([e.state for e in experiences if e is not None])).float().to(device)
        actions = torch.from_numpy(np.vstack([e.action for e in experiences if e is not None])).long().to(device)
        rewards = torch.from_numpy(np.vstack([e.reward for e in experiences if e is not None])).float().to(device)
        next_states = torch.from_numpy(np.vstack([e.next_state for e in experiences if e is not None])).float().to(
            device)
        dones = torch.from_numpy(np.vstack([e.done for e in experiences if e is not None]).astype(np.uint8)).float().to(
            device)

        return (states, actions, rewards, next_states, dones)

    def __len__(self):
        """Return the current size of internal memory."""
        return len(self.memory)

DQN 算法流程

技巧

自定义一个 Qnetwork;
自定一个 agent,replay buffer;
其中 agent 内存在连个相同结构的网络(target network, local network)

for episoids = 0,1,2,···,max do

  1. 将当前状态 s 输入模型,输出动作预测值;
  2. 动作输入环境,得到(state, action, reward, next_state, done)经验轨迹保存在 buffer 中;
  3. 当 replaybuffer 数据足够一个 batch 后开始抽样一个 batch 数据用于训练;
  4. 将 next state 输入 target network 得到目标的 Q 值并按公式计算;
  5. 将当前 state 输入 local network 得到期望的 Q 值;
  6. loss = (Q_expected, Q_target);
  7. 使用优化器进行反向传播更新参数;
  8. 同步 target network 与 local network 的模型参数

组合算法

上面的策略梯度是基于策略的算法,DQN 是基于价值的算法,AC 算法是将这两种方式组合起来的组合算法。该算法需要维护两个网络,actor 网络用于产生动作, critic 网络用于为该动作打分。

核心公式: $V_\pi(s_t) = E_A[Q_\pi(s_t,A)] = \sum_a \pi(a|s_t) \cdot Q_\pi(s_t,a)$
使用神经网络拟合该公式。

AC

环境状态输入策略网络得到动作概率,通过价值网络对该动作进行打分,不断优化两个网络直至收敛。

0%