PyTorch石头剪刀布博弈模型梯度未计算、参数不更新求助
石头剪刀布双人博弈模型问题修复及PyTorch机制解析
问题背景
我是PyTorch新手,尝试实现石头剪刀布双人博弈模型,目标是找出Rock/Paper/Scissors的最优选择分布。游戏规则:Rock获胜时赢2美元,其余胜负规则与常规一致。但编写的代码无法正常工作:离散损失函数有效性存疑,反向传播时模型参数无法更新,梯度未被计算。
核心问题分析
torch.argmax切断计算图:argmax是不可微分操作,执行后模型输出到最终选择的路径无梯度,导致参数无法更新。- 手动设置
requires_grad无效:计算图断裂后,即使手动开启loss的requires_grad,也无法追溯到模型参数的梯度。 - 离散损失无梯度流动:基于硬判断(
==)的损失函数输出是离散值,没有连续梯度,无法驱动参数更新。 - 输入设计不合理:用随机数作为模型输入无意义,我们需要学习固定的最优策略分布,无需依赖外部输入。
修正后的代码
import torch import torch.nn as nn import torch.optim as optim class StrategyModel(nn.Module): def __init__(self): super(StrategyModel, self).__init__() # 模型无需外部输入,直接输出三个动作的logits self.fc = nn.Linear(1, 3) def forward(self): # 用固定输入[1.0],让模型学习固定策略分布 x = torch.tensor([1.0]) logits = self.fc(x) return logits # 初始化两个玩家模型 model1 = StrategyModel() model2 = StrategyModel() # 收益矩阵:行=玩家1动作,列=玩家2动作,值=玩家1的收益 # 动作索引:0=Rock, 1=Paper, 2=Scissors payoff_matrix = torch.tensor([ [0, -1, 2], # Rock vs Rock/Paper/Scissors [1, 0, -1], # Paper vs ... [-2, 1, 0] # Scissors vs ... ], dtype=torch.float32) optimizer1 = optim.SGD(model1.parameters(), lr=0.1) optimizer2 = optim.SGD(model2.parameters(), lr=0.1) epochs = 1000 for epoch in range(epochs): optimizer1.zero_grad() optimizer2.zero_grad() # 获取logits并转为概率分布(softmax保证概率和为1) logits1 = model1() logits2 = model2() prob1 = nn.functional.softmax(logits1, dim=0) prob2 = nn.functional.softmax(logits2, dim=0) # 计算玩家1的期望收益:E[收益] = 玩家1概率 @ 收益矩阵 @ 玩家2概率 expected_payoff1 = torch.matmul(torch.matmul(prob1, payoff_matrix), prob2) # 玩家1最大化期望收益,损失取负 loss1 = -expected_payoff1 loss1.backward(retain_graph=True) # 保留计算图供玩家2反向传播 optimizer1.step() # 玩家2最小化玩家1的期望收益(等价于最大化自身收益) loss2 = expected_payoff1 loss2.backward() optimizer2.step() if (epoch + 1) % 100 == 0: print(f"Epoch {epoch+1}:") print(f"玩家1策略分布 (Rock/Paper/Scissors): {prob1.detach().numpy().round(4)}") print(f"玩家2策略分布 (Rock/Paper/Scissors): {prob2.detach().numpy().round(4)}") print(f"玩家1期望收益: {expected_payoff1.item():.4f}\n")
关键修复点说明
- 模型简化与输入调整:去掉冗余网络层,用固定输入让模型专注学习固定策略分布,避免随机输入干扰。
- 概率分布替代硬选择:用
softmax将logits转为概率分布,保持计算图可微性,确保梯度能传递到模型参数。 - 连续损失函数设计:基于期望收益计算损失,损失值连续且有明确的梯度方向,能有效驱动参数更新。玩家1和玩家2的损失函数分别对应“最大化收益”和“最小化对手收益”的博弈目标。
- 计算图保留:第一次反向传播时设置
retain_graph=True,保证玩家2的反向传播能复用同一计算图。
内容的提问来源于stack exchange,提问作者badinmaths
相关产品推荐
相关产品推荐

