本文主要讲述了向量生成图像的原理、限制及训练方法。首先介绍了向量生成图像的基本原理和局限性。此外,通过约束向量和图像token化,实现了向量的非连续化,使得每个向量对应一个具体的图像特征。最后,详细阐述了训练过程中的关键概念、目标和流程,包括训练的必要性、训练目标和流程,以及解决训练过程中问题的方法,如使用神经网络预测像素和逐步学习预测像素的能力。
图像编码
图像编码与解码过程
- 图像编码: 将一张图片(如250x250)输入Encoder(可以是CNN、DNN或Transformer等),编码成一个256维的向量。
- 图像解码: 使用decoder将256维的向量解码回原始尺寸的图像(250x250)。
- 实现目标: 使得编码解码后的图像与原始图像的差异(x-x’)趋向于零,即尽可能保留核心信息,去除冗余信息。
- 有损压缩: 由于解码后的图像不可能完全与原始图像一致,因此这种压缩方式称为有损压缩,但目标是使信息损失尽可能少。
图像编码的应用与局限性
- 应用场景: 图像编码可以用于以图搜图,即如果两张图片压缩后的信息相似度非常高,可以认为它们的原图在语义上有某种相似。
- 局限性: 图像编码不能做生成。因为解码器的训练只是针对特定范围的向量,随机生成的向量可能超出解码器的范围,导致无法解码。
- 原因: 解码器的设计只是针对训练样本中对应的压缩向量,没有覆盖到全部的空间。因此,随机生成的向量可能无法被正确解码。
VAE模型
VAE损失函数
- 损失函数组成: VAE的损失函数由两部分组成,一部分是重构损失(L2损失),另一部分是KL散度损失。
- 重构损失: 用于衡量生成图像与原始图像之间的差异。
- KL散度损失: 用于衡量潜在空间分布与标准正态分布之间的差异。
损失函数:
VAE训练过程
- 编码器:编码器网络通过多层卷积神经网络(CNN)将输入图像转换为潜在空间的均值和方差向量。
- 均值向量: 通过线性层从编码器的特征图中生成。
- 方差向量: 同样通过线性层从编码器的特征图中生成。
- 解码器: 解码器网络通过反卷积操作将潜在空间的向量还原为图像。
- 重参数技巧: 为了使模型可训练,采用重参数技巧,将潜在空间的采样过程转化为可导的形式,其中∈是标准正态分布采样的噪声。
训练步骤
- 前向传播: 输入图像通过编码器得到均值和方差,通过重参数技巧采样得到潜在向量,再通过解码器还原为图像。
- 计算损失: 根据重构损失和KL散度损失计算总损失。
- 反向传播: 通过优化器更新模型参数。
def forward(self, x):
# 编码器: 从图像中获得均值和方差
mu,log_var=self.encode(x)
# 采样Z
z=self.reparameters(mu, log_var)
# Z还原成图像
y= self.decode(z)
return y,mu, log_var
VAE应用案例
- 生成图像: 训练完成后,VAE模型可以从标准正态分布中随机采样潜在向量,通过解码器生成新的图像。
- 生成效果: 生成的图像与手写数字图像非常相似,证明了VAE模型在图像生成任务中的有效性。
- 模型局限性: 尽管VAE在图像生成方面表现出色,但它并不是完美的,存在一些问题,如潜在空间向量可能不是连续的特征表示。
def_init_ (self, input_dim,dim,n_embedding):
super()._init_ ()
self.encoder = nn.Sequential(nn.conv2d(input_dim, dim,4,2,1),
nn.ReLu(),nn.conv2d(dim,dim,4,2,1),
nn.ReLU(),nn.conv2d(dim,dim,3,1,1),
ResidualBlock(dim),ResidualBlock(dim))
self,vq_embedding=nn.Embedding(n_embedding, dim)
self.vg_embedding.weight.data.uniform (-1.0/n_embedding,
1.0 /n_embedding)
self.decoder = Sequential(
nn.conv2d(dim,dim,3,1,1),
ResidualBlock(dim),ResidualBlock(dim),
nn.ConvTranspose2d(dim,dim,4,2,1),nn.ReLU(),
nn.convTranspose2d(dim,input dim,4,2,1))
self.n downsample=2
...
VQ-VAE
基本概念
向量表示: VQ-VAE中的向量是连续向量。
Encoder与Decoder: Encoder将输入数据编码为连续向量z,其中z~N( ų, ∂²);Decoder则尝试从向量z中重构出原始数据,通过最小化来优化。
正态分布选择原因:
- 解析形式简单,便于后续运算。
- 定义域为负无穷到正无穷,具有广泛的适用性。
- 中心极限定理表明,大量样本的均值分布趋于正态分布。
VQ-VAE的实际应用问题
连续向量与实际应用的不匹配: 在实际应用中,我们希望编码器输出的码具有实际的物理意义,而非仅仅是连续向量。
VQ-VAE的改进:引入非连续化token
- 非连续化token的引入:为了使编码器的输出更具实际意义,VQ-VAE引入了非连续化的token,如性别、年龄、体型等属性。
- 示例说明: 以一幅体型普通的青年男子画像为例,我们希望编码器能够输出表示性别(男/女)、年龄(少年/青年/壮年/老年)和体型(瘦弱/普通/肥胖/强壮)的非连续化token,而不是连续的数值。
- VQ-VAE的作用: VQ-VAE通过引入量化步骤,将连续的向量空间转换为离散的token空间,从而实现了对数据的更有效编码和解码。
VQ-VAE的工作原理
工作原理概述: VQ-VAE通过Encoder将输入数据编码为连续向量,然后经过量化步骤将这些向量转换为离散的token。Decoder则负责从这些token中重构出原始数据。
量化步骤的关键性: 量化步骤是VQ-VAE的核心,它确保了编码器的输出具有实际的物理意义和可解释性。通过量化,我们可以将连续的向量空间映射到有限的token集合上,从而简化了后续的处理和分析。
VQ-VAE流程概述
- 输入图像: 首先输入一张图像。
- Encoder处理: 图像经过Encoder处理,被分成多个区域(token)。
- Token向量化: 每个区域(token)对应一个特定的向量。
- 向量解码: 这些向量通过Decoder可以复原出原始图像。
与VAE的对比: VQ-VAE相对于VAE多了一个token化的步骤。
- Token化过程
- Token化定义:将图像经过Encoder处理后得到的区域(或特征)转化为离散的token。
- 向量对应:每个token对应一个特定的向量。
- 多分类问题:通过softmax等操作,将每个区域的特征分类到最近的token(即进行多分类)。
- Embedding空间:分类后的token在embedding空间中找到对应的向量。
- 向量转换与解码
- 向量转换:图像经过token化后,每个token对应一个向量,这些向量放在一起形成向量序列。
- 解码过程:向量序列通过Decoder可以复原出原始图像。
- 向量个数与图像关系:向量的个数与图像大小、划分区域有关。
与K-means的类比
K-means原理: K-means算法通过找到数据点的中心点,用中心点的向量来代表一类数据的向量。
VQ-VAE与K-means的类比:
编码器输出向量:相当于K-means中的数据点。
Embedding空间中的向量:相当于K-means中的中心点。
Token化过程:相当于每个数据点找到最近的中心点,并用中心点的向量来表示。
流程相似性:vQ-VAE中的token化、向量化、解码过程与K-means的聚类、代表、复原过程有一定的相似性。
流程优化与理解
流程优化: 从训练角度看,VQ-VAE的流程中有些地方可能显得冗余,如先token化再找到向量,但实际上这是一个向量到向量的转换过程。
核心内容: 关键在于理解图像如何被token化,以及token如何对应到向量,并通过解码复原图像。
流程总结: 输入图像 -> Encoder处理 -> 找最近的向量 -> 解码复原图像,关键在于token化、向量化、解码这三个核心步骤。
VQ-VAE训练组件
Encoder:需要训练,是vQ-VAE模型中的一个重要组件。
Decoder:同样需要训练,与Encoder共同构成vQ-VAE模型的核心。
Embedding Space:对应的向量空间,也是需要训练的部分。
训练目标
图像完全恢复:第一个训练目标是希望图像能够完全恢复,即存在函数使图像得以复原。
聚类接近: 第二个训练目标是希望每个Zê离对应的中心点尽可能接近,以实现更好的聚类效果。
训练中的问题与解决方法
问题: 在训练过程中,存在一个跳跃性的东西,即找到最近的点直接用最近的替代,这导致导数不存在。
影响: 导数不存在意味着无法使用梯度下降法进行优化。
思考: 如果要拓展训练方法,需要思考如何在没有导数的情况下进行有效的训练。
VQ-VAE损失函数
- 重建损失函数
定义: 重建损失函数用于衡量输入图像x与通过解码器重构的图像之间的差异。
问题: 在训练过程中,由于Zq是通过最近邻搜索得到的,因此不可导,导致梯度无法回传。
- 梯度阻断法
定义: 梯度阻断法是一种解决不可导问题的技巧,通过在前向传播时正常计算,反向传播时忽略特定部分的梯度。
sg函数: sg(stop gradient)函数在前向传播时正常计算,反向传播时忽略其梯度,确保训练过程不受影响。 - 嵌入空间优化
目标: 使编码器的输出Ze(x)与量化向量Zq(x)尽可能接近,优化嵌入空间。
损失函数: 嵌入空间优化损失函数为:
训练过程: 在训练过程中,固定Zq,通过调整编码器来使Ze接近,类似于Word2Vec训练embedding的过程。 - 总损失函数
组成:VQ-VAE的总损失函数由重建损失函数和嵌入空间优化损失函数两部分组成。
公式:总损失函数为重建损失与嵌入空间优化损失之和,即整体优化目标。
训练流程:
第一步,通过梯度阻断法训练重建损失,使输入图像x与重构图像尽可能接近。
第二步,优化嵌入空间,使编码器的输出与量化向量尽可能接近,通过固定Zq调整编码器实现。
核心问题:Zq的导数无法回传,需采用特殊训练方法解决。
VQ-VAE模型推理
模型训练与编码过程:
- 模型训练: 训练vQ-VAE模型,使其能够学习图像的编码和解码过程。
- 编码过程: 通过编码器(Encoder)将图像转换成向量序列,这个向量序列是离散的,并且每个向量都对应于一个特定的token。
向量序列与embedding space:
- 向量序列:编码后的图像表示为一系列向量,这些向量在embedding space中有对应的位置。
- embedding space:是一个向量空间,其中每个点都代表一个可能的token或向量。在VQ-VAE中,通过查找最近的点来找到编码向量对应的token。
vq-vae模型生成图像的问题:
- 生成问题: VQ-VAE模型虽然可以将图像编码为向量序列,并找到对应的token,但在生成新图像时存在问题。
- 原因:生成新图像需要知道向量在embedding space中的分布,但VQ-VAE模型并不知道这个分布,因此无法从无到有地生成新图像。
- 示例:如果想生成一个新的图像,需要随机选择一个token,但由于不知道分布,所以无法确定这个token在embedding space中的位置,也就无法生成对应的图像。
. vq-vae模型的局限性:
- 局限性:VQ-VAE模型只能对图像进行token化,即将图像转换成一系列token,但不能用于生成新图像。
- 原因:如前所述,模型不知道向量在embedding space中的分布,因此无法生成新的、合理的向量序列来对应到新的图像。
- 对比:与传统的VAE模型相比,VQ-VAE多了Token化的步骤,但这也带来了生成能力上的限制。
- 训练过程:在训练过程中,模型通过最小化编码后的向量与原始图像之间的重构误差来优化参数。但由于不知道分布,所以无法生成新的图像。
- 解决思路:若要让VQ-VAE具有生成能力,需要找到一种方法来学习或估计向量在embedding space中的分布。然而,这在实际操作中是非常困难的,也是VQ-VAE模型的一个主要局限性。
PixelCNN
定义: PixelCNN是一种将图像当成GPT来进行生成的模型。
核心思想: 把图像当成GPT来进行生成,通过预测图像中的像素值来逐步构建整张图像。
像素预测过程: PixelCNN通过已知的前几个区域的像素值,利用卷积神经网络和softmax函数预测下一个像素的值。像素值有256个取值可能,因此预测结果是一个1到256的概率分布。假设已知一张黑白图像前四个区域的像素值,通过PixelCNN可以预测出第五个区域的像素值,然后依次预测后续像素,直至恢复出整张图像。
方法: 在训练时,第一个像素是随机生成的。在推理时,也需要随机生成第一个像素作为起点。
卷积的特殊设计
正常的卷积神经网络可以看到一个点周围的所有点,但PixelCNN在预测时不能“看到”当前像素及其之后的像素。因此,PixelCNN的卷积需要做特殊处理,即进行遮挡(mask),确保在预测当前像素时只能看到其前面的像素。
例如:A类卷积在第一次卷积时只能看到前面的点,看不到自己;B类卷积在后续卷积时能看到自己。PixelCNN结合了A类和B类卷积,以确保既能逐步预测像素,又不会漏看或多看信息。
训练过程与交叉熵损失函数
训练过程:
输入九个像素,通过PixelCNN预测九个像素的概率分布,与真实像素值进行比较,通过交叉熵损失函数优化模型。
交叉熵损失函数:
用于衡量预测概率分布与真实概率分布之间的差异,通过最小化交叉熵损失来训练模型。
像素CNN在图像生成中的应用
图像token化:如果图像被token化,PixelCNN仍然可以应用。此时,模型预测的是token的概率分布,而不是像素值。
流程: 训练一个像素CNN模型,输入token化的图像,模型会预测下一个token,然后逐步恢复出整个图像的token序列,进而恢复出图像。
优势: 只需要随机生成第一个token,然后通过PixelCNN就可以逐步恢复出整个图像的分布,无需随机整个图像的tokens。
代码实现:通过Python和PyTorch实现PixelCNN的训练和推理过程,包括加载模型、采样图像、显示图像等步骤。
核心代码
- VQ-VAE模型训练步骤:VQ-VAE模型的训练分为四个主要步骤,包括训练VQ-VAE模型、测试VQ-VAE模型通过可视化重建结果、训练生成模型(在本项目中使用Gated PixelCNN)、以及采样VQ-VAE。
- Token与Embedding关系:VQ-VAE模型包含encoder、decoder以及token对应的向量(即embedding)。Encoder将图像转换为离散的token序列,而decoder则将这些token序列还原为图像。Token对应的向量(embedding)在训练过程中学习如何最好地表示这些token。
- 前向传播过程
- Encoder: 输入图像x通过encoder生成连续的特征表示ze。
- Token化: ze通过查找最近邻的embedding向量被量化为离散的token序列zq。
- Decoder输入: Decoder的输入是ze与(zq - ze)的和,其中(zq - ze)部分被detach以停止梯度流动,这主要是为了反向传播时方便求导。
- 重建图像: Decoder最终输出重建的图像x_hat。
vqvae =VQVAE(img_shape[0],cfg['dim'], cfg['n_embedding']).cuda()
gen model = PixelcNNwithEmbedding(cfg['pixelcnn_n blocks"],
cfg['pixelcnn_dim'],
cfg['pixelcnn linear_ dim'], True,
cfg['n_embedding']).cuda()
# 1. Train VQVAE
train_vqvae(vqvae,
img_shape=(img_shape[1], img_shape[2]),
device=device,
ckpt_path=cfg['vqvae_path'],
batch_size=cfg['batch_size'],
dataset_type=cfg['dataset_type'],
lr=cfg['lr'],
n_epochs=cfg['n_epochs'],
1_w_embedding=cfg['l_w_embedding'],
1_w_commitment=cfg['l_w_commitment'])
# 2.Test VOVAE by visualizaing reconstruction result
vqvae.load_state_dict(torch.load(cfg['vqvae_path']))
dataloader = get_dataloader(cfg['dataset type'],
16,
img_shape=(img_shape[1], img_shape[2]))
img = next(iter(dataloader)).to(device)
reconstruct(vqvae,img,device, cfg['dataset_type'])
#3.Train Generative model(Gated pixelcNN in our project )
vqvae.load_state_dict(torch.load(cfg['vqvae_path']))
train_generative_model( vqvae,
gen_model,
img_shape=(img_shape[1],img_shape[2]),
device=device,
ckpt_path=cfg['gen_model_path'],
dataset_type=cfg['dataset_type'],
batch_size=cfg['batch_size_2'],
n_epochs=cfg['n_epochs_2'])
# 4. Sample VQVAE
vqvae.load_state_dict(torch,load(cfg['vqvae_path']))
gen_model.load_state_dict(torch.load(cfg['gen_model path']))
sample_imgs(vqvae,
gen_model,
cfg['img_shape'],
device=device,
dataset_type=cfg['dataset_type'])
重建效果
通过展示输入图像与重建图像的对比,可以直观地看到VQ-VAE模型在图像重建任务上的表现。例如,输入数字"3”的图像,重建后依然能够清晰辨认出是数字“3”。
生成模型训练
- 生成模型目标: 在VQ-VAE模型训练完成后,需要进一步训练生成模型(如PixelCNN),以便能够生成新的图像。
- 训练数据:生成模型的训练数据是VQ-VAE模型编码后的token序列。
训练过程:
- 输入: PixelCNN的输入是VQ-VAE编码后的token序列。
- 预测: PixelCNN通过自回归的方式逐个像素地预测图像中的下一个token。
- 损失函数: 使用交叉熵损失函数来衡量预测token与真实token之间的差异,并通过优化器(如Adam)来更新模型参数。
采样策略:在采样阶段,可以采用不同的初始化策略,例如全一向量或从真实图像中采样第一个token,然后通过PixelCNN逐像素生成剩余的token,最终得到生成的图像。