<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>AI on 安橙的博客</title><link>https://blog.ans20xx.com/tags/ai/</link><description>Recent content in AI on 安橙的博客</description><generator>Hugo -- 0.161.1</generator><language>zh</language><lastBuildDate>Fri, 15 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.ans20xx.com/tags/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Day 02 · Linux / 容器基础回顾</title><link>https://blog.ans20xx.com/posts/ai/day02/</link><pubDate>Fri, 15 May 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/day02/</guid><description>深入 Linux 隔离原语 cgroups 与 namespaces，掌握 Docker GPU 容器的启动链路，动手编写 CUDA Dockerfile 并运行第一个 GPU 容器。</description></item><item><title>Day 03 · GPU 硬件与体系结构</title><link>https://blog.ans20xx.com/posts/ai/day03/</link><pubDate>Fri, 15 May 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/day03/</guid><description>拆解 GPU 微架构：从 SM、Warp 调度到 Tensor Core，理解 HBM-L2-SMEM 存储层级与算术强度，对比 A100/H100/H20 代际演进。</description></item><item><title>Day 01 · AI Infra 全景与学习环境</title><link>https://blog.ans20xx.com/posts/ai/day01/</link><pubDate>Thu, 14 May 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/day01/</guid><description>AI Infra 60 天学习计划的起点：梳理从用户 prompt 到 GPU kernel 的完整链路，搭建开发环境，理解推理与训练基础设施的全景图。</description></item><item><title>AI 数学基础</title><link>https://blog.ans20xx.com/posts/ai/ai-%E6%B6%89%E5%8F%8A%E7%9A%84%E6%95%B0%E5%AD%A6%E7%9F%A5%E8%AF%86/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/ai-%E6%B6%89%E5%8F%8A%E7%9A%84%E6%95%B0%E5%AD%A6%E7%9F%A5%E8%AF%86/</guid><description>&lt;h1 id="线性代数"&gt;线性代数&lt;/h1&gt;
&lt;h2 id="向量与向量空间"&gt;向量与向量空间&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-51326487"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-51326487" style="display:none;"&gt;
- 向量与向量空间
- 什么是向量
- 向量是一个有方向的量
- 几何视角：空间中从原点出发的一支箭头，方向和长度都有意义
- 代数视角：一组有序的数字
- 示例
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505104026041.png,96,87)
- 这是一个三维向量，每个数字对应一个坐标轴上的分量。
- 词嵌入
- 一个词（token）会被映射成一个几百甚至几千维的向量
- 比如 &amp;#34;猫&amp;#34; 这个词可能被表示成一个 768 维的向量——你可以把它想象成 768 个坐标轴上的一个点
- 语义相近的词在这个空间里位置接近
- 向量的基本运算
- 向量加法
- 两个向量相加，对应分量分别相加
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505104141640.png,287,77)
- 几何意义: 把 $\vec{b}$ 的起点接到 $\vec{a}$ 的终点，结果是合向量。
- 在 LLM 里的例子：有研究发现，词向量之间存在近似的语义关系
- vec(&amp;#34;国王&amp;#34;)−vec(&amp;#34;男人&amp;#34;)&amp;#43;vec(&amp;#34;女人&amp;#34;)≈vec(&amp;#34;女王&amp;#34;)
- 标量乘法
- 用一个数（标量）乘以向量，每个分量都乘以这个数
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505111258217.png,172,77)
- 几何意义：把向量拉伸或压缩
- 点积
- 定义
- 两个同维度向量的点积
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505114508393.png,360,73)
- 示例
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505114528207.png,483,99)
- 几何意义
- 点积有另一种等价写法
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505114553768.png,165,50)
- 其中 $\theta$ 是两向量之间的夹角
- 关键洞察
- 点积可以衡量两个向量&amp;#34;有多相似&amp;#34;。
- 这正是 Attention 机制里 Query 和 Key 做点积的本质——算两个向量的相关程度
- 向量范数(Norm)
- 范数衡量向量的&amp;#34;长度&amp;#34;或&amp;#34;大小&amp;#34;
- L2 范数（最常用）
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505115921185.png,251,61)
- 就是我们熟悉的欧几里得距离
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505115946653.png,276,63)
- L1 范数
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505120034974.png,255,43)
- 各分量绝对值之和，在正则化（防止过拟合）中常用。
- 余弦相似度
- 把点积和范数组合起来，就得到余弦相似度——LLM 里衡量语义相似性的核心工具
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505120438471.png,383,76)
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/05/20260505120456734.png,389,164)
- 余弦相似度只关心方向，不关心长度
- 两个词的向量可能长度不同，但如果方向相同，说明它们在语义上是一致的
- 向量空间
- 满足以下条件的集合叫向量空间
- 元素（向量）之间可以相加，可以被标量乘
- 在这个集合里做加法和乘法，结果还在这个集合里
- 最关键的概念是维度（Dimension）：向量空间需要多少个基向量来描述其中所有的点
- GPT-2 用 768 维的向量空间来表示词义，GPT-3 用 12288 维。维度越高，理论上能编码的信息越丰富
- Numpy 代码
-
```python
import numpy as np
# ─── 1. 创建向量 ───────────────────────────────────────
a = np.array([1, 2, 3], dtype=float)
b = np.array([4, -1, 2], dtype=float)
print(&amp;#34;向量 a:&amp;#34;, a)
print(&amp;#34;向量 b:&amp;#34;, b)
# ─── 2. 向量加法与标量乘法 ─────────────────────────────
print(&amp;#34;\n向量加法 a &amp;#43; b:&amp;#34;, a &amp;#43; b)
print(&amp;#34;标量乘法 2 * a:&amp;#34;, 2 * a)
# ─── 3. 点积 ──────────────────────────────────────────
dot_product = np.dot(a, b)
print(&amp;#34;\n点积 a · b:&amp;#34;, dot_product)
# 手动验证
manual_dot = sum(a[i] * b[i] for i in range(len(a)))
print(&amp;#34;手动计算点积:&amp;#34;, manual_dot)
# ─── 4. L2 范数 ────────────────────────────────────────
norm_a = np.linalg.norm(a)
norm_b = np.linalg.norm(b)
print(&amp;#34;\n‖a‖₂ =&amp;#34;, norm_a)
print(&amp;#34;‖b‖₂ =&amp;#34;, norm_b)
# ─── 5. 余弦相似度 ─────────────────────────────────────
cos_sim = dot_product / (norm_a * norm_b)
print(&amp;#34;\n余弦相似度(a, b):&amp;#34;, cos_sim)
# ─── 6. 模拟词嵌入：哪个词和&amp;#34;猫&amp;#34;最相似？ ──────────────
# 用随机向量模拟（实际中是模型学习出来的）
np.random.seed(42)
embedding_dim = 8 # 简化为 8 维演示
word_vectors = {
&amp;#34;猫&amp;#34;: np.random.randn(embedding_dim),
&amp;#34;狗&amp;#34;: np.random.randn(embedding_dim),
&amp;#34;汽车&amp;#34;: np.random.randn(embedding_dim),
&amp;#34;小猫&amp;#34;: np.random.randn(embedding_dim),
}
# 手动让&amp;#34;猫&amp;#34;和&amp;#34;小猫&amp;#34;更相似
word_vectors[&amp;#34;小猫&amp;#34;] = word_vectors[&amp;#34;猫&amp;#34;] &amp;#43; np.random.randn(embedding_dim) * 0.3
def cosine_similarity(v1, v2):
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
query = word_vectors[&amp;#34;猫&amp;#34;]
print(&amp;#34;\n与&amp;#34;猫&amp;#34;的余弦相似度：&amp;#34;)
for word, vec in word_vectors.items():
if word != &amp;#34;猫&amp;#34;:
sim = cosine_similarity(query, vec)
print(f&amp;#34; {word}: {sim:.4f}&amp;#34;)
```
&lt;/textarea&gt;
&lt;h2 id="矩阵基本运算"&gt;矩阵基本运算&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-18523476"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-18523476" style="display:none;"&gt;
- 矩阵基本运算
- 矩阵是什么
- 是数字排列成的二维表格，用行数 x 列数描述它的形状（称为&amp;#34;维度&amp;#34;或&amp;#34;shape&amp;#34;）
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507220522540.png,142,68)
- 这是一个 2×3 矩阵（2 行 3 列）。用 $A_{ij}$​ 表示第 i 行第 j 列的元素，比如 $A_{12} = 2$
- 矩阵的本质是线性变换。
- 描述的是&amp;#34;把一个向量变成另一个向量&amp;#34;的规则。
- 矩阵与向量的乘法
- 计算规则
- 矩阵 $A(m \times n)$ 乘以向量 $\vec{x}$（n 维），结果是一个 m 维向量
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507221328789.png,353,92)
- 结果的每一行，就是矩阵那一行与向量做点积。
- 具体例子
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507221813500.png,388,92)
- 一个 3×2 的矩阵，把一个 2 维向量变成了 3 维向量。
- 维度变了——这正是&amp;#34;变换&amp;#34;的含义。
- 几何直觉
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507221947557.png,126,66)
- 该矩阵可以把任意 2D 向量逆时针旋转 90 度
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507222314744.png,114,66)
- 原来朝右的向量，变成了朝上的向量。矩阵就是这样编码变换规则的。
- 矩阵 A 乘以向量 $\vec{x}$ 等于把 $\vec{x}$ 所在的空间拉伸、旋转、投影到另一个空间。
- LLM 中的应用
- Transformer 里，每个 token 的向量 $\vec{x}$ 乘以权重矩阵 $W_Q$​，得到 Query 向量
- $\vec{q} = W_Q\vec{x}$
- 这就是一次线性变换——把输入向量投影到&amp;#34;Query 空间&amp;#34;
- 矩阵乘法
- 计算规则
- 两个矩阵相乘：$A(m\times k) \times B (k\times n) = C(m\times n)$
- 关键约束
- A 的列数必须等于 B 的行数（都是 k）。
- 结果矩阵 C 的第 i 行第 j 列
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507224234717.png,165,72)
- 即 A 的第 i 行与 B 的第 j 列做点积。
- 具体例子
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/07/20260507224403814.png,121,212)
- 矩阵乘法的本质：变换的复合
- 单独看计算规则很枯燥。真正重要的是它的意义
- 矩阵 AB 表示&amp;#34;先做变换 B，再做变换 A&amp;#34;。
- 就像函数复合 $f(g(x))$，矩阵乘法是在组合两个线性变换。
- 神经网络的多层结构，本质上就是多个矩阵变换串联在一起，每一层都对数据做一次变换。
- 矩阵乘法的重要性质
- 不满足交换律
- $AB \neq BA$（大多数情况下）
- 先旋转再缩放，和先缩放再旋转，结果不同——顺序很重要。
- 满足结合律
- $(AB)C=A(BC)$
- 这让我们可以灵活选择计算顺序（影响效率，不影响结果）
- 转置
- 把矩阵的行和列互换，记作 $A^T$
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509003910492.png,283,81)
- $A_{ij}^T=A_{ji}$
- 转置的重要性质
- $(AB)^T=B^TA^T$
- $(\vec{a}^T\vec{b}) = \vec{a}\cdot \vec{b}$
- 转置把向量点积统一进了矩阵符号
- LLM 的直接应用
- Attention 公式里的 $QK^T$ 就是对 K 做转置后再和 Q 相乘，目的是让每个 Query 向量和每个 Key 向量都算一次点积，得到注意力分数矩阵。
- 逆矩阵
- 对于方阵(行数=列数) A，如果存在矩阵 $A^{-1}$ 使得 $AA^{-1}=A{-1}A=I$
- 其中 I 是单位矩阵，对角线全是 1，其余是 0，那么 $A^{-1}$ 叫做 A 的逆矩阵
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509004417750.png,115,77)
- 单位矩阵就像数字里的 1，乘以任何矩阵都不改变它：$AI=IA=A$
- 几何直觉：A 把空间做了某种变换，$A^{-1}$ 就是吧这个变换撤销，还原回去
- 注意：不是所有方阵都有逆矩阵。如果矩阵把空间&amp;#34;压扁&amp;#34;了（比如把三维压成二维），就无法恢复，这样的矩阵不可逆
- 在 LLM 里，矩阵是怎么用的
- Transformer 输入是一个序列，比如 4 个 token，每个 token 用 8 维向量表示，整体表示成矩阵 X，形状（4x8）
- 要生成 Query、Key、Value，分别乘以三个权重矩阵
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509004625263.png,279,31)
- 这三个矩阵乘法，就是在把输入向量投影到三个不同的子空间，分别用于&amp;#34;我在找什么&amp;#34;（Q）、&amp;#34;我有什么&amp;#34;（K）、&amp;#34;我的内容是什么&amp;#34;（V）。
- 注意力分数：$score=QK^T$
- Q 是 $4\times d_k$，$K^T$ 是 $d_k\times 4$，结果是 $4\times 4$ 的矩阵
- 结果是每个 token 和其他每个 token 的相关程度
- 整条公式 $QK^T$ 的每一个元素，就是一对 Query 和 Key 向量的点积
- Numpy 实战
-
```python
import numpy as np
# ─── 1. 矩阵与向量的乘法 ──────────────────────────────
A = np.array([[1, 2],
[3, 4],
[5, 6]]) # 3×2 矩阵
x = np.array([1, -1]) # 2 维向量
result = A @ x # @ 是矩阵乘法运算符
print(&amp;#34;A @ x =&amp;#34;, result) # 应得 [-1, -1, -1]
# ─── 2. 矩阵乘法 ──────────────────────────────────────
B = np.array([[1, 2],
[3, 4]])
C = np.array([[5, 6],
[7, 8]])
print(&amp;#34;\nB @ C =\n&amp;#34;, B @ C)
print(&amp;#34;C @ B =\n&amp;#34;, C @ B)
print(&amp;#34;交换律不成立:&amp;#34;, np.allclose(B @ C, C @ B)) # False
# ─── 3. 转置 ──────────────────────────────────────────
M = np.array([[1, 2, 3],
[4, 5, 6]])
print(&amp;#34;\n原矩阵 shape:&amp;#34;, M.shape) # (2, 3)
print(&amp;#34;转置后 shape:&amp;#34;, M.T.shape) # (3, 2)
print(&amp;#34;转置:\n&amp;#34;, M.T)
# ─── 4. 模拟 Attention 里的 QK^T ──────────────────────
np.random.seed(0)
seq_len = 4 # 4 个 token
d_model = 8 # 每个 token 8 维
d_k = 4 # Query/Key 的维度
# 输入序列矩阵：4 个 token，每个 8 维
X = np.random.randn(seq_len, d_model)
# 权重矩阵（实际中是训练得到的）
W_Q = np.random.randn(d_model, d_k)
W_K = np.random.randn(d_model, d_k)
# 计算 Q 和 K
Q = X @ W_Q # shape: (4, 4)
K = X @ W_K # shape: (4, 4)
# 计算注意力分数矩阵
scores = Q @ K.T # shape: (4, 4)
print(&amp;#34;\nQ shape:&amp;#34;, Q.shape)
print(&amp;#34;K^T shape:&amp;#34;, K.T.shape)
print(&amp;#34;注意力分数矩阵 shape:&amp;#34;, scores.shape)
print(&amp;#34;注意力分数矩阵:\n&amp;#34;, scores.round(2))
# 每个元素 scores[i][j] 就是第 i 个 token 对第 j 个 token 的注意力分数
print(&amp;#34;\ntoken 0 对所有 token 的注意力分数:&amp;#34;, scores[0].round(2))
```
&lt;/textarea&gt;
&lt;h2 id="线性变换的几何直觉"&gt;线性变换的几何直觉&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-24817356"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-24817356" style="display:none;"&gt;
- 线性变换的几何直觉
- 核心洞察：矩阵的列=基向量的去向
- 什么是基向量
- 二维平面最自然的一组基向量
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509005936990.png,141,61)
- 任何 2D 向量都可以写成基向量的组合
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509005955004.png,108,54)
- 矩阵的读法
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509010125456.png,111,61)
- $\hat{i}$ 经过 A 变换后，落在 $\begin{bmatrix} 2 \\ 1 \end{bmatrix}$
- $\hat{j}$ 经过 A 变换后，落在 $\begin{bmatrix} -1 \\ 3 \end{bmatrix}$
- 线性变换有一个神奇的性质：它保留了向量加法和数乘。
- 只要你知道基向量被变到哪里，整个空间所有向量的去向就都确定了
- 这就是矩阵能用一组数字描述整个变换的原因
- 矩阵×向量，本质是用向量的分量作为系数，对矩阵的列做线性组合
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509010714977.png,244,59)
- 几种常见的线性变换
- 缩放
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509152812843.png,61,60)
- $\hat{i}$ 拉到 [2,0], $\hat{j}$ 拉到 [0,2]，整个空间被均匀放大 2 倍
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509152901112.png,57,59)
- 不均匀缩放，横向拉伸 3 倍，纵向不变。
- 旋转
- 逆时针旋转角度 $\theta$
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509153055957.png,164,55)
- 错切 (Shear)
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509153129655.png,59,55)
- $\hat{i}$ 不动，$\hat{j}$ 从 [0,1] 移动到 [1,1]。整个空间像被协推的扑克牌
- 投影 (Projection)
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509153234697.png,58,60)
- $\hat{i}$ 不动，$\hat{j}$ 压扁到原点，整个 2D 平面被投影到 $x$ 轴，降了一维
- 这个变换是不可逆的，一旦把平面压扁成一条线，无法恢复
- 反射 (Reflection)
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509153344443.png,74,57)
- $\hat{i}$ 翻到 [-1,0]，整个空间沿 y 轴镜像翻转
- 行列式：变换的缩放因子
- 行列式 $det(A)$ 是一个数
- 这个变换把单位面积或体积放大缩小了多少倍
- 几何意义
- $\hat{i}$ 和 $\hat{j}$ 围成的单位正方形，面积是 1
- 变换后，这两个向量会围成一个平行四边形，这个平行四边形的面积就是 $|det(A)|$
- 二阶行列式公式
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509153655269.png,164,60)
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509153803344.png,408,167)
- det(A) = 0 -&amp;gt; 矩阵不可逆 -&amp;gt; 变换降低了维度
- 秩 (Rank)：变换后的输出维度
- 秩 (rank(A)) 是另外一个数
- 回答：变换后，所有向量落到的空间有几维
- 直观理解
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509154254876.png,93,55)
- [2,4] = 2x[1,2]，两列共线，无论 $\hat{i}$ 和 $\hat{j}$ 落到哪里，它们都在一条直线上
- 整个 2d 平面被压成了一条 1D 直线，rank(A) = 1
- 如果两列线性无关（不共线），秩为 2，变换后仍然是 2D 平面，满秩
- 满秩 vs 不满秩
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509155152785.png,531,126)
- 秩的另一种表述
- rank(A) = A 的列向量中线性无关的最大个数
- 也等于行向量中线性无关的最大个数，行秩=列秩
- 线性相关与无关
- 一组向量是线性相关的，意味着其中某个向量可以由其他向量的线性组合得到
- n 个线性无关的向量，才能&amp;#34;撑起&amp;#34;一个 n 维空间
- 如果你有 100 个向量，但它们都共线（线性相关），实际上只描述了一条 1D 直线
- 连接到 LLM
- 为什么 LLM 用高维向量
- GPT-3 用 12288 维的词向量
- 维度越高，能容纳的&amp;#34;线性无关方向&amp;#34;越多，理论上能编码越丰富的语义特征
- 情感、词性、领域、时态、语气……每个特征可以是一个独立的方向。
- 低秩的危险
- 如果训练出的某个权重矩阵秩很低，意味着它实际上只在少数几个方向上有效，浪费了表达能力
- 这是&amp;#34;模型坍缩&amp;#34;的一种数学表现
- LoRA 的精妙之处
- LoRA（Low-Rank Adaptation）微调的核心思想：微调时新增的参数变化矩阵 $\delta W$ 通常是低秩的
- 如果 $\delta W$ 是 1024x1024 的矩阵，参数量是约 100 万。但如果它的秩只有 8，可以分解成：$\delta W = A\cdot B$
- 其中 A 是 1024 x 8，B 是 8 x 1024，参数量降到约 1.6 万
- Attention 的几何意义
- $Q=XW_Q$，这是在用矩阵 $W_Q$ 把输入向量变换到 Query 空间
- $W_Q$ 的秩决定了 Query 空间的自由度—能从输入里提取多少个独立的&amp;#34;问题&amp;#34;。
- 可视化代码
-
```python
import numpy as np
import matplotlib.pyplot as plt
def plot_transformation(matrix, title):
&amp;#34;&amp;#34;&amp;#34;可视化一个 2x2 矩阵的变换效果&amp;#34;&amp;#34;&amp;#34;
# 原始基向量
i_hat = np.array([1, 0])
j_hat = np.array([0, 1])
# 变换后
i_new = matrix @ i_hat
j_new = matrix @ j_hat
# 画一个网格点
x = np.linspace(-2, 2, 9)
y = np.linspace(-2, 2, 9)
X, Y = np.meshgrid(x, y)
points = np.stack([X.ravel(), Y.ravel()])
transformed = matrix @ points
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
# 原空间
axes[0].scatter(points[0], points[1], c=&amp;#39;lightblue&amp;#39;, s=10)
axes[0].arrow(0, 0, *i_hat, head_width=0.1, color=&amp;#39;red&amp;#39;, label=&amp;#39;i_hat&amp;#39;)
axes[0].arrow(0, 0, *j_hat, head_width=0.1, color=&amp;#39;green&amp;#39;, label=&amp;#39;j_hat&amp;#39;)
axes[0].set_title(&amp;#34;变换前&amp;#34;)
axes[0].set_xlim(-3, 3); axes[0].set_ylim(-3, 3)
axes[0].grid(True); axes[0].axhline(0); axes[0].axvline(0)
axes[0].set_aspect(&amp;#39;equal&amp;#39;)
# 变换后空间
axes[1].scatter(transformed[0], transformed[1], c=&amp;#39;lightcoral&amp;#39;, s=10)
axes[1].arrow(0, 0, *i_new, head_width=0.1, color=&amp;#39;red&amp;#39;)
axes[1].arrow(0, 0, *j_new, head_width=0.1, color=&amp;#39;green&amp;#39;)
axes[1].set_title(f&amp;#34;变换后\ndet={np.linalg.det(matrix):.2f}, &amp;#34;
f&amp;#34;rank={np.linalg.matrix_rank(matrix)}&amp;#34;)
axes[1].set_xlim(-5, 5); axes[1].set_ylim(-5, 5)
axes[1].grid(True); axes[1].axhline(0); axes[1].axvline(0)
axes[1].set_aspect(&amp;#39;equal&amp;#39;)
plt.suptitle(title); plt.tight_layout(); plt.show()
# ─── 试试不同的变换 ───────────────────────────────
# 1. 缩放
plot_transformation(np.array([[2, 0], [0, 1.5]]), &amp;#34;缩放：x 方向 2 倍，y 方向 1.5 倍&amp;#34;)
# 2. 旋转 45 度
theta = np.pi / 4
plot_transformation(
np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]]),
&amp;#34;旋转 45 度&amp;#34;
)
# 3. 错切
plot_transformation(np.array([[1, 1], [0, 1]]), &amp;#34;错切&amp;#34;)
# 4. 投影到 x 轴（注意 det=0, rank=1）
plot_transformation(np.array([[1, 0], [0, 0]]), &amp;#34;投影到 x 轴（降维！）&amp;#34;)
# 5. 反射
plot_transformation(np.array([[-1, 0], [0, 1]]), &amp;#34;沿 y 轴反射&amp;#34;)
```
&lt;/textarea&gt;
&lt;h2 id="特征值与特征向量"&gt;特征值与特征向量&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-43876251"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-43876251" style="display:none;"&gt;
- 特征值与特征向量
- 变换中不变的方向
- 一个矩阵作用于空间，所有向量都被旋转、拉伸、扭曲。绝大多数向量变换后，方向都改变了
- 但有些特殊的向量——它们经过变换后，方向不变，只是被拉长或缩短
- 这种&amp;#34;在变换中保持方向&amp;#34;的向量，就叫做特征向量（eigenvector）。它被拉伸的倍数，叫做特征值（eigenvalue）
- 形式化定义
- 特征值方程
- $A\vec{v}=\lambda\vec{v}$
- 矩阵 A 作用在向量 $\vec{v}$ 上，结果等于把 $\vec{v}$ 缩放 $\lamda$ 倍
- $\lamda$ 是特征值（一个标量，可以是正、负、零，甚至复数）
- 几何含义
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509211904890.png,438,253)
- 关键洞察：特征向量给出的是矩阵变换的&amp;#34;主轴&amp;#34;。沿着这些主轴，复杂的矩阵变换简化成了简单的&amp;#34;拉伸&amp;#34;
- 怎么求特征值
- 推导
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509212329174.png,460,246)
- 行列式为 0 意味着矩阵把空间压扁了，存在一些非零向量被压成了零向量——那些被压扁的方向就是特征方向
- 实际计算
- 求特征值
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509213017060.png,589,239)
- 求特征向量
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509213047640.png,502,350)
- 特征分解
- 如果 $n\times n$ 矩阵 A 有 n 个线性无关的特征向量，可以写成 $A=PDP^{-1}$
- 公式解析
- $P$ 是把特征向量按列排起来的矩阵
- $D$ 是对角矩阵，对角线上是对应的特征值
- $P^{-1}$ 是 $P$ 的逆矩阵
- 几何含义
- 任何复杂的线性变换 A，都可以分解成三步简单操作：
- $P^{-1}$: 把空间转一下，让特征方向对齐到坐标轴
- $D$: 沿坐标轴各方向独立缩放（因为 D 是对角矩阵）
- $P$: 把空间转回来
- 整个复杂变换，本质上就是沿着特征方向的简单缩放
- 矩阵的 n 次幂
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/09/20260509213619982.png,250,40)
- 计算量从 100 次矩阵乘法降到 n 次标量幂运算
- 这是 PageRank、马尔可夫链稳态分析的核心计算技巧
- PCA：特征值的经典应用
- PCA（主成分分析，Principal Component Analysis）是降维最常用的算法。它的数学本质就是特征分解
- 问题背景
- 假设你有 1000 个数据点，每个是 768 维向量
- 可视化、分析都很困难
- 能不能找到 2 个最重要的&amp;#34;方向&amp;#34;，把数据投影到这两个方向上，保留尽可能多的信息
- PCA 的答案：找数据协方差矩阵的特征向量，按特征值大小排序，取前 k 个
- 为什么有效
- 协方差矩阵 C 描述了数据在各维度的&amp;#34;散布情况&amp;#34;
- 它的特征向量给出了数据散布最大的方向——这些就是&amp;#34;主成分&amp;#34;
- 特征值越大，说明数据沿那个方向变化越剧烈，包含的信息越多
- 如果你的 1000 个数据点几乎都集中在一条直线附近
- 那条直线就是第一主成分（最大特征值对应的特征向量）
- 用它一个维度就能描述大部分信息
- PCA 的步骤
- 把数据矩阵 X 中心化：每一列减去该列均值
- 计算协方差矩阵：$C=\frac 1{n-1}X^TX$
- 对 C 做特征分解：$C=PDP^{-1}$
- 选 D 中最大的 k 个特征值对应的特征向量，组成投影矩阵 W
- 降维后的数据: $X_{new}=XW$
- 连接到 LLM
- 词嵌入的可视化
- GPT 的 768 维词向量没法直接看。
- 用 PCA 把它降到 2D 或 3D，就能在散点图上观察
- &amp;#34;国王&amp;#34;&amp;#34;女王&amp;#34;&amp;#34;公主&amp;#34;这些词是否聚在一起？
- 这是分析模型语义的常用手段。
- 模型权重分析
- Transformer 的注意力矩阵分析中，研究者会看注意力权重矩阵的特征值分布
- 如果特征值过于集中（少数几个特征值很大，其他都很小）
- 说明模型在过度关注某些方向，可能存在退化现象。
- RoPE 位置编码的内在结构
- 旋转位置编码（RoPE）本质上是用一组旋转矩阵作用在 Query 和 Key 上
- 这些旋转矩阵的特征值（在复数域）正是 $e^{i\theta}$，对应频率的位置信息
- 模型压缩的根基
- 特征分解的更一般形式 SVD是各种模型压缩、剪枝、低秩近似的数学基础
- Numpy 代码实现
-
```python
import numpy as np
import matplotlib.pyplot as plt
# ─── 1. 求特征值和特征向量 ────────────────────────────
A = np.array([[3, 1],
[0, 2]], dtype=float)
eigenvalues, eigenvectors = np.linalg.eig(A)
print(&amp;#34;特征值:&amp;#34;, eigenvalues) # [3., 2.]
print(&amp;#34;特征向量（按列）:\n&amp;#34;, eigenvectors)
# 验证 A v = λ v
v0 = eigenvectors[:, 0] # 第一个特征向量
λ0 = eigenvalues[0]
print(&amp;#34;\nA @ v0 =&amp;#34;, A @ v0)
print(&amp;#34;λ0 * v0 =&amp;#34;, λ0 * v0)
print(&amp;#34;两者相等:&amp;#34;, np.allclose(A @ v0, λ0 * v0))
# ─── 2. 验证特征分解 A = P D P^(-1) ────────────────
P = eigenvectors
D = np.diag(eigenvalues)
A_reconstructed = P @ D @ np.linalg.inv(P)
print(&amp;#34;\n重构 A:\n&amp;#34;, A_reconstructed)
print(&amp;#34;与原 A 相等:&amp;#34;, np.allclose(A, A_reconstructed))
# ─── 3. 用特征分解快速算 A^10 ──────────────────────
A10_naive = np.linalg.matrix_power(A, 10)
A10_eigen = P @ np.diag(eigenvalues**10) @ np.linalg.inv(P)
print(&amp;#34;\n两种方法算 A^10 是否一致:&amp;#34;, np.allclose(A10_naive, A10_eigen))
# ─── 4. 手写 PCA 并可视化 ───────────────────────────
np.random.seed(42)
# 生成一些 2D 数据：长椭圆形分布
n = 200
mean = [0, 0]
cov = [[3, 2], [2, 2]]
data = np.random.multivariate_normal(mean, cov, n)
# Step 1: 中心化
data_centered = data - data.mean(axis=0)
# Step 2: 协方差矩阵
C = (data_centered.T @ data_centered) / (n - 1)
# Step 3: 特征分解
eigvals, eigvecs = np.linalg.eigh(C) # eigh 用于对称矩阵，更稳定
# Step 4: 按特征值从大到小排序
idx = np.argsort(eigvals)[::-1]
eigvals = eigvals[idx]
eigvecs = eigvecs[:, idx]
print(&amp;#34;\n协方差矩阵的特征值:&amp;#34;, eigvals)
print(&amp;#34;第一主成分（最大特征值方向）:&amp;#34;, eigvecs[:, 0])
print(&amp;#34;第二主成分:&amp;#34;, eigvecs[:, 1])
# 可视化：原数据 &amp;#43; 两个主成分方向
plt.figure(figsize=(8, 8))
plt.scatter(data[:, 0], data[:, 1], alpha=0.5, label=&amp;#39;数据&amp;#39;)
# 画两个主成分方向（用特征值缩放表示重要程度）
origin = data.mean(axis=0)
for i, (val, vec) in enumerate(zip(eigvals, eigvecs.T)):
plt.arrow(*origin, *(vec * np.sqrt(val) * 2),
head_width=0.15, color=[&amp;#39;red&amp;#39;, &amp;#39;green&amp;#39;][i],
label=f&amp;#39;PC{i&amp;#43;1} (λ={val:.2f})&amp;#39;, linewidth=2)
plt.axis(&amp;#39;equal&amp;#39;)
plt.grid(True)
plt.legend()
plt.title(&amp;#34;PCA：特征向量指出数据散布最大的方向&amp;#34;)
plt.show()
# ─── 5. 降维：把 2D 数据投影到 1D ─────────────────
# 只用第一主成分
W = eigvecs[:, 0:1] # shape (2, 1)
data_1d = data_centered @ W
print(f&amp;#34;\n降维前 shape: {data.shape}&amp;#34;)
print(f&amp;#34;降维后 shape: {data_1d.shape}&amp;#34;)
# 计算保留的&amp;#34;信息比例&amp;#34;
info_kept = eigvals[0] / eigvals.sum()
print(f&amp;#34;用 1 维保留了 {info_kept:.1%} 的信息&amp;#34;)
```
&lt;/textarea&gt;
&lt;h2 id="svd-奇异值分解"&gt;SVD (奇异值分解)&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-16347852"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-16347852" style="display:none;"&gt;
- SVD (奇异值分解)
- 为什么需要 SVD
- 特征分解 $A = PDP^{-1}$ 有两个限制
- 只能用于方阵（行数=列数）
- 不是所有的方阵都能分解（要求有 n 个线性无关的特征向量）
- 任何 $m\times n$ 的矩阵都能做 SVD 分解，没有任何限制
- SVD 公式
- 对任意矩阵 $A$ ($m\times n$) $A=U\Sigma V^T$
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510154340941.png,429,164)
- 奇异值通常按从大到小排列：$\sigma_1 \ge \sigma_2 \ge ... \ge \sigma _r \ge 0$, r 是矩阵的秩
- 几何解释
- 矩阵代表线性变换。SVD 说的是——任何线性变换，都可以分解成&amp;#34;旋转 → 缩放 → 旋转&amp;#34;三步
- 把向量 $\vec{x}$ 应用矩阵 $A$: $A\vec{x} = U\Sigma V^T\vec{x}$
- $V^T\vec{x}$: 对 $\vec{x}$ 做 一次旋转/反射
- $\Sigma(\cdot)$: 沿坐标轴各方向独立缩放(缩放倍数=奇异值)
- $U(\cdot)$: 再做一次旋转/反射
- 与特征分解的对比
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510154940144.png,461,207)
- 奇异值的含义
- 衡量矩阵的重要方向
- 最大的奇异值 $\sigma_1$ 对应矩阵最&amp;#34;主要&amp;#34;的变换方向；后面的奇异值一次描述次要方向。
- 决定矩阵的秩
- 非零奇异值的个数 = 矩阵的秩
- 衡量矩阵的&amp;#34;信息含量&amp;#34;
- 如果一个矩阵的奇异值快速衰减，说明矩阵的信息几乎全在前两个方向上，后面的方向可以安全丢弃
- SVD 与 LoRA
- 问题背景
- 微调一个 7B 参数的 LLM，要更新所有参数代价极大
- LoRA 的观察：微调时的参数变化 $\Delta W$ 通常是低秩的——也就是说，虽然 $\Delta W$ 是个大矩阵，它真正有效的&amp;#34;主方向&amp;#34;很少
- LoRA 的做法
- 不直接学习 $\Delta W$，而是学习两个小矩阵 A 和 B $\Delta W \approx BA$
- 如果 $\Delta W$ 是 4096x4096，参数量是 1700 万
- 如果用 LoRA 设秩为 8，则 A 是 8x4096，B 是 4096x8，参数量约 6.5 万，减少 250 倍
- SVD 在 LLM 中的其他应用
- 词嵌入分析
- 对一个 $50000\times 768$ 的词嵌入矩阵做 SVD，看奇异值衰减情况，可以判断词嵌入空间的有效维度
- Attention 矩阵分析
- 研究 Transformer 注意力权重矩阵的奇异值分布，可以诊断模型是否出现&amp;#34;注意力坍缩&amp;#34;——所有注意力都集中在少数几个 token 上
- 模型压缩
- 把训练好的权重矩阵做 SVD，丢弃小奇异值，用低秩矩阵替代，可以压缩模型大小
- 推荐系统的根基
- 经典的协同过滤推荐算法，本质就是对&amp;#34;用户-物品评分矩阵&amp;#34;做 SVD 低秩近似
- NumPy 代码实战
-
```python
import numpy as np
import matplotlib.pyplot as plt
# ─── 1. 基本 SVD 分解 ─────────────────────────────────
np.random.seed(42)
A = np.random.randn(5, 3) # 一个 5x3 的非方阵
U, sigma, VT = np.linalg.svd(A, full_matrices=False)
print(&amp;#34;A shape:&amp;#34;, A.shape)
print(&amp;#34;U shape:&amp;#34;, U.shape) # (5, 3)
print(&amp;#34;奇异值:&amp;#34;, sigma) # 长度为 3 的数组
print(&amp;#34;V^T shape:&amp;#34;, VT.shape) # (3, 3)
# 验证 A = U Σ V^T
A_reconstructed = U @ np.diag(sigma) @ VT
print(&amp;#34;\n重构误差:&amp;#34;, np.linalg.norm(A - A_reconstructed))
# ─── 2. 验证 U 和 V 是正交矩阵 ────────────────────────
print(&amp;#34;\nU^T @ U =\n&amp;#34;, (U.T @ U).round(4)) # 应近似为单位矩阵
print(&amp;#34;\nV @ V^T =\n&amp;#34;, (VT @ VT.T).round(4)) # 应近似为单位矩阵
# ─── 3. 低秩近似：用 SVD 压缩图像 ─────────────────────
# 创建一个简单的&amp;#34;图像&amp;#34;（一个矩阵）
np.random.seed(0)
image = np.zeros((50, 50))
# 加几个明显的结构
image[10:20, 10:40] = 1
image[25:35, 15:35] = 0.7
image[40:48, 5:45] = 0.5
image &amp;#43;= np.random.randn(50, 50) * 0.1
# 对图像做 SVD
U, sigma, VT = np.linalg.svd(image)
# 用不同 k 值重构
fig, axes = plt.subplots(1, 5, figsize=(15, 3))
axes[0].imshow(image, cmap=&amp;#39;gray&amp;#39;)
axes[0].set_title(f&amp;#34;原图\n所有 50 个奇异值&amp;#34;)
axes[0].axis(&amp;#39;off&amp;#39;)
for i, k in enumerate([1, 3, 10, 30]):
image_k = U[:, :k] @ np.diag(sigma[:k]) @ VT[:k, :]
axes[i&amp;#43;1].imshow(image_k, cmap=&amp;#39;gray&amp;#39;)
info_kept = (sigma[:k]**2).sum() / (sigma**2).sum()
axes[i&amp;#43;1].set_title(f&amp;#34;k={k}\n信息保留 {info_kept:.1%}&amp;#34;)
axes[i&amp;#43;1].axis(&amp;#39;off&amp;#39;)
plt.suptitle(&amp;#34;SVD 低秩近似：用前 k 个奇异值还原矩阵&amp;#34;)
plt.tight_layout()
plt.show()
# ─── 4. 奇异值衰减图 ──────────────────────────────────
plt.figure(figsize=(8, 4))
plt.plot(sigma, &amp;#39;o-&amp;#39;)
plt.yscale(&amp;#39;log&amp;#39;)
plt.xlabel(&amp;#39;奇异值序号&amp;#39;)
plt.ylabel(&amp;#39;奇异值大小（对数尺度）&amp;#39;)
plt.title(&amp;#39;奇异值衰减情况&amp;#39;)
plt.grid(True)
plt.show()
# ─── 5. 模拟 LoRA：用低秩分解近似一个权重矩阵 ───────
# 假设原始权重矩阵
W = np.random.randn(1024, 1024) * 0.01
# 假设这是&amp;#34;微调后的变化&amp;#34;——故意构造成低秩的
np.random.seed(1)
B_true = np.random.randn(1024, 8)
A_true = np.random.randn(8, 1024)
delta_W_true = B_true @ A_true # 真实秩为 8 的变化
# 用 SVD 提取最佳秩-8 近似
U, sigma, VT = np.linalg.svd(delta_W_true)
k = 8
delta_W_approx = U[:, :k] @ np.diag(sigma[:k]) @ VT[:k, :]
print(&amp;#34;\n--- LoRA 模拟 ---&amp;#34;)
print(f&amp;#34;原始 ΔW 参数量: {1024 * 1024:,}&amp;#34;)
print(f&amp;#34;LoRA 形式 (B &amp;#43; A) 参数量: {1024 * k &amp;#43; k * 1024:,}&amp;#34;)
print(f&amp;#34;压缩比: {1024 * 1024 / (1024 * k &amp;#43; k * 1024):.1f}x&amp;#34;)
print(f&amp;#34;近似误差: {np.linalg.norm(delta_W_true - delta_W_approx):.6f}&amp;#34;)
```
- SVD vs 特征分解 vs PCA 总结
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510161623378.png,546,158)
- 有趣的关系
- 对对称正定矩阵，特征分解和 SVD 等价
- PCA 可以通过对中心化数据矩阵 X 直接做 SVD 实现，比先算协方差矩阵更稳定
&lt;/textarea&gt;</description></item><item><title>AIInfra 学习</title><link>https://blog.ans20xx.com/posts/ai/aiinfra-%E5%AD%A6%E4%B9%A0/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/aiinfra-%E5%AD%A6%E4%B9%A0/</guid><description>&lt;h1 id="gpu-体系结构--cuda-入门--profiling"&gt;GPU 体系结构 + CUDA 入门 + Profiling&lt;/h1&gt;
&lt;h2 id="aiinfra-全景--学习内容"&gt;AIInfra 全景 + 学习内容&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-14265837"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-14265837" style="display:none;"&gt;
- AIInfra 全景 &amp; 学习内容
- 理论部分
- AIInfra 是什么
- AI Infra 不是一个单一的东西，而是一整套支撑「让模型在合适的硬件上、以合适的成本、稳定地训练和服务用户」的技术栈
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510163128065.png,726,300)
- 一条 prompt 的完整生命周期
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/Clipboard_Screenshot_1778404995.png,500,400)
- 训练 vs 推理的关键差异
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510180216416.png,655,286)
- 动手部分
- 环境检查清单
-
```bash
# 1. 操作系统
uname -a # 期望 Linux x86_64，推荐 Ubuntu 22.04
cat /etc/os-release
# 2. GPU &amp; 驱动
nvidia-smi # 看到 GPU 型号、驱动版本、CUDA 版本
nvidia-smi topo -m # 看 GPU 间互联拓扑（NVLink/PCIe）
# 3. CUDA Toolkit
nvcc --version # 没装就先装，建议 12.x
# 4. Python 环境（推荐 uv 或 conda）
python --version # 3.10 / 3.11 都可
pip --version
```
- 装 PyTorch &amp;#43; transformers
-
```bash
# 用 conda 建一个干净环境
conda create -n aiinfra python=3.10 -y
conda activate aiinfra
# PyTorch（按你的 CUDA 版本选，下面以 CUDA 12.1 为例）
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
# 推理常用库
pip install transformers accelerate sentencepiece
```
- 验证
```python
# check.py
import torch
print(&amp;#34;torch:&amp;#34;, torch.__version__)
print(&amp;#34;cuda available:&amp;#34;, torch.cuda.is_available())
print(&amp;#34;device count:&amp;#34;, torch.cuda.device_count())
print(&amp;#34;device name:&amp;#34;, torch.cuda.get_device_name(0))
```
- 跑通第一个 LLM 推理
- 选一个小模型（千万别第一次就拉 70B），比如 Qwen2.5-0.5B-Instruct 或 TinyLlama-1.1B：
-
```python
# first_infer.py
import time, torch
from transformers import AutoTokenizer, AutoModelForCausalLM
model_id = &amp;#34;Qwen/Qwen2.5-0.5B-Instruct&amp;#34; # 国内可换镜像
tok = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id, torch_dtype=torch.float16, device_map=&amp;#34;cuda&amp;#34;
)
prompt = &amp;#34;用一句话解释什么是 KV Cache。&amp;#34;
inputs = tok(prompt, return_tensors=&amp;#34;pt&amp;#34;).to(&amp;#34;cuda&amp;#34;)
torch.cuda.synchronize()
t0 = time.time()
out = model.generate(**inputs, max_new_tokens=128, do_sample=False)
torch.cuda.synchronize()
t1 = time.time()
print(tok.decode(out[0], skip_special_tokens=True))
print(f&amp;#34;\n耗时 {t1-t0:.2f}s, 生成 {out.shape[1]-inputs.input_ids.shape[1]} tokens&amp;#34;)
```
- 监控
```bash
watch -n 0.5 nvidia-smi # 观察显存占用、SM 利用率
```
&lt;/textarea&gt;
&lt;h2 id="linux-容器回顾"&gt;Linux 容器回顾&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-86325147"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-86325147" style="display:none;"&gt;
- Linux/容器基础回顾
- 理论部分
- Linux 进程隔离三件套
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510201727118.png,716,170)
- 需要记住的几个 namespace：pid、net、mnt、uts、ipc、user
- GPU 不在 namespace 隔离范围内 —— 这就是为什么需要 nvidia-container-toolkit
- NUMA、CPU 亲和性、与 GPU 的关系
- 一台 8 卡 GPU 服务器，CPU 和 GPU 之间的距离不是均等的
-
```
[ NUMA Node 0 ] [ NUMA Node 1 ]
CPU0–47 CPU48–95
├─ GPU0 (PCIe) ├─ GPU4
├─ GPU1 ├─ GPU5
├─ GPU2 ├─ GPU6
└─ GPU3 └─ GPU7
```
- 如果你的数据加载进程在 NUMA 0，但用的是 GPU 4，每条数据都要跨 NUMA 走 UPI，吞吐立即掉一截
-
```bash
numactl --hardware # 看 NUMA 拓扑
numactl --cpunodebind=0 --membind=0 python train.py # 绑到 NUMA 0
taskset -c 0-15 python ... # 绑到具体 CPU 核
nvidia-smi topo -m # 看 GPU 与 CPU 的拓扑距离 (PIX/PHB/NODE/SYS)
```
- 训练任务的 dataloader worker 必须和它要喂的 GPU 在同一个 NUMA node 上
- 容器与 GPU：为什么需要 nvidia-container-toolkit
- 普通容器只能隔离 CPU/内存/网络，看不到 GPU 设备
- 驱动在宿主机，CUDA Toolkit 在容器里
- 宿主机驱动版本必须 ≥ 容器里 CUDA 编译要求的最低版本
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/10/20260510203843759.png,585,612)
- 动手部分
- 操作 namespace 和 cgroup
- 直观感受「容器不过是一组 namespace &amp;#43; cgroup 的进程」
-
```
# 1. 用 unshare 起一个独立 PID namespace 的 shell
sudo unshare --pid --fork --mount-proc bash
ps aux # 只看到几个进程！这就是 PID namespace
exit
# 2. 看自己进程的 namespace
ls -l /proc/self/ns/
# 3. cgroup v2：看当前 shell 的资源限制
cat /proc/self/cgroup
cat /sys/fs/cgroup/memory.max 2&amp;gt;/dev/null || echo &amp;#34;no limit&amp;#34;
```
- 安装 nvidia-container-toolkit
-
```bash
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list \
| sed &amp;#39;s#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g&amp;#39; \
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
- 验证
```bash
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi
```
- 写自己的 AI Infra 开发镜像
-
```dockerfile
# 基础镜像：CUDA 12.4 &amp;#43; cuDNN &amp;#43; Ubuntu 22.04
FROM nvidia/cuda:12.4.1-cudnn-devel-ubuntu22.04
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# 系统依赖
RUN apt-get update &amp;&amp; apt-get install -y --no-install-recommends \
python3.10 python3-pip python3.10-venv \
git curl wget vim numactl htop \
build-essential ninja-build \
&amp;&amp; rm -rf /var/lib/apt/lists/*
RUN ln -sf /usr/bin/python3.10 /usr/bin/python &amp;&amp; \
ln -sf /usr/bin/pip3 /usr/bin/pip
# Python 依赖
RUN pip install --no-cache-dir \
torch==2.4.0 torchvision \
--index-url https://download.pytorch.org/whl/cu124
RUN pip install --no-cache-dir \
transformers accelerate sentencepiece \
jupyterlab ipython \
nvitop py-spy
WORKDIR /workspace
CMD [&amp;#34;bash&amp;#34;]
```
- 构建 &amp;#43; 运行
```bash
docker build -t aiinfra-dev:0.1 .
# 跑起来，挂载工作目录、暴露 jupyter 端口
docker run --rm -it \
--gpus all \
--shm-size=8g \
-v $PWD:/workspace \
-p 8888:8888 \
aiinfra-dev:0.1
```
- NUMA 绑定
- 多卡机器
```bash
# 先看拓扑
nvidia-smi topo -m
numactl --hardware
# 把推理脚本绑到 GPU0 同 NUMA 的 CPU 上
CUDA_VISIBLE_DEVICES=0 numactl --cpunodebind=0 --membind=0 \
python first_infer.py
```
&lt;/textarea&gt;
&lt;h2 id="gpu-硬件与体系结构"&gt;GPU 硬件与体系结构&lt;/h2&gt;
&lt;div
class="mindmap-container"
id="mindmap-14853276"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-14853276" style="display:none;"&gt;
- GPU 硬件与体系结构
- 理论部分
- 一张图看懂 GPU
- 以 NVIDIA H100 (Hopper) 为例
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/11/20260511002451179.png,756,565)
- H100 一共有 132 个 SM（消费卡 4090 是 128 SM，A100 是 108 SM）
- SM 是 GPU 的核，所有的 CUDA kernel 都在 SM 上执行
- 算力：FP16/BF16 Tensor Core ≈ 989 TFLOPS，FP8 ≈ 1979 TFLOPS
- 显存带宽：HBM3 ≈ 3 TB/s
- L2 Cache：50 MB（A100 是 40MB）
- NVLink：单卡对外 900 GB/s（A100 600 GB/s，4090 没 NVLink）
- SM 内部
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/11/20260511003227058.png,561,620)
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/11/20260511003301355.png,686,280)
- 关键洞察
- Warp Divergence：一个 warp 里 32 个线程如果走不同分支（if/else），GPU 会 顺序执行两条路径，性能直接腰斩。这就是为什么 GPU 不擅长复杂控制流
- Tensor Core 是深度学习的命门
- CUDA Core 一条指令算 1 个 FMA（乘加）
- Tensor Core 一条指令算 数百个 FMA
- 所以 H100 标称的 989 TFLOPS 几乎全来自 Tensor Core，CUDA Core 只有 ~67 TFLOPS
- 如果你的 kernel 没用上 Tensor Core，就只用了 GPU 7% 的算力
- 显存层级：从 Register 到 HBM
- GPU 是带宽为王的设备
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/05/11/20260511003449699.png,713,234)
- 核心结论
- 访问 HBM 比访问 Register 慢 500 倍
- 所以高性能 kernel 的核心套路就是：把数据从 HBM 搬到 Shared Memory，重复使用
- 这正是 FlashAttention 的核心思想
-
&lt;/textarea&gt;</description></item><item><title>钉钉天元 AI 实践</title><link>https://blog.ans20xx.com/posts/ai/%E9%92%89%E9%92%89%E5%A4%A9%E5%85%83ai%E5%AE%9E%E8%B7%B5/</link><pubDate>Wed, 18 Mar 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/%E9%92%89%E9%92%89%E5%A4%A9%E5%85%83ai%E5%AE%9E%E8%B7%B5/</guid><description>&lt;p&gt;客户情报 + 销售助理&lt;/p&gt;
&lt;p&gt;
&lt;div class="post-img-view"&gt;
&lt;a data-fancybox="" href="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318114947436.png" onclick="if(!window.Fancybox){event.preventDefault()}"&gt;
&lt;img loading="lazy" decoding="async" src="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318114947436.png" alt="" /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
&lt;div class="post-img-view"&gt;
&lt;a data-fancybox="" href="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318114803504.png" onclick="if(!window.Fancybox){event.preventDefault()}"&gt;
&lt;img loading="lazy" decoding="async" src="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318114803504.png" alt="" /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
&lt;div class="post-img-view"&gt;
&lt;a data-fancybox="" href="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318114824674.png" onclick="if(!window.Fancybox){event.preventDefault()}"&gt;
&lt;img loading="lazy" decoding="async" src="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318114824674.png" alt="" /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;
&lt;div class="post-img-view"&gt;
&lt;a data-fancybox="" href="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318115224633.png" onclick="if(!window.Fancybox){event.preventDefault()}"&gt;
&lt;img loading="lazy" decoding="async" src="https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/03/18/20260318115224633.png" alt="" /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;/p&gt;</description></item><item><title>ChromeAI 安装</title><link>https://blog.ans20xx.com/posts/tools/%E5%AE%89%E8%A3%85chrome-ai/</link><pubDate>Tue, 17 Mar 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/tools/%E5%AE%89%E8%A3%85chrome-ai/</guid><description>&lt;h1 id="实验元数据-meta-data"&gt;实验元数据 (Meta Data)&lt;/h1&gt;
&lt;p&gt;实验编号/标题：ChromeAI 安装&lt;/p&gt;</description></item><item><title>LLM 复习</title><link>https://blog.ans20xx.com/posts/ai/llm-%E5%A4%8D%E4%B9%A0/</link><pubDate>Sun, 22 Feb 2026 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/llm-%E5%A4%8D%E4%B9%A0/</guid><description>&lt;h1 id="预备知识"&gt;预备知识&lt;/h1&gt;
&lt;div
class="mindmap-container"
id="mindmap-54821367"
style="width:100%; height:860px; min-height: 860px;"
&gt;&lt;/div&gt;
&lt;textarea id="mindmap-data-54821367" style="display:none;"&gt;
- 预备知识
- 线性代数
- 向量与矩阵乘法
- 向量与向量乘法
- 内积
- 计算：对应元素相乘再相加，结果是一个标量
- $a\cdot b=\sum_{i=1}^n a_ib_i$
- 几何意义：衡量两个向量的相似度
- 如果内积为 0，向量正交
- 内积也可以表示为 $||a||||b||cos(\theta)$，即 a 在 b 方向上的投影长度乘以 b 的长度
- 外积
- 计算：一个列向量乘以一个行向量，结果是一个矩阵
- 意义：构造一个秩为 1 的矩阵。在 SVD 中，复杂的举证就是由多个这样的秩 1 矩阵加权累加的
- 列空间
- 定义
- 想象矩阵 A 的每一列都是一个导航箭头（向量）
- 如果 A 有两列 a1,a2，那么这两根箭头张开所能到达的所有地方，就是一个平面
- 这个平面就是矩阵 A 的列空间
- 列空间就是利用矩阵里的列向量，通过加减、缩放所能拼凑出的所有可能的结果向量的集合
- 矩阵与向量的乘法
- 假设有矩阵 A 和向量 x
- 线性组合
- 矩阵 A 乘以向量 x，等价于将 A 的列向量按照 x 中的元素进行加权求和
- 结果向量 b 必然落在矩阵 A 的列空间内
- 线性变换
- 将矩阵 A 看作一个函数或算子，它把输入向量 x 旋转、伸缩或投影到了一个新的位置
- 特征值/特征向量的学习，本质就是在寻找这个变换中方向不变的特殊向量
- 矩阵与向量的乘法
- 行乘列（传统定义）
- C 中第 i 行第 j 列的元素，是 A 的第 i 行与 B 的第 j 列的内积
- 列变换视角
- 把 B 看作一组列向量[b1,b2,...,bn]，那么 AB 的结果就是[Ab1,Ab2,...,Abn]
- 意义：矩阵 A 同时对 B 的每一列进行了相同的线性变换
- 分块矩阵乘法
- 将大矩阵划分为子矩阵进行运算
- 是计算机高性能计算和处理大数据时的核心原理
- 关键运算性质
- 不满足交换律：一般情况下 AB!=BA，矩阵乘法的顺序至关重要
- 满足结合律：A(BC)=(AB)C，意味着在计算长链乘法时，可以通过改变计算顺序来优化计算量
- 转置性质：$(AB)^T=B^TA^T$
- 范数
- 定义：范数是一个将向量映射到非负实数的函数，直观可以理解为衡量向量的大小或长度
- 没有范数，无法定义距离，也无法优化模型
- 性质
- 非负性：||x||&amp;gt;=0，且只有当 x 是零向量时，范数才是 0
- 齐次性：$||kx||=|k|\cdot ||x||$，向量放大 k 倍，长度也放大 k 倍
- 三角不等式：||x&amp;#43;y||&amp;lt;=||x||&amp;#43;||y||，两边之和大于第三边
- 常见的向量范数
- 公式
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/02/22/20260222152155557.png,192,81)
- L1 范数
- 计算：所有元素绝对值之和。$||x||_1=\sum|x_i|$
- 几何：只能沿格子线走
- 特性：会倾向于让向量中的许多元素变为 0，从而产生稀疏性
- 应用：L1正则化，用于特征选择，剔除不重要的变量
- L2 范数
- 计算：元素平方和再开方。$||x||_2=\sqrt{\sum x_i^2}$
- 几何：计算两点之间的直线距离（最直观的距离）
- 特性：对大数值非常敏感，处处可导，计算方便
- 应用：L2 正则化，防止模型过拟合；深度学习中的权重衰减。
- $L\infty$ 范数
- 计算：向量中绝对值最大的那个元素的值
- 应用：用于衡量最坏情况下的误差
- 矩阵范数
- Frobenius 范数
- 计算：把矩阵看成一个大向量，所有元素的平方和再开方
- 用途：衡量两个矩阵之间的距离，用于矩阵分解（SVD 或推荐系统）的损失函数。
- 基
- 定义
- 在向量空间里，基就是坐标系
- 在二维平面上，习惯用 x 轴 (1,0) 和 y 轴(0,1) 作为基。
- 任何一个点 (3,4) 都可以看作是：在 x 轴方向走 3 步，在 y 轴方向走 4 步。
- 基决定了观察和描述向量的视角。
- 特征值与特征向量
- 定义
- 对于一个方阵 Ai，如果存在一个非零向量 v 和一个标量 $\lambda$，满足如下等式
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/02/22/20260222172925249.png,88,37)
- 那么 v 就是特征向量，$\lambda$ 就是对应的特征值
- 特征值分解
- 如果一个 nxn 矩阵 A 有 n 个线性无关的特征向量，它可以被分解为
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/02/22/20260222173125585.png,119,42)
- Q：由特征向量组成的矩阵
- $\Lambda$ (Lambda)：对角矩阵，对角线上是对应的特征值
- 奇异值分解
- 数学定义
- 对于任何 m*n 的矩阵 A，都可以分解为
- ![](https://an-img.oss-cn-hangzhou.aliyuncs.com/2026/02/22/20260222153210370.png,107,40)
- U(m x n 阶)：左奇异值向量矩阵，它是正交矩阵（各列互相垂直且长度为 1），代表了变换后的输出空间的基。
- $\sum$ (m x n 阶)：奇异值矩阵，只有对角线有值，称为奇异值（$\sigma_1,\sigma_2, \dots$$），按从小到大排列，代表了每个方向上的权重或重要性。
- $V^T$ (n x n 阶)：右奇异向量矩阵的转置，也是正交矩阵，代表了输入空间的基。
- 几何直观
- 如果把矩阵 A 看作一个变换，SVD 告诉我们这个变换可以拆为 3 步：
- $V^T$（旋转）：将输入向量旋转到特定的方向，使其与奇异向量对齐。
- $\sum$（缩放）：在这些特定的方向上进行拉伸或压缩，奇异值越大，拉伸幅度越大。
- U （旋转）：再次旋转，将结果映射到最终的输出空间。
- 概率统计
- 最大似然
- 有一组数据 $D={x_i}^n_{i=1}$，选择了一个参数化模型 p(x|θ)
- 似然：把数据当成已发生的事实，把 θ 当成变量，问在这个 θ 下，数据出现的可能性有多大
- 最大似然估计：选一个 $\hat\theta$ 让 L(θ) 最大
&lt;/textarea&gt;</description></item><item><title>概率统计</title><link>https://blog.ans20xx.com/posts/ai/%E6%A6%82%E7%8E%87%E7%BB%9F%E8%AE%A1/</link><pubDate>Sun, 03 Aug 2025 00:00:00 +0000</pubDate><guid>https://blog.ans20xx.com/posts/ai/%E6%A6%82%E7%8E%87%E7%BB%9F%E8%AE%A1/</guid><description>程序员需要知道的数学知识-概率统计篇</description></item></channel></rss>