- 示例工程
【免费下载链接】NYU-DLSP20
NYU Deep Learning Spring 2020
本篇技术指南以 NYU Deep Learning Spring 2020(NYU-DLSP20,仓库pytorch-Deep-Learning)第一周实践课 docs/it/week01/01-3.md 为核心,系统讲解"为何要通过变换把数据变得线性可分"这一深度学习核心思想,并配套开源仓库中的 Jupyter Notebook 02-space_stretching.ipynb 给出可复现的 PyTorch 实验。读完本文,你将掌握线性变换与仿射变换的本质、SVD 分解如何拆解任意线性映射、tanh等非线性如何把点云"压"成可分类的形状,以及如何用nn.Linear构造并可视化随机神经网络的空间变换——这些正是后续课程中一切分类器与表征学习的基础。
动机:高维空间里的图像分类难题
课程以一个非常直观的例子引出话题:假设用一台 1 百万像素(1 megapixel)的相机拍摄一张照片,该图像大约有 1000×1000 个像素,每个像素又有红、绿、蓝(RGB)三个颜色通道。于是,一张图像就可以被看作 300 万维空间中的一个点。
问题随之而来:在如此巨大的维度下,我们想分类的许多"有趣的图像"——例如一只狗 vs. 一只猫——在原始像素空间中几乎落在同一个区域,彼此重叠、难以区分。因此,分类的关键不在于"直接观察原始空间",而在于对数据进行变换,把点移动到新的位置,使不同类别的点在新空间中彼此分离。
一句话概括课程的核心思想:利用线性变换和非线性变换,把数据点映射到一个新空间,使它们变得线性可分(linearly separable)。
线性变换:二维空间中的矩阵乘法
回忆线性代数的基础:在 2 维空间中,线性变换等价于矩阵乘法。以下是几类典型的线性变换及其矩阵特征:
- 旋转(Rotation):当变换矩阵是正交矩阵(orthonormal)时;
- 缩放(Scaling):当变换矩阵是对角矩阵时;
- 反射(Reflection):当变换矩阵的行列式为负时;
- 剪切(Shearing):一般性的线性变换形态。
需要注意:仅平移(translation)不是线性变换,因为线性变换要求把原点 0 仍映射到 0,而平移做不到这一点;平移属于仿射变换(affine transformation)。
回到图像分类的例子,我们可以分两步处理数据:先通过平移把数据点聚集到 0 附近,再用对角矩阵缩放,相当于对该区域进行"放大"(zoom in)。最后,通过在空间中寻找分隔直线,把不同类别的点划分到各自的类别。用矩阵语言表述就是:变换(平移 + 缩放 + 旋转……)把点搬到可分的位置,再做线性分类。
在 PyTorch 中,最常用的"线性层"nn.Linear(in, out, bias=True)执行的正是仿射变换:y = x Wᵀ + b。当设置bias=False时,它就退化为纯粹的线性变换(矩阵乘法),这也是后续实验中构造"纯线性映射"的关键开关。
数据可视化:用网络把五色螺旋"拉伸"开
为了直观展示"变换使数据可分",课程使用了一个经典数据集:五色螺旋(five-colour spiral)。
螺旋共有五个分支,每个分支对应一种不同颜色。数据点生活在二维平面中,可以用二元组(x, y 坐标)表示;而"颜色"则代表第三个维度,可理解为每个点所属的类别。我们的目标就是训练一个网络,把每个点按颜色分离开来。
| 输入点(网络之前) | 输出点(网络之后) |
|---|---|
(图 1:五色螺旋。左为网络输入前的原始点云,右为网络处理后的输出点云。)
可以看到,网络的作用本质上是**"拉伸"空间这块布料(space fabric):训练收敛后,五种颜色被网络分别映射到最终流形(manifold)的不同子空间中,每个颜色在新空间中都变成线性可分**的——可以使用"一对多(one vs. all)"回归将其区分开。
从矩阵角度看:图中的向量可以用一个5×2 矩阵表示,将该矩阵与每个点相乘,就能为五种颜色各返回一个分数(score);每个点再根据分数归属到得分最高的颜色类别。这里输出维度是 5(对应五种颜色),输入维度是 2(对应每个点的 x、y 坐标)。用一句话总结:这个网络把输入空间"布料"拿过来,执行了由若干矩阵与非线性函数参数化的空间变换。
网络架构:2 → 100 → 2 → 5
课程给出了用于该可视化的具体网络结构,这是一个带有嵌入层的浅层全连接网络:
(图 2:网络架构)
各层职责如下:
- 第一个矩阵(
nn.Linear(2, 100)):把 2 维输入映射到一个 100 维的中间隐藏层; - 非线性层 ReLU:即取正部分函数 $( \cdot )^+$(Rectified Linear Unit),为网络注入非线性表达能力;
- 嵌入层(embedding layer):把 100 维隐藏层映射到 2 维输出,目的是在二维平面上可视化变换后的点云;
- 最终投影层(
nn.Linear(2, 5)):把 2 维嵌入投影到 5 维输出层,每一维对应一种颜色的得分。
这套"编码到高维 → 压回低维可视化 → 再投影到类别得分"的架构,与第二周 04-spiral_classification.ipynb 中的螺旋分类实验(D=2, C=3, H=100,即 2 维输入、3 类、100 个隐藏单元)一脉相承,可对照学习。
实战:随机投影与空间拉伸 Jupyter Notebook
本小节对应的可运行实验是仓库根目录下的 02-space_stretching.ipynb。该 Notebook 从零生成随机点云,依次演示线性变换、SVD 分解、tanh非线性变换以及未训练的随机神经网络对空间的"扭曲",是理解本讲全部概念的最佳动手材料。
环境准备
原文档提到运行 Notebook 需要预先安装课程环境。以仓库实际内容为准:
- 环境定义见 environment.yml,其中声明了环境名
NYU-DL,依赖包括pytorch、torchvision、torchtext、matplotlib、jupyterlab、ipympl、opencv、librosa以及 pip 安装的torchviz等; - 完整安装步骤见 README.md:先安装 Miniconda(Python ≥ 3.7),克隆仓库后在仓库根目录执行
conda env create -f environment.yml并激活环境,随后启动jupyter lab或jupyter notebook即可。
注意:原文档中写作 "pDL" 环境,但仓库实际的 environment.yml 与环境安装文档 README.md 均使用环境名
NYU-DL,请以仓库实际内容为准。
Notebook 开头部分的关键设置代码如下:
from res.plot_lib import set_default, show_scatterplot, plot_bases %matplotlib inline set_default() torch.manual_seed(0)其中set_default()来自 res/plot_lib.py,会将绘图风格统一为暗色背景(dark_background+bmh),并设置黑色坐标轴与图像底色;torch.manual_seed(0)用于固定随机种子,保证实验可复现。
PyTorchdevice:把张量搬到 CPU 或 GPU
PyTorch 既可以运行在 CPU 上,也可以运行在 GPU 上。CPU 适合处理顺序型任务,而 GPU 擅长大规模并行计算。在执行计算之前,必须先把张量(tensor)和模型显式转移到目标设备的内存中,只需两行代码:
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") X = torch.randn(n_points, 2).to(device)- 第一行创建名为
device的变量:如果检测到可用 GPU 则赋值为"cuda:0",否则默认回退到"cpu"; - 第二行创建形状为
(n_points, 2)的随机张量,并通过.to(device)将其发送到设备内存。
在 Notebook 中,n_points = 1_000,即生成 1000 个 2 维随机点,其分布来自标准正态分布torch.randn。之后模型的构建也要记得调用model.to(device),确保权重与输入位于同一设备。课程其余所有实验(如 04-spiral_classification.ipynb)都沿用了这个统一的设备管理写法。
Jupyter Notebook 小技巧
在 Notebook 单元格中,把光标放到某个函数名上,按下Shift + Tab即可弹出该函数的文档签名(docstring),是快速查阅 PyTorch API 的高效方式,建议全程配合使用。
可视化线性变换:SVD 分解拆解矩阵
线性变换可以表示为一个矩阵。利用奇异值分解(Singular Value Decomposition, SVD),可以把任意矩阵分解为三个组成部分,每一部分对应一种不同的线性变换:
$$ W = U\begin{bmatrix}s_1 & 0 \ 0 & s_2 \end{bmatrix} V^\top $$
- 矩阵 $U$ 和 $V^\top$ 是正交矩阵,代表旋转与反射变换;
- 中间的对角矩阵代表缩放变换,其对角线上的元素 $s_1$、$s_2$ 就是奇异值。
奇异值的大小直接决定变换的"脾气":较大的奇异值把点拉开(stretch),较小的奇异值把点挤在一起(squeeze)。Notebook 中通过torch.svd(W)计算随机矩阵的奇异值,并用Y = X @ W.t()完成变换(注意 PyTorch 的矩阵乘方向,权重需转置)。课程实际展示的一组随机矩阵变换结果如下:
| 原始点 | $s_1 = 1.540, s_2 = 0.304$ | $s_1 = 0.464, s_2 = 0.017$ |
|---|---|---|
(图 3:随机矩阵的线性变换。可以观察到奇异值对点云拉伸/压缩程度的直接影响。)
Notebook 中该部分使用 Numpy/PyTorch 随机生成矩阵;不过课程指出,也可以直接使用 PyTorch 的nn.Linear类并设置bias = False来创建线性变换:
model = nn.Sequential(nn.Linear(2, 2, bias=False)) model.to(device) with torch.no_grad(): Y = model(X)在 res/plot_lib.py 中,plot_bases(OI)会用红色/绿色箭头绘制单位基向量,帮助我们直观看到矩阵如何旋转、反射坐标轴。
非线性变换:用tanh把点云压成正方形
线性变换可以旋转、反射、拉伸和压缩,但无法让空间弯曲——要"弯"出可分性,必须引入非线性。课程演示的变换如下:
$$ f(\vx) = \tanh\Bigg(\begin{bmatrix} s & 0 \ 0 & s \end{bmatrix} \vx \Bigg) $$
即:先用一个对角缩放矩阵(对角元都是 $s$)把点向外拉伸,再用双曲正切(hyperbolic tangent)将结果压回 $(-1, +1)$ 区间。
回顾 $\tanh(\cdot)$ 的函数图像:它在 0 附近近似线性、两端饱和于 ±1。
(图 4:双曲正切非线性)
这个非线性的效果是把点约束在 -1 与 +1 之间,从而形成一个(近似)正方形。随着缩放系数 $s$ 增大,越来越多的点被推向正方形的边缘——点被"摊开"得更远,也就更容易被分类器分开。
| $s=1$ 时的非线性变换 | $s=5$ 时的非线性变换 |
|---|---|
(图 5:非线性变换。对比 $s=1$ 与 $s=5$,可见缩放因子把更多点推到边界。)
对应的 Notebook 实现非常值得细读:它用nn.Sequential(nn.Linear(2, 2, bias=False), nn.Tanh())构建"缩放 + 非线性"的组合,然后通过model[0].weight.data.copy_(W)直接把线性层权重设为s * torch.eye(2)(缩放对角矩阵),再对s = 1..5循环绘制变换结果。这一写法展示了如何用数据拷贝(copy_)精确控制网络权重,是深入理解"权重即矩阵"的绝佳示范。
未训练的随机神经网络:线性 + 非线性 + 线性的复合扭曲
最后,课程可视化了一个简单且未训练的神经网络所执行的变换。网络结构为:
nn.Linear(2, n_hidden) → nn.Tanh() → nn.Linear(n_hidden, 2)即:一个执行仿射变换的线性层,紧跟一个双曲正切非线性,最后再接一个线性层。Notebook 中n_hidden = 5,并随机生成 5 个这样的网络分别可视化。
(图 6:未训练神经网络的变换结果)
观察图 6 可以发现:经过线性层 → 非线性 → 线性层的复合作用,变换结果明显不同于前面看到的纯线性变换或单层tanh变换——空间被折叠、拉伸,出现了更复杂的结构。这正是多层网络表达力的直观体现。Notebook 中还提供了一个更深版本:5 个nn.Linear(2, 5)+nn.ReLU()交替的 4 隐层网络,并借助%matplotlib widget与interpolate()函数,在输入与输出点云之间做 150 步的平滑插值动画,直观展示"空间布料"被逐层扭曲的整个过程。
从源码结构看,本实验刻意使用随机(未训练)权重,说明"哪怕不做任何学习,只要堆叠线性与非线性层,网络就能产生复杂的空间变换";而要让这种变换服务于分类,则需要后续课程中的损失函数与梯度下降来"驯服"这些变换。这一思路与 04-spiral_classification.ipynb 中"训练后螺旋被线性分离"的实验形成完整闭环。
可视化工具链:res/plot_lib.py的支撑作用
上述所有可视化都离不开仓库中的绘图工具模块 res/plot_lib.py。它为本讲提供了三个核心函数:
set_default():统一切换暗色绘图风格(dark_background+bmh),并设置坐标轴与画布为黑色,保证 Notebook 中的图形在深色主题下清晰可读;show_scatterplot(X, colors, title):绘制点云散点图。其实现会通过plt.imread('res/ziegler.png')读取一张调色板图像,把每个点的colors值映射为对应像素颜色,从而渲染出五色螺旋等彩色点云;plot_bases(OI):用红色、绿色箭头绘制单位基向量,帮助观察矩阵变换对坐标系的影响。
该模块同时被 04-spiral_classification.ipynb(提供plot_data、plot_model等分类可视化工具)等后续实验复用,是整个课程 Notebook 家族的公共可视化基础设施。
小结与延伸
本文围绕 NYU-DLSP20 第一周实践课 docs/it/week01/01-3.md 完成了从理论到代码的完整梳理:
- 动机:高维(如 300 万维图像)空间中同类数据纠缠在一起,必须依靠变换实现线性可分;
- 线性变换:旋转、缩放、反射、剪切分别对应正交矩阵、对角矩阵、负行列式等矩阵性质,平移属于仿射变换;
- 网络拉伸空间:2 → 100(ReLU)→ 2(嵌入可视化)→ 5(类别得分)的浅层网络即可把五色螺旋按类别分开;
- SVD 视角:任意矩阵可分解为"旋转/反射 × 缩放 × 旋转/反射",奇异值决定点云的拉伸与压缩;
- 非线性必要:
tanh把点压进 $(-1, 1)$ 正方形,增大缩放系数 $s$ 使点推向边缘、更易分类; - 随机网络:线性 + 非线性 + 线性的复合即可产生复杂空间扭曲,为后续"训练出有用变换"埋下伏笔。
如果你想把概念落到键盘上,直接运行仓库根目录的 02-space_stretching.ipynb,按 README.md 中的说明用 environment.yml 创建NYU-DL环境即可复现全部实验;想进一步验证"训练后线性可分"的完整流程,可继续学习第二周的 04-spiral_classification.ipynb。
- 示例工程
【免费下载链接】NYU-DLSP20
NYU Deep Learning Spring 2020
相关推荐
NYU-DLSP20 周课笔记 01-3:线性代数、空间变换与可视化——从 SVD 到神经网络"空间拉伸"
NYU DLSP20 周课笔记 01 3:线性代数、空间变换与可视化——从 SVD 到神经网络"空间拉伸" 导读 本文对应 NYU Deep Learning
示例工程NYU-DLSP20 第 1 周动手实践:用数据变换、SVD 与可视化理解神经网络的"空间拉伸"
NYU DLSP20 第 1 周动手实践:用数据变换、SVD 与可视化理解神经网络的"空间拉伸" 本篇指南基于 NYU Deep Learning Spring
示例工程NYU-DLSP20 深度学习课程:把神经网络当作“空间变换”——基于 SVD 与 PyTorch 的线性/非线性变换可视化实战
NYU DLSP20 深度学习课程:把神经网络当作“空间变换”——基于 SVD 与 PyTorch 的线性/非线性变换可视化实战 本文基于 NYU DLSP20
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考