CS Graphics
Computer Graphics and Diffusion Learning
PyTorch
PyTorch 是一个开源的 Python 机器学习库,基于 Torch,底层由 C++ 实现。
其主要有两大特征:
- 类似于 NumPy 的张量计算,能在 GPU 或 MPS 等硬件加速器上加速
- 基于带自动微分系统的深度神经网络
张量 Tensor
张量就是一个多维数组,类似于 NumPy 的 ndarray,但它多了两个专为深度学习设计的能力:
- GPU 加速:张量可以在显卡上运行,速度远比 CPU 快
- 自动微分:PyTorch 可以自动记录张量上的所有运算,从而自动计算神经网络所需的梯度
可以根据维度来直观理解张量:
- 0 维张量(Scalar):一个纯数字(如
3) - 1 维张量(Vector):一行数字(如
[1, 2, 3]) - 2 维张量(Matrix):一个表格,有行和列
- 3 维张量:像一叠表格。在深度学习中,一张彩色图片通常表示为三维张量(宽,高,RGB 三个通道)
数据集和数据加载器 Dataset and DataLoader
数据集就是数据的封装
torch.utils.data.Dataset 是一个抽象类,其核心任务是:告诉程序如何读取一条数据及其对应的标签
当自定义数据集时,必须实现三个关键方法:
__init__: 在实例化数据集对象时运行一次__len__:返回数据集的总样本数__getitem__:根据索引(index)读取某一个样本,可以进行数据增强(比如把图片旋转、缩放或转成张量)
数据加载器就是数据的调度
torch.utils.data.DataLoader 是一个迭代器,它包装了 Dataset,提供非常强大的数据调度功能
Transforms
数据并不总是以训练机器学习算法所需的最终处理形式呈现。我们使用 transforms 来对数据进行一些处理,使其适用于训练
所有 TorchVision 数据集都有两个参数, transform 用于修改特征,target_transform 用于修改标签, 它们接受包含转换逻辑的可调用对象。torchvision.transforms 模块提供了几种常用的转换。
构建神经网络
神经网络由执行数据操作的层 / 模块组成。神经网络本身就是一个由其他模块组成的模块,这种嵌套结构允许轻松构建和管理复杂的架构
这个东西本质上就是对输入的图片数字化之后进行一些运算,转化出来一个对应不同结果的概率,大概流程:
- 图片数字化:将图片转成代表颜色深浅的数字矩阵($0-255$)
- 运算(Linear 线性层):就是做 $y=wx+b$,把输入的像素值乘权重 $w$,加上偏置 $b$
- 转化(ReLU 激活层):就是 $y=max(0,x)$
- 输出概率(Softmax):把这一堆算出来的“得分”,按照比例压缩到 $0-1$ 之间,哪个概率最大就猜他是谁
ReLU:本质上就是把直线折断,因为如果没有这个过程的话,不管叠加多少次 $y=wx+b$,它始终都可以合并成一个直线方程,实际上是没办法用直线来呈现现实世界图案,但简单的遇负归零动作可以让他拼接成复杂形状曲线。
自动微分
在训练神经网络时,最常用的算法是反向传播,模型的参数会根据损失函数相对于给定参数的梯度进行调整
为了计算这些梯度,PyTorch 提供了一个内置的微分引擎,即 torch.autograd
优化模型参数
所谓人工智能学习或者大模型训练,本质上就是暴力试错+疯狂微调,也就是常说的监督学习(Supervised Learning),其过程其实是:
- 向前传播(Forward Pass):其实就是瞎猜,一开始模型里的参数(所有的权重 $w$ 和 偏置 $b$ 全都是随机生成的数字
- 计算损失(Loss):这部分就是对答案并算分,用事先准备好的正确答案(标签 Label),跟机器瞎猜的结果做对比。错的越离谱,系统给出的惩罚分数(Loss 值)就越高
- 反向传播与梯度下降(Backward & Gradient Descent):就是改错,机器会通过微积分求导的方式,顺藤摸瓜地往回找哪个参数有问题,要进行调整
Diffusion Models Beat GANs on Image Synthesis
Motivation
GAN 当时在很多图像生成任务上是 SOTA,但 GAN 难训练、容易 collapse,而且 diversity 不一定好;diffusion model 更稳定、覆盖更好,但在 LSUN / ImageNet 这类困难数据集上还落后于 GAN。
GAN 有一个很强的能力:可以牺牲 diversity 来换 fidelity。也就是让生成图像更好看、更像真实图片,但代价是多样性下降。BigGAN 里有 truncation trick,简单说就是生成时别从太极端的 latent 采样,只采样“更安全、更典型”的区域。这样图会更漂亮,但模式更少。
这篇论文的核心 Motivation 就是,能不能把 GAN 的两个优势带到 diffusion 里:
- 更好的架构
- 一个可以调节 fidelity-diversity trade-off 的旋钮
Introduction 写到,他们假设 diffusion 和 GAN 的差距来自两点:一是 GAN 架构被大量探索和优化,二是 GAN 能在 fidelity 和 diversity 之间取舍;因此他们要通过 architecture improvement 和 classifier guidance 把这些能力带给 diffusion。
核心概念
Image Synthesis: 图像生成。即让模型生成看起来像真实数据集里的图片。
Noise: 噪声。一个和图片同样大小的随机 tensor,通常来自高斯分布,可以理解为花屏。
Generative Adversarial Network(GAN): 生成对抗网络。是非监督式学习的一种方法,通过两个神经网络相互博弈的方式进行学习。生成网络从潜在空间(latent space)中随机取样作为输入,其输出结果需要尽量模仿训练集中的真实样本。判别网络的输入则为真实样本或生成网络的输出,其目的是将生成网络的输出从真实样本中尽可能分辨出来。而生成网络则要尽可能地欺骗判别网络。两个网络相互对抗、不断调整参数,最终目的是使判别网络无法判断生成网络的输出结果是否真实。
Diffusion Model: 其想法如下
训练时:真实图片 -> 慢慢加噪声 -> 变成噪声图
生成时:纯噪声 -> 慢慢去噪 -> 变成真实感图片
Diffusion Model 通过反转一个逐步加噪过程来采样。采样从噪声 $x_T$ 开始,逐步得到更少噪声的 $x_{T-1}, x_{T-2}, \cdots$,最后得到样本 $x_0$。每个 Timestep $t$ 对应一个噪声等级,$x_t$ 可以看作原图 $x_0$ 和噪声的混合。
$x_0$:干净图片
$x_1$:加了一点噪声
$x_2$:更多噪声
$\cdots$
$x_T$:几乎纯噪声
模型要学的的是反方向:看到 $x_t$,预测怎么回到 $x_{t-1}$
但论文里采用 Ho et al. 的常见参数化方式:不直接预测 $x_{t-1}$,而是预测噪声 $\epsilon$。也就是:
输入:带噪图片 $x_t$,Timestep $t$
输出:模型认为里面的噪声 $\epsilon_\theta(x_t, t)$
训练目标:让预测噪声接近真实加入的噪声 $\epsilon$
论文里提到,训练时随即取真实样本 $x_0$,随机 Timestep $t$,随机噪声 $\epsilon$,产生 $x_t$,然后用 MSE loss 训练模型预测真实噪声,即 $\Vert \epsilon_\theta(x_t, t) - \epsilon \Vert^2$
Fidelity: 准确度。单张图片看起来有多真、多清晰、多符合类别。比如让模型生成英短猫,生成出来像真的英短,那么 Fidelity 就会高。
Diversity: 模型是不是能覆盖真实数据里的各种变化。比如同样生成猫,不只是生成一种角度、一种姿势、一种背景,而是能够生成各种猫、各种姿态、各种光照、各种构图。
GAN 的问题经常是:Fidelity 高,但是 Diversity 可能差。
Diffusion 的优势是:Diversity / Coverage 好,但以前 Fidelity 不一定打得过 GAN(这篇论文就是想把 Diffusion 的 Fidelity 拉上来,同时保留较好的 Coverage)