为什么我的纹理合成算法只产生块状/嘈杂、不合理的输出?



我的最终目标是创建一个用于神经风格迁移的脚本,但是,在为所述任务编写代码时,我偶然发现了某个问题:算法的纹理合成部分似乎在再现艺术风格方面存在一些问题。为了解决这个问题,我决定创建另一个脚本,尝试使用神经网络自行解决纹理合成的任务。

TL;博士。。。即使在自己解决了问题之后,我的脚本仍然会产生块状/嘈杂、不合理的输出。

我试着看看其他人是如何解决这个任务的,但我发现的大多数都是更复杂的解决方案("快速神经风格转移"等(。另外,我找不到太多的PyTorch实现。

由于我已经花了几天时间尝试解决这个问题,并且考虑到我是PyTorch框架的新手,我决定向StackOverflow社区寻求帮助和建议。 😐

我为我的模型使用 VGG16 网络...

class VGG16(nn.Module):
def __init__(self):
super(VGG16, self).__init__()
vgg_fs = models.vgg16(pretrained=True).features
self.sl1 = nn.Sequential()
self.sl2 = nn.Sequential()
self.sl3 = nn.Sequential()
self.sl4 = nn.Sequential()
self.sl5 = nn.Sequential()
for i in range(4):
self.sl1.add_module(str(i), vgg_fs[i])
for i in range(4, 9):
self.sl2.add_module(str(i), vgg_fs[i])
for i in range(9, 16):
self.sl3.add_module(str(i), vgg_fs[i])
for i in range(16, 23):
self.sl4.add_module(str(i), vgg_fs[i])
for i in range(23, 30):
self.sl5.add_module(str(i), vgg_fs[i])
for p in self.parameters():
p.requires_grad_(False)
def forward(self, x):
h = self.sl1(x)
h1 = h
h = self.sl2(h)
h2 = h
h = self.sl3(h)
h3 = h
h = self.sl4(h)
h4 = h
h = self.sl5(h)
h5 = h
return_tuple = namedtuple('hidden_states', ['h1', 'h2', 'h3', 'h4', 'h5'])
ret = return_tuple(h1, h2, h3, h4, h5)
return ret

然后,我有一些用于语法矩阵计算和归一化的函数......

def comp_gram(f):
(b, c, h, w) = f.shape
f = f.view(b, c, h * w)
g = f.bmm(f.transpose(1, 2)) 
g = g / (c * h * w)
return g
def norm(b):
mean    = torch.Tensor([0.485, 0.456, 0.406]).cuda().view(3, 1, 1)
std     = torch.Tensor([0.229, 0.224, 0.225]).cuda().view(3, 1, 1)
return (b - mean) / std

最后,我的训练功能...

def train(model, style_img, w=224, h=224, iters=32, lr=1):
style = torch.from_numpy(np.array(Image.open(style_img))).cuda().float()
style = style / 255.
style = style.view(1, style.size()[2], *style.size()[:2])
style_fts = model(norm(style))
style_gms = [comp_gram(f) for f in style_fts]
img = torch.rand(*style.size()[:2], h, w, requires_grad=True, device='cuda')
optimizer = optim.Adam([img], lr=lr)
mse_loss = nn.MSELoss()
plt.ion()
for i in range(iters):
optimizer.zero_grad()
actvs = model(norm(img))
lss = 0.
for f, gm in zip(actvs, style_gms):
g = comp_gram(f)
lss += mse_loss(g, gm)
lss.backward()
optimizer.step()
if (i % 5 == 0) or (i == iters - 1):
plt.title('Iter#{:04d}'.format(i))
plt.imshow(img.detach().cpu().view(*img.shape[2:], img.shape[1]))
plt.pause(1e-3)
print('[iter#{:04d}]: Losst-> {:}'.format(i, lss.item()))
plt.ioff()
plt.subplot(121)
plt.title('Original')
plt.imshow(style.cpu().view(*style.size()[2:], style.size()[1]))
plt.subplot(122)
plt.title('Style')
plt.imshow(img.detach().cpu().view(*img.size()[2:], img.size()[1]))
plt.show()

我希望算法以某种方式、形状或形式产生绘画的风格,但这并没有发生。 🤷 ♂️

(由于我很遗憾没有足够的声誉来发布图片,你可以在这里找到我不合理的输出图片:https://mattmoony.github.io/cdn/conv-net_pytorch-style-transfer/problem.png(

我真诚地希望您能够帮助我,并且我能够将这个问题用作学习经验。谢谢!😊

>万岁! 🙊

经过又一天的研究和测试,我终于发现了代码中的错误。

问题不在于训练过程或模型本身,而在于负责加载样式图像的行。(这篇文章帮助我发现了这个问题(

所以。。。我在脚本中添加了以下两个函数...

def load_img(p):
img = Image.open(p).convert('RGB')
im_transform = transforms.Compose([
transforms.ToTensor()
])
img = im_transform(img).unsqueeze(0).cuda()
return img
def to_img(t):
img = t.cpu().clone().detach()
img = img.numpy().squeeze()
img = img.transpose(1, 2, 0)
img = img.clip(0, 1)
return img

并在我的训练功能中使用了它们...

def train(...):
...
style = load_img(style_img)
...
if i % 5 == 0:
plt.title('Iter#{:04d}'.format(i))
plt.imshow(to_img(img))
plt.pause(1e-3)
...
<etc.>
...

我很高兴我能够找出脚本中存在问题的部分是什么,并且我将尽最大努力避免将来出现类似的错误。

我希望这可以帮助任何遇到类似问题的人,或者至少激励他们继续寻求解决方案。 🤠

最新更新