自动编码器与图像操作:从聚类到生成与攻击
立即解锁
发布时间: 2025-09-06 00:06:05 阅读量: 17 订阅数: 44 AIGC 


现代计算机视觉与PyTorch
### 自动编码器与图像操作:从聚类到生成与攻击
#### 1. 卷积自动编码器与图像预测
卷积自动编码器在图像预测方面比普通自动编码器表现更优,能做出更清晰的图像预测。你可以尝试改变编码器和解码器中的通道数量,并分析结果的变化。
#### 2. 使用t - SNE对相似图像进行分组
在之前的内容中,我们假设相似图像会有相似的嵌入表示,不同图像则有不同的嵌入表示,并将每个图像表示为低维向量。但尚未详细研究图像相似度度量和嵌入表示。
这里,我们将使用t - SNE技术把卷积自动编码器的64维瓶颈向量降维到二维空间,使相似的数据点聚集在一起,不同的数据点远离彼此。具体步骤如下:
1. 初始化列表以存储潜在向量和图像的对应类别:
```python
latent_vectors = []
classes = []
```
2. 遍历验证数据加载器中的图像,存储编码器层的输出和每个图像的对应类别:
```python
for im,clss in val_dl:
latent_vectors.append(model.encoder(im).view(len(im),-1))
classes.extend(clss)
```
3. 拼接潜在向量的NumPy数组:
```python
latent_vectors = torch.cat(latent_vectors).cpu().detach().numpy()
```
4. 导入t - SNE并指定将向量转换为二维向量:
```python
from sklearn.manifold import TSNE
tsne = TSNE(2)
```
5. 对图像嵌入执行t - SNE的拟合变换:
```python
clustered = tsne.fit_transform(latent_vectors)
```
6. 绘制拟合t - SNE后的数据点:
```python
fig = plt.figure(figsize=(12,10))
cmap = plt.get_cmap('Spectral', 10)
plt.scatter(*zip(*clustered), c=classes, cmap=cmap)
plt.colorbar(drawedges=True)
```
通过上述操作,我们可以看到同一类别的图像聚集在一起,这证明了瓶颈层的值使得相似图像具有相似的值。
#### 3. 理解变分自动编码器(VAEs)
##### 3.1 VAEs的需求
在之前的聚类场景中,当嵌入向量处于两个聚类之间时,无法保证能生成逼真的图像。VAEs可以解决这个问题,它能生成均值为0、标准差为1的向量,从而确保生成的图像也具有这样的统计特性。
为了说明普通方法的局限性,我们按以下步骤生成图像:
1. 计算验证图像的潜在向量:
```python
latent_vectors = []
classes = []
for im,clss in val_dl:
latent_vectors.append(model.encoder(im))
classes.extend(clss)
latent_vectors = torch.cat(latent_vectors).cpu().detach().numpy().reshape(10000, -1)
```
2. 生成随机向量:
```python
rand_vectors = []
for col in latent_vectors.transpose(1,0):
mu, sigma = col.mean(), col.std()
rand_vectors.append(sigma*torch.randn(1,100) + mu)
```
3. 绘制重构图像:
```python
rand_vectors=torch.cat(rand_vectors).transpose(1,0).to(device)
fig,ax = plt.subplots(10,10,figsize=(7,7)); ax = iter(ax.flat)
for p in rand_vectors:
img = model.decoder(p.reshape(1,64,2,2)).view(28,28)
show(img, ax=next(ax))
```
从输出结果可以看出,生成的图像不如之前清晰,因为我们事先不知道能生成逼真图像的嵌入向量范围。
##### 3.2 VAEs的工作原理
VAEs构建网络的方式使得从预定义分布生成的随机向量能够生成逼真的图像。具体策略如下:
1. 编码器为每个图像输出两个向量,一个表示均值,另一个表示标准差。
2. 从这两个向量中获取一个修改后的向量,它是均值与标准差乘以一个随机小数的和,且修改后的向量与原向量维度相同。
3. 将修改后的向量作为输入传递给解码器以获取图像。
4. 优化的损失值是KL散度损失和均方损失的组合:
- KL散度损失:衡量均值向量和标准差向量的分布与0和1的偏差。
- 均方损失:用于重构(解码)图像的优化。
##### 3.3 KL散度
KL散度用于解释两组数据分布之间的差异。在我们的场景中,希望瓶颈特征值遵循均值为0、标准差为1的正态分布,因此使用KL散度损失来衡量瓶颈特征值与预期分布的差异。其计算公式为:
\[
KL divergence = \frac{1}{n} \sum_{i=1}^{n} \left( \frac{\sigma_{i}^{2} + \mu_{i}^{2}}{2} - \log(\sigma_{i}) - \frac{1}{2} \right)
\]
其中,\(\sigma\)和\(\mu\)分别表示每个输入图像的均值和标准差。通过最小化均方误差确保均值向量分布在0附近,通过公式中的其他项确保标准差向量分布在1附近。
##### 3.4 构建VAE
以下是构建VAE以生成手写数字新图像的代码:
1. 安装必要的库并加载数据:
```python
!pip install -q torch_snippets
from torch_snippets import *
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torchvision.utils import make_grid
device = 'cuda' if torch.cuda.is_available() else 'cpu'
train_dataset = datasets.MNIST(root='MNIST/', train=True, transform=transforms.ToTensor(), download=True)
test_dataset = datasets.MNIST(root='MNIST/', train=False, transform=transforms.ToTensor(), download=True)
train_loader = torch.utils.data.DataLoader(dataset = train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset= test_dataset, batch_size=64, shuffle=False)
```
2. 定义VAE神经网络类:
```python
class VAE(nn.Module):
def __init__(self, x_dim, h_dim1, h_dim2, z_dim):
super(VAE, self).__init__()
self.d1 = nn.Linear(x_dim, h_dim1)
self.d2 = nn.Linear(h_dim1, h_dim2)
self.d31 = nn.Linear(h_dim2, z_dim)
self.d32 = nn.Linear(h_dim2, z_dim)
self.d4 = nn.Linear(z_dim, h_dim2)
self.d5 = nn.Linear(h_dim2, h_dim1)
self.d6 = nn.Linear(h_dim1, x_dim)
def encoder(self, x):
h = F.relu(self.d1(x))
h = F.relu(self.d2(h))
return self.d31(h), self.d32(h)
def sampling(self, mean, log_var):
std = torch.exp(0.5*log_var)
eps = torch.randn_like(std)
return eps.mul(std).add_(mean)
def decoder(self, z):
h = F.relu(self.d4(z))
h = F.relu(self.d5(h))
return F.sigmoid(self.d6(h))
def forward(self, x):
mean, log_var = self.encoder(x.view(-1, 784))
z = self.sampling(mean, log_var)
return self.decoder(z), mean, log_var
```
3. 定义训练和验
0
0
复制全文
相关推荐








