系列 · 线性代数 · 第 3 篇

线性代数(三):矩阵作为线性变换

矩阵不是数字表格 -- 它们是变换空间的机器。本章展示如何将旋转、缩放、剪切、反射和投影视为矩阵,以及为什么矩阵乘法意味着变换的复合。

核心思想#

翻开一本传统教材,矩阵通常被描述为“数字排成的矩形阵列”。你会学到如何加法、乘法甚至求逆,但没人告诉你为什么乘法规则是这样设计的,也没人解释为什么 $AB$ 通常不等于 $BA$

线性代数(三):矩阵作为线性变换 — 章节概览图

符号运算掩盖了一个简单而深刻的真相。

矩阵是一个改变空间的函数。

每个 $m \times n$ 的矩阵就像一台机器:输入一个 $n$ 维向量,输出一个 $m$ 维向量。一旦你理解了这一点,那些看似奇怪的规则就不再神秘了——它们不过是记录基向量变化的方式而已。

本章内容包括:

  • 定义线性变换,并揭示其几何特征;
  • 说明“一个矩阵完全由它对基向量的作用决定”;
  • 构建一个直观图库,展示旋转、缩放、剪切、反射和投影的效果;
  • 推导出“矩阵乘法就是变换的复合”,从而自然解释非交换性;
  • 讨论逆矩阵(撤销变换)、核与像,以及矩阵奇异时的情况。

前置知识第 1 章 (向量、加法、数乘)和第 2 章 (线性无关、基、张成空间)。


矩阵是一个函数#

$$A: \mathbb{R}^{n} \longrightarrow \mathbb{R}^{m}, \qquad \vec{v} \mapsto A\vec{v}.$$

输入一个向量,输出一个向量。这一章的任务就是讲清楚这种函数到底能干什么。

复印机类比: 把复印机的缩放比例调到 150%,原稿上的每个点都会被映射到离中心 1.5 倍远的位置。这就是一种特定的变换——均匀缩放。矩阵可以表示更多类似的“几何机器”,如旋转、剪切、反射、投影及其各种组合。

什么样的函数才算“线性”?#

$$T(\vec{u} + \vec{v}) = T(\vec{u}) + T(\vec{v}) \qquad \text{(加法保持)}$$ $$T(c\,\vec{v}) = c\,T(\vec{v}) \qquad \text{(数乘保持)}$$

这两条代数规则在几何上有一个很直观的表现,通过观察整数网格的变形就能明白。

标准基与单位网格

线性变换可以对上面这张图做任何操作,但必须遵守以下规则:

  • 原点不动: $T(\vec{0}) = \vec{0}$ (把 $c=0$ 代入数乘规则就能证明)。
  • 直线还是直线: 不允许弯曲。
  • 平行线仍然平行,间距保持均匀。 变形后的网格仍然是网格——可能歪了、拉长了,甚至压扁了,但每个格子还是同形状的平行四边形。

橡皮膜类比: 想象这张图画在一块钉在原点的橡皮膜上。你可以拉伸、旋转、剪切,甚至压平,但不能撕开或折叠。能做到的就是线性变换;做不到的(撕开、折叠)就不是。

不属于线性变换的例子#

知道哪些变换不是线性变换同样重要:

  • 平移: $T(\vec{v}) = \vec{v} + \vec{b}$ 把原点挪走了,违反了 $T(\vec{0}) = \vec{0}$ 。它是仿射变换,不是线性变换。(后面我会用齐次坐标把它“救回来”。)
  • 弯曲: 把直线变成曲线的变换。
  • 平方或分量乘积: 比如 $T(x, y) = (x^{2}, y)$$T(x, y) = (xy, y)$ ,破坏了加法保持性。

核心洞见:列就是基向量的落点#

这是本章最重要的一句话,建议读两遍:

矩阵完全由它如何变换基向量决定。矩阵的列正好是这些基向量的落点。

$$\vec{v} = \begin{pmatrix} x \\ y \end{pmatrix} = x\,\hat{\imath} + y\,\hat{\jmath}.$$ $$T(\vec{v}) = T(x\,\hat{\imath} + y\,\hat{\jmath}) = x\,T(\hat{\imath}) + y\,T(\hat{\jmath}).$$ $$A = \Big[\;T(\hat{\imath})\;\Big|\;T(\hat{\jmath})\;\Big] = \begin{pmatrix} a & b \\ c & d \end{pmatrix},$$ $$ \begin{pmatrix} a & b \\ c & d \end{pmatrix}\begin{pmatrix} x \\ y \end{pmatrix} = x\begin{pmatrix} a \\ c \end{pmatrix} + y\begin{pmatrix} b \\ d \end{pmatrix} = \begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}. $$

右边可以看作一个配方:矩阵乘向量就是用 $\vec{v}$ 的分量对矩阵的列做加权求和。一旦理解了这一点,我就不再需要死记硬背公式,而是直接“读”出结果。

示例#

$$ A = \begin{pmatrix} 2 & -1 \\ 1 & 3 \end{pmatrix}, \qquad A\begin{pmatrix} 3 \\ 2 \end{pmatrix} = 3\begin{pmatrix} 2 \\ 1 \end{pmatrix} + 2\begin{pmatrix} -1 \\ 3 \end{pmatrix} = \begin{pmatrix} 4 \\ 9 \end{pmatrix}. $$

不需要背公式,直接记住“3 倍第一列加 2 倍第二列”就够了。


二维变换图谱#

为了更直观地理解,我用同一种方式展示五种变换:左边是原始单位网格,右边是变形后的网格。$\hat{\imath}$蓝色标记,$\hat{\jmath}$紫色标记,绿色的单位正方形用来观察面积变化。

旋转#

$$R_{\theta} = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix}.$$

逆时针旋转 30 度

几个常用角度值得记住:

角度矩阵效果
$90^{\circ}$$\begin{pmatrix}0&-1\\1&0\end{pmatrix}$逆时针转四分之一圈
$180^{\circ}$$\begin{pmatrix}-1&0\\0&-1\end{pmatrix}$半圈(等于取反)
$-90^{\circ}$$\begin{pmatrix}0&1\\-1&0\end{pmatrix}$顺时针转四分之一圈

游戏开发小贴士: 在 2D 游戏中,每次按下“左转”键,玩家的方向向量都会乘以 $R_{\Delta\theta}$ 。旋转保持长度和角度不变,所以角色转身时不会拉伸变形。

缩放#

$$S = \begin{pmatrix} s_{x} & 0 \\ 0 & s_{y} \end{pmatrix}.$$

缩放:x 方向 2 倍,y 方向 1.5 倍

单位正方形变成 $s_{x} \times s_{y}$ 的矩形,面积扩大了 $s_{x}s_{y}$ 倍。这个乘积就是行列式——下一章的核心内容。

Photoshop 中调整图像大小的操作本质上就是这个:每个像素坐标都乘以一个对角矩阵 $S$

剪切#

$$H = \begin{pmatrix} 1 & k \\ 0 & 1 \end{pmatrix}.$$

水平剪切

变换后,$x$ 坐标变为 $x + ky$ :点的位置越高,推得越远。斜体字就是典型例子——字母底部固定,顶部倾斜。风吹高草则是垂直方向的剪切。

注意 $\det H = 1$ :剪切不会改变面积,尽管形状被扭曲得很厉害。

反射#

反射就是翻转某个方向,矩阵依然回答“基向量去哪了”这个问题:

反射轴矩阵效果
关于 $x$$\begin{pmatrix}1&0\\0&-1\end{pmatrix}$上下翻转
关于 $y$$\begin{pmatrix}-1&0\\0&1\end{pmatrix}$左右翻转
关于直线 $y = x$$\begin{pmatrix}0&1\\1&0\end{pmatrix}$$x$$y$ 互换
关于原点$\begin{pmatrix}-1&0\\0&-1\end{pmatrix}$等价于 $180^{\circ}$ 旋转

反射的行列式为 $-1$ :面积不变,但方向反转(右手系变成左手系)。这个负号正是反射与旋转的本质区别。

投影#

$$P_{x} = \begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix}.$$

整个二维平面被压缩成一条一维直线。这就像正午阳光下的阴影投影。更一般地,在原点穿过、方向为单位向量 $\vec{u}$ 的直线上投影,对应矩阵 $P = \vec{u}\vec{u}^{\!\top}$

投影是第一种会丢失信息的变换:$(1, 2)$$(1, 99)$ 都被投影到 $(1, 0)$ 。这种不可逆性正是它的特点——后面我们会用奇异矩阵进一步解释这种现象。

小结表#

变换矩阵行列式是否可逆
旋转 $\theta$$\begin{pmatrix}\cos\theta&-\sin\theta\\\sin\theta&\cos\theta\end{pmatrix}$$+1$
缩放 $(s_{x}, s_{y})$$\operatorname{diag}(s_{x}, s_{y})$$s_{x}s_{y}$当两者都非零时
水平剪切$\begin{pmatrix}1&k\\0&1\end{pmatrix}$$+1$
任意反射多种形式$-1$是(自身就是它的逆)
投影到一条直线秩 1$0$

矩阵乘法 = 变换的复合#

线性代数(三):矩阵作为线性变换 — 章节小结图

终于可以解释矩阵乘法的规则了。

$$\vec{v} \;\xrightarrow{A}\; A\vec{v} \;\xrightarrow{B}\; B(A\vec{v}).$$ $$B(A\vec{v}) \;\equiv\; (BA)\vec{v}.$$

这不是需要证明的定理,而是矩阵乘法的设计目标。至于那套“行乘列”的奇怪规则,其实只是当你一步步推导“$\hat{\imath}$ 经过 $A$$B$ 后跑到哪里”时自然得出的结果。

从右往左读的规则: 在表达式 $CBA\vec{v}$ 中,最右边的矩阵最先起作用。读的时候要记住:“先 $A$ ,再 $B$ ,最后 $C$ 。” 这和日常语言的顺序相反,也是图形学代码中 bug 的常见来源——所以每次写这种表达式时,我都会在心里默念一遍。

为什么顺序重要:看图说话#

$A = R_{45^{\circ}}$ (逆时针旋转 45 度),$B = \operatorname{diag}(2, 1)$ (沿 $x$ 方向拉伸 2 倍)。先 $A$$B$

矩阵乘法即变换复合

第三幅图可以从三个角度理解,结果完全一致:

  1. 几何上: 先把单位正方形转 45 度,再横向拉伸。
  2. 代数上: $BA = \begin{pmatrix}2&0\\0&1\end{pmatrix}\begin{pmatrix}\frac{\sqrt{2}}{2}&-\frac{\sqrt{2}}{2}\\\frac{\sqrt{2}}{2}&\frac{\sqrt{2}}{2}\end{pmatrix} = \begin{pmatrix}\sqrt{2}&-\sqrt{2}\\\frac{\sqrt{2}}{2}&\frac{\sqrt{2}}{2}\end{pmatrix}$
  3. 从列看: $BA$ 的第一列是 $B$ 作用在 $A$ 的第一列上,也就是 $B$ 作用在 $A\hat{\imath}$ 上——也就是 $\hat{\imath}$ 经过两次变换后的最终位置。第二列同理。
$$A B = \begin{pmatrix}\frac{\sqrt{2}}{2}&-\frac{\sqrt{2}}{2}\\\frac{\sqrt{2}}{2}&\frac{\sqrt{2}}{2}\end{pmatrix}\begin{pmatrix}2&0\\0&1\end{pmatrix} = \begin{pmatrix}\sqrt{2}&-\frac{\sqrt{2}}{2}\\\sqrt{2}&\frac{\sqrt{2}}{2}\end{pmatrix} \neq BA.$$

几何上:先把正方形拉成宽长方形再旋转,得到的平行四边形和“先转再拉”完全不同。矩阵乘法不交换,因为变换的复合本身就不交换。 故事讲完了。

结合律的实际意义#

矩阵乘法满足结合律$(AB)C = A(BC)$ 。这不只是代数上的小性质,而是让 3D 图形渲染变快的关键。

$$M = T \cdot R \cdot S.$$

如果有一百万个顶点,千万别对每个顶点分别做 $S$$R$$T$ (那样要做 300 万次矩阵-向量乘法)。正确做法是先算出 $M$ ,然后对每个顶点只做一次 $M\vec{v}$ ——速度提升三倍,数值稳定性也更好。 GPU 的渲染管线就是基于这个原理设计的。

单位矩阵与逆矩阵:什么都不做,以及撤销操作#

单位矩阵#

$$I = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}.$$

从几何上看,变换前后的网格完全一样:

恒等变换

单位矩阵满足 $IA = AI = A$ ,对任何矩阵 $A$ 都成立。它就像数字世界里的“1”。

逆矩阵#

$$A^{-1} A \;=\; A A^{-1} \;=\; I.$$

从几何角度想,下面这些例子都很直观:

  • $R_{\theta}^{-1} = R_{-\theta}$ (反方向再转一次就回来了)。
  • $\operatorname{diag}(s_{x}, s_{y})^{-1} = \operatorname{diag}(1/s_{x}, 1/s_{y})$ ,前提是两个缩放因子都不为零。
  • 反射变换的逆就是它自己——反射两次就回到起点。

什么时候存在逆?#

不是所有变换都能被撤销。比如投影会把 $y$ 方向的信息丢掉,任何丢失维度的变换都无法逆转$(1, 2)$$(1, 5)$ 投影后都变成 $(1, 0)$ ,只看 $(1, 0)$ 根本无法还原原来的 $y$ 值。

判断是否可逆的标准很简单——我们会在第 4 章 详细讨论——就是:

$A$ 可逆 $\iff$ $A$ 不会压缩任何维度 $\iff$ $\det(A) \neq 0$

$2 \times 2$ 逆矩阵公式#

$$A^{-1} = \frac{1}{ad - bc}\begin{pmatrix} d & -b \\ -c & a \end{pmatrix}.$$

你可以试着把它和 $A$ 相乘,结果一定是单位矩阵 $I$ 。建议动手验证一下。

奇异矩阵:平面坍塌的时刻#

$$S = \begin{pmatrix} 1 & 2 \\ 2 & 4 \end{pmatrix}.$$

第二行是第一行的两倍,第二列也是第一列的两倍。代数上看,$\det(S) = 1 \cdot 4 - 2 \cdot 2 = 0$ 。几何上呢?

奇异矩阵把平面压成直线

平面上的所有点都被映射到同一条直线 $y = 2x$ 上——也就是由列向量 $(1, 2)$ 张成的那条线。单位正方形被压缩成一段零面积的线段。图中橙色的网格线全都重叠在这条直线上,因为所有输入都被映射到了这条线上。

这就是一个奇异矩阵(不可逆矩阵)。接下来我给两个重要的子空间起个名字。

核:被压缩为零的方向#

$$\ker(A) = \{\,\vec{v} : A\vec{v} = \vec{0}\,\}.$$

对于上面的 $S$ ,所有形如 $\vec{v} = t\,(2, -1)$ 的向量都满足 $S\vec{v} = \vec{0}$ ——这正是图中那条灰色虚线标出的“核方向”。这个核是一条 1 维直线。

直观理解:核就是矩阵消灭掉的方向。一个矩阵可逆的充要条件是它的核只包含零向量。

像:能到达的所有输出#

$$\operatorname{Im}(A) = \{\,A\vec{v} : \vec{v} \in \mathbb{R}^{n}\,\}.$$

$S$ 来说,像就是直线 $y = 2x$ 。它也叫列空间,因为它正好是矩阵各列张成的子空间。$S$ 的两列分别是 $(1, 2)$$(2, 4)$ ,它们都在同一条直线上,所以只能张成一条直线,而不是整个平面。

秩-零化度定理#

$$\dim\ker(A) + \dim\operatorname{Im}(A) = n,$$

其中 $n$ 是输入空间的维数。简单说:矩阵每压扁一维(核多一维),输出就少一维(像少一维)。对我们的 $S$ 来说,$1 + 1 = 2$第 5 章 讨论线性方程组时还会再见到这个公式。


三维及更高维度的变换#

所有概念都能自然推广。在 $\mathbb{R}^{3}$ 中,线性变换用一个 $3 \times 3$ 矩阵表示,矩阵的三列分别是基向量 $\hat{\imath}$$\hat{\jmath}$$\hat{k}$ 变换后的位置。

$$R_{z}(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{pmatrix}.$$ $$P_{xy} = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 0 \end{pmatrix}.$$

这个三维投影是前面提到的奇异矩阵在高维空间的对应形式。它把三维空间压缩到二维平面,因此 $\det = 0$ ,无法逆变换。


Python:可视化变换#

本章所有图片的生成脚本都在 scripts/figures/linear-algebra/03-matrices-as-linear-transformations.py。它的核心思路很简单,就是一个函数,用来展示矩阵对单位正方形的作用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import numpy as np
import matplotlib.pyplot as plt

def plot_transform(A, title="变换"):
    """画出矩阵 A 对单位正方形的变换效果"""
    square = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]).T  # 2 x 5
    transformed = A @ square                                       # 核心代码

    fig, axes = plt.subplots(1, 2, figsize=(10, 5))
    for ax, shape, label, color in [
        (axes[0], square,      "变换前",                          "#2563eb"),
        (axes[1], transformed, f"变换后 (det={np.linalg.det(A):.2f})", "#10b981"),
    ]:
        ax.fill(shape[0], shape[1], alpha=0.3, color=color)
        ax.plot(shape[0], shape[1], color=color, linewidth=2)
        ax.set_xlim(-3, 3); ax.set_ylim(-3, 3)
        ax.set_aspect("equal"); ax.grid(True, alpha=0.3)
        ax.set_title(label)
    plt.suptitle(title); plt.tight_layout(); plt.show()

plot_transform(np.array([[2,   0],   [0,   1.5]]), "缩放")
plot_transform(np.array([[1,   0.5], [0,   1  ]]), "剪切")
plot_transform(np.array([[-1,  0],   [0,   1  ]]), "关于 y 轴反射")
plot_transform(np.array([[1,   2],   [2,   4  ]]), "奇异矩阵:压成一条直线")

一个简单的 2D 游戏变换类#

游戏引擎用齐次坐标把缩放、旋转和平移合并到一个矩阵里。二维点 $(x, y)$ 被存为 $(x, y, 1)$ ,这样单个 $3 \times 3$ 矩阵就能同时处理平移:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import numpy as np

class Transform2D:
    """把缩放、旋转和平移合成为一个 3x3 矩阵"""

    def __init__(self):
        self.position = np.array([0.0, 0.0])
        self.rotation = 0.0           # 弧度
        self.scale    = np.array([1.0, 1.0])

    def matrix(self) -> np.ndarray:
        c, s = np.cos(self.rotation), np.sin(self.rotation)
        S = np.diag([self.scale[0], self.scale[1], 1.0])
        R = np.array([[c, -s, 0],
                      [s,  c, 0],
                      [0,  0, 1]])
        T = np.array([[1, 0, self.position[0]],
                      [0, 1, self.position[1]],
                      [0, 0, 1]])
        # 从右往左读:先缩放,再旋转,最后平移
        return T @ R @ S

    def apply(self, points: np.ndarray) -> np.ndarray:
        pts = np.asarray(points)
        homo = np.ones((3, len(pts)))
        homo[:2, :] = pts.T
        return (self.matrix() @ homo)[:2, :].T

t = Transform2D()
t.position = np.array([100.0, 50.0])
t.rotation = np.pi / 4               # 45 度
t.scale    = np.array([2.0, 1.5])
print(t.apply([[-1, -1], [1, -1], [1, 1], [-1, 1]]))

这就是 Unity、Unreal、Godot 等 3D 引擎常用的“TRS”模式(Translate × Rotate × Scale)。


常见问题#

平移是线性变换吗?#

不是。平移会移动原点,导致 $T(\vec{0}) \neq \vec{0}$ 。为了用矩阵表示平移,计算机图形学引入了齐次坐标:把二维点 $(x, y)$ 表示为三维向量 $(x, y, 1)$ ,然后用一个 $3 \times 3$ 矩阵将 $t_{x}$$t_{y}$ 加到前两个坐标上。虽然平移在 $\mathbb{R}^{2}$ 中不是线性变换,但在 $\mathbb{R}^{3}$ 中,如果限制在平面 $z = 1$ 上,它就是线性的。

矩阵乘法为什么定义得这么奇怪?#

因为它的规则是为了满足“矩阵乘积 = 变换复合”这个目标而设计的。从 $(BA)\vec{v} = B(A\vec{v})$ 这个要求出发,推导出每个元素的值,“行乘列”的公式自然就出来了。这不是随意定的,而是由几何需求决定的。

旋转矩阵有什么特别之处?#

旋转矩阵能保持长度和角度。代数上看,它满足 $R^{\!\top} R = I$ (正交矩阵),并且 $\det R = +1$ (保持方向,不翻转)。这两个性质共同定义了特殊正交群 $\mathrm{SO}(2)$ ,这也是所有流畅旋转动画背后的数学基础。

怎么快速判断一个矩阵是旋转、缩放、剪切还是投影?#

看行列式和列向量:

  • $\det = +1$ 且列向量正交单位化 $\Rightarrow$ 旋转;
  • $\det = -1$ 且列向量正交单位化 $\Rightarrow$ 反射;
  • 列向量与坐标轴平行 $\Rightarrow$ 沿轴缩放;
  • $\det = 0$ $\Rightarrow$ 奇异矩阵,降维了,没有逆;
  • 其他情况通常是剪切、沿非轴方向的一般缩放,或者它们的组合。

总结#

记住一句话就够了:

矩阵是一种线性变换,它的列告诉你基向量被映射到了哪里。

其他内容都是从这句话延伸出来的:

  • 矩阵乘以向量,就是用向量的分量对矩阵的列做加权求和。
  • 矩阵相乘,就是变换的叠加,顺序是从右到左。
  • 矩阵乘法不满足交换律,因为“先旋转再拉伸”和“先拉伸再旋转”在几何上完全不同。
  • 单位矩阵什么都不改变;逆矩阵则会撤销原矩阵的操作。
  • 如果一个矩阵把某个方向压缩成零($\det = 0$ ),它就是奇异矩阵:被压缩的方向是核,剩下的部分是像(也就是列空间)。

为了更直观,我一直用二维空间来讲解。下一章我会引入行列式的概念,用来量化变换对空间的拉伸或压缩程度,并解释为什么 $\det(AB) = \det(A)\det(B)$


下一步#

第 4 章 :行列式的秘密。 行列式是一个数字,用来表示变换对体积的缩放比例。我会解释它在复合变换时为什么是相乘关系,符号变化为什么会反映方向反转,以及 $\det = 0$ 为什么正好对应我们刚刚讨论的奇异情况。

本系列

线性代数 18 篇

  1. 01 线性代数(一):向量的本质——不仅仅是箭头
  2. 02 线性代数(二):线性组合与向量空间
  3. 03 线性代数(三):矩阵作为线性变换 当前
  4. 04 线性代数(四):行列式的秘密
  5. 05 线性代数(五):线性方程组与列空间
  6. 06 线性代数(六):特征值与特征向量
  7. 07 线性代数(七):正交性与投影——当向量互不干扰
  8. 08 线性代数(八):对称矩阵与二次型
  9. 09 线性代数(九):奇异值分解 SVD
  10. 10 线性代数(十):矩阵范数与条件数——数值计算的健康体检
  11. 11 线性代数(十一):矩阵微积分与优化——从梯度到反向传播
  12. 12 线性代数(十二):稀疏矩阵与压缩感知——少即是多的数学奇迹
  13. 13 线性代数(十三):张量与多线性代数——从标量到高维数据立方体
  14. 14 线性代数(十四):随机矩阵理论——混沌中的秩序
  15. 15 线性代数(十五):机器学习中的线性代数——从 PCA 到推荐系统
  16. 16 线性代数(十六):深度学习中的线性代数——从全连接到 Transformer
  17. 17 线性代数(十七):计算机视觉中的线性代数——从像素到三维重建
  18. 18 线性代数(十八):前沿应用与总结——量子计算、GNN、大模型,与十八章回望

读有所得?

GitHub 关注我 → 新文周更

GitHub