From 94a737182266644864e6a30674f4d19ef7ff0684 Mon Sep 17 00:00:00 2001 From: hisatri Date: Fri, 25 Jul 2025 10:36:25 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E8=AE=BA=E6=96=87=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=AB=A0=E8=8A=82=E5=86=85?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paper/main.tex | 3 +- paper/preamble.tex | 1 + paper/sections/00_abstract.tex | 1 + paper/sections/01_introduction.tex | 9 +-- paper/sections/02_problem_analyze.tex | 12 ++-- paper/sections/03_numerical_design.tex | 59 +++++++++++++++ paper/sections/03_training.tex | 60 ---------------- paper/sections/04_training.tex | 99 ++++++++++++++++++++++++++ 8 files changed, 170 insertions(+), 74 deletions(-) create mode 100644 paper/sections/03_numerical_design.tex delete mode 100644 paper/sections/03_training.tex create mode 100644 paper/sections/04_training.tex diff --git a/paper/main.tex b/paper/main.tex index 1b03a71..9b34fcb 100644 --- a/paper/main.tex +++ b/paper/main.tex @@ -18,6 +18,7 @@ \input{sections/00_abstract} \input{sections/01_introduction.tex} \input{sections/02_problem_analyze.tex} -\input{sections/03_training.tex} +\input{sections/03_numerical_design.tex} +\input{sections/04_training.tex} \end{document} diff --git a/paper/preamble.tex b/paper/preamble.tex index 1944c1f..7e2bb98 100644 --- a/paper/preamble.tex +++ b/paper/preamble.tex @@ -47,3 +47,4 @@ % 其他设置 \setcounter{tocdepth}{3} % 目录深度 \setcounter{secnumdepth}{3} % 章节编号深度 + diff --git a/paper/sections/00_abstract.tex b/paper/sections/00_abstract.tex index 9b125c5..ad40645 100644 --- a/paper/sections/00_abstract.tex +++ b/paper/sections/00_abstract.tex @@ -8,3 +8,4 @@ \end{abstract} \textbf{关键词:} 2048游戏、深度强化学习、相对位置编码、self-attention、估值策略网络 + diff --git a/paper/sections/01_introduction.tex b/paper/sections/01_introduction.tex index 4c780ca..a9aa749 100644 --- a/paper/sections/01_introduction.tex +++ b/paper/sections/01_introduction.tex @@ -12,12 +12,9 @@ \item 难以处理不同位置间的长距离依赖关系 \end{itemize} -Self-attention机制的出现为解决这些问题提供了新的思路。通过引入2D相对位置编码,我们可以: -\begin{itemize} - \item 显式建模网格中任意两个位置间的关系 - \item 捕获全局的状态信息 - \item 学习位置无关的特征表示 -\end{itemize} +Self-attention机制的出现为解决这些问题提供了新的思路。 +通过引入2D相对位置编码,我们可以在捕获全局状态信息的同时,对棋盘任意两个位置的关系进行建模, +同时学习到位置无关的特征表示。 \subsection{符号定义} \begin{itemize} diff --git a/paper/sections/02_problem_analyze.tex b/paper/sections/02_problem_analyze.tex index 00cb44c..fefc057 100644 --- a/paper/sections/02_problem_analyze.tex +++ b/paper/sections/02_problem_analyze.tex @@ -18,14 +18,10 @@ 为了解决此问题,我们可以对棋盘状态进行对数变换。 令棋盘状态为一个矩阵 $K \in \mathbb{N}$, -其中 $K_{i,j}$ 表示在 $(i,j)$ 位置的数字,空位记为 $0$。 +其中 $K_{i,j}$ 表示在 $(i,j)$ 位置的数字,空位记为 $1$ (2048游戏中不会有1出现,同时用1做掩码无需额外判断)。 我们定义一个新的状态表示矩阵 $K'$,其元素 $K'_{i,j}$ 通过以下映射获得: \begin{equation} - K'_{i,j} = - \begin{cases} - \log_2(K_{i,j}) & \text{if } K_{i,j} > 0 \\ - 0 & \text{if } K_{i,j} = 0 - \end{cases} + K'_{i,j} = \log_2(K_{i,j}) \end{equation} 通过这种对数变换,我们可以将指数增长的数值尺度压缩到一个线性、紧凑的整数范围。 这种方法同样适用于任意边长的矩形棋盘。 @@ -119,4 +115,6 @@ \begin{equation} V(N) = (\log_2(N) - 1) \cdot N \end{equation} - +\begin{equation} + V(N') = (N'-1) \cdot 2^{N'} \label{eq:log_value_formula} +\end{equation} diff --git a/paper/sections/03_numerical_design.tex b/paper/sections/03_numerical_design.tex new file mode 100644 index 0000000..ff2aeb5 --- /dev/null +++ b/paper/sections/03_numerical_design.tex @@ -0,0 +1,59 @@ +\section{数值设计} + +我们使用\texttt{SQLite}存储数据,这是因为\texttt{SQLite}在反序列化对象时的性能消耗可以接受,其相关生态也更加丰富和成熟。 + +\subsection{棋盘状态表示} + +如前文所言,对于一个$H \times W$的2048游戏棋盘,其方块数字的最大值$N_{\text{max}} = 2^{(H \times W + 1)}$, +对数变化后的方块最大值即为$N'_{\text{max}} = H \times W + 1$。 +对于$10 \times 10$的棋盘,$N'_{\text{max}} = 101$,\texttt{INT8}足以表示其范围。 + +因此,棋盘状态矩阵可以设计为一个\texttt{numpy.ndarray},数据类型为\texttt{np.int8}。 + +\subsection{动作价值表示} + +动作价值,实际上代表当前动作进行到终局时,棋盘的状态价值。 + +数字$N$的累计价值为 $V(N) = (\log_2(N) - 1) \cdot N$ 。 +对于一个$H \times W$的棋盘,其方块数字的最大值$N_{\text{max}} = 2^{(H \times W + 1)}$,则该方块的最大累计价值为: +\begin{equation} +V(N_{\text{max}}) = (\log_2(2^{(H \times W + 1)}) - 1) \cdot 2^{(H \times W + 1)} = (H \times W) \cdot 2^{(H \times W + 1)} +\end{equation} + +整个棋盘的最大累计价值理论上为: +\begin{align} +V_{\text{total}} &= \sum_{i=1}^{H} \sum_{j=1}^{W} V(i,j) \\ +&= V(N_{\text{max}}) + V(N_{\text{max}}/2) + V(N_{\text{max}}/4) + \dots + V(8) + V(4) \\ +&\lesssim V(2 \times N_{\text{max}}) \\ +&= (H \times W + 1) \cdot 2^{(H \times W + 2)} +\end{align} + +对于一个$4 \times 4$的棋盘,其最大累计价值为$17 \times 2^{18} = 4,456,448$,虽然在\texttt{INT32}范围内,但当拓展到$10 \times 10$的棋盘时,其累计价值上界为$101 \times 2^{102} \approx 5.15 \times 10^{32}$,远超\texttt{INT64}的表示范围(约$9.22 \times 10^{18}$)。 + +然而,在实际游戏过程中,$V_{\text{total}}$的取值具有高度的稀疏性: +由于2048游戏的合并规则,棋盘上的数字呈现指数级分布,大部分位置的数值相对较小, +只有少数位置达到较高数值。因此,实际的累计价值远小于理论上界。 +同时,相同的分数差距,随着总分的增长,其在游戏能力上的区分度会逐渐降低。 +通过对数变换$\log_2(V_{\text{total}})$,可以将数值范围压缩至$[0, \log_2(101 \times 2^{102})] = [0, 108.66]$, +完全在\texttt{FP32}的有效精度范围内,且能保持足够的数值精度用于价值函数的区分。 + +因此,动作价值矩阵可以设计为一个\texttt{numpy.ndarray},数据类型为\texttt{np.float32},存储对数变换后的价值。 + +\subsection{最大价值(\texttt{MAX\_VALUE})} + +这是一个64位高精度浮点数,它用于准确地代表当前状态-策略对的价值,即这个策略所模拟到的最高分。 +它不参与训练和推理,当传入的状态-策略对与现有的缓存中的某个状态重复时,这个值用于判断是否更新缓存中的价值向量。 + +我们认为具有更高终局分数的状态-策略对更有价值。 + +\subsection{棋盘尺寸} + +这是一个16位整数,用于代表棋盘的尺寸。其前8位二进制为代表棋盘的高度,后8位代表棋盘的宽度。 + +例如,一个$7 \times 5$的棋盘,其尺寸编码为\texttt{0b0000011100000101},或是\texttt{0x0705}。 + +\subsection{注释} + +游戏策略代码从设计之初就考虑到使用对数(0,1,2,3……)即$N'$表示棋盘上的数字,因此无需进行转换。 + +但是分数计算需要使用公式~\eqref{eq:log_value_formula}计算后取对数。 diff --git a/paper/sections/03_training.tex b/paper/sections/03_training.tex deleted file mode 100644 index 8d59024..0000000 --- a/paper/sections/03_training.tex +++ /dev/null @@ -1,60 +0,0 @@ -\section{模型训练} -为了训练一个强大的估值决策模型,我们采用蒙特卡洛树搜索(MCTS)生成高质量的训练数据,并设计一个轻量级的残差卷积网络(RNCNN)进行初步学习与迭代。 - -\subsection{蒙特卡洛树搜索策略} -采用纯MCTS(Pure MCTS)为初始模型生成训练数据。MCTS的每次迭代包含四个核心步骤,以当前棋盘状态为根节点,不断扩展搜索树。 - -\begin{itemize} - \item \textbf{选择 (Selection)}: 从根节点开始,根据UCT(Upper Confidence bounds applied to Trees)公式递归选择子节点,直到达到一个未完全扩展的叶子节点。UCT公式平衡了节点的探索(Exploration)与利用(Exploitation): - \[ \text{UCT} = \underset{i}{\arg\max} \left( \bar{v}_i + C \cdot \sqrt{\frac{\ln(N)}{n_i}} \right) \] - 其中 $\bar{v}_i$ 是子节点 $i$ 的平均价值,$N$ 是父节点访问次数,$n_i$ 是子节点 $i$ 访问次数,$C$ 是探索常数。 - - \item \textbf{扩展 (Expansion)}: 当选择过程到达一个叶子节点 $L$ 时,如果该节点代表的局面不是终局,则为其创建一个或多个子节点,对应于从 $L$ 出发所有合法的移动。 - - \item \textbf{模拟 (Simulation)}: 从新扩展的子节点中选择一个,开始进行模拟(也称Rollout)。在此阶段,我们采用快速的随机策略(例如,在所有合法移动中随机选择一个)持续进行游戏,直到达到终局状态。终局的分数将作为本次模拟的价值。 - - \item \textbf{反向传播 (Backpropagation)}: 将模拟得到的终局分数 $v$ 从该叶子节点开始,沿着选择路径反向传播回根节点。路径上的每一个节点都会更新其访问次数 $n$ 和累积价值 $V$,并重新计算其平均价值 $\bar{v} = V/n$。 -\end{itemize} - -\subsection{数据结构} -通过大量的MCTS模拟,我们将叶子节点的信息转换为神经网络可学习的训练样本。每个样本包含: -\begin{itemize} - \item 棋盘状态 $S$:一个 $H \times W$ 的矩阵,代表游戏局面。 - \item 策略-价值对 $(\pi, v)$:其中 $\pi$ 是从状态 $S$ 出发的一个合法移动(例如:上、下、左、右),$v$ 是在该分支下通过后续模拟所能达到的最高分。 -\end{itemize} -我们将 $(S, \pi)$ 作为键(key),当一次完整的MCTS模拟结束后,解析所有扩展出的叶子节点。对于每个叶子节点 $(S, \pi)$,其价值 $v$ 等于它后续所有模拟游戏中的最高分。 -\begin{itemize} - \item 如果一个键 $(S, \pi)$ 没有命中缓存,则写入 $(S, \pi) \rightarrow v$。 - \item 如果一个叶子节点的新分数大于缓存中的值,则更新 $(S, \pi) \rightarrow v$。 -\end{itemize} -在进行指定次数的MCTS模拟后,导出所有缓存的 $(S, \pi) \rightarrow v$ 对,作为最终的训练数据集。 - -\subsection{残差卷积网络L0} -RNCNN\_L0 是一个极小的、用于快速推理和迭代的估值决策模型。其设计目标是在有限的计算资源下,学习到基本的局面评估能力。其结构定义如下: - -\begin{itemize} - \item \textbf{输入层 (Input Layer)}: - 棋盘状态 $S$(一个 $H \times W$ 的矩阵)首先进行特征化处理。我们将每个格子的值 $V$ 转换为 $C$ 个特征平面(channel),每个平面代表一个特定的瓦片值(例如,$V \rightarrow \log_2(V)$,然后进行独热编码)。输入张量的维度为 $(H, W, C)$。 - - \item \textbf{卷积主干 (Convolutional Body)}: - 输入张量首先通过一个卷积层,然后送入一个由 $N$ 个残差块(Residual Block)组成的序列。 - \begin{itemize} - \item \textbf{初始卷积层}: 一个$3 \times 3$的卷积核,输出64个特征图,进行批量归一化(Batch Normalization)和ReLU激活。 - \item \textbf{残差块}: 每个残差块包含两个卷积层。输入通过第一个 $3 \times 3$ 卷积层(BN+ReLU),再通过第二个 $3 \times 3$ 卷积层(BN),然后将结果与块的输入相加(残差连接),最后通过一个ReLU激活函数。所有卷积层保持64个通道数。 - \end{itemize} - - \item \textbf{输出头 (Output Head)}: - 残差主干的输出特征图被送入一个最终的输出模块,该模块直接预测四个动作的价值。 - \begin{itemize} - \item 一个 $1 \times 1$ 的卷积层,将通道数从64降至16,进行BN和ReLU激活。 - \item 将特征图展平(Flatten)成一维向量。 - \item 一个全连接层(Fully Connected Layer),将向量映射到4个输出神经元,分别对应四个移动方向(上、下、左、右)的预测价值。 - \end{itemize} -\end{itemize} -模型的损失函数采用均方误差(Mean Squared Error),计算网络预测的四通道价值与MCTS生成数据中对应动作的价值 $v$ 之间的差距。 - -\subsection{模型初始化} -我们计划在3$\times$3的小棋盘上,依靠纯蒙特卡洛树的快速搜索能力,生成大量的初始数据。小棋盘状态空间较小,MCTS能更快地收敛到有意义的策略,为模型提供高质量的初始训练样本。 - -\subsection{L0迭代} -在纯蒙特卡洛生成的数据上学习到的大量初始数据,将提供给RNCNN\_L0进行监督学习训练。训练完成的L0模型可以反过来指导MCTS中的选择和模拟阶段,形成一个自我博弈(self-play)的增强回路,不断迭代优化模型性能。 diff --git a/paper/sections/04_training.tex b/paper/sections/04_training.tex new file mode 100644 index 0000000..7bcd59c --- /dev/null +++ b/paper/sections/04_training.tex @@ -0,0 +1,99 @@ +\section{模型训练} +为了训练一个强大的估值决策模型,我们采用蒙特卡洛树搜索(MCTS)生成高质量的训练数据, +并设计一个轻量级的残差卷积网络(RNCNN)进行初步学习与迭代。 + +\subsection{蒙特卡洛树搜索策略} +我们采用纯蒙特卡洛树搜索(Pure MCTS)为初始模型生成训练数据。 +MCTS的每次迭代包含四个核心步骤,以当前棋盘状态为根节点,不断扩展搜索树。 + +\begin{itemize} + \item \textbf{选择 (Selection)}: + %% 修改点:将UCT公式本身与选择策略分开,表述更严谨 + 从根节点开始,根据UCT(Upper Confidence bounds applied to Trees)选择策略递归选择子节点, + 直到达到一个未完全扩展的叶子节点。该策略会选择具有最大UCT值的子节点 $i$。节点 $i$ 的UCT值计算公式为: + \[ \text{UCT}_i = \bar{v}_i + C \cdot \sqrt{\frac{\ln(N)}{n_i}} \] + 其中,$\bar{v}_i$ 是子节点 $i$ 的平均回报(mean return),$N$ 是其父节点的访问次数,$n_i$ 是子节点 $i$ 的访问次数, + $C$ 是平衡探索与利用的常数。$i$ 遍历当前节点所有已发现的子节点。 + + \item \textbf{扩展 (Expansion)}: 当选择过程到达一个叶子节点 $L$ 时,若该节点所代表的局面非终局, + 则为其创建一个或多个子节点,对应于从状态 $L$ 出发的所有合法走法。 + + \item \textbf{模拟 (Simulation)}: + 从新扩展的子节点中选择一个,开始进行快速走子(Rollout)。在此阶段,我们采用一个快速的默认策略 + (例如,在所有合法移动中均匀随机选择)进行游戏,直至达到终局状态。终局的收益(如 胜/负/平 对应 +1/-1/0,或游戏得分) + 被记录为本次模拟的回报 $z$。 + + \item \textbf{反向传播 (Backpropagation)}: + 将模拟得到的回报 $z$ 从该叶子节点开始,沿选择路径反向传播至根节点。 + 路径上的每个节点 $j$ 都会更新其统计量:访问次数 $n_j \leftarrow n_j + 1$, + 总回报 $V_j \leftarrow V_j + z$。其平均回报也相应更新为 $\bar{v}_j = V_j / n_j$。 +\end{itemize} + +\subsection{数据结构} +通过大量的MCTS模拟,我们将每个访问过的状态及其MCTS分析结果转化为神经网络可学习的训练样本。 + +我们为每个经过充分模拟的状态 $S$ 生成一个训练目标。 +该目标是一个动作价值向量 $\mathbf{\pi}(S) \in \mathbb{R}^{|\mathcal{A}|}$, +其中 $\mathcal{A} = \{\text{上, 下, 左, 右}\}$ 是动作空间。 +向量的每个分量 $\pi_a(S)$ 代表在状态 $S$ 下, +执行动作 $a$ 后,MCTS估算出的期望回报。 + +\begin{itemize} + \item 对于不合法的移动或在MCTS中未被探索到的动作 $a$, + 我们将其价值设为一个特殊的掩码值$\pi_a = -1$,并在计算损失函数时忽略这些项。 + \item 所有状态 $S$ 及其对应的动作价值向量 $\mathbf{\pi}(S)$ 被存储在一个持久化的缓存中。 + 该缓存结构为 $\text{Cache}: \mathcal{S} \rightarrow \mathbb{R}^{|\mathcal{A}|}$, + 其中 $\mathcal{S}$ 是所有遇到过的状态集合。为了高效检索,我们使用状态的哈希值作为键。 +\end{itemize} + +缓存的更新策略如下: +\begin{itemize} + \item \textbf{初始写入:} 若状态 $S$ 不在缓存中,则在完成对 $S$ 的MCTS模拟后,将映射 $S \mapsto \mathbf{\pi}(S)$ 添加到缓存中。 + \item \textbf{缓存更新:} + 我们定义状态 $S$ 的(估计)价值为其最优动作的价值,即 $v_{\text{state}}(S) = \max_{a \in \mathcal{A}} \pi_a(S)$。 + 若状态 $S$ 已在缓存中,但在新一轮MCTS模拟后得到了新的价值向量 $\mathbf{\pi}'(S)$,且其状态价值 $v'_{\text{state}}(S) > v_{\text{state}}(S)$,则我们将缓存中的条目更新为 $S \mapsto \mathbf{\pi}'(S)$。此策略旨在保留能导向更优结果的搜索信息。 +\end{itemize} + +最终,我们将缓存中的数据转换为一个训练集 $\mathcal{D}$。对于缓存中的每一个 $(S, \mathbf{\pi}(S))$ 对, +我们将其展开为多个独立的样本,形成训练集 $\mathcal{D} = \{(S, a, \pi_a(S)) \mid \forall S \in \text{Cache}, \forall a \in \text{valid\_actions}(S)\}$。 + +\subsection{残差卷积网络L0} +RNCNN\_L0 是一个为快速推理和迭代设计的轻量级估值决策模型。其结构如下: + +\begin{itemize} + \item \textbf{输入层 (Input Layer)}: + 棋盘状态 $S \in \mathbb{R}^{H \times W}$ 首先经过特征化处理。 + 将每个非空格子的值 $V$ 通过对数函数(如 $k = \log_2(V)$)映射为整数索引, + 再进行独热编码,形成 $C$ 个特征平面(channel)。最终的输入张量维度为 $(H, W, C)$,其中 $C$ 是编码后的特征总数。 + + \item \textbf{卷积主干 (Convolutional Body)}: + 输入张量经过以下处理: + \begin{itemize} + \item \textbf{初始卷积层}: 一个 $3 \times 3$ 的填充卷积层,保持空间维度不变,后接批量归一化(Batch Normalization)和ReLU激活函数。 + \item \textbf{残差块序列}: 两个连续的残差块,每个残差块包含两个卷积层。输入首先通过一个 $3 \times 3$ 卷积层(BN+ReLU), + 再通过第二个 $3 \times 3$ 卷积层(BN),然后将结果与块的输入进行逐元素相加(残差连接),最后通过一个ReLU激活函数。 + \end{itemize} + + \item \textbf{输出头 (Output Head)}: + 卷积主干输出的特征图被送入一个专门设计的输出模块: + \begin{itemize} + \item 四个并行的 $1 \times 1$ 卷积层,每个对应一个方向(上、下、左、右),将特征图扩展为 $(H, W, 4)$ 的张量。 + \item 对每个方向通道分别应用全局最大池化(Global Max Pooling),得到四个标量值,分别对应四个方向的动作价值。 + \end{itemize} +\end{itemize} +模型的损失函数采用均方误差(Mean Squared Error, MSE)。 +对于训练集中的每个样本 $(S, a, \pi_a(S))$,损失函数计算网络对状态 $S$ 预测的动作 $a$ 的价值与MCTS提供的目标价值 $\pi_a(S)$ 之间的差距。 + +\subsection{模型初始化} +我们在 $3 \times 3$ 的小棋盘上,依靠纯MCTS的快速搜索能力,生成大量的初始训练数据。 +通过约200,000次完整的self-play对局(每局平均约50步),我们累积了约1000万个棋盘状态对作为训练样本。 +由于小棋盘的状态空间有限,MCTS能够更快地收敛到高质量的策略,从而为模型提供优质的初始训练样本。 + +\subsection{L0迭代与迁移} +RNCNN\_L0模型在纯MCTS生成的初始数据上进行监督学习训练。 +训练完成的L0模型可以反过来指导MCTS的选择与模拟阶段,以替代纯随机的Rollout策略, +从而形成一个自我对弈(self-play)的强化学习回路,持续迭代并提升模型性能。 + +L0模型的轻量级设计使其能够直接迁移到 $4 \times 4$ 和 $5 \times 5$ 的棋盘上运行, +为更大规模棋盘上的MCTS提供基础的估值和策略指导。由于其架构中使用了填充卷积和全局池化操作, +模型可以自然地适应不同尺寸的输入,无需额外的结构调整。 \ No newline at end of file