# Basic Math

## 1. sin、cos、二维旋转与 RoPE

> **一句话直觉：**只要给定旋转角度 $\theta$，$\cos\theta$ 和 $\sin\theta$ 就能精确确定单位圆上的位置 $(x,y)$。

[[BASIC_MATH_ROTATION_ROPE]]

### 1.1 单位圆：角度如何变成坐标

想象一个圆心在 $(0,0)$、半径为 $1$ 的圆：

1. 从最右端 $(1,0)$ 开始，此时角度为 $0$。
2. 沿圆周逆时针旋转 $\theta$。
3. 指针尖端落在 $(x,y)$，其中水平投影是余弦，垂直投影是正弦：

$$
(x,y)=(\cos\theta,\sin\theta).
$$

因为半径为 $1$，勾股定理同时给出：

$$
\cos^2\theta+\sin^2\theta=1.
$$

这说明 $(\cos\theta,\sin\theta)$ 一定仍在单位圆上。

| 旋转角度 $\theta$ | $\cos\theta$：$x$ | $\sin\theta$：$y$ | 圆上点 | 几何位置 |
|---|---:|---:|---|---|
| $0^\circ=0$ rad | $1$ | $0$ | $(1,0)$ | 最右端 |
| $90^\circ=\frac{\pi}{2}$ rad | $0$ | $1$ | $(0,1)$ | 最顶端 |
| $180^\circ=\pi$ rad | $-1$ | $0$ | $(-1,0)$ | 最左端 |
| $270^\circ=\frac{3\pi}{2}$ rad | $0$ | $-1$ | $(0,-1)$ | 最底端 |

### 1.2 从极坐标到笛卡尔坐标

单位圆只是半径 $r=1$ 的特例。若向量长度为 $r$：

$$
x=r\cos\theta,\qquad y=r\sin\theta.
$$

- $r$ 决定向量有多长。
- $\theta$ 决定向量朝哪个方向。
- $\cos\theta$ 和 $\sin\theta$ 把“长度 + 角度”转换为普通的 $x,y$ 坐标。

### 1.3 旋转矩阵从哪里来：先旋转两个基向量

任意二维向量都可以由两个坐标轴单位箭头组合：

$$
\vec e_1=\begin{bmatrix}1\\0\end{bmatrix},\qquad
\vec e_2=\begin{bmatrix}0\\1\end{bmatrix},\qquad
\begin{bmatrix}x\\y\end{bmatrix}=x\vec e_1+y\vec e_2.
$$

线性变换的关键是：**知道两个基向量被送到哪里，就知道任意向量被送到哪里。**

#### 第一个基向量 $\vec e_1$

$\vec e_1$ 原本位于单位圆的 $0^\circ$。逆时针旋转 $\theta$ 后：

$$
\vec e_1'=
\begin{bmatrix}
\cos\theta\\
\sin\theta
\end{bmatrix}.
$$

#### 第二个基向量 $\vec e_2$

$\vec e_2$ 原本位于 $90^\circ$，再旋转 $\theta$ 后位于 $90^\circ+\theta$：

$$
\cos(90^\circ+\theta)=-\sin\theta,
\qquad
\sin(90^\circ+\theta)=\cos\theta.
$$

因此：

$$
\vec e_2'=
\begin{bmatrix}
-\sin\theta\\
\cos\theta
\end{bmatrix}.
$$

### 1.4 为什么这两个结果正好是矩阵的两列

把旋转后的基向量依次放入矩阵的列：

$$
R(\theta)
=\begin{bmatrix}\vec e_1'&\vec e_2'\end{bmatrix}
=\begin{bmatrix}
\cos\theta&-\sin\theta\\
\sin\theta&\cos\theta
\end{bmatrix}.
$$

矩阵乘法会用输入坐标 $x,y$ 对这两列做线性组合：

$$
R(\theta)
\begin{bmatrix}x\\y\end{bmatrix}
=x\vec e_1'+y\vec e_2'
=\begin{bmatrix}
x\cos\theta-y\sin\theta\\
x\sin\theta+y\cos\theta
\end{bmatrix}.
$$

> **记忆方法：**旋转矩阵的第 1 列回答“原来的 $x$ 轴转到哪里”，第 2 列回答“原来的 $y$ 轴转到哪里”。

### 1.5 具体例子：把 $(1,0)$ 逆时针旋转 $90^\circ$

因为 $\cos90^\circ=0$、$\sin90^\circ=1$：

$$
R(90^\circ)=
\begin{bmatrix}0&-1\\1&0\end{bmatrix}.
$$

于是：

$$
\begin{bmatrix}x'\\y'\end{bmatrix}
=\begin{bmatrix}0&-1\\1&0\end{bmatrix}
\begin{bmatrix}1\\0\end{bmatrix}
=\begin{bmatrix}0\\1\end{bmatrix}.
$$

原本在 $x$ 轴正方向的点 $(1,0)$，准确到达 $y$ 轴正方向的点 $(0,1)$。

```python
import math
import torch

theta = math.pi / 2  # 90°，三角函数在代码中通常使用弧度
R = torch.tensor([
    [math.cos(theta), -math.sin(theta)],
    [math.sin(theta),  math.cos(theta)],
])

v = torch.tensor([1.0, 0.0])
v_rotated = R @ v
print(v_rotated.round())  # tensor([0., 1.])
```

### 1.6 RoPE：把 token 位置变成特征空间中的旋转角度

RoPE 不旋转屏幕上的点；它把 query 和 key 的特征维度两两配对。对第 $i$ 个二维特征对：

$$
\begin{bmatrix}u_{2i}'\\u_{2i+1}'\end{bmatrix}
=R(m\omega_i)
\begin{bmatrix}u_{2i}\\u_{2i+1}\end{bmatrix},
$$

其中：

- $m$ 是 token 的位置。
- $\omega_i$ 是第 $i$ 个特征对使用的旋转频率。
- $m\omega_i$ 是该位置在这个二维子空间中的旋转角度。
- 不同特征对使用不同频率，所以模型同时获得短距离和长距离的位置变化。

关键的相对位置性质来自旋转矩阵：

$$
R(\alpha)^T R(\beta)=R(\beta-\alpha).
$$

因此位置 $m$ 的 query 与位置 $n$ 的 key 做内积时：

$$
\left(R(m\omega_i)q_i\right)^T
\left(R(n\omega_i)k_i\right)
=q_i^T R((n-m)\omega_i)k_i.
$$

虽然每个 token 按自己的**绝对位置**旋转，但注意力内积最终自然出现位置差 $n-m$。这就是 RoPE 能把**相对位置信息**放进 attention score 的几何原因。

### 面试记忆点

- 单位圆：$\theta\mapsto(\cos\theta,\sin\theta)$。
- 旋转矩阵的两列，是旋转后的两个基向量。
- 矩阵乘法就是用 $x,y$ 重新组合这两个新基向量。
- RoPE 对每一对特征重复二维旋转，角度为“位置 × 频率”。
- $R(m)^TR(n)=R(n-m)$ 使 query–key 内积依赖相对位置差。

## 2. 导数、概率与 Gradient 推导

> 主要整理自 [Topic 6 Notes — RLVR, GRPO & RL Environments](https://app.notion.com/p/38014e31dd1381a7bb22c4979a7b6287) 的 **Math basic** 段落。目标不是背微积分，而是看懂 LLM 训练公式中每一步为何成立。

### 2.1 三个必须记住的导数

[[BASIC_MATH_DERIVATIVE_MAP]]

| 函数 | 导数 | 直觉 |
|---|---|---|
| $f(x)=x$ | $f'(x)=1$ | 自变量增加一点，函数同样增加一点。 |
| $f(x)=\log x$ | $f'(x)=1/x$ | 小概率区域的变化会被放大。 |
| $f(x)=e^x$ | $f'(x)=e^x$ | 指数函数的增长率等于自身。 |

链式法则把多个函数连接起来。若 $L=f(g(x))$：

$$
\frac{\partial L}{\partial x}
=\frac{\partial L}{\partial g}
\frac{\partial g}{\partial x}.
$$

神经网络只是把它重复很多次；backprop 是从 loss 开始，按相反方向高效计算这些局部导数的乘积。

### 2.2 Log-derivative trick：为什么 policy gradient 会出现 $\nabla\log\pi$

从 $\log p_\theta(y)$ 求导：

$$
\nabla_\theta\log p_\theta(y)
=\frac{\nabla_\theta p_\theta(y)}{p_\theta(y)}.
$$

两边乘 $p_\theta(y)$：

$$
\boxed{\nabla_\theta p_\theta(y)
=p_\theta(y)\nabla_\theta\log p_\theta(y)}.
$$

这一步非常重要：reward 或离散 sampling 本身不需要可导；我们只需要对**模型给已采样序列的 log probability**求导。

例如期望奖励：

$$
J(\theta)=\sum_y p_\theta(y)r(y).
$$

代入上面的恒等式：

$$
\nabla_\theta J
=\sum_y p_\theta(y)r(y)\nabla_\theta\log p_\theta(y)
=\mathbb E_{y\sim p_\theta}
\left[r(y)\nabla_\theta\log p_\theta(y)\right].
$$

> **记忆：**原来要求 $\nabla p$；log trick 把它变成可由模型直接计算的 $\nabla\log p$。

### 2.3 为什么 log-sum-exp 的 gradient 就是 softmax

定义：

$$
\operatorname{LSE}(z)=\log\sum_k e^{z_k}.
$$

对第 $j$ 个 logit 求导，依次使用 $\log$、求和与 $e^x$ 的导数：

$$
\frac{\partial\operatorname{LSE}(z)}{\partial z_j}
=\frac{1}{\sum_k e^{z_k}}\cdot e^{z_j}
=\frac{e^{z_j}}{\sum_k e^{z_k}}
=\operatorname{softmax}(z)_j.
$$

所以 softmax 不是凭空出现的；它就是 `logsumexp` 对每个 logit 的梯度。

### 2.4 自回归序列概率：乘法变成 log 加法

LLM 一次预测一个 token。对于 $y=(y_1,\ldots,y_T)$：

$$
p_\theta(y\mid x)
=\prod_{t=1}^{T}p_\theta(y_t\mid x,y_{<t}).
$$

取 log 后：

$$
\log p_\theta(y\mid x)
=\sum_{t=1}^{T}\log p_\theta(y_t\mid x,y_{<t}).
$$

具体例子：

| token | 条件概率 |
|---|---:|
| $A\mid x$ | $0.50$ |
| $B\mid x,A$ | $0.40$ |
| $C\mid x,A,B$ | $0.80$ |

$$
p(ABC\mid x)=0.50\times0.40\times0.80=0.16,
$$

$$
\log p(ABC\mid x)=\log0.50+\log0.40+\log0.80\approx-1.833.
$$

- 概率相乘容易变成极小数。
- log probability 相加更稳定，也能把每个 token 的贡献拆开。
- SFT、PPO、GRPO 中看到的 sequence log-prob，本质都是 token log-prob 的和。

### 2.5 Monte Carlo estimation：采样平均近似期望

理论期望需要遍历所有可能输出：

$$
\mathbb E_{y\sim p_\theta}[f(y)]
=\sum_y p_\theta(y)f(y).
$$

但语言序列的组合空间太大，无法穷举。Monte Carlo 的做法是从模型随机采样 $N$ 个序列：

$$
y^{(1)},\ldots,y^{(N)}\sim p_\theta,
$$

再用样本均值近似期望：

$$
\boxed{
\mathbb E[f(y)]
\approx\frac{1}{N}\sum_{i=1}^{N}f\left(y^{(i)}\right)
}.
$$

例如采样 5 个回答，verifier rewards 是 $[1,0,1,1,0]$：

$$
\widehat{\mathbb E[r]}=\frac{1+0+1+1+0}{5}=0.60.
$$

- 样本越多，估计通常越稳定，但 rollout 成本越高。
- 样本均值 $\bar r$ 常作为 baseline。
- 方差 $\frac{1}{N}\sum_i(r_i-\bar r)^2$ 衡量样本波动；标准差是方差的平方根。

### 2.6 训练目标：我们到底在求什么

训练希望知道：**稍微改变每个模型参数 $\theta$，loss 会如何变化？**

$$
\theta
\rightarrow h
\rightarrow z
\rightarrow p
\rightarrow L,
$$

其中：

- $h$：Transformer 最后一层 hidden state。
- $z=Wh$：LM head 输出的 logits；$z_j$ 是 vocabulary 中第 $j$ 个 token 的未归一化分数。
- $p=\operatorname{softmax}(z)$：每个 token 的预测概率。
- $L=-\log p_b$：ground-truth token 为 $b$ 时的 cross-entropy loss。

Backprop 从右向左使用 chain rule：

$$
\frac{\partial L}{\partial\theta}
=\frac{\partial L}{\partial z}
\frac{\partial z}{\partial h}
\frac{\partial h}{\partial\theta}.
$$

Gradient descent 再沿着梯度的反方向更新：

$$
\boxed{\theta\leftarrow\theta-\alpha\nabla_\theta L}.
$$

### 2.7 推导 softmax + cross-entropy gradient

[[BASIC_MATH_GRADIENT_FLOW]]

正确 token 是 $b$。先把 loss 展开：

$$
L=-\log p_b
=-\log\frac{e^{z_b}}{\sum_k e^{z_k}}
=-z_b+\log\sum_k e^{z_k}.
$$

现在对任意 logit $z_j$ 求导：

$$
\frac{\partial L}{\partial z_j}
=-\frac{\partial z_b}{\partial z_j}
+\frac{\partial}{\partial z_j}\log\sum_k e^{z_k}.
$$

第一项只有 $j=b$ 时为 $-1$；第二项就是 softmax：

$$
\boxed{
\frac{\partial L}{\partial z_j}
=p_j-\mathbf 1[j=b]
}.
$$

也就是：

$$
\frac{\partial L}{\partial z}=p-\operatorname{onehot}(b).
$$

若 $z=[2,1,0]$、正确 token 是中间的 $B$：

$$
p=[0.665,0.245,0.090],
$$

$$
\frac{\partial L}{\partial z}
=[0.665,\;0.245-1,\;0.090]
=[0.665,-0.755,0.090].
$$

- 正确 token $B$ 的梯度为负；执行 $z\leftarrow z-\alpha\nabla_zL$ 后，$z_B$ 会增大。
- 错误 token 的梯度为正；更新后它们的 logits 会减小。
- Softmax 会让所有概率竞争，因此提高正确类别也会相对压低其他类别。

```python
import torch
import torch.nn.functional as F

# 三个 vocabulary tokens 的 logits；正确 token 是索引 1（B）
z = torch.tensor([2.0, 1.0, 0.0], requires_grad=True)
target = torch.tensor([1])

loss = F.cross_entropy(z.unsqueeze(0), target)
loss.backward()

print(F.softmax(z, dim=-1))
# tensor([0.6652, 0.2447, 0.0900])

print(loss)
# tensor(1.4076)

print(z.grad)
# tensor([ 0.6652, -0.7553,  0.0900])
# exactly: probability - one_hot(target)
```

### 2.8 与 SFT / policy gradient 的连接

SFT 的单个序列目标可以写成：

$$
L_{\text{SFT}}=-\log\pi_\theta(y\mid x).
$$

Policy-gradient surrogate 很像带符号、带权重的 SFT：

$$
L_{\text{RL}}=-A\log\pi_\theta(y\mid x).
$$

| Advantage $A$ | 更新方向 |
|---:|---|
| $A>0$ | 提高刚才 sampled response 的概率。 |
| $A<0$ | 降低刚才 sampled response 的概率。 |
| $A=0$ | 这条 response 不提供 policy-gradient signal。 |

### 本节面试记忆点

- 三个导数：$x\to1$、$\log x\to1/x$、$e^x\to e^x$。
- `logsumexp` 的 gradient 是 softmax。
- Sequence probability 是 token probabilities 相乘；sequence log-probability 是 token log-probabilities 相加。
- Monte Carlo 用随机样本均值近似无法穷举的期望。
- Softmax + CE 的核心结果：$\nabla_zL=p-\operatorname{onehot}(b)$。
- Backprop 用 chain rule 把 logits gradient 一层层传回参数 $\theta$。
- Log-derivative trick 让不可导的 reward / sampling 问题转成对 $\log\pi_\theta$ 求导。
