强化学习 -- 无导数随机优化算法玩俄罗斯方块Tetris(交叉熵方法CE + ADP近似动态规划CBMPI)

论文:ADP 近似动态规划玩 Tetris 俄罗斯方块

无导数随机优化方法 是一类不依赖目标函数梯度信息 ,通过随机采样、迭代更新来寻找最优解的优化算法,

核心适用于梯度难以计算、不存在或计算成本极高的复杂优化场景。

本文综述了一种基于近似动态规划 ADP 的俄罗斯方块求解算法 CBMPI

针对传统 ADP 依赖值函数 近似导致性能受限的问题,该算法创新性转向策略空间搜索

通过 "采样 - 回归器 - 分类器 " 三步流程实现策略优化:

基于 m 步截断滚动 采样估计价值函数,利用最小二乘拟合回归器近似值函数

借助 CMA-ES 优化分类器得到近似贪婪策略。

效果:在 20×10 大型棋盘上,CBMPI 平均消除 5100 万行,

首次使 ADP 类算法性能超越交叉熵(CE)方法,且样本用量仅为 CE 的 1/6,突破了传统ADP的局限性。

目录

[0. Motivaition:](#0. Motivaition:)

[1. 相关工作:](#1. 相关工作:)

[1.1 值函数算法](#1.1 值函数算法)

[1.2 描述棋盘的特征](#1.2 描述棋盘的特征)

[1.3 交叉熵方法 CEM](#1.3 交叉熵方法 CEM)

[1.4 noisy CE 玩 CartPole](#1.4 noisy CE 玩 CartPole)

[2. CBMPI 采样 + 回归器 + 分类器](#2. CBMPI 采样 + 回归器 + 分类器)

[3. 与其他方法的区别比较](#3. 与其他方法的区别比较)


0. Motivaition:

CE -> 直接学习策略参数 在Tetris 表现好 ;传统 ADP 算法几乎完全依赖 价值函数近似表现不好。

启发:采用在策略空间内搜索的 ADP 算法,而非传统的、在值函数空间内搜索的算法。

  • 状态 :由当前棋盘布局 与正在下落的方块共同定义;
  • 动作 :方块的所有可行旋转 角度与放置位置的组合;
  • 奖励 :最大化该状态对应的游戏得分
  • 特性:状态 s 下执行动作 a 的 s' 和 r 是固定的。

1. 相关工作:

1.1 值函数算法与局限性

(如值迭代、λ-PI); 值函数空间 F 是一组用于近似 "状态价值函数v(s)" 的函数族。

直接学值函数:

  1. 定义值函数的特征 ϕ(s)(比如最大列高度、各列高度、列高度差以及孔洞数量);
  2. 采样近似估计状态真实价值 v(s)
  3. 利用回归等方法 得到 ϕ(s) = v(s) * w;给状态打分

学习完值函数,可以进行贪心策略 转换为得分最高的状态:

局限性是:如果值函数本身难以被值函数空间 F 准确表征,那么推导出来的策略性能会很差。

1.2 描述 Tetris 盘面的三种特征

  1. Bertsekas:22个特征 棋盘孔洞数量、每列高度、相邻两列的高度差以及棋盘最大高度。

  2. D-T特征:6 + 3 的特征(在后文的实验中最优)

  3. 高斯核 RBF 特征 exp (−|c−ih/4|²/(2 (h/5)²))

1.3 交叉熵方法 CEM

(Cross Entropy Method)找最优的均值和方差

每轮迭代 用现在的参数采样 n个样本,分别玩 L 把得到分数;

用排名前 ρ% 的参数的均值和方差,计算新的均值方差,进入下一轮迭代。

交叉熵 CE 参考学习文献:

Learning Tetris Using the Noisy Cross-Entropy Method 论文链接 带噪交叉熵(防止过早收敛)

A Tutorial on the Cross-Entropy Method Download PDF

1.4 noisy CE 玩 CartPole

4维状态 s(位置、速度、角度、角速度) -> 1 维动作 (向左还是向右推)

交叉熵学权重 w;再用 w与s的内积 决定动作

  1. 玩一把 评估权重 w。
python 复制代码
import gymnasium as gym
import numpy as np

def evaluation(env, W):
    """使用参数向量W为策略运行1个episode,返回该episode的奖励"""
    reward_sum = 0
    state, _ = env.reset()
    while True:
        action = int(np.dot(W, state) > 0) # w*s 内积决定动作
        state, reward, terminated, truncated, info = env.step(action)
        reward_sum += reward
        if terminated or truncated:
            break
    return reward_sum
  1. 利用均值和方差 产生一堆4维向量;随着步数衰减的噪声
python 复制代码
def init_params(mu, sigma, n):
    """使用均值向量mu和标准差向量sigma创建参数矩阵"""
    m = mu.shape[0]
    w_matrix = np.zeros((n, m)) # 行数为样本数 列数为w维度

    for p in range(m): # 每列正态分布
        w_matrix[:, p] = np.random.normal(
            loc=mu[p], # 均值
            scale=sigma[p] + 1e-17,  # 标准差
            size=(n,)
        )

    return w_matrix


def get_constant_noise(step):
    """随时间衰减的噪声"""
    return np.maximum(5 - step / 10.0, 0)

3. 迭代训练 生成 n 组权重 保留分数前 p 名的;并用前 p 的均值方差进入下一轮迭代。

python 复制代码
n = 40  # 每代种群大小
p = 8  # 精英集大小
n_iter = 30  # 训练迭代次数
env = gym.make('CartPole-v1', render_mode=None) # 训练时

# 参数向量的均值(mu)和标准差(sigma) 对应状态空间维度
mu = np.random.uniform(size=env.observation_space.shape[0])
sigma = np.random.uniform(low=0.001, size=env.observation_space.shape[0])


for i in range(n_iter):
    # 根据当前均值方差 初始化参数向量数组
    w = init_params(mu, sigma, n)

    # 评估每个参数向量
    reward_sums = np.zeros(n)
    for k in range(n):
        reward_sums[k] = evaluation(env, w[k, :])

    # 选取奖励最高的p个向量(精英集)
    rankings = (np.argsort(reward_sums))[-p:]  # 根据奖励对参数向量排序
    top_vectors = w[rankings, :]

    # 用精英集更新 均值和方差
    for q in range(top_vectors.shape[1]):
        mu[q] = top_vectors[:, q].mean()
        sigma[q] = top_vectors[:, q].std() + get_constant_noise(i) # 方差加噪声
    print("=" * 80)
    print(f"iteration: {i}, mean reward: {reward_sums.mean():.2f}")
    print(f"reward range: {reward_sums.min():.2f} to {reward_sums.max():.2f}\n")

    if reward_sums.mean() > 480: # 算平均分+早停
        print("Solved!")
        break

env.close()
  1. 测试最终的权重w。
python 复制代码
# 测试最终的权重w
env_test = gym.make('CartPole-v1', render_mode="human") # 测试时human模式
print("\nTesting final policy...")
test_rewards, final_W = [], mu
print("parameters: ", final_W)

for test_ep in range(10):
    # 使用最终的均值作为策略参数
    reward = evaluation(env_test, final_W)
    test_rewards.append(reward)
    print(f"Test episode {test_ep + 1}: Reward = {reward}")

print(f"\nAverage test reward: {np.mean(test_rewards):.2f}")

env_test.close()

2. CBMPI 采样 + 回归器 + 分类器

输入:值函数空间 F (包含ϕ(s)值特征向量 )策略空间 Π (包含φ(s,a)动作特征向量)状态分布 µ

(这两个空间,再学习参数,和 DQN 之类的方法 差别很大)

  1. rollouts 利用上一轮得到的 π 采样轨迹,近似 动作价值函数v(s) 和状态价值函数 Q(s,a)

  2. 回归器 根据状态的特征 回归 v(s)

  3. 分类器 利用 v(s) 学策略

步骤1:rollouts 往后 m 步,用 π_k(s|a) 采样轨迹 (由上一轮迭代的步骤3得到)

得到 状态价值函数 V(s) 和 动作价值函数 Q(s,a) 的估计值。

其中 m 步截断,m 步之后的价值 由上一次迭代的价值回归器 v_k-1(s_m) 得到。

V(s) 和 Q(s,a) 本来需要分别采样 ,但为了效率更高 共用采样样本集D(实验发现效果并未下降)

步骤 2(回归器)近似值函数,回归问题。

在值函数空间 F 中找一个函数 v_k,尽可能接近 "当前策略 π_k 对应的 m 步贝尔曼算子结果"。

(本文使用最小二乘 求解得系数 w )(这一部分衔接 相关工作中 值函数算法)

步骤 3(分类器)近似贪婪策略

在策略空间中找一个策略 π_{k+1} ,使得它尽可能接近 "基于当前值函数的最优贪婪策略"。

新的 π_{k+1} 在下一次迭代时 用于 rollouts。

训练数据集为:动作空间大小为 |A|,则对于每个状态对应长度为 |A| 的向量

为每个动作对应的 Q(s,a) 与 最优值差多少,Q(s,a) - max Q(s,a)。

状态 s 下的策略 π,依赖于策略参数权重 u ,是策略特征向量 φ(s,a) 的权重。

策略特征向量 φ(s,a) 和 值特征向量 ϕ(s) 都是盘面相关的特征表征

u * φ(s,a) 对应分数最大的动作 a 即为 π(s) 的输出动作。

调权重 u :CMA-ES 协方差矩阵自适应进化策略

优势:在训练集已知的情况下 评估 u 只需计算经验误差,无需任何游戏模拟

而交叉熵(CE )方法在策略评估 阶段,必须运行多局游戏才能完成评估。

故 相同效果的情况下,只需要CE 1/6 的样本用量

3. 与其他方法的区别比较

此为 m 步截断:

m=1 则为经典值迭代 算法(从值函数推导策略,每一步都做 "一步贝尔曼更新");

m=∞ 则为策略迭代 算法(精确计算 当前策略的价值函数,相当于无限步贝尔曼更新)。


移除回归器 模块不拟合 v ,仅使用截断长度为 m 的滚动采样轨迹;则退化为 直接策略迭代(DPI)。

DPI 只看 m 步内的奖励 ,忽略 v(s_m);而 CBMPI 上一步的回归器 v_k-1 帮忙评估状态 s_m


继承 CbPI 的核心思想:在策略空间中搜索 (而非从值函数推导策略),

避免传统 ADP "值函数 难以被值函数空间 F 准确表征" ,那么策略性能会很差 的局限性。


两个参考的 Tetris github 项目:

https://github.com/LoveDaisy/tetris_game

https://github.com/corentinpla/Learning-Tetris-Using-the-Noisy-Cross-Entropy-Method

相关推荐
2501_907136822 小时前
AI写的软件:legado图源(开源阅读)异次元图源调试器
人工智能·软件需求
LiFileHub2 小时前
深度学习全景解析:从技术原理到十大领域落地实践
人工智能·深度学习
lbb 小魔仙2 小时前
AI Agent 开发终极手册:Manus、MetaGPT 与 CrewAI 深度对比
人工智能·ai
适应规律2 小时前
GPU利用率分析
人工智能
Silence_Jy2 小时前
Kimi K2技术报告
人工智能·python·深度学习·transformer
AI Echoes2 小时前
自定义 LangChain 文档加载器使用技巧
数据库·人工智能·python·langchain·prompt·agent
长河2 小时前
OpenSpec 实战:用规范驱动开发破解 AI 编程协作难题
人工智能
最晚的py2 小时前
rnn循环神经网络
人工智能·rnn·深度学习·神经网络
90后小陈老师2 小时前
Java项目接入AI大模型的四种方式
java·开发语言·人工智能