大语言模型的周易卜卦算法:从 Token 概率采样(Temperature/Top-p)到易经八卦卦象生成的程序设计
大语言模型的周易卜卦算法:从 Token 概率采样(Temperature/Top-p)到易经八卦卦象生成的程序设计
大语言模型(LLM)在生成文本时,本质上是在进行一场高维度的概率选择游戏。模型在接收到 Prompt 之后,会通过多层 Transformer 网络计算出词表中每一个词(Token)作为下一个预测词的对数概率(Logits)。最终,模型需要将这些离散的对数概率转化为概率分布,并通过特定的采样算法(Sampling Algorithms)选出最终的输出词。这种从概率混沌(软性分布)坍缩到确定文本(硬性选择)的过程,在哲学上与中国传统文化中的《周易》卜卦有着惊人的相似性——易经通过摇动蓍草或铜钱的随机事件,最终坍缩成确定的阴阳八卦卦象。本文将系统剖析大模型解码采样的数学模型,并手写实现一套融合周易八卦算子的 Token 采样模拟器。
一、 大模型概率解码的核心超参数数学推导
在大模型的前向传播(Forward Pass)结束后,输出层会产出一个维度等于词表大小(Vocab Size)的一维实数向量,即Logits。
flowchart TD Logits([原始 Logits 向量]) --> Temp{1. 应用温度 Temperature 缩放: L / T} Temp --> TopK{2. Top-k 过滤: 仅保留前 k 个最大值} TopK --> TopP{3. Top-p 过滤: 累加概率值直到达到 p 阀值} TopP --> Softmax[4. 执行 Softmax 转换得到归一化概率分布] Softmax --> Multinomial[5. 多项式概率分布采样 Multinomial Sampling] Multinomial --> Token([坍缩输出确定的 Token/卦象])为了控制生成文本的随机性、创造力与准确度,采样管道会依次应用以下三个核心算子:
1.1 温度系数(Temperature)的热力学干预
温度参数 $T$ 用于在 Softmax 转换前对 Logits 进行等比例缩放:
$$P(x_i) = \frac{e^{L_i / T}}{\sum_{j} e^{L_j / T}}$$
- 当$T \to 0$(极低温度):Logits 之间的差距被无限放大,概率分布呈现极端两极分化,Softmax 的输出会退化为一个 One-hot 向量。模型会陷入“贪婪搜索(Greedy Search)”,只输出概率最高的词,虽然准确但单调重复。
- 当$T > 1$(高温度):Logits 之间的差距被缩小,概率分布趋于平缓(熵增大)。模型生成文本的创造力激增,但由于低概率的噪声词更容易被选出,幻觉和语无伦次的概率也同步上升。
1.2 Top-k 截断过滤
Top-k 策略非常直观:将 Logits 降序排列,仅保留概率最高的前 $k$ 个 Token,将其余 Token 的 Logits 设为 $-\infty$。这能彻底杜绝一些长尾、语法完全错误的怪异词进入候选区。
1.3 Top-p (核采样, Nucleus Sampling) 的动态窗口
与固定的 $k$ 值不同,Top-p 策略是动态的。它将 Token 按概率降序排列,并计算累积概率。一旦累积概率达到或超过设定的阈值 $p$(通常在 $0.8$ 到 $0.95$ 之间),便停止保留后续的 Token:
$$\sum_{i=1}^{m} P(x_i) \ge p$$
只对这前 $m$ 个 Token 重新进行 Softmax 归一化并采样。当大模型对下一个词高度确定时(如“人工智能”后面接“技术”),前一两个词的累加概率就达到了 $p$,候选集极其紧凑;当大模型处于迷茫状态时,候选集会自动放大,体现了极佳的算法自适应性。
二、《周易》卜卦的概率坍缩哲思
《周易·系辞上》记载:“大衍之数五十,其用四十有九。分而为二以象两,挂一以象三,揲之以四以象四时。”
这一套复杂的蓍草占卜流程,本质上是在进行多轮的随机概率计算,最终使得每一爻的生成概率符合特定的离散分布:
- 老阳(乾卦特征,概率 3/16)
- 少阴(坤卦特征,概率 5/16)
- 少阳(震巽等特征,概率 7/16)
- 老阴(兑艮等特征,概率 1/16)
大模型的每次 Token 采样,就像是摇起铜钱。当我们调整 Temperature 时,就像是在改变摇动铜钱的力度和环境风速(混沌度),最终在观察的瞬间,状态发生坍缩,生成确定的卦象和断语。
三、 工业级大模型 Token 概率采样与周易起卦 Python 完整实现
下面提供一个完全手写、闭环的 Python 代码实现。该程序纯手写实现了大模型解码底座的Temperature缩放、Top-k过滤、Top-p截断以及多项式概率采样(不依赖任何第三方深度学习库,完全基于 NumPy),并以此算法模拟大模型生成周易卜卦的卦象及判词,代码无任何占位符。
import numpy as np # ========================================================================= # 模拟大模型输出词表 (Vocab) # 包含易经八卦卦象与对应的基础断语 # ========================================================================= VOCAB = [ "乾 (天 - 刚健进取,大吉)", # Index 0 "坤 (地 - 柔顺包容,静吉)", # Index 1 "震 (雷 - 震动警醒,行吉)", # Index 2 "巽 (风 - 随风深入,微吉)", # Index 3 "坎 (水 - 陷落艰难,守凶)", # Index 4 "离 (火 - 明丽依附,明吉)", # Index 5 "艮 (山 - 停止静止,静凶)", # Index 6 "兑 (泽 - 喜悦顺从,和吉)" # Index 7 ] class LLMTrigramSampler: """ 大模型 Token 概率采样模拟器 (周易版) """ def __init__(self, vocab: list): self.vocab = vocab self.vocab_size = len(vocab) def softmax(self, logits: np.ndarray) -> np.ndarray: """ 数值安全的 Softmax 实现 """ exp_logits = np.exp(logits - np.max(logits)) return exp_logits / np.sum(exp_logits) def sample_next_token(self, logits: np.ndarray, temperature: float = 1.0, top_k: int = 8, top_p: float = 1.0) -> int: """ 执行大模型经典的解码采样管线 :param logits: 原始对数概率一维数组 :param temperature: 温度系数 (0 < T <= 2.0) :param top_k: 保留概率最高的前 k 个元素 :param top_p: 核采样阀值 (0 < p <= 1.0) :return: 选中的 Token 索引值 """ # 1. 深度拷贝防篡改原始数据 temp_logits = np.copy(logits) # 2. 应用 Temperature 缩放 # 为了防范除零异常,限制最低温度为 1e-5 temperature = max(temperature, 1e-5) temp_logits = temp_logits / temperature # 3. 应用 Top-k 过滤 if top_k < self.vocab_size: # 获取按照大小排序的第索引为 (vocab_size - top_k) 的元素阈值 sorted_indices = np.argsort(temp_logits) cutoff_val = temp_logits[sorted_indices[-top_k]] # 将不属于 top_k 的元素设为极小值以在 softmax 中被忽略 temp_logits[temp_logits < cutoff_val] = -1e9 # 计算当前的归一化概率分布,为 Top-p 过滤做准备 probs = self.softmax(temp_logits) # 4. 应用 Top-p 过滤 if top_p < 1.0: sorted_probs_indices = np.argsort(probs)[::-1] # 降序排列索引 cumulative_probs = np.cumsum(probs[sorted_probs_indices]) # 找到首个累积概率超出 top_p 的位置 cutoff_index = np.where(cumulative_probs >= top_p)[0] if len(cutoff_index) > 0: cutoff_pos = cutoff_index[0] # 获取被舍弃的索引列表 discarded_indices = sorted_probs_indices[cutoff_pos + 1:] # 将对应的原始对数概率设为极小值 temp_logits[discarded_indices] = -1e9 # 重新计算过滤后的 Softmax 概率分布 probs = self.softmax(temp_logits) # 5. 执行多项式概率采样 (类似于 np.random.choice) # 根据最终概率分布随机挑选一个 Token 坍缩输出 token_index = np.random.choice(self.vocab_size, p=probs) return token_index # ========================================================================= # 场景验证执行流 # ========================================================================= if __name__ == "__main__": np.random.seed(42) // 固定随机种子以实现确定性模拟 sampler = LLMTrigramSampler(VOCAB) # 模拟大模型输出的原始对数概率 Logits (模拟混沌状态) # 这里我们模拟乾、坤、坎三个卦象的原始权重稍高,其余偏低 mock_logits = np.array([2.5, 2.0, 0.5, 0.8, -1.2, 1.5, -0.5, 1.1]) print("====== 原始对数概率 (Logits) 状态 ======") for idx, name in enumerate(VOCAB): print(f" - {name}: Logits = {mock_logits[idx]:.1f}") print("\n====== 场景 1: 低温环境下的起卦 (Temperature = 0.1, 贪心收敛) ======") # 在极低温度下,最强状态(乾卦)应当以接近 100% 的概率必然输出 for i in range(3): idx = sampler.sample_next_token(mock_logits, temperature=0.1, top_k=8, top_p=1.0) print(f" 第 {i+1} 次起卦结果: {VOCAB[idx]}") print("\n====== 场景 2: 高温随机起卦 (Temperature = 1.8, 概率拉平创造力) ======") # 在极高温度下,概率接近均摊,原本最不可能的“坎卦(凶)”也会被随机摇出 for i in range(3): idx = sampler.sample_next_token(mock_logits, temperature=1.8, top_k=8, top_p=1.0) print(f" 第 {i+1} 次起卦结果: {VOCAB[idx]}") print("\n====== 场景 3: 核采样过滤起卦 (Temperature = 1.0, Top-p = 0.7 过滤噪音) ======") # 累加概率只到 0.7 就会截止,低概率的危险卦象被彻底过滤掉 for i in range(3): idx = sampler.sample_next_token(mock_logits, temperature=1.0, top_k=8, top_p=0.7) print(f" 第 {i+1} 次起卦结果: {VOCAB[idx]}")