CS Graphics

Computer Graphics and Diffusion Learning

PyTorch

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 模块提供了几种常用的转换。

构建神经网络

神经网络由执行数据操作的层 / 模块组成。神经网络本身就是一个由其他模块组成的模块,这种嵌套结构允许轻松构建和管理复杂的架构

这个东西本质上就是对输入的图片数字化之后进行一些运算,转化出来一个对应不同结果的概率,大概流程:

  1. 图片数字化:将图片转成代表颜色深浅的数字矩阵($0-255$)
  2. 运算(Linear 线性层):就是做 $y=wx+b$,把输入的像素值乘权重 $w$,加上偏置 $b$
  3. 转化(ReLU 激活层):就是 $y=max(0,x)$
  4. 输出概率(Softmax):把这一堆算出来的“得分”,按照比例压缩到 $0-1$ 之间,哪个概率最大就猜他是谁

ReLU:本质上就是把直线折断,因为如果没有这个过程的话,不管叠加多少次 $y=wx+b$,它始终都可以合并成一个直线方程,实际上是没办法用直线来呈现现实世界图案,但简单的遇负归零动作可以让他拼接成复杂形状曲线。

自动微分

在训练神经网络时,最常用的算法是反向传播,模型的参数会根据损失函数相对于给定参数的梯度进行调整

为了计算这些梯度,PyTorch 提供了一个内置的微分引擎,即 torch.autograd

优化模型参数

所谓人工智能学习或者大模型训练,本质上就是暴力试错+疯狂微调,也就是常说的监督学习(Supervised Learning),其过程其实是:

  1. 向前传播(Forward Pass):其实就是瞎猜,一开始模型里的参数(所有的权重 $w$ 和 偏置 $b$ 全都是随机生成的数字
  2. 计算损失(Loss):这部分就是对答案并算分,用事先准备好的正确答案(标签 Label),跟机器瞎猜的结果做对比。错的越离谱,系统给出的惩罚分数(Loss 值)就越高
  3. 反向传播与梯度下降(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 里:

  1. 更好的架构
  2. 一个可以调节 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)