☰
空间拉伸实战:用线性代数、SVD 与神经网络变换理解深度学习(NYU-DLSP20 第一周实践课)
2026/10/10 2:36:37 网站建设 项目流程
  • 示例工程

【免费下载链接】NYU-DLSP20

NYU Deep Learning Spring 2020

项目地址:https://gitcode.com/gh_mirrors/pyt/pytorch-Deep-Learning
点击查看免费下载

本篇技术指南以 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:网络架构)

各层职责如下:

  1. 第一个矩阵(nn.Linear(2, 100)):把 2 维输入映射到一个 100 维的中间隐藏层;
  2. 非线性层 ReLU:即取正部分函数 $( \cdot )^+$(Rectified Linear Unit),为网络注入非线性表达能力;
  3. 嵌入层(embedding layer):把 100 维隐藏层映射到 2 维输出,目的是在二维平面上可视化变换后的点云;
  4. 最终投影层(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 完成了从理论到代码的完整梳理:

  1. 动机:高维(如 300 万维图像)空间中同类数据纠缠在一起,必须依靠变换实现线性可分;
  2. 线性变换:旋转、缩放、反射、剪切分别对应正交矩阵、对角矩阵、负行列式等矩阵性质,平移属于仿射变换;
  3. 网络拉伸空间:2 → 100(ReLU)→ 2(嵌入可视化)→ 5(类别得分)的浅层网络即可把五色螺旋按类别分开;
  4. SVD 视角:任意矩阵可分解为"旋转/反射 × 缩放 × 旋转/反射",奇异值决定点云的拉伸与压缩;
  5. 非线性必要:tanh把点压进 $(-1, 1)$ 正方形,增大缩放系数 $s$ 使点推向边缘、更易分类;
  6. 随机网络:线性 + 非线性 + 线性的复合即可产生复杂空间扭曲,为后续"训练出有用变换"埋下伏笔。

如果你想把概念落到键盘上,直接运行仓库根目录的 02-space_stretching.ipynb,按 README.md 中的说明用 environment.yml 创建NYU-DL环境即可复现全部实验;想进一步验证"训练后线性可分"的完整流程,可继续学习第二周的 04-spiral_classification.ipynb。

  • 示例工程

【免费下载链接】NYU-DLSP20

NYU Deep Learning Spring 2020

项目地址:https://gitcode.com/gh_mirrors/pyt/pytorch-Deep-Learning
点击查看免费下载

相关推荐

上一篇:Reflex 项目结构完全指南:从 `reflex init` 生成的每个文件说起
下一篇:Chalice持续部署指南:generate-pipeline一键生成CodePipeline流水线

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询