资讯动态

多智能体离散纳什均衡求解:迭代最优响应与MATLAB实现

发布时间:2026/10/17 7:49:29 来源:尧图企业网站定制
1. 从标题拆解多智能体离散纳什均衡的真实需求1.1 这个标题到底在说什么先把标题拆开看多智能体系统、离散纳什均衡、寻觅算法、MATLAB代码。四个词组合在一起指向的是一个非常具体的工程问题——当多个理性决策者同时存在于一个共享环境中每个人的可选动作是有限的、离散的比如合作/背叛买/卖/持有走左/走右如何找到一个稳定状态使得任何一方单独改变自己的策略都不会让自己变得更好。这个稳定状态就是纳什均衡。离散这两个字是理解整个问题的钥匙。连续博弈里策略是区间上的实数可以用梯度、可以用KKT条件去求极值但离散博弈里策略空间是一个有限集合梯度根本不存在你没法对第3个动作求导。这就意味着所有基于微积分的方法全部失效必须换一套思路——要么枚举要么用学习动态去逼近要么用势博弈的结构去降维。我见过太多人一上来就想套连续优化的框架结果卡在怎么对离散动作求梯度这一步上出不来。所以这篇东西我打算把离散这个约束从头讲透再给一套能直接跑的MATLAB实现。1.2 谁需要看这篇内容三类人最需要做多智能体强化学习的研究生你的环境动作空间是离散的你想验证你的学习算法是否收敛到纳什均衡需要一个基准求解器来对照。做博弈论课程作业的本科生老师让你求一个双矩阵博弈的纳什均衡你不想手算想要代码。做分布式决策的工程师比如资源分配、频谱共享、任务卸载这类场景每个节点独立决策你想知道系统会不会稳定下来。如果你属于以上任何一类这篇内容里的代码和思路你可以直接拿去改。MATLAB的好处是矩阵操作天然适合博弈的收益矩阵表示写起来比Python还短。1.3 为什么离散纳什均衡比连续难求这里必须把为什么难讲清楚否则后面的算法选择你理解不了。连续博弈求纳什均衡本质是解一个互补问题或者不动点问题有成熟的Lemke-Howson、投影梯度等方法。但离散博弈的纳什均衡存在性虽然由Nash定理保证有限博弈必有混合策略纳什均衡可求解复杂度是PPAD完全的——通俗说就是这个问题在计算上被认为是难的不存在多项式时间的精确算法除非PPADP而这被广泛认为不成立。所以实际工程中我们做的都是近似求解或者特定结构下的精确求解。特定结构包括势博弈potential game、超模博弈supermodular game、零和博弈。这几种结构下均衡的求解会大幅简化。我下面的算法设计会围绕如何利用结构和如何做近似两条线展开。注意如果你拿到的是一个一般的、没有特殊结构的离散博弈别指望有快速精确算法。这时候要么接受近似解要么把问题规模压到能枚举的程度。2. 离散纳什均衡的核心概念与数学基础2.1 博弈的标准形式与收益矩阵一个标准形式博弈用三元组表示参与者集合 $N {1, 2, ..., n}$每个参与者的策略集 $S_i$以及收益函数 $u_i: S_1 \times S_2 \times ... \times S_n \rightarrow \mathbb{R}$。对于两人博弈收益可以写成两个矩阵 $A$ 和 $B$其中 $A_{ij}$ 是行玩家选策略 $i$、列玩家选策略 $j$ 时行玩家的收益$B_{ij}$ 是列玩家的收益。这就是所谓的双矩阵博弈。在MATLAB里这两个矩阵就是普通的二维数组。比如经典的囚徒困境% 囚徒困境收益矩阵 % 策略1: 合作(C), 策略2: 背叛(D) A [-1, -3; % 行玩家收益 0, -2]; B [-1, 0; % 列玩家收益 -3, -2];这里 $A_{11} -1$ 表示双方都合作时各自收益-1比如各判1年$A_{12} -3$ 表示行玩家合作、列玩家背叛时行玩家收益-3。这个矩阵结构决定了均衡是背叛背叛。2.2 纯策略均衡与混合策略均衡纯策略纳什均衡是指每个参与者都确定性地选择一个策略且没有人愿意单方面偏离。用数学语言策略组合 $s^* (s_1^, ..., s_n^)$ 是纯策略纳什均衡当且仅当对所有 $i$ 和所有 $s_i \in S_i$$$u_i(s_i^, s_{-i}^) \geq u_i(s_i, s_{-i}^*)$$其中 $s_{-i}^*$ 表示除 $i$ 以外其他参与者的策略。混合策略纳什均衡允许参与者以概率分布随机选择策略。设 $\sigma_i$ 是参与者 $i$ 的混合策略一个概率向量则均衡条件是$\sigma_i$ 的支撑集概率大于0的策略中每个纯策略的期望收益都相等且不低于支撑集外的策略。离散博弈里纯策略均衡不一定存在比如石头剪刀布但混合策略均衡一定存在。这是Nash在1950年证明的。2.3 离散带来的三个技术难点难点一不可微。连续博弈可以用梯度下降找均衡离散博弈没有梯度。你只能比较不同策略的收益值做离散的改进。难点二组合爆炸。$n$ 个参与者、每人 $m$ 个策略纯策略组合有 $m^n$ 个。$n10, m5$ 就是将近一千万个组合枚举不现实。难点三均衡不唯一。离散博弈经常有多个纳什均衡算法找到哪个取决于初始化和路径。这在工程上是个大问题——你可能想要最好的那个均衡但算法只保证找到一个。实操心得如果你的问题有多个均衡先想清楚你要哪个。是帕累托最优的那个还是风险占优的那个不同目标对应不同的选择准则代码里的初始化策略也要相应调整。3. 寻觅算法的整体设计与选型逻辑3.1 为什么选迭代最优响应作为主算法求解离散纳什均衡的算法有很多Lemke-Howson、支撑枚举、同伦方法、迭代最优响应Iterative Best Response, IBR、虚拟对弈Fictitious Play、复制者动态Replicator Dynamics等。我选迭代最优响应作为主算法理由有三第一实现简单。核心逻辑就是每个人轮流选对自己最好的策略一个循环加一个max操作就搞定MATLAB里几行代码。第二物理意义清晰。它模拟的是理性 agent 逐步调整策略的过程和分布式系统的实际行为吻合。你在做多智能体系统时agent 本来就是这么决策的。第三在势博弈中保证收敛。势博弈有一个标量势函数每次最优响应都会让势函数不减所以必然收敛到纯策略纳什均衡。这是理论保证不是启发式。但IBR也有缺点在一般博弈中可能循环震荡不收敛。所以我会配合混合策略求解作为补充用线性规划求两人零和博弈的混合均衡用支撑枚举求小规模一般博弈的混合均衡。3.2 算法整体架构整个求解框架分三层第一层结构检测。判断输入的博弈是否属于势博弈、零和博弈等特殊结构。如果是走快速路径。第二层纯策略求解。用迭代最优响应找纯策略纳什均衡配合随机重启避免陷入局部循环。第三层混合策略求解。当纯策略不存在或不收敛时用线性规划或支撑枚举求混合策略均衡。这个分层设计的好处是简单问题快速解决复杂问题有兜底方案。实际跑的时候大部分工程问题在第一层或第二层就解决了。3.3 MATLAB作为实现工具的优势用MATLAB写博弈求解代码有几个天然优势矩阵操作收益矩阵的索引、切片、max操作都是一行代码比C简洁太多。优化工具箱求混合策略均衡本质是线性规划linprog直接调用。可视化收敛曲线、策略演化图plot几行就出来调试时非常直观。无需编译改完直接跑迭代速度快。当然MATLAB也有缺点循环慢。所以我在代码里尽量用向量化操作替代for循环后面会具体讲怎么优化。4. 核心算法的MATLAB实现细节4.1 收益矩阵的构建与规范化第一步是把你的问题转化成收益矩阵。假设你有 $n$ 个参与者每人 $m$ 个策略你需要构建一个 $n$ 维的收益张量。但MATLAB对高维张量操作不如矩阵方便所以对于两人博弈我用两个矩阵对于多人博弈我用元胞数组存每个参与者的收益。function payoff buildPayoff(nPlayers, nActions, payoffFunc) % nPlayers: 参与者数量 % nActions: 每个参与者的策略数可以是向量 % payoffFunc: 收益函数句柄输入策略组合输出各参与者收益 if isscalar(nActions) nActions repmat(nActions, 1, nPlayers); end totalProfiles prod(nActions); payoff cell(1, nPlayers); for i 1:nPlayers payoff{i} zeros(nActions); end % 枚举所有策略组合 for idx 1:totalProfiles profile ind2sub(nActions, idx); u payoffFunc(profile); for i 1:nPlayers sub num2cell(profile); payoff{i}(sub{:}) u(i); end end end这段代码的关键是ind2sub它把线性索引转成多维策略组合。对于两人博弈payoff{1}和payoff{2}就是矩阵 $A$ 和 $B$。注意如果策略数很大枚举所有组合会爆内存。这时候不要构建完整张量而是用函数句柄按需计算收益。我在代码里留了一个开关超过阈值就切换到按需模式。4.2 迭代最优响应算法实现这是核心中的核心。逻辑是每轮让一个参与者计算自己所有策略在当前对手策略下的收益选最大的那个。如果所有人都不再改变策略就找到了纯策略纳什均衡。function [eqProfile, converged, history] iterativeBestResponse(payoff, nActions, maxIter, tol) % payoff: 元胞数组每个参与者的收益张量 % nActions: 每个参与者的策略数 % maxIter: 最大迭代次数 % tol: 收敛容差连续多少次无人改变视为收敛 nPlayers length(payoff); if nargin 3, maxIter 1000; end if nargin 4, tol 5; end % 随机初始化 profile randi(nActions); history zeros(maxIter, nPlayers); stableCount 0; converged false; for iter 1:maxIter history(iter, :) profile; changed false; for i 1:nPlayers % 计算参与者i在当前对手策略下的各策略收益 currentPayoff getPayoffForPlayer(payoff{i}, profile, i); [~, bestAction] max(currentPayoff); if bestAction ~ profile(i) profile(i) bestAction; changed true; end end if ~changed stableCount stableCount 1; if stableCount tol converged true; break; end else stableCount 0; end end eqProfile profile; history history(1:iter, :); end function vals getPayoffForPlayer(payoffTensor, profile, playerIdx) % 固定其他参与者策略提取该参与者在各策略下的收益 nActions size(payoffTensor); vals zeros(nActions(playerIdx), 1); for a 1:nActions(playerIdx) sub num2cell(profile); sub{playerIdx} a; vals(a) payoffTensor(sub{:}); end end这里有个细节值得说stableCount机制。为什么要连续多次无人改变才算收敛因为离散博弈里可能出现两个人轮流改变、永远不停的循环。要求连续5次无人改变能过滤掉大部分伪收敛。这个数字5是我实测下来的经验值太小容易误判太大浪费时间。4.3 混合策略均衡的线性规划求解对于两人零和博弈混合策略纳什均衡可以转化为线性规划。设行玩家的混合策略为 $x$列向量列玩家的为 $y$博弈值 $v$。行玩家要最大化 $v$约束是无论列玩家怎么选行玩家的期望收益都不低于 $v$$$\max v \quad \text{s.t.} \quad A^T x \geq v \cdot \mathbf{1}, \quad \sum x_i 1, \quad x \geq 0$$MATLAB实现function [x, y, v] solveZeroSumLP(A) % A: 行玩家收益矩阵零和博弈中列玩家收益为 -A [m, n] size(A); % 行玩家问题: max v, s.t. A*x v, sum(x)1, x0 % 转化为 linprog 标准形式: min -v % 变量: [x; v] f [zeros(m,1); -1]; A_ub [-A, ones(n,1)]; % -A*x v 0 b_ub zeros(n,1); A_eq [ones(1,m), 0]; b_eq 1; lb [zeros(m,1); -inf]; options optimoptions(linprog, Display, off); [sol, ~, exitflag] linprog(f, A_ub, b_ub, A_eq, b_eq, lb, [], options); if exitflag ~ 1 warning(线性规划未收敛); x ones(m,1)/m; v 0; else x sol(1:m); v sol(end); end % 列玩家问题对称求解 f2 [zeros(n,1); 1]; A_ub2 [A, -ones(m,1)]; % A*y - v 0 b_ub2 zeros(m,1); A_eq2 [ones(1,n), 0]; b_eq2 1; lb2 [zeros(n,1); -inf]; [sol2, ~, exitflag2] linprog(f2, A_ub2, b_ub2, A_eq2, b_eq2, lb2, [], options); if exitflag2 1 y sol2(1:n); else y ones(n,1)/n; end end这段代码里A_ub和b_ub的构造是关键。原始约束是 $A^T x \geq v$移项得 $-A^T x v \leq 0$对应A_ub [-A, ones(n,1)]。这个转换我一开始也写错过把符号搞反了结果求出来的策略完全不对。你写的时候一定要对着约束逐项检查。4.4 势博弈的快速求解路径如果博弈是势博弈存在一个势函数 $\Phi$使得任何单方面策略改变带来的收益变化等于势函数的变化$$u_i(s_i, s_{-i}) - u_i(s_i, s_{-i}) \Phi(s_i, s_{-i}) - \Phi(s_i, s_{-i})$$势博弈的好处是迭代最优响应必然收敛到纯策略纳什均衡而且收敛速度很快。检测势博弈的方法是比较所有策略对的收益差如果满足上述等式就是势博弈。function [isPotential, Phi] checkPotentialGame(payoff, nActions) nPlayers length(payoff); isPotential true; Phi []; % 简化检测只对两人博弈做完整检测 if nPlayers 2 A payoff{1}; B payoff{2}; [m, n] size(A); Phi zeros(m, n); % 用A的累积和构造候选势函数 for i 1:m for j 1:n Phi(i,j) A(i,j) B(i,j); end end % 验证势函数条件 for i 1:m for j 1:n for i2 1:m if A(i,j) - A(i2,j) ~ Phi(i,j) - Phi(i2,j) isPotential false; return; end end end end end end对于两人博弈如果 $A B$ 的差分满足条件就是势博弈。常见的势博弈包括拥塞博弈、合作博弈、某些资源分配博弈。识别出来之后直接用IBR求解收敛性有保证。5. 完整实操流程与参数调优5.1 从问题到代码的完整流程假设你要解决一个具体的多智能体决策问题完整流程是这样的第一步定义策略空间。确定每个agent有多少个可选动作。比如3个agent每人3个动作策略组合共27个。第二步构建收益函数。这是最需要领域知识的一步。收益函数决定了博弈的性质也决定了均衡的位置。我建议先用简单的线性收益函数测试确认代码跑通后再换成复杂的。第三步检测博弈结构。调用checkPotentialGame判断是否势博弈。如果是走快速路径如果不是走通用路径。第四步运行求解器。先用IBR尝试纯策略均衡设置最大迭代1000次、收敛容差5。如果收敛输出结果如果不收敛切换到混合策略求解。第五步验证均衡。这一步很多人会跳过但非常重要。验证方法是对每个参与者检查是否存在单方面偏离能提高收益。如果不存在确认是纳什均衡。function isNE verifyNashEquilibrium(profile, payoff, nActions) nPlayers length(payoff); isNE true; for i 1:nPlayers currentPayoff getPayoffForPlayer(payoff{i}, profile, i); currentVal currentPayoff(profile(i)); if any(currentPayoff currentVal 1e-6) isNE false; fprintf(参与者 %d 可以偏离: 当前收益 %.4f, 最优收益 %.4f\n, ... i, currentVal, max(currentPayoff)); return; end end end5.2 参数选择的经验值几个关键参数的经验值都是我踩坑踩出来的参数推荐值说明最大迭代次数1000一般问题200次内收敛1000是安全上限收敛容差5连续5次无人改变视为收敛太小误判太大浪费随机重启次数10多均衡问题时重启10次取最好的线性规划容差1e-8linprog默认值一般不用改收益比较容差1e-6浮点比较必须用容差不能直接用实操心得收益比较容差这个参数最容易被忽略。MATLAB浮点运算有误差两个理论上相等的收益可能差1e-15如果你用比较会误判为可以偏离导致算法永远不收敛。我一开始就栽在这个坑上调了半天才发现是浮点误差。5.3 收敛性调试与可视化调试收敛问题最好的办法是把策略演化画出来。我写了一个可视化函数function plotConvergence(history, nActions) [iters, nPlayers] size(history); figure; for i 1:nPlayers subplot(nPlayers, 1, i); plot(1:iters, history(:,i), o-, LineWidth, 1.5); ylim([0.5, nActions(i)0.5]); yticks(1:nActions(i)); ylabel(sprintf(Agent %d, i)); grid on; end xlabel(迭代次数); sgtitle(策略演化过程); end如果曲线在几个值之间来回跳说明算法在循环需要增加随机重启或切换到混合策略。如果曲线很快稳定说明收敛良好。如果曲线一直不变但验证不是均衡说明初始化就卡住了需要换初始点。6. 常见问题与排查技巧实录6.1 算法不收敛的六种原因这是我实际遇到过的所有不收敛情况按出现频率排序原因一博弈本身没有纯策略纳什均衡。比如石头剪刀布你怎么迭代都不会收敛。这时候必须用混合策略。判断方法如果IBR跑满1000次还在震荡大概率是这个问题。原因二浮点误差导致伪偏离。前面说过的收益差1e-15被误判为偏离。解决方法所有比较加容差。原因三策略空间太大随机初始化不好。策略组合上百万时随机初始化可能落在很差的区域。解决方法用启发式初始化比如让每个agent先选自己的安全策略。原因四收益函数有噪声。如果你的收益是仿真出来的有随机性那每次计算的收益都不一样算法会一直震荡。解决方法固定随机种子或者对多次仿真取平均。原因五迭代顺序导致循环。轮流更新时A改了B改B改了A又改回去。解决方法随机化更新顺序或者用同步更新所有人同时改。原因六收敛容差设得太小。要求连续100次无人改变可能永远达不到。解决方法容差设5就够了。6.2 均衡验证失败的排查表现象可能原因解决方法验证说可以偏离但偏离后收益只高1e-10浮点误差增大比较容差到1e-6验证说可以偏离收益高很多算法没收敛增加迭代次数或重启多个agent同时可以偏离不是均衡点继续迭代或换算法验证通过但结果不合理收益函数建模错误检查收益矩阵构建每次运行结果不同多均衡或随机性固定种子多次运行取众数6.3 性能优化的三个技巧技巧一向量化收益计算。getPayoffForPlayer里的for循环是性能瓶颈。对于两人博弈可以一次性计算% 优化前循环 vals zeros(m,1); for a 1:m vals(a) A(a, profile(2)); end % 优化后向量化 vals A(:, profile(2));这一改速度提升几十倍。对于多人博弈可以用sub2ind把多维索引转成线性索引一次性取出所有收益。技巧二预计算收益表。如果收益函数计算很慢预先算好所有策略组合的收益存起来迭代时直接查表。代价是内存但速度提升明显。技巧三并行随机重启。多均衡问题时需要多次重启用parfor并行化results cell(1, nRestarts); parfor r 1:nRestarts [profile, conv, ~] iterativeBestResponse(payoff, nActions); results{r} struct(profile, profile, converged, conv); end注意parfor里不能有依赖顺序的操作随机种子要每个worker独立设置否则所有worker用同一个种子重启就失去意义了。7. 从两人博弈扩展到多人博弈的实操要点7.1 多人博弈的收益存储问题两人博弈用矩阵三人以上就得用高维数组或元胞数组。MATLAB的高维数组操作比较别扭我的做法是用线性索引。假设3个agent每人3个策略收益张量是3×3×3。要取agent 1在策略(2,1,3)下的收益nActions [3, 3, 3]; profile [2, 1, 3]; idx sub2ind(nActions, profile(1), profile(2), profile(3)); val payoffTensor(idx);如果要取agent 1在所有策略下的收益固定其他agent可以这样vals zeros(nActions(1), 1); for a 1:nActions(1) idx sub2ind(nActions, a, profile(2), profile(3)); vals(a) payoffTensor(idx); end7.2 多人博弈的计算复杂度控制3人每人3策略是27个组合还好。但5人每人5策略就是3125个组合10人每人10策略就是100亿个组合完全不可行。控制复杂度的方法利用稀疏性很多策略组合在实际中不会出现只存储有效的组合。函数式收益不预存收益表每次按需计算。适合收益函数简单的情况。分解方法如果博弈可以分解成多个子博弈分别求解再组合。近似方法用采样估计收益牺牲精度换速度。我一般建议策略组合超过10万个就别用精确方法了考虑近似算法或者问题重构。7.3 多人势博弈的特殊处理多人势博弈有个很好的性质势函数可以直接构造。对于拥塞博弈这类典型的多智能体势博弈势函数就是所有资源上的拥塞成本之和。function Phi congestionPotential(profile, costFunc) % profile: 每个agent选择的资源 % costFunc: 资源成本函数输入资源上的agent数量输出成本 nResources max(profile); Phi 0; for r 1:nResources count sum(profile r); for k 1:count Phi Phi costFunc(r, k); end end end这个势函数的意义是每次agent改变策略势函数的变化等于该agent收益的变化。所以最大化势函数就是找均衡。可以用贪心算法快速求解。8. 代码组织与工程化建议8.1 推荐的目录结构discrete-nash-solver/ ├── main.m % 主入口 ├── core/ │ ├── iterativeBestResponse.m │ ├── solveZeroSumLP.m │ ├── checkPotentialGame.m │ └── verifyNashEquilibrium.m ├── utils/ │ ├── buildPayoff.m │ ├── getPayoffForPlayer.m │ └── plotConvergence.m ├── examples/ │ ├── prisonerDilemma.m │ ├── congestionGame.m │ └── zeroSumGame.m └── tests/ └── testSolver.m这样组织的好处是核心算法和工具函数分离例子独立测试独立。改算法不影响例子加例子不影响核心。8.2 用OOP封装求解器MATLAB支持面向对象把求解器封装成类用起来更清爽classdef NashSolver handle properties Payoff NActions MaxIter 1000 Tol 5 end methods function obj NashSolver(payoff, nActions) obj.Payoff payoff; obj.NActions nActions; end function [profile, conv] solvePure(obj) [profile, conv, ~] iterativeBestResponse(... obj.Payoff, obj.NActions, obj.MaxIter, obj.Tol); end function [x, y, v] solveMixed(obj) if length(obj.Payoff) ~ 2 error(混合策略求解仅支持两人博弈); end [x, y, v] solveZeroSumLP(obj.Payoff{1}); end function isNE verify(obj, profile) isNE verifyNashEquilibrium(profile, obj.Payoff, obj.NActions); end end end用的时候solver NashSolver(payoff, [3, 3]); [profile, conv] solver.solvePure(); if conv solver.verify(profile) fprintf(找到纯策略纳什均衡: [%s]\n, num2str(profile)); endOOP的好处是参数集中管理不用每次调用都传一堆参数。缺点是MATLAB的OOP性能略低于函数式但对这个规模的问题影响不大。8.3 测试用例设计写求解器一定要有测试用例否则改一处坏一处。我常用的测试用例囚徒困境已知均衡是背叛背叛验证算法能找到。协调博弈有两个纯策略均衡验证算法能找到其中一个。石头剪刀布无纯策略均衡验证算法正确报告不收敛混合策略求解给出(1/3, 1/3, 1/3)。势博弈验证势函数单调不减。随机博弈验证找到的策略确实满足纳什条件。function testSolver() % 测试1: 囚徒困境 A [-1, -3; 0, -2]; B [-1, 0; -3, -2]; solver NashSolver({A, B}, [2, 2]); [profile, conv] solver.solvePure(); assert(conv isequal(profile, [2, 2]), 囚徒困境测试失败); % 测试2: 石头剪刀布 A [0, -1, 1; 1, 0, -1; -1, 1, 0]; solver2 NashSolver({A, -A}, [3, 3]); [~, conv2] solver2.solvePure(); assert(~conv2, 石头剪刀布不应有纯策略均衡); [x, y, v] solver2.solveMixed(); assert(abs(v) 1e-6, 零和博弈值应为0); assert(all(abs(x - 1/3) 1e-6), 混合策略应均匀); fprintf(所有测试通过\n); end这套测试跑一遍基本能覆盖主要功能。每次改代码先跑测试通过了再跑实际数据。9. 实际应用场景与扩展方向9.1 典型应用场景场景一无线频谱共享。多个基站竞争有限的频段每个基站选择使用哪个频段。收益是吞吐量减去干扰。这是典型的拥塞博弈是势博弈IBR快速收敛。场景二任务卸载。边缘计算中多个用户决定任务在本地执行还是卸载到边缘服务器。收益是时延和能耗的加权。策略是离散的本地/卸载适合本方法。场景三广告竞价。多个广告主竞争广告位每个广告主选择出价档位。收益是曝光量减去成本。这是离散博弈可能有混合策略均衡。场景四交通路径选择。司机选择走哪条路收益是负的通行时间。这是经典的拥塞博弈势函数存在均衡就是用户均衡。9.2 与强化学习的结合现在多智能体强化学习很热但RL的收敛性分析往往依赖纳什均衡的概念。你可以用本方法求出的均衡作为基准评估RL算法是否收敛到了均衡。具体做法用IBR求出均衡策略然后跑你的MARL算法看最终策略和均衡策略的距离。如果距离很小说明RL收敛到了均衡如果距离大说明RL找到了其他稳定点或者没收敛。function dist evaluateMARLConvergence(marlPolicy, neProfile) % marlPolicy: MARL学到的策略概率分布 % neProfile: 纳什均衡策略 dist 0; for i 1:length(neProfile) target zeros(size(marlPolicy{i})); target(neProfile(i)) 1; dist dist norm(marlPolicy{i} - target, 1); end end9.3 扩展到不完全信息博弈本方法假设收益函数是公开的每个agent知道所有人的收益。如果是不完全信息博弈每个agent只知道自己的收益就需要用贝叶斯博弈的框架。扩展思路把收益函数参数化每个agent对参数有一个先验分布。求解时对参数空间做采样在每个采样点上求均衡然后对结果做贝叶斯平均。这个方法计算量大但思路直接。另一个方向是用在线学习的方法agent通过反复博弈逐渐学习对手的策略最终收敛到均衡。这类方法包括虚拟对弈、遗憾匹配等和本方法可以互补。10. 我在实际项目中的几点体会最后分享几个我在实际项目中积累的体会都是文档里不会写的。第一先验证问题有没有均衡再写求解器。我见过太多人花一周写求解器最后发现问题是石头剪刀布结构根本没有纯策略均衡。花十分钟用理论判断一下能省一周时间。第二收益函数的量纲要统一。如果你的收益是吞吐量减去时延吞吐量单位是Mbps时延单位是ms直接相减没有意义。必须先归一化或者加权。我见过因为量纲问题导致均衡完全错误的案例。第三小规模问题手算验证。2×2的博弈手算均衡只要几分钟。用你的代码跑一遍对上了再跑大规模问题。这一步能抓出大部分bug。第四保存中间结果。求解过程可能跑很久把每次迭代的策略和收益存下来出问题时能回溯。我一般存成mat文件文件名带时间戳。第五多均衡时要有选择准则。算法找到一个均衡就停了但这个均衡可能不是你要的。常见的准则有帕累托最优、风险占优、收益最大。在代码里加一个后处理步骤把所有找到的均衡收集起来按准则排序。这套代码我从两人博弈写到多人博弈从纯策略写到混合策略中间踩的坑基本都写在这篇里了。你拿去改的时候建议先从囚徒困境这种简单例子跑通再换成你的实际问题。遇到不收敛对照第6节的排查表逐项检查大部分问题都能定位到。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑