---
title: "概念-AlphaGPT-后缀表达式与栈式虚拟机"
date: 2026-07-21
tags: [AlphaGPT, 择时, 虚拟机, 概念]
source: "AlphaGPT择时框架"
---

## 一句话

公式写成**后缀表达式**(逆波兰式),虚拟机像"照着卡片顺序在桌上摆卡、做运算"的机器人,
桌子就是**栈(stack)**,念完剩下的唯一一张卡就是因子值。

对应代码:`timing_adapter/dynamic_vm.py` 的 `DynamicStackVM.execute`。

---

## 公式为什么是后缀式(RPN)

平常写 `close - high` 叫中缀式(算子夹中间)。机器更喜欢后缀式——算子放操作数后面:

```
   中缀(人看):  close - high
   后缀(机器):  close  high  SUB
                 先报两个数,   再报"相减"
```

为什么?因为**后缀式能用一个栈顺序执行,不需要括号、不需要回头看**。这正好契合
"模型一个 token 一个 token 往外吐"——吐出来的顺序就是执行的顺序。 ^为什么后缀

配合[[概念-AlphaGPT-动态词表]],`close`=3、`high`=2、`SUB`=8,公式在模型眼里就是
数字序列 `[3, 2, 8]`。

---

## 核心画面:摆卡片

想象桌上摆卡片,两种卡:
- **数字卡**(如 close、high):摆一张,桌上多一张卡
- **运算卡**(如减法):放下它,它**立刻抓走桌上最近的两张卡,算出结果,再当成一张新卡放回**

算 `close - high`:
```
  摆【close】  →  桌上: [close]
  摆【high】   →  桌上: [close][high]
  摆【减法】   →  抓走两张,算完放回 → 桌上: [close-high]
```
摆完剩 1 张,就是最终结果。**公式 = 一串按顺序摆下的卡片。** ^摆卡片

---

## 虚拟机执行:卡是"魔方的一整层"

一张"数字卡"不是一个数,而是**魔方的一整层** `[70,728]`(70品种×728天的 close)。
公式 `[3, 2, 8]` 执行过程:

```
  token 3 → "3<7,特征" → 取魔方第3层(close表)压栈 → 桌上:[close表]
  token 2 → "2<7,特征" → 取魔方第2层(low表)压栈  → 桌上:[close表][low表]
  token 8 → "8>=7,减法" → 抓两张表逐格相减       → 桌上:[(close-low)表]
  念完 → 桌上剩1张 → 这张 [70,728] 就是因子值 ✅
```

- "数字卡" = 去魔方取一整层 `feat_tensor[:, token, :]`
- "运算卡" = 对整张表逐格运算(70×728 个格子一起算,GPU 很快) ^执行

---

## 三个防御机制(代码里那些 if 的由来)

**① 病句检查**:念完后桌上必须**恰好剩 1 张**。剩多张(没收拢)或中途运算时卡不够,
判定废公式,返回 `None`。(不过采样时 `action_mask` 已在写的时候拦掉大部分,
见 [[概念-AlphaGPT-公式生成器与合法性掩码]],这里是最后保险。)

**② 脏数据清洗**:每做完一次运算,立刻检查 `isnan/isinf`,有就地擦干净
(`nan_to_num` 换成 0 或 ±1),防一个坏格子污染后续所有运算。 ^nan清洗

**③ 兜底**:整个执行套 try/except,任何运算炸了不中断训练,直接判废、给低分。

---

## 一句话收尾

**虚拟机 = 照着公式卡片顺序、在"栈"这张桌子上摆数据/做运算的机器人;"数字卡"是魔方的
一整层,"运算卡"对整张表逐格计算,念完剩下的唯一一张表就是因子值。**

---

## 相关笔记
- [[MOC-AlphaGPT择时框架]] — 架构入口
- [[概念-AlphaGPT-动态词表]] — token 如何区分特征/算子(offset)
- [[概念-AlphaGPT-公式生成器与合法性掩码]] — 公式是怎么被"写"出来的
- [[概念-AlphaGPT-数据加载与期货缺失值处理]] — 魔方张量的来历

