You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 07:04:55