Symbolic Regression (DeepSets + LSTM Generator) / 符号回归(DeepSets + LSTM 生成器)
EN | A symbolic-regression model that discovers a mathematical expression from a set of data points. Packaged as a self-contained HuggingFace-style directory — it runs locally without the
transformerslibrary, while the layout remains fully compatible with publishing to the HuggingFace Hub.中文 | 一个「从数据点集合中发现数学表达式」的符号回归模型。已将原工程封装为 HuggingFace 风格的自包含目录,不依赖
transformers库即可本地运行, 同时目录结构与发布到 HuggingFace Hub 完全兼容。
1. What This Model Does / 这个模型解决什么问题
EN
Given a set of observed data — N data points, each with D independent variables x and one
dependent variable y — the model re-derives the hidden functional form f(x) such that
y ≈ f(x).
It directly generates an expression string (e.g. sin(x0)*x1 + exp(x0)), rather than only
outputting fitted values. This is its core advantage over ordinary regression (which returns only
coefficients).
Typical applications
- Physical / engineering experimental data → reverse-engineer empirical formulas
- Curious about a black-box relationship → obtain an interpretable expression
- Anomalous-expression detection / formula simplification
中文
给定一组观测数据 —— N 个数据点,每个点含 D 个自变量 x 和一个因变量 y ——
模型试图反推出隐藏在数据背后的函数解析式 f(x),使其满足 y ≈ f(x)。
它直接生成一段数学表达式字符串(如 sin(x0)*x1 + exp(x0)),而不是只输出拟合值。
这是它区别于普通回归模型(只给系数)的核心能力。
典型应用
- 物理/工程实验数据 → 逆推经验公式
- 好奇某个黑盒函数的关系 → 得到可解释表达式
- 异常表达式检测 / 公式简化
2. Neural Connection Diagrams / 神经元连接图
2.1 Overall Architecture / 整体架构图
graph LR
subgraph Input / 输入
X["X<br/>[B, N, 4]"]
Y["y<br/>[B, N]"]
end
subgraph DeepSets Encoder / 编码器
CONCAT["concat v = [X | y]<br/>[B, N, 5]"]
PHI["φ network<br/>Linear 5→128→128→64<br/>+ ReLU"]
POOL["pooling<br/>mean + max<br/>[B, 128]"]
RHO["ρ network<br/>Linear 128→64→64<br/>+ ReLU"]
Z["condition vector z<br/>[B, 64]"]
end
subgraph LSTM Decoder / 解码器
H0["h0 = z<br/>[1, B, 64]"]
C0["c0 = z<br/>[1, B, 64]"]
EMB["Embedding<br/>29 → 32"]
LSTM["LSTM<br/>input=32, hidden=64"]
PROJ["Linear 64→29"]
OUT["logits<br/>[B, T, 29]"]
end
TOKEN["token sequence<br/>[B, T]"]
EXPR["expression<br/>sin(x)+1"]
X --> CONCAT
Y --> CONCAT
CONCAT --> PHI
PHI --> POOL
POOL --> RHO
RHO --> Z
Z --> H0
Z --> C0
H0 --> LSTM
C0 --> LSTM
TOKEN --> EMB
EMB --> LSTM
LSTM --> PROJ
PROJ --> OUT
OUT -->|argmax/sample| TOKEN
TOKEN -->|decode| EXPR
2.2 Encoder Internal Diagram / 编码器内部连接图
graph LR
subgraph φ_elem_MLP_shared
V["v<br/>[B,N,5]"]
L1["Linear<br/>W1: 128×5<br/>b1: 128"]
R1["ReLU"]
L2["Linear<br/>W2: 128×128<br/>b2: 128"]
R2["ReLU"]
L3["Linear<br/>W3: 64×128<br/>b3: 64"]
R3["ReLU"]
H["h<br/>[B,N,64]"]
end
subgraph Pooling / 池化
MEAN["mean<br/>[B,64]"]
MAX["max<br/>[B,64]"]
CAT["concat<br/>[B,128]"]
end
subgraph ρ_setMLP
L4["Linear<br/>W4: 64×128<br/>b4: 64"]
R4["ReLU"]
L5["Linear<br/>W5: 64×64<br/>b5: 64"]
Z["z<br/>[B,64]"]
end
V --> L1 --> R1 --> L2 --> R2 --> L3 --> R3 --> H
H --> MEAN --> CAT
H --> MAX --> CAT
CAT --> L4 --> R4 --> L5 --> Z
2.3 LSTM Decoder Internal Diagram / LSTM 解码器内部连接图
graph TD
subgraph Init State / 初始状态
Z["z<br/>[B,64]"]
H0["h0 = z<br/>[1,B,64]"]
C0["c0 = z<br/>[1,B,64]"]
end
subgraph LSTM step t
XT["token x_t<br/>[B,1]"]
EMB["Embedding<br/>[29,32]<br/>e_t: [B,32]"]
GATE_I["input gate / 输入门 i<br/>σ(W_ii·e + W_hi·h + b)"]
GATE_F["forget gate / 遗忘门 f<br/>σ(W_if·e + W_hf·h + b)"]
GATE_O["output gate / 输出门 o<br/>σ(W_io·e + W_ho·h + b)"]
GATE_G["candidate / 候选 g<br/>tanh(W_ig·e + W_hg·h + b)"]
CT["c_t = f⊙c_{t-1} + i⊙g"]
HT["h_t = o⊙tanh(c_t)<br/>[B,64]"]
end
subgraph Projection / 输出投影
PROJ["Linear<br/>W6: 29×64<br/>b6: 29"]
LOGITS["logits<br/>[B,29]"]
end
NEXT["next token<br/>argmax or sample"]
Z --> H0
Z --> C0
XT --> EMB --> GATE_I
EMB --> GATE_F
EMB --> GATE_O
EMB --> GATE_G
H0 --> GATE_I
H0 --> GATE_F
H0 --> GATE_O
H0 --> GATE_G
C0 --> CT
GATE_I --> CT
GATE_F --> CT
GATE_G --> CT
CT --> HT
GATE_O --> HT
HT --> PROJ --> LOGITS --> NEXT
NEXT -->|loop / 循环| XT
3. Parameter Matrices per Layer / 每一层的矩阵参数表
3.1 Encoder (DeepSets) / 编码器
| Layer / 层名 | Type / 层类型 | Weight W / 权重 | Bias b / 偏置 | In→Out / 输入→输出 | Act / 激活 | Params / 参数量 |
|---|---|---|---|---|---|---|
encoder.phi.0 | Linear | W1: [128, 5] | b1: [128] | 5 → 128 | ReLU | 5×128+128=768 |
encoder.phi.2 | Linear | W2: [128, 128] | b2: [128] | 128 → 128 | ReLU | 128×128+128=16,512 |
encoder.phi.4 | Linear | W3: [64, 128] | b3: [64] | 128 → 64 | ReLU | 128×64+64=8,256 |
| pooling / 池化 | mean+max | — | — | [B,N,64] → [B,128] | — | 0 |
encoder.rho.0 | Linear | W4: [64, 128] | b4: [64] | 128 → 64 | ReLU | 128×64+64=8,256 |
encoder.rho.2 | Linear | W5: [64, 64] | b5: [64] | 64 → 64 | — | 64×64+64=4,160 |
Encoder total / 编码器合计:37,952 params
3.2 Decoder (LSTM generator) / 解码器
| Layer / 层名 | Type / 层类型 | Weight W / 权重 | Bias b / 偏置 | In→Out / 输入→输出 | Act / 激活 | Params / 参数量 |
|---|---|---|---|---|---|---|
decoder.embedding.weight | Embedding | E: [29, 32] | — | 29 (vocab) → 32 | — | 29×32=928 |
decoder.lstm | LSTM | W_ii/W_if/W_io/ig: each [256, 32] (packed as weight_ih_l0: [256,32]) | b_ih: [256] | 32 → 64 (4 gates / 4门) | sigmoid/tanh | 256×32+256=8,448 |
| W_hi/W_hf/W_ho/W_hg: each [256, 64] (packed as weight_hh_l0: [256,64]) | b_hh: [256] | 64 → 64 (4 gates / 4门) | sigmoid/tanh | 256×64+256=16,640 | ||
decoder.proj | Linear | W6: [29, 64] | b6: [29] | 64 → 29 | — | 64×29+29=1,885 |
Decoder total / 解码器合计:27,901 params
Model total / 模型总计:37,952 + 27,901 = 65,853 params (~66K)
3.3 LSTM Gate Matrix Details / LSTM 门控内部矩阵详解
EN | In PyTorch the LSTM weights are packed into two big matrices (4 gates concatenated):
中文 LSTM 的权重在 PyTorch 中被打包成两个大矩阵(4 个门拼在一起):
| PyTorch param / 参数名 | Shape / 形状 | Meaning / 数学含义 | Split / 拆分后 |
|---|---|---|---|
weight_ih_l0 | [256, 32] | 4 gates' weights for input e_t / 4门对输入 e_t | W_ii[64,32], W_if[64,32], W_ig[64,32], W_io[64,32] |
weight_hh_l0 | [256, 64] | 4 gates' weights for hidden h_{t-1} / 4门对隐状态 | W_hi[64,64], W_hf[64,64], W_hg[64,64], W_ho[64,64] |
bias_ih_l0 | [256] | 4 gates' input bias / 4门对输入的偏置 | b_ii[64], b_if[64], b_ig[64], b_io[64] |
bias_hh_l0 | [256] | 4 gates' hidden bias / 4门对隐状态的偏置 | b_hi[64], b_hf[64], b_hg[64], b_ho[64] |
Gate updates / 每个时间步的运算:
| Gate / 门 | Formula / 公式 | Role / 作用 |
|---|---|---|
| input / 输入门 i | $\mathbf{i}t = \sigma(\mathbf{W}{ii} \mathbf{e}t + \mathbf{b}{ii} + \mathbf{W}{hi} \mathbf{h}{t-1} + \mathbf{b}_{hi})$ | how much new info enters / 新信息写入多少 |
| forget / 遗忘门 f | $\mathbf{f}t = \sigma(\mathbf{W}{if} \mathbf{e}t + \mathbf{b}{if} + \mathbf{W}{hf} \mathbf{h}{t-1} + \mathbf{b}_{hf})$ | how much old memory to keep / 旧记忆保留多少 |
| candidate / 候选 c̃ | $\tilde{\mathbf{c}}t = \tanh(\mathbf{W}{ig} \mathbf{e}t + \mathbf{b}{ig} + \mathbf{W}{hg} \mathbf{h}{t-1} + \mathbf{b}_{hg})$ | new candidate value / 生成新候选值 |
| output / 输出门 o | $\mathbf{o}t = \sigma(\mathbf{W}{io} \mathbf{e}t + \mathbf{b}{io} + \mathbf{W}{ho} \mathbf{h}{t-1} + \mathbf{b}_{ho})$ | how much to output / 输出多少 |
| memory / 记忆更新 | $\mathbf{c}_t = \mathbf{f}t \odot \mathbf{c}{t-1} + \mathbf{i}_t \odot \tilde{\mathbf{c}}_t$ | fuse old & new / 新旧记忆融合 |
| hidden / 隐状态 | $\mathbf{h}_t = \mathbf{o}_t \odot \tanh(\mathbf{c}_t)$ | final output / 最终输出 |
4. Linear Operations of Each Block / 每一块的线性运算详解
EN | Let $\mathbf{W}$ / $\mathbf{b}$ denote learnable parameters, $\sigma$ the sigmoid, $\odot$ element-wise multiplication. 中文 下面用 $\mathbf{W}$ / $\mathbf{b}$ 表示可学习参数,$\sigma$ 表示 sigmoid,$\odot$ 表示逐元素乘。 中文说明通常在英文说明之后,公式语言无关。
4.0 Input Assembly (no params) / 输入组装(无参数)
EN | Concatenate the 4 inputs and the target into a 5-dim vector.
中文 把每个数据点的 4 个自变量与目标值拼接成 5 维向量:
$$ \mathbf{v}_n^{(i)} = \big[, x_1^{(i)},; x_2^{(i)},; x_3^{(i)},; x_4^{(i)},; y^{(i)} ,\big] \in \mathbb{R}^{5} $$
where $i$ runs over the $B$ samples and $n$ over the $N$ data points. Matrix form: $V \in \mathbb{R}^{B \times N \times 5}$. Missing variables (fewer than 4) are zero-padded. 其中 $i$ 遍历样本 $1 \dots B$,$n$ 遍历数据点 $1 \dots N$。所有点的矩阵形式为 $V \in \mathbb{R}^{B \times N \times 5}$。真实变量不足 4 的部分以 0 补齐。
4.1 Encoder Block 1 — φ network (element-wise MLP) / 编码器第 1 段
EN | φ is applied independently to every data point with shared weights across points. This is the key DeepSets property that guarantees permutation invariance.
中文 φ 对每一个数据点独立计算,且权重共享(同一个 MLP 应用于所有点)。 这是 DeepSets 保证「排列不变」的关键。
$$ \varphi: ;; \mathrm{Linear}(5 !\to! 128) \to \mathrm{ReLU} \to \mathrm{Linear}(128 !\to! 128) \to \mathrm{ReLU} \to \mathrm{Linear}(128 !\to! 64) $$
Point-wise transform (same for all $(i,n)$) / 逐点变换:
$$ \mathbf{h}_1^{(i,n)} = \mathrm{ReLU}!\big(\mathbf{v}^{(i,n)} \mathbf{W}_1^\top + \mathbf{b}_1\big), \quad \mathbf{W}_1 \in \mathbb{R}^{128 \times 5},; \mathbf{b}_1 \in \mathbb{R}^{128} $$
$$ \mathbf{h}_2^{(i,n)} = \mathrm{ReLU}!\big(\mathbf{h}_1^{(i,n)} \mathbf{W}_2^\top + \mathbf{b}_2\big), \quad \mathbf{W}_2 \in \mathbb{R}^{128 \times 128},; \mathbf{b}_2 \in \mathbb{R}^{128} $$
$$ \mathbf{h}^{(i,n)} = \mathrm{ReLU}!\big(\mathbf{h}_2^{(i,n)} \mathbf{W}_3^\top + \mathbf{b}_3\big), \quad \mathbf{W}_3 \in \mathbb{R}^{64 \times 128},; \mathbf{b}_3 \in \mathbb{R}^{64} $$
Dimension flow: $V ;[B, N, 5] ;\xrightarrow{;\varphi;}; \mathbf{h} ;[B, N, 64]$ 维度变化:$V ;[B, N, 5] ;\xrightarrow{;\varphi;}; \mathbf{h} ;[B, N, 64]$
Why 5? Because each row is $(x_1, x_2, x_3, x_4, y)$, five components. 为什么是 5?因为每行代表 $(x_1, x_2, x_3, x_4, y)$ 五个分量。
4.2 Encoder Block 2 — sample-dim aggregation (set pooling) / 编码器第 2 段
EN | Compress the features of the N points of the same set into one vector, using two
complementary poolings.
中文 把同一数据集的 $N$ 个点的特征压缩成一个向量,用两种互补的池化:
$$ \bar{\mathbf{h}}^{(i)} = \frac{1}{N} \sum_{n=1}^{N} \mathbf{h}^{(i,n)} \in \mathbb{R}^{64} \quad \text{(mean, 总体水平)} $$
$$ \hat{\mathbf{h}}^{(i)} = \max_{n} ; \mathbf{h}^{(i,n)} \in \mathbb{R}^{64} \quad \text{(max, 最极端数据点)} $$
Concatenation yields $[\bar{\mathbf{h}} ;|; \hat{\mathbf{h}}] \in \mathbb{R}^{B \times 128}$. Padding rows are set to $-\infty$ before max. 拼接后得到 $[\bar{\mathbf{h}} ;|; \hat{\mathbf{h}}]$ 的池化特征。padding 行在取 max 时先置 $-\infty$。
mean captures overall intensity; max captures the most extreme point; they complement each other. mean 捕获「总体强度」,max 捕获「最极端数据点」,两者互补。
4.3 Encoder Block 3 — ρ network (set-level MLP) / 编码器第 3 段
EN | Pass the pooled result through another MLP to get the final condition vector z.
中文 把池化结果再过一层 MLP,得到最终条件向量 $\mathbf{z}$:
$$ \mathbf{z}_{\text{in}}^{(i)} = \big[, \bar{\mathbf{h}}^{(i)} ;\big|; \hat{\mathbf{h}}^{(i)} ,\big] \in \mathbb{R}^{128} $$
$$ \mathbf{p}1^{(i)} = \mathrm{ReLU}!\big(\mathbf{z}{\text{in}}^{(i)} \mathbf{W}_4^\top + \mathbf{b}_4\big), \quad \mathbf{W}_4 \in \mathbb{R}^{64 \times 128},; \mathbf{b}_4 \in \mathbb{R}^{64} $$
$$ \mathbf{z}^{(i)} = \mathbf{p}_1^{(i)} \mathbf{W}_5^\top + \mathbf{b}_5, \quad \mathbf{W}_5 \in \mathbb{R}^{64 \times 64},; \mathbf{b}_5 \in \mathbb{R}^{64} $$
Dimension flow: $\mathbb{R}^{B \times 128} \to \mathbb{R}^{B \times 64}$ 维度变化:$\mathbb{R}^{B \times 128} \to \mathbb{R}^{B \times 64}$
At this point, a variable-length, unordered point set is encoded into a fixed-dim vector z. The whole φ → pooling → ρ path is permutation-invariant — the essence of DeepSets. 至此,我们把「一个变长、无序的点集」编码成了固定维度的向量 $\mathbf{z}$, 并且整个路径 φ → 池化 → ρ 都是排列不变的 —— 正是 DeepSets 的核心性质。
4.4 LSTM Init-State Injection (no params) / LSTM 初始状态注入
EN | Copy the encoded vector z directly into the initial hidden state and cell.
中文 把编码向量 $\mathbf{z}$ 直接拷贝成 LSTM 的初始隐状态和记忆单元:
$$ \mathbf{h}_0^{(i)} = \mathbf{c}_0^{(i)} = \mathbf{z}^{(i)} \in \mathbb{R}^{64} $$
Reshape to [1, B, 64] for the layer dimension.
送入 LSTM 时扩一维层维度:$\mathrm{hidden}, \mathrm{cell} \in \mathbb{R}^{1 \times B \times 64}$。
4.5 Embedding Layer / 嵌入层
EN | Map each token ID to a learnable vector.
中文 把每个 token ID 变成可学习向量:
$$ \mathbf{e}_t = \mathbf{E}[x_t] \in \mathbb{R}^{32}, \quad \mathbf{E} \in \mathbb{R}^{29 \times 32} $$
Dimension flow: $\mathrm{token} ;[B, T] \to \mathbf{e} ;[B, T, 32]$ 维度变化:$\mathrm{token} ;[B, T] \to \mathbf{e} ;[B, T, 32]$
4.6 LSTM (single layer, hidden=64) / LSTM(单层)
EN | Given token embedding e_t and previous h_{t-1}, c_{t-1}, the LSTM updates per gate.
中文 LSTM 在每个时间步 $t$ 按门控机制更新隐状态:
$$ \mathbf{i}t = \sigma!\big(\mathbf{W}{ii} \mathbf{e}t + \mathbf{b}{ii} + \mathbf{W}{hi} \mathbf{h}{t-1} + \mathbf{b}_{hi}\big) \quad \text{(input gate / 输入门)} $$
$$ \mathbf{f}t = \sigma!\big(\mathbf{W}{if} \mathbf{e}t + \mathbf{b}{if} + \mathbf{W}{hf} \mathbf{h}{t-1} + \mathbf{b}_{hf}\big) \quad \text{(forget gate / 遗忘门)} $$
$$ \mathbf{o}t = \sigma!\big(\mathbf{W}{io} \mathbf{e}t + \mathbf{b}{io} + \mathbf{W}{ho} \mathbf{h}{t-1} + \mathbf{b}_{ho}\big) \quad \text{(output gate / 输出门)} $$
$$ \tilde{\mathbf{c}}t = \tanh!\big(\mathbf{W}{ig} \mathbf{e}t + \mathbf{b}{ig} + \mathbf{W}{hg} \mathbf{h}{t-1} + \mathbf{b}_{hg}\big) \quad \text{(candidate / 候选记忆)} $$
$$ \mathbf{c}_t = \mathbf{f}t \odot \mathbf{c}{t-1} + \mathbf{i}_t \odot \tilde{\mathbf{c}}_t \quad \text{(memory update / 记忆更新)} $$
$$ \mathbf{h}_t = \mathbf{o}_t \odot \tanh(\mathbf{c}_t) \quad \text{(output / 隐状态输出)} $$
Dimension flow: $\mathbf{e} ;[B, T, 32] \to \mathbf{h} ;[B, T, 64]$ 维度变化:$\mathbf{e} ;[B, T, 32] \to \mathbf{h} ;[B, T, 64]$
4.7 Output Projection (no activation) / 输出投影
EN | Linearly project the hidden state to vocab space, obtaining logits per token.
中文 把隐状态向量线性投影到词表空间,得到每个 token 的 logits:
$$ \mathrm{logits}_t = \mathbf{h}_t \mathbf{W}_6^\top + \mathbf{b}_6, \quad \mathbf{W}_6 \in \mathbb{R}^{29 \times 64},; \mathbf{b}_6 \in \mathbb{R}^{29} $$
Dimension flow: $\mathbf{h} ;[B, T, 64] \to \mathrm{logits} ;[B, T, 29]$ 维度变化:$\mathbf{h} ;[B, T, 64] \to \mathrm{logits} ;[B, T, 29]$
4.8 Decoding Strategies (generation) / 解码策略(生成时)
- Greedy / 贪心:$x_t^* = \arg\max_k , \ell_{t,k}$
- Temperature sampling / 温度采样:$p(k) = \mathrm{softmax}!\big(\mathrm{logits}_t / \tau\big)_k$
| temperature $\tau$ / 温度 | Behavior / 行为 |
|---|---|
| low ($\tau < 1$) / 低温 | more deterministic, more repetitive, close to greedy / 更确定,更重复 |
| high ($\tau > 1$) / 高温 | more random, more exploration, good for diversity / 更随机,更探索 |
Auto-regressive loop 自回归推进:Embedding → LSTM → Linear each step until <EOS> or
$T_{\max} = 50$ steps / 重复 Embedding → LSTM → Linear,直到生成 <EOS> 或达到 $T_{\max}=50$。
5. Vocabulary / 词表(共 29 个)
EN | The model uses a fixed 29-token vocabulary for expressions. Digits are split digit-by-digit
(e.g. 134 → 1,3,4). All variables are normalized to <VAR> (x0, x1, x all map to the same token).
中文 模型使用固定的 29 个 token 表达数学表达式。数字按位展开(如 134 → 1,3,4),
变量全部归一化为 <VAR>(x0, x1, x 均映射为同一 token)。
| Index / 索引 | Token | Meaning / 说明 |
|---|---|---|
| 0 | ( | left paren / 左括号(特殊 token) |
| 1 | ) | right paren / 右括号(特殊 token) |
| 2 | <PAD> | padding; ignore_index in training / 填充;训练时 ignore_index |
| 3 | <SOS> | start of sequence / 序列开始 |
| 4 | <EOS> | end of sequence / 序列结束 |
| 5 | <VAR> | unified variable placeholder / 统一变量占位 |
| 6-10 | + - * / ^ | binary operators / 二元运算符 |
| 11-16 | sin cos tan exp log sqrt | unary functions / 单目函数 |
| 17-18 | pi e | constants / 常量 |
| 19-28 | 0 1 ... 9 | digits (split) / 个位数字(按位展开) |
6. Total Parameter Breakdown / 参数规模总表
| Module / 模块 | Layer / 层 | Weight shape / 权重形状 | Params / 参数量 |
|---|---|---|---|
| φ network | Linear | W1: [128,5], b1: [128] | 768 |
| φ network | Linear | W2: [128,128], b2: [128] | 16,512 |
| φ network | Linear | W3: [64,128], b3: [64] | 8,256 |
| pooling / 池化 | mean+max | — | 0 |
| ρ network | Linear | W4: [64,128], b4: [64] | 8,256 |
| ρ network | Linear | W5: [64,64], b5: [64] | 4,160 |
| Embedding | — | E: [29,32] | 928 |
| LSTM input gate projection | weight_ih_l0 | [256,32] + [256] | 8,448 |
| LSTM hidden gate projection | weight_hh_l0 | [256,64] + [256] | 16,640 |
| output projection / 输出投影 | Linear | W6: [29,64], b6: [29] | 1,885 |
| Total / 合计 | — | — | 65,853 |
The model is very light at ~66K parameters, fast inference on CPU. 模型体量约 6.6 万参数,很轻量,可在 CPU 上快速推理。
7. Pre-Training (Teacher-Forcing) / 预训练
EN | Training data is constructed by a random expression generator:
- Random expression trees (variable depth), converted to infix strings
- Random data points (X, y); y is z-score-normalized to remove scale
- Random variable count (padded to D_MAX=4)
Loss / 损失函数:
$$ \mathcal{L} = \mathcal{L}{\mathrm{CE}} + \lambda \cdot \frac{\overline{\mathrm{len}}}{T{\max}}, \quad \lambda = 0.02 $$
- $\mathcal{L}_{\mathrm{CE}}$: cross-entropy with
ignore_index=PAD(teacher-forcing) 带ignore_index=PAD的交叉熵(teacher-forcing)。 - The length penalty encourages short expressions (Occam's razor), preventing long meaningless sequences / 长度惩罚项鼓励短表达式(奥卡姆剃刀)。
- Optimizer Adam, $\mathrm{lr} = 10^{-3}$, grad clip $\mathrm{max_norm} = 1.0$ 优化器 Adam,$\mathrm{lr} = 10^{-3}$,梯度裁剪 $\mathrm{max_norm} = 1.0$。
8. Self-Training on User Data / 面向用户数据的自我训练
EN | The user only provides their own (X, y); no ground-truth expression is needed.
中文 用户只需提供自己的 (X, y),无需给出表达式真值。程序自动:
- Split / 拆分:split (X, y) into train/test subsets (default 7:3) 把 (X, y) 按比例拆成训练子集与测试子集(默认 7:3)
- Generate candidates / 生成候选:model sampling (temperature + init-state noise) mixed with random expressions / 从模型采样(带温度+初态扰动)+ 随机表达式生成混合
- Self-evaluate / 自我评估:use train-set $R^2$ as reward 用训练子集的拟合优度 $R^2$ 作为奖励:
$$ R^2 = 1 - \frac{\sum_{i} (y_i - \hat{y}i)^2}{\sum{i} (y_i - \bar{y})^2} $$
- Self-fine-tune / 自我微调:CE fine-tune generator with high-$R^2$ candidates as pseudo labels; plus REINFORCE updates with rewards 对高 R² 的候选做伪标签交叉熵微调生成器,并用 rewards 做 REINFORCE 更新
- Elite retention + rollback / 精英保留 + 回滚:keep the historical best expression across rounds; if a round worsens, restore the previous model 历史最优表达式跨轮保留;某轮变差则恢复上一轮模型
- Early stop / 提前停止:stop if test $R^2 > 0.995$ or no improvement for several rounds — this satisfies「正确率高就不继续训练」/ 若测试 R²>0.995 或连续多轮无改善则停止。
split train/test → generate candidates → self-eval R² → pseudo-label fine-tune → elite pool → stop when good
拆 train/test → 生成候选 → 自我评估 R² → 伪标签微调 → 精英池 → 达标即停
9. Directory Structure / 目录结构与文件说明
EN | This directory is self-contained: a user who clones it can run inference and self-training without any file from the parent project — only PyTorch is required (a local copy of the HF weights ships inside the package).
中文 | 本目录完全自包含:拿到整个文件夹的人无需任何父工程文件即可运行推理与自我训练, 仅需 PyTorch(HF 权重已内置在包内)。
huggingface/
├── README.md 本 Model Card / 双语模型卡
│
├── ★ HuggingFace 风格文件(from_pretrained 加载所需)/ HF-style files
│ ├── configuration_symbolic_regression.py 配置类 → 生成 config.json
│ ├── tokenization_symbolic_regression.py 分词器:表达式 ↔ token ID
│ ├── modeling_symbolic_regression.py 模型:DeepSets 编码器 + LSTM 解码器
│ ├── __init__.py 包导出 SymbolicRegressionConfig/Tokenizer/Model
│ │
│ └── hf_symbolic_regression/ 内置本地权重(离线可直接加载)
│ ├── config.json
│ ├── pytorch_model.bin 约 270 KB
│ └── tokenizer.json
│
├── ★ 平铺共享依赖(自包含副本,供父工程脚本复用)/ flat shared deps
│ ├── config.py 全局超参数
│ ├── vocab.py 词表 + 表达式 ↔ 索引 转换
│ ├── model.py 根模型:DeepSets + LSTM(非 HF 包装版本)
│ ├── data_generator.py 随机表达式生成器
│ ├── dataset.py PyTorch Dataset / DataLoader
│ ├── evaluate.py R² / token 准确率等评估
│ └── self_train.py 自我训练算法(REINFORCE + 伪标签微调)
│
├── ★ 入口工具 / entry tools
│ ├── run_hf_self_train.py demo(推理)+ selftrain(自我训练)
│ ├── convert_original_checkpoint.py checkpoint 转换(模型作者使用)
│ └── upload_to_hub.py 上传分发包到 HuggingFace Hub
EN The scripts resolve imports via an explicit
sys.pathbootstrap, so you can run them from any working directory (e.g.cd huggingface && python run_hf_self_train.py demo).中文 脚本通过文件头部的
sys.path自引导解析导入,因此可以在任意工作目录下运行 (例如cd huggingface && python run_hf_self_train.py demo)。
10. Quick Start / 快速上手
10.1 Run inference demo / 推理 demo
cd huggingface
python run_hf_self_train.py demo
10.2 Self-train on your data / 对用户数据做自我训练
cd huggingface
python run_hf_self_train.py selftrain \
--x "0.1,0.6,1.1,1.6,2.1,2.6,3.0" \
--y "0.60,1.07,1.34,1.40,1.27,0.96,0.64" \
--rounds 15 --candidates 96
10.3 (For model authors) Convert the pre-trained checkpoint /(模型作者)转换预训练权重
python huggingface/convert_original_checkpoint.py
# produces / 产出 huggingface/hf_symbolic_regression/{config.json, pytorch_model.bin}
10.4 Python API
from modeling_symbolic_regression import SymbolicRegressionModel
from tokenization_symbolic_regression import SymbolicRegressionTokenizer
import torch
tok = SymbolicRegressionTokenizer()
model = SymbolicRegressionModel.from_pretrained("hf_symbolic_regression", tokenizer=tok)
# build a sample point set / 构造一个样本点集
N, D_MAX = 40, 4
X = torch.randn(1, N, D_MAX)
y = torch.randn(1, N)
n_samples = torch.tensor([N])
exprs = model.generate(X, y, n_samples) # 返回 token 序列,可用 tok.decode 转表达式
tokens = exprs[0]
print(tok.decode(tokens.tolist()))
11. Training & Reproduction / 训练与复现
EN | This project depends on shared config.py / vocab.py / data_generator.py /
self_train.py in the project root. huggingface/ loads them by inserting the parent dir into
sys.path, so it imports correctly regardless of the working directory.
中文 本工程依赖共享的 config.py / vocab.py / data_generator.py / self_train.py
位于项目根目录。huggingface/ 通过自动插入父目录到 sys.path 的方式加载它们。
To re-pretrain, run in the project root / 需要重新预训练时在根目录执行:
python train.py # produces / 产出 checkpoints/model_final.pt
Then convert to HF weights / 再执行转换:
python huggingface/convert_original_checkpoint.py
12. Known Limitations / 已知限制
- Current pre-trained distribution favors "random deep expressions", so coverage of simple targets is incomplete; self-training compensates / 预训练分布偏向深表达式,对简单目标覆盖不完全, 自我训练阶段负责补齐。
- The generator uses greedy/temperature sampling; occasionally it may output unmatched parentheses or out-of-domain expressions; self-evaluation filters them / 极个别情况可能输出括号不闭合或 未定义域表达式;自我评估会将其判为无效候选并过滤。
- Supports up to 4 variables (D_MAX); more requires re-configuration and re-training 支持变量数 ≤ 4(D_MAX),更多变量需扩展配置并重训。
13. License / 许可证
EN | Apache License 2.0 — no usage restrictions. Free for research, learning, and commercial use (including closed-source commercial use); modification and redistribution are also free; you may, however, add a commercial license of your own to redistribute or extend it.
中文 Apache License 2.0 —— 不设任何使用门槛。允许研究、学习、商业使用(含闭源商业 使用),允许自由修改和再发布;你可以同时在此之上加你自己的商业证书进行再分发或扩展。