news 2026/5/28 1:25:58

用Python玩转强化学习:手把手教你用NumPy实现赌徒问题的MDP求解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Python玩转强化学习:手把手教你用NumPy实现赌徒问题的MDP求解

用Python玩转强化学习:手把手教你用NumPy实现赌徒问题的MDP求解

在人工智能领域,强化学习正以其独特的决策能力改变着我们解决问题的思维方式。而马尔科夫决策过程(MDP)作为强化学习的理论基础,其重要性不言而喻。今天,我们将通过一个经典案例——赌徒问题,来深入理解MDP的核心概念,并掌握两种经典算法:策略迭代(Policy Iteration)和值迭代(Value Iteration)的Python实现。

赌徒问题看似简单,却完美展现了MDP的所有关键要素:状态、动作、奖励和策略。通过这个案例,我们不仅能理解强化学习的基本原理,还能获得宝贵的编程实践经验。本文将使用NumPy和Matplotlib这两个Python基础库,从零开始构建完整的求解器,并通过可视化手段直观展示算法的收敛过程和最优策略。

1. 赌徒问题与MDP基础

赌徒问题描述了一个简单的赌博场景:玩家每次可以选择下注一定金额,有概率ph赢得等额赌注,也有概率(1-ph)输掉赌注。游戏在玩家资产达到100美元或归零时结束。这个看似简单的设定,却包含了MDP的所有核心要素:

  • 状态(State):当前持有的资本金额,s ∈ {0,1,2,...,99}
  • 动作(Action):每次下注的金额,a ∈ {1,2,...,min(s,100-s)}
  • 奖励(Reward):只有达到100美元时获得+1奖励,其他情况为0
  • 折扣因子(γ):这里设为1,表示不考虑未来奖励的折扣

理解这些基本概念是后续算法实现的基础。值得注意的是,赌徒问题的状态空间和动作空间都是离散且有限的,这使得它成为学习MDP的理想案例。

# 基本参数设置示例 GOAL = 100 # 目标金额 ph = 0.4 # 硬币正面朝上的概率 states = np.arange(GOAL + 1) # 所有可能的状态

2. 策略迭代算法实现

策略迭代是解决MDP问题的经典方法之一,它通过交替进行策略评估和策略改进来逐步优化策略。下面我们详细分解实现步骤:

2.1 策略评估

策略评估的目标是计算当前策略下的状态价值函数。我们采用迭代法,直到价值函数收敛(变化小于阈值θ):

def policy_evaluation(self): while True: old_state_values = self.state_values.copy() self.sweeps_history.append(old_state_values) # 记录迭代历史 for s in self.states[1:self.goal]: # 跳过0和100状态 actions = np.arange(min(s, self.goal - s)) + 1 action_returns = [] for a in actions: # 计算动作a的期望回报 ret = self.ph * (self.gamma * self.state_values[s + a]) + \ (1 - self.ph) * (self.gamma * self.state_values[s - a]) action_returns.append(ret) # 使用当前策略选择动作(这里假设策略是平均选择) self.state_values[s] = np.mean(action_returns) # 检查收敛 delta = abs(self.state_values - old_state_values).max() if delta <= self.theta: break

2.2 策略改进

在得到准确的价值函数后,我们可以改进策略,使其在每个状态都选择能带来最大期望回报的动作:

def policy_improvement(self): policy_stable = True for s in self.states[1:self.goal]: actions = np.arange(min(s, self.goal - s)) + 1 old_a = self.policy[s] action_returns = [] for a in actions: ret = self.ph * (self.gamma * self.state_values[s + a]) + \ (1 - self.ph) * (self.gamma * self.state_values[s - a]) action_returns.append(ret) # 选择回报最大的动作 argmax_a = actions[np.argmax(np.round(action_returns, 5))] self.policy[s] = argmax_a if policy_stable and argmax_a != old_a: policy_stable = False return policy_stable

2.3 完整策略迭代流程

将策略评估和策略改进结合起来,就构成了完整的策略迭代算法:

class PolicyIteration: def __init__(self, goal=100, proba_h=0.4, theta=1e-9, gamma=1): self.ph = proba_h self.gamma = gamma self.goal = goal self.theta = theta self.states = np.arange(self.goal + 1) self.state_values = np.zeros(self.goal + 1) self.state_values[self.goal] = 1.0 # 达到目标的价值为1 self.policy = np.zeros(self.goal + 1) self.sweeps_history = [] def iterate(self): while True: self.policy_evaluation() policy_stable = self.policy_improvement() if policy_stable: break

3. 值迭代算法实现

值迭代是另一种解决MDP的重要方法,它将策略评估和策略改进结合在一个步骤中,通常收敛更快。

3.1 值迭代核心算法

值迭代直接寻找最优价值函数,然后在收敛后提取最优策略:

def truncated_policy_evaluation(self): while True: old_state_values = self.state_values.copy() self.sweeps_history.append(old_state_values) for s in self.states[1:self.goal]: actions = np.arange(min(s, self.goal - s)) + 1 action_returns = [] for a in actions: ret = self.ph * (self.gamma * self.state_values[s + a]) + \ (1 - self.ph) * (self.gamma * self.state_values[s - a]) action_returns.append(ret) # 关键区别:直接取最大值而不是平均值 self.state_values[s] = np.max(action_returns) delta = abs(self.state_values - old_state_values).max() if delta <= self.theta: break

3.2 提取最优策略

在值函数收敛后,我们可以提取出最优策略:

def optimal_policy(self): for s in self.states[1:self.goal]: actions = np.arange(min(s, self.goal - s)) + 1 action_returns = [] for a in actions: ret = self.ph * (self.gamma * self.state_values[s + a]) + \ (1 - self.ph) * (self.gamma * self.state_values[s - a]) action_returns.append(ret) argmax_a = actions[np.argmax(np.round(action_returns, 5))] self.policy[s] = argmax_a

3.3 完整值迭代实现

class ValueIteration: def __init__(self, goal=100, proba_h=0.4, theta=1e-9, gamma=1): self.ph = proba_h self.gamma = gamma self.goal = goal self.theta = theta self.states = np.arange(self.goal + 1) self.state_values = np.zeros(self.goal + 1) self.state_values[self.goal] = 1.0 self.policy = np.zeros(self.goal + 1) self.sweeps_history = [] def solve(self): self.truncated_policy_evaluation() self.optimal_policy()

4. 结果分析与可视化

实现算法后,我们需要对结果进行分析和可视化,以深入理解两种算法的特点和差异。

4.1 值函数收敛过程

我们可以绘制值函数在迭代过程中的变化:

def plot_value_convergence(sweeps_history, goal=100): plt.figure(figsize=(10, 6)) for i, sweep in enumerate(sweeps_history): if i % 5 == 0: # 每隔5次迭代绘制一次 plt.plot(sweep, alpha=0.8, label=f'Iteration {i}') plt.xlabel('Capital') plt.ylabel('Value Estimates') plt.title('Value Function Convergence') plt.legend() plt.show()

4.2 最优策略可视化

最优策略展示了在不同资本状态下应该下注多少:

def plot_policy(policy, goal=100): plt.figure(figsize=(10, 4)) plt.bar(range(goal), policy[:goal]) plt.xlabel('Capital') plt.ylabel('Optimal Stake') plt.title('Optimal Policy') plt.show()

4.3 算法对比

策略迭代和值迭代在ph=0.4时的表现对比:

特性策略迭代值迭代
收敛速度较慢较快
每次迭代复杂度较高较低
策略特性分段式激进与保守周期性激进与保守
适用场景策略变化不大的问题大规模状态空间问题

从实现角度看,值迭代通常更适合大规模问题,而策略迭代在策略空间较小时可能更有效。在赌徒问题中,当ph=0.4时,两种算法得到的最优策略存在显著差异:

  • 策略迭代产生的策略更加分段化,在某些资本范围内采取激进策略,在另一些范围则保守
  • 值迭代产生的策略则呈现出周期性模式,激进与保守交替出现

这种差异源于两种算法在更新方式上的本质区别:策略迭代在每次迭代中完全评估当前策略,而值迭代则始终朝着最优价值函数方向更新。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 1:21:05

一个开发工程师每天怎么用 Git + Gerrit 协作开发代码。

Git Gerrit 从零到开发工程师学习笔记1. 为什么开发工程师必须学习 GitGit 是现代软件开发中最重要的基础工具之一。它的作用不是简单地“保存代码”&#xff0c;而是帮助开发者管理代码的每一次变化。如果没有 Git&#xff0c;项目很容易变成这样&#xff1a;项目_最终版 项目…

作者头像 李华
网站建设 2026/5/28 1:20:06

Python微服务架构设计:构建可扩展的分布式系统

Python微服务架构设计&#xff1a;构建可扩展的分布式系统引言 微服务架构已经成为现代后端开发的主流范式。作为一名从Python转向Rust的后端开发者&#xff0c;我在实践中总结了微服务架构设计的最佳实践。本文将深入探讨Python中微服务架构的设计与实现&#xff0c;帮助你构建…

作者头像 李华
网站建设 2026/5/28 1:20:05

Rust缓存策略:构建高性能数据访问层

Rust缓存策略&#xff1a;构建高性能数据访问层引言 缓存是提升系统性能的关键技术。作为一名从Python转向Rust的后端开发者&#xff0c;我在实践中总结了Rust中缓存策略的最佳实践。本文将深入探讨Rust中的缓存实现策略&#xff0c;帮助你构建高性能的数据访问层。 一、缓存核…

作者头像 李华
网站建设 2026/5/28 1:15:20

解决Keil MDK中ULINK调试器连接LPC4330的Flash烧录问题

1. 问题现象与背景解析 最近在调试NXP LPC4330-Xplorer开发板的SPIFI Flash烧录时&#xff0c;遇到了一个典型的调试器连接问题。具体场景是使用Keil MDK开发环境和ULINKpro调试器&#xff0c;尝试烧录基于Application Note 272的音频录制示例代码时&#xff0c;Vision IDE弹出…

作者头像 李华