vAIbe_2048 / PLAN.md
forthezero's picture
Upload 13 files
0642513 verified

项目计划:基于Transformer的2048游戏AI

技术方案概述

硬件约束

  • AMD Ryzen 5 PRO 4650U (6核12线程) CPU
  • 8GB RAM
  • 无NVIDIA GPU,纯CPU训练
  • 需要小型高效的模型架构

整体架构

┌─────────────────────────────────────────────────────────┐
│                    GUI主窗口 (PyQt5)                      │
├─────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────────────────────────┐ │
│  │  2048游戏面板 │  │         训练状态面板              │ │
│  │   (4x4网格)   │  │  - 当前分数/局面分数              │ │
│  │              │  │  - 训练速度 (games/sec)          │ │
│  │              │  │  - 累积分数变化曲线               │ │
│  │              │  │  - 局面分数变化曲线               │ │
│  └──────────────┘  └──────────────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│  控制面板: [训练模式] [演示模式] [开始/停止] [AI托管]     │
└─────────────────────────────────────────────────────────┘

模块设计

1. 游戏核心模块 (game.py)

class Game2048:
    """2048游戏核心逻辑"""
    
    def __init__(self):
        self.board: np.ndarray  # 4x4棋盘
        self.accumulated_score: int  # 累积分数
        self.situational_score: float  # 局面分数
        
    def reset(self) -> None: ...
    def move(self, direction: int) -> tuple[bool, bool]: ...  # (moved, game_over)
    def get_state(self) -> np.ndarray: ...  # 返回当前局面
    def calculate_situational_score(self) -> float: ...

局面分数计算公式:

situation_score = (
    empty_cells * 10 +                           # 空格越多越好
    max_consecutive_adjacent * 15 +              # 连续相邻数字越多越好
    log2(max_tile) * 5 -                         # 最高数字的对数
    monotonicity_penalty                         # 单调性惩罚(避免混乱)
)

2. Transformer模型 (model.py)

考虑到CPU训练的限制,采用小型Transformer:

class Game2048Transformer(nn.Module):
    """小型Transformer用于2048决策"""
    
    def __init__(self):
        # 输入: 4x4棋盘 + 2个分数特征
        # 将棋盘展平为16个token,每个token代表一个格子的状态
        
        self.embedding = nn.Embedding(16, 64)  # 0-15 表示 log2(value),16表示空
        self.score_embedding = nn.Linear(2, 64)  # 两种分数的embedding
        
        encoder_layer = nn.TransformerEncoderLayer(
            d_model=64,
            nhead=4,
            dim_feedforward=128,
            dropout=0.1,
            batch_first=True
        )
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=2)
        
        self.policy_head = nn.Linear(64, 4)   # 输出4个动作的概率
        self.value_head = nn.Linear(64, 1)    # 输出状态价值

模型大小估算:

  • Embedding: 17 * 64 = 1,088 参数
  • Transformer (2层): ~50,000 参数
  • 输出头: ~300 参数
  • 总计: ~52,000 参数 - 非常小,适合CPU训练

3. 训练模块 (trainer.py)

采用 Actor-Critic + PPO 策略:

class PPOTrainer:
    """PPO训练器"""
    
    def __init__(self, model, lr=1e-4):
        self.model = model
        self.optimizer = torch.optim.Adam(model.parameters(), lr=lr)
        
    def compute_advantage(self, rewards, values, dones):
        # 计算GAE (Generalized Advantage Estimation)
        ...
        
    def update(self, trajectories):
        # PPO更新逻辑
        ...

奖励设计:

reward = (
    accumulated_score_delta * 0.3 +     # 累积分数增量(权重低)
    situational_score * 0.7 +           # 局面分数(权重高)
    game_over_penalty * (-100)          # 游戏结束惩罚
)

4. 多进程训练 (parallel.py)

利用6核CPU,同时运行多个游戏实例:

class ParallelGameEnv:
    """并行游戏环境"""
    
    def __init__(self, num_envs=4):
        self.num_envs = num_envs
        self.envs = [Game2048() for _ in range(num_envs)]
        
    def step(self, actions: list[int]) -> list[Transition]:
        # 并行执行动作,返回状态转移
        ...

5. GUI模块 (gui.py)

使用 PyQt5 构建界面:

class MainWindow(QMainWindow):
    """主窗口"""
    
    def __init__(self):
        self.game_widget = GameBoardWidget()
        self.stats_widget = StatsWidget()
        self.control_widget = ControlWidget()
        
        # 训练线程
        self.training_thread = TrainingThread()
        
    def switch_mode(self, mode: str): ...
    def update_display(self): ...

文件结构

game2048/
├── TASK.md          # 任务描述
├── PLAN.md          # 本文件
├── main.py          # 入口文件
├── game.py          # 游戏核心逻辑
├── model.py         # Transformer模型定义
├── trainer.py       # PPO训练器
├── parallel.py      # 多进程训练
├── gui.py           # GUI界面
├── utils.py         # 工具函数
├── requirements.txt # 依赖
└── checkpoints/     # 模型保存目录

实现步骤

阶段1: 核心游戏逻辑

  1. 实现 game.py - 2048游戏规则
  2. 实现局面分数计算
  3. 编写游戏逻辑单元测试

阶段2: 模型与训练

  1. 实现 model.py - Transformer模型
  2. 实现 trainer.py - PPO训练器
  3. 实现 parallel.py - 多进程环境
  4. 验证训练流程可以运行

阶段3: GUI界面

  1. 实现 gui.py - 主窗口和游戏面板
  2. 实现训练状态可视化(分数曲线)
  3. 实现模式切换(训练/演示)

阶段4: 整合与优化

  1. 整合所有模块
  2. 性能优化
  3. 模型保存/加载功能

依赖

torch>=2.0.0
numpy>=1.24.0
PyQt5>=5.15.0
matplotlib>=3.7.0

训练策略细节

状态表示

  • 棋盘状态:将每个格子的值转换为 log2(value),空格为0
  • 分数归一化:累积分数和局面分数归一化到 [0, 1]

动作空间

  • 0: 上
  • 1: 下
  • 2: 左
  • 3: 右

训练超参数

  • Learning rate: 1e-4
  • Batch size: 64
  • PPO clip ratio: 0.2
  • GAE lambda: 0.95
  • Discount factor (gamma): 0.99
  • 并行环境数: 4 (根据CPU核心数调整)

停止条件

  • 连续100局游戏平均分数无提升
  • 用户手动停止