自动编码器与图像操作:风格迁移与深度伪造
立即解锁
发布时间: 2025-09-01 01:17:03 阅读量: 3 订阅数: 12 AIGC 


现代计算机视觉与PyTorch
# 自动编码器与图像操作:风格迁移与深度伪造
## 1. 理解神经风格迁移
想象一下,你想绘制一幅梵高风格的图像。在这种情况下,神经风格迁移就派上用场了。神经风格迁移结合内容图像和风格图像,使合成图像在保留内容图像内容的同时,呈现风格图像的风格。
### 1.1 神经风格迁移的工作原理
我们有一个风格图像和一个内容图像,目标是保留内容图像的内容,并叠加风格图像的颜色和纹理。其过程如下:
1. 尝试修改原始图像,将损失值分为内容损失和风格损失。内容损失衡量生成图像与内容图像的差异,风格损失衡量风格图像与生成图像的相关性。
2. 实际中,损失计算基于图像的特征层激活值,而非原始图像。例如,第 2 层的内容损失是内容图像和生成图像在通过第 2 层时激活值的平方差。这是因为特征层捕捉了原始图像的某些属性,较高层对应原始图像前景的轮廓,较低层对应细粒度对象的细节。
### 1.2 风格损失的计算:Gram 矩阵
计算生成图像和风格图像的相似度时,Gram 矩阵很有用。Gram 矩阵的计算公式如下:
\[
L_{GG}(Style) = \frac{1}{4N_l^2M_l^2} \sum_{ij}(G_{GlS_{ij}} - G_{GlG_{ij}})^2
\]
其中,$GM_l$ 是风格图像 $S$ 和生成图像 $G$ 在第 $l$ 层的 Gram 矩阵值,$N_l$ 是特征图的数量,$M_l$ 是特征图的高度乘以宽度。
Gram 矩阵是通过矩阵与其转置相乘得到的。例如,对于一个特征输出为 32 x 32 x 256 的层,Gram 矩阵计算每个通道中 32 x 32 值与所有通道值的相关性,结果是一个 256 x 256 的矩阵。我们比较风格图像和生成图像的 256 x 256 值来计算风格损失。
Gram 矩阵在风格迁移中很重要,因为在成功的风格迁移中,目标图像的局部特征应与风格图像相似。即使内容不同,让目标图像具有与风格图像相似的颜色、形状和纹理是风格迁移的关键。
### 1.3 执行神经风格迁移的策略
实现神经风格迁移的高级策略如下:
1. 将输入图像通过预训练模型。
2. 提取预定义层的层值。内容损失通过比较内容图像和生成图像的特征激活差异来计算,风格损失通过先计算预定义层的 Gram 矩阵,再比较生成图像和风格图像的 Gram 矩阵来计算。
3. 将生成图像通过模型,提取相同预定义层的值。
4. 计算每个层对应内容图像和生成图像的内容损失。
5. 将风格图像通过模型的多个层,计算风格图像的 Gram 矩阵值。
6. 将生成图像通过与风格图像相同的层,计算其对应的 Gram 矩阵值。
7. 提取两个图像 Gram 矩阵值的平方差,得到风格损失。
8. 总体损失是风格损失和内容损失的加权平均值。
9. 使总体损失最小的生成图像就是最终感兴趣的图像。
### 1.4 代码实现
以下是实现上述策略的代码:
```python
# 1. 导入相关包
!pip install torch_snippets
from torch_snippets import *
from torchvision import transforms as T
from torch.nn import functional as F
device = 'cuda' if torch.cuda.is_available() else 'cpu'
# 2. 定义数据预处理和后处理函数
from torchvision.models import vgg19
preprocess = T.Compose([
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
T.Lambda(lambda x: x.mul_(255))
])
postprocess = T.Compose([
T.Lambda(lambda x: x.mul_(1./255)),
T.Normalize(mean=[-0.485/0.229, -0.456/0.224, -0.406/0.225], std=[1/0.229, 1/0.224, 1/0.225])
])
# 3. 定义 GramMatrix 模块
class GramMatrix(nn.Module):
def forward(self, input):
b, c, h, w = input.size()
feat = input.view(b, c, h * w)
G = feat @ feat.transpose(1, 2)
G.div_(h * w)
return G
# 4. 定义 Gram 矩阵的 MSE 损失,GramMSELoss
class GramMSELoss(nn.Module):
def forward(self, input, target):
out = F.mse_loss(GramMatrix()(input), target)
return out
# 5. 定义模型类,vgg19_modified
class vgg19_modified(nn.Module):
def __init__(self):
super().__init__()
features = list(vgg19(pretrained=True).features)
self.features = nn.ModuleList(features).eval()
def forward(self, x, layers=[]):
order = np.argsort(layers)
_results, results = [], []
for ix, model in enumerate(self.features):
x = model(x)
if ix in layers:
_results.append(x)
for o in order:
results.append(_results[o])
return results if layers is not [] else x
vgg = vgg19_modified().to(device)
# 6. 导入内容和风格图像
!wget https://www.dropbox.com/s/z1y0fy2r6z6m6py/60.jpg
!wget https://www.dropbox.com/s/1svdliljyo0a98v/style_image.png
# 7. 确保图像调整为相同形状,512 x 512 x 3
imgs = [Image.open(path).resize((512, 512)).convert('RGB') for path in ['style_image.png', '60.jpg']]
style_image, content_image = [preprocess(img).to(device)[None] for img in imgs]
# 8. 指定内容图像可修改
opt_img = content_image.data.clone()
opt_img.requires_grad = True
# 9. 指定定义内容损失和风格损失的层
style_layers = [0, 5, 10, 19, 28]
content_layers = [21]
loss_layers = style_layers + content_layers
loss_fns = [GramMSELoss()] * len(style_layers) + [nn.MSELoss()] * len(content_layers)
loss_fns = [loss_fn.to(device) for loss_fn in loss_fns]
# 10. 定义内容和风格损失的权重
style_weights = [1000 / n ** 2 for n in [64, 128, 256, 512, 512]]
content_weights = [1]
weights = style_weights + content_weights
# 11. 计算风格目标值和内容目标值
style_targets = [GramMatrix()(A).detach() for A in vgg(style_image, style_layers)]
content_targets = [A.detach() for A in vgg(content_image, content_layers)]
targets = style_targets + content_targets
# 12. 定义优化器和迭代次数
max_iters = 500
optimizer = optim.LBFGS([opt_img])
log = Report(max_iters)
# 13. 执行优化
iters = 0
while iters < max_iters:
def closure():
global iters
iters += 1
optimizer.zero_grad()
out = vgg(opt_img, loss_layers)
layer_losses = [weights[a] * loss_fns[a](A, targets[a]) for a, A in enumerate(out)]
loss = sum(layer_losses)
loss.backward()
log.record(pos=iters, loss=loss, end='\r')
return loss
optimizer.step(closure)
# 14. 绘制损失变化图
log.plot(log=True)
# 15. 绘制内容和风格图像组合的图像
with torch.no_grad():
out_img = postprocess(opt_img[0]).permute(1, 2, 0)
show(out_img)
```
### 1.5 神经风格迁移流程
```mermaid
graph LR
A[输入内容图像和风格图像] --> B[通过预训练模型]
B --> C[提取预定义层值]
C --> D[计算内容损失和风格损失]
D --> E[优化图像使
```
0
0
复制全文
相关推荐









