Skip to content

强化学习基础

概述

强化学习 (Reinforcement Learning, RL) 研究智能体 (Agent) 如何通过与环境 (Environment) 的交互学习最优行为策略 (Optimal Policy)。与监督学习不同,RL 不需要标注数据,而是通过试错 (Trial-and-Error) 和延迟奖励 (Delayed Reward) 学习。本文介绍 RL 的数学基础——马尔可夫决策过程 (MDP)、贝尔曼方程 (Bellman Equation)、Q-Learning 和策略梯度 (Policy Gradient) 方法。

马尔可夫决策过程 (MDP)

MDP 是 RL 问题的形式化框架,定义为五元组 \((\mathcal{S}, \mathcal{A}, P, R, \gamma)\)

  • \(\mathcal{S}\):状态空间 (State Space)
  • \(\mathcal{A}\):动作空间 (Action Space)
  • \(P(s'|s,a)\):状态转移概率 (Transition Probability)
  • \(R(s,a,s')\):即时奖励函数 (Reward Function)
  • \(\gamma \in [0,1)\):折扣因子 (Discount Factor)

金融 MDP 建模

MDP 要素 交易场景的映射
状态 \(s_t\) 当前持仓、价格序列、技术指标
动作 \(a_t\) 买入、卖出、持有、下单量
奖励 \(r_t\) 交易收益 - 交易成本
转移 \(P\) 市场动态(未知且非平稳)
折扣 \(\gamma\) 时间偏好(通常取 0.99-0.999)

马尔可夫性质 (Markov Property):

\[P(s_{t+1}|s_t, a_t, s_{t-1}, a_{t-1}, \ldots) = P(s_{t+1}|s_t, a_t)\]

金融市场的马尔可夫性

严格意义上,金融市场不满足马尔可夫性质,因为价格动态依赖于历史信息(如动量效应)。实践中,通过在状态中纳入足够的历史信息(如过去 \(k\) 期的价格、成交量),可以近似满足马尔可夫性。

贝尔曼方程 (Bellman Equation)

状态值函数 (State Value Function)

策略 \(\pi\) 下状态 \(s\) 的值函数定义为从 \(s\) 出发的期望累积奖励:

\[V^{\pi}(s) = \mathbb{E}_{\pi}\left[\sum_{t=0}^{\infty} \gamma^t r_t \bigg| s_0 = s\right]\]

贝尔曼期望方程:

\[V^{\pi}(s) = \sum_{a} \pi(a|s) \left[R(s,a) + \gamma \sum_{s'} P(s'|s,a) V^{\pi}(s')\right]\]

动作值函数 (Action Value Function)

\[Q^{\pi}(s,a) = R(s,a) + \gamma \sum_{s'} P(s'|s,a) \sum_{a'} \pi(a'|s') Q^{\pi}(s',a')\]

贝尔曼最优方程 (Bellman Optimality Equation)

\[V^*(s) = \max_{a} \left[R(s,a) + \gamma \sum_{s'} P(s'|s,a) V^*(s')\right]\]
\[Q^*(s,a) = R(s,a) + \gamma \sum_{s'} P(s'|s,a) \max_{a'} Q^*(s',a')\]

最优策略为:\(\pi^*(s) = \arg\max_a Q^*(s,a)\)

Q-Learning

Q-Learning 是一种无模型 (Model-free) 的离策略 (Off-policy) 方法,通过时序差分 (Temporal Difference, TD) 更新 Q 值:

\[Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t)\right]\]

其中 \(\alpha\) 为学习率 (Learning Rate),中括号内为 TD 误差 (TD Error):

\[\delta_t = r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t)\]

深度 Q 网络 (DQN)

当状态空间连续或高维时,使用神经网络 \(Q(s,a;\theta)\) 近似 Q 函数:

import torch
import torch.nn as nn
import numpy as np
from collections import deque
import random

class DQN(nn.Module):
    def __init__(self, state_dim, action_dim, hidden_dim=128):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(state_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, action_dim)
        )

    def forward(self, x):
        return self.net(x)

class DQNAgent:
    def __init__(self, state_dim, action_dim, lr=1e-3, gamma=0.99,
                 epsilon=1.0, epsilon_decay=0.995, epsilon_min=0.01):
        self.q_net = DQN(state_dim, action_dim)
        self.target_net = DQN(state_dim, action_dim)
        self.target_net.load_state_dict(self.q_net.state_dict())
        self.optimizer = torch.optim.Adam(self.q_net.parameters(), lr=lr)
        self.memory = deque(maxlen=100000)
        self.gamma = gamma
        self.epsilon = epsilon
        self.epsilon_decay = epsilon_decay
        self.epsilon_min = epsilon_min
        self.action_dim = action_dim

    def act(self, state):
        if random.random() < self.epsilon:
            return random.randint(0, self.action_dim - 1)
        with torch.no_grad():
            q_values = self.q_net(torch.FloatTensor(state))
            return q_values.argmax().item()

    def learn(self, batch_size=64):
        if len(self.memory) < batch_size:
            return
        batch = random.sample(self.memory, batch_size)
        states, actions, rewards, next_states, dones = zip(*batch)

        states = torch.FloatTensor(np.array(states))
        actions = torch.LongTensor(actions)
        rewards = torch.FloatTensor(rewards)
        next_states = torch.FloatTensor(np.array(next_states))
        dones = torch.FloatTensor(dones)

        # 当前 Q 值
        q_values = self.q_net(states).gather(1, actions.unsqueeze(1))
        # 目标 Q 值
        with torch.no_grad():
            next_q = self.target_net(next_states).max(1)[0]
            target = rewards + self.gamma * next_q * (1 - dones)

        loss = nn.MSELoss()(q_values.squeeze(), target)
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

        self.epsilon = max(self.epsilon * self.epsilon_decay, self.epsilon_min)

DQN 的关键技巧

  • 经验回放 (Experience Replay):打破样本相关性
  • 目标网络 (Target Network):稳定训练目标
  • Double DQN:缓解 Q 值过高估计
  • Dueling DQN:分离状态值与优势函数

策略梯度 (Policy Gradient)

REINFORCE 算法

直接参数化策略 \(\pi_\theta(a|s)\),通过梯度上升最大化期望回报:

\[J(\theta) = \mathbb{E}_{\pi_\theta}\left[\sum_{t=0}^{T} \gamma^t r_t\right]\]

策略梯度定理 (Policy Gradient Theorem):

\[\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}\left[\sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot G_t\right]\]

其中 \(G_t = \sum_{k=t}^{T} \gamma^{k-t} r_k\) 为从时刻 \(t\) 开始的累积回报 (Return)。

带基线的 REINFORCE

引入基线 \(b(s_t)\) 减小方差:

\[\nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}\left[\sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot (G_t - b(s_t))\right]\]

通常使用值函数 \(V(s_t)\) 作为基线,此时 \(G_t - V(s_t)\) 称为优势函数 (Advantage Function) \(A(s_t, a_t)\)

class REINFORCEAgent:
    def __init__(self, state_dim, action_dim, lr=1e-3, gamma=0.99):
        self.policy = nn.Sequential(
            nn.Linear(state_dim, 128),
            nn.ReLU(),
            nn.Linear(128, action_dim),
            nn.Softmax(dim=-1)
        )
        self.optimizer = torch.optim.Adam(self.policy.parameters(), lr=lr)
        self.gamma = gamma

    def act(self, state):
        probs = self.policy(torch.FloatTensor(state))
        dist = torch.distributions.Categorical(probs)
        action = dist.sample()
        return action.item(), dist.log_prob(action)

    def update(self, log_probs, rewards):
        # 计算折扣回报
        returns = []
        G = 0
        for r in reversed(rewards):
            G = r + self.gamma * G
            returns.insert(0, G)
        returns = torch.FloatTensor(returns)
        returns = (returns - returns.mean()) / (returns.std() + 1e-8)

        # 策略梯度更新
        policy_loss = []
        for log_prob, G in zip(log_probs, returns):
            policy_loss.append(-log_prob * G)
        loss = torch.stack(policy_loss).sum()

        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

值方法 vs 策略方法

特性 值方法 (Q-Learning) 策略方法 (Policy Gradient)
动作空间 离散 离散/连续
收敛性 可能震荡 局部最优
方差 高(可降低)
适用场景 离散交易决策 连续仓位调整

金融交易中的连续仓位控制天然适合策略梯度方法,而离散的买/卖/持决策则可使用 Q-Learning。

Actor-Critic 架构

结合值方法与策略方法的优势:

\[\nabla_\theta J(\theta) \approx \mathbb{E}\left[\nabla_\theta \log \pi_\theta(a_t|s_t) \cdot A^{\pi}(s_t, a_t)\right]\]
\[A^{\pi}(s_t, a_t) = r_t + \gamma V_\phi(s_{t+1}) - V_\phi(s_t)\]

其中 Actor \(\pi_\theta\) 负责策略优化,Critic \(V_\phi\) 负责值估计。

小结

强化学习为金融决策问题提供了理论框架与算法工具。MDP 的形式化使交易问题的建模系统化,贝尔曼方程奠定了值函数估计的理论基础,Q-Learning 和策略梯度分别适用于离散和连续的金融决策场景。后续章节将深入探讨 RL 在投资组合优化、订单执行等具体金融任务中的应用。