笔记|扩散模型(二):DDIM 理论与实现
论文链接:Denoising
Diffusion Implicit Models
在上一篇文章中我们进行了
DDPM 的理论推导,并且自己编写代码实现了 DDPM
的训练和采样过程。虽然取得了还不错的效果,但 DDPM
有一个非常明显的问题:采样过程很慢。因为 DDPM
的反向过程利用了马尔可夫假设,所以每次都必须在相邻的时间步之间进行去噪,而不能跳过中间步骤。原始论文使用了
1000 个时间步,所以我们在采样时也需要循环 1000
次去噪过程,这个过程是非常慢的。
为了加速 DDPM 的采样过程,DDIM 在不利用马尔可夫假设的情况下推导出了
diffusion 的反向过程,最终可以实现仅采样 20~100 步的情况下达到和 DDPM
采样 1000 步相近的生成效果,也就是提速 10~50 倍。这篇文章将对 DDIM
的理论进行讲解,并实现 DDIM 采样的代码。
DDPM 的反向过程
首先我们回顾一下 DDPM 反向过程的推导,为了推导出 \(q(\mathbf{x}_{t-1}|\mathbf{x}_t)\)
这个条件概率分布,DDPM
利用贝叶斯公式将其变成了先验分布的组 ...
笔记|扩散模型(一):DDPM 理论与实现
感谢 qq、wbs、hsh 等读者对本文提出的宝贵意见(大拍手
论文链接:Denoising
Diffusion Probabilistic Models
端午假期卷一卷,开一个新坑系统性地整理一下扩散模型的相关知识。扩散模型的名字来源于物理中的扩散过程,对于一张图像来说,类比扩散过程,向这张图像逐渐加入高斯噪声,当加入的次数足够多的时候,图像中像素的分布也会逐渐变成一个高斯分布。当然这个过程也可以反过来,如果我们设计一个神经网络,每次能够从图像中去掉一个高斯噪声,那么最后就能从一个高斯噪声得到一张图像。虽然一张有意义的图像不容易获得,但高斯噪声很容易采样,如果能实现这个逆过程,就能实现图像的生成。
这个过程可以形象地用上图表示,扩散模型中有两个过程,分别是前向过程(从图像加噪得到噪音)和反向过程(从噪音去噪得到图像)。在上图中,向图像
\(\mathbf{x}_0\)
逐渐添加噪声可以得到一系列的 \(\mathbf{x}_1,\mathbf{x}_2,...,\mathbf{x}_T\),最后的
\(\mathbf{x}_T\)
即接近完全的高斯噪声,这个过程显然是比较容易 ...
笔记|Normalizing Flow 理论与实现(一):基础理论
Normalizing
flow(标准化流)是一类对概率分布进行建模的工具,它能完成简单的概率分布(例如高斯分布)和任意复杂分布之间的相互转换,经常被用于
data generation、density estimation、inpainting 等任务中,例如 Stability
AI 提出的 Stable Diffusion
3 中用到的 rectified flow 就是 normalizing flow 的变体之一。
为了便于理解,在正式开始介绍之前先简要说明一下 normalizing flow
的做法。如上图所示,为了将一个高斯分布 \(z_0\) 转换为一个复杂的分布 \(z_K\),normalizing flow 会对初始的分布
\(z_0\)
进行多次可逆的变换,将其逐渐转换为 \(z_K\)。由于每一次变换都是可逆的,从 \(z_K\) 出发也能得到高斯分布 \(z_0\)。这样,我们就实现了复杂分布与高斯分布之间的互相转换,从而能从简单的高斯分布建立任意复杂分布。
对 diffusion models 比较熟悉的读者可能已经发现了,这个过程和
diffusi ...
技术相关|使用 Pytorch 进行分布式训练
其实 Pytorch 分布式训练已经不算什么新技术了,之所以专门写一篇 blog
是因为今天训模型的时候出现了一个没见过的问题,在调试的时候发现自己平时都是用别人写好的分布式代码,没有深入研究过其中的实现细节,因此感觉有必要整理吸收一下。
最简单的数据并行
作为最简单的并行计算方式,使用 nn.DataParallel
只需要添加一行代码即可完成:
123456module = nn.DataParallel( module, # 原始模型 device_ids=None, # 使用的显卡 output_device=None, # 输出汇总的显卡 dim=0 # Batch 所在维度)
除此之外,其他的部分和单卡训练的内容基本上都相同。在使用
nn.DataParallel
进行训练时,在每次前向传播时,nn.DataParallel
会做以下几件事:
切分数据:对于输入的 Tensor,其会被沿 batch
维度切分成多份,用于输入不同的显卡;对于元组、列表、字典等类型,其会被浅拷贝 ...
技术相关|Linux 虚拟机的安全加固
近期正在部署一个服务,刚刚准备开放公网端口,在开放之前先简单做一下安全加固,以我使用的
Ubuntu 22.04.1 LTS 系统为例。
ssh 加固
更换登录端口
默认的 ssh 端口为 22,为了防止端口扫描&暴力破解,我将 ssh
端口修改为 27001(以此为例)。首先编辑
/etc/ssh/sshd_config:
12# Port 22Port 27001
保存后用 service sshd restart 重启 sshd
服务,即可重置 ssh 端口。
禁用 root 登陆
随后需要禁止 root
账户登陆,首先创建普通用户:useradd -d /home/littlenyima -m littlenyima,然后使用
passwd littlenyima 为新用户创建一个密码。把用户添加到 sudo
用户组:visudo /etc/sudoers
12root ALL=(ALL:ALL) ALLlittlenyima ALL=(ALL:ALL) ALL
然后编辑 /etc/ssh/sshd_config,禁用 root
账户登陆,保存后重启 sshd 服务:
...
技术相关|对 Python built-in pprint 进行拓展
把上一个阶段的工作收尾之后,终于有时间实现一些平时想实现但比较麻烦就一直懒得弄的功能。事情的起因是这样的:刚刚我正在研究
Human3.6M
数据集的标注,这个数据集的标注是一个类似 JSON 的格式。并且除了一般的
JSON 文件结构外,其中还有一些字段的值是高维 numpy
数组。我试着将其中的两项打印出来,命令行瞬间被一大堆各种各样的数值填满了。尽管
IPython Terminal
的输出有自带的格式化功能,但整个输出的格式还是被巨大的数组打乱了。
实际上我平时经常行地遇到这种问题,一般的解决方法是仿照
mmcv.parallel.collate
中的形式写一个递归打印函数,然后把诸如
np.ndarray、torch.Tensor 以及
mmcv.DataContainer 这种高维数据的 __repr__
函数映射为一个形式类似 lambda x: f"{x.shape}, {x.dtype}"
的函数。
这种方式虽然能在一定程度上解决高维数据打印的问题,但是由于函数逻辑未经仔细考虑,打印的效果依然不是非常好,甚至在一些
corner ...
杂谈|还能不能完整听首歌了
本文转载自微信公众号「鸦栖」还能不能完整听首歌了。
前段时间和同学一起去天津转了转,路上聊起已经解散的哪吒乐队和当下搞乐队面临的困境,进而提到了他的一个大学同学。这位同学坚持着在抖音平台上发一些自己弹唱的视频,并且口音有趣会聊天,直播效果不错。后来她差不多算是成为了一个小网红,目前有一百多万粉丝。
在同学的手机上我听了两段她的作品,加起来一共十几秒。听完我陷入了沉思,想当场锐评一下,但想了想感觉说出来就好像是我酸了之后开始冷嘲热讽一样,于是欲言又止。不得不承认,我确实羡慕得不行。这个人唱得怎么样呢?唱得挺好的,音准不错共鸣到位又是网红声线,作为普通人我觉得蛮不错的。有没有缺点呢?也有并且挺明显,气息不太稳(应该是腹部没怎么用力,有的地方声音发颤)并且感觉只是在复刻旋律,没什么个人特点。
当然,仅靠这十几秒很难听出来一个人真正的水平如何,直接评价某某优点某某不足未免过于武断且主观。但我能够确定的是,这不是我想象中百万粉丝的歌手唱出的歌,因此也可以说我就是酸了,怎么唱成这样就能有一百多万粉丝呢??我平时基本不用抖音,所以不是很清楚抖音平台创作者的粉丝体量。不过对比
bilibili 我 ...
杂谈|《波西米亚狂想曲》与流浪者
本文转载自微信公众号「鸦栖」《波西米亚狂想曲》与流浪者。
在开始写正文之前先碎碎念几句,我的公众号又双叒重启了。前两个公众号要么半路弃坑,要么因为想重新规划而注销了,最近又开始想写一些东西,希望这个号可以存活得久一点(x)
这个公众号的名字「鸦栖」来自我在几个月之前做的一个梦:在深蓝色的天空下是铁红色的土地,三个戴着乌鸦面具、身穿皮制长袍的人围着篝火起舞。木柴猛烈燃烧噼啪作响,冒出的火星随着热空气升腾起来。(虽然乌鸦面具是欧洲某个时代的医生的装束,但这个场景更像是某种古老的神秘宗教仪式)
醒来后我便想到了一个与渡鸦有关的名字,但一搜发现已经被注册成商标了,于是我在那个名字的基础上稍作调整变成了现在这个样子。
昨天在学院的晚会上唱了《波西米亚狂想曲》,这首歌有一点难,对于我来说也是一个比较大的挑战。虽然作为乐手上台我已经习以为常,但作为歌手上台演出这还是第一次。一直以来我对歌手的印象都是:只要上台别把词忘了就是成功,但当我自己面对一个舞台的时候,我发现歌手需要考虑的事情也非常多。
不同于在 KTV
想到哪唱到哪,歌手在舞台上不仅需要考虑自己的唱法、真假音切换等一系列技术性问题,还要 ...
技术相关|在内网搭建开发环境
最近依然是在绝赞跑代码做实验,然而因为学长需要在我用的服务器上
debug,所以我换到了组里的另一台机器上。但是这台机器有一个非常坑爹的地方,就是它没法连接外网。我用
ssh 连了一下发现并不能连通,ping
也全是超时,最后先 ssh
到了组里的另一台服务器上,又从这台服务器在内网连,才成功登录。
登录上去后测试了一下网络环境,发现果然只能连接内网,不能连外网。试图定位了一下原因但是无果(感觉很有可能是硬件问题,比如网卡坏了或者机房网线掉了),于是我最后决定通过搭建一系列代理来实现内外网相互连通。下面来记录一下配置的过程,出于安全相关的考虑,以下使用的
ip 地址均为编造的示例地址。
配置正向代理
在内网上,我已经有了一台可以连接外网的机器 A(ip 地址为
192.168.10.1),以及一台无法连接外网,但可以通过内网进行访问的机器
B(ip 地址为 192.168.10.2)。
为了使机器 B 能够访问外网,一个比较直接的方法是以机器 A
作为代理,将流量包在外网和机器 B 之间进行转发。我使用的是轻量级
HTTP/HTTPS 代理 tinyproxy。
首先安装 tinypr ...
技术相关 | 编译 Pytorch 扩展时替换 nvcc 版本
2023-3-28 更新:这一文章中修改 pytorch 源代码的解决方式在 pytorch
最新的发行版(预计为 2.1.0 版本)中将过时。大约一周之前 pytorch
的主分支合并了 一个 pull
request,其对通过修改环境变量来指定 nvcc 提供了支持,现在只需将 nvcc
路径赋值给 $PYTORCH_NVCC 即可。
今天解决了一个有点复杂的环境问题,记录一下解决的过程。
在复现 ReferFormer
时,需要编译一个 Deformable Attention
算子。在编译的过程中,nvcc 使用了一个叫做
--generate-dependencies-with-compile 的
flag。非常不幸的是,我现有开发环境中的 nvcc 并不支持这一个
flag,导致我无法编译这个算子。为了解决这个问题,我首先确定了现有的
nvcc 版本:
1234nvcc: NVIDIA (R) Cuda compiler driverCopyright (c) 2005-2019 NVIDIA CorporationBuilt on Fri_Feb__8_19:08:1 ...