PyTorch实现Deep Dream

  • A+
所属分类:深度学习
摘要这篇文章简单介绍一些Deep Dream的原理,和使用Pytorch进行简单的实现。

Deep Dream原理介绍

其实Deep Dream大致的原理和CNN可视化Convolutional Features是有些相似的,这个是希望整个layer的激活值都很大,而Feature的可视化是希望某个layer中的某个filter的激活值最大。

其实两个都差不多了。Deep Dream简单的步骤如下图所示,说一下第5步,我个人感觉是为了保证最后的图片可以保持原来图片的样子,所以每次都需要进行Blend。

整个过程是一个递归的过程,具体的实现可以看后面讲的实现。

PyTorch实现Deep Dream

代码实现

参考链接:deep-dream-in-pytorch

导入使用的库

  1. import torch
  2. from torchvision import models, transforms
  3. import torch.optim as optim
  4. import numpy as np
  5. from matplotlib import pyplot
  6. %matplotlib inline
  7. from PIL import Image, ImageFilter, ImageChops

定义超参数

  1. CUDA_ENABLED = True
  2. # Deep dream configs
  3. LAYER_ID = 28 # The layer to maximize the activations through
  4. NUM_ITERATIONS = 5 # Number of iterations to update the input image with the layer's gradient
  5. LR = 0.2
  6. # We downscale the image recursively, apply the deep dream computation, scale up, and then blend with the original image 
  7. # to achieve better result.
  8. NUM_DOWNSCALES = 20
  9. BLEND_ALPHA = 0.5

定义Deep Dream的类

这里我们使用预训练好的vgg16网络来进行测试。我们首先定义基类,定义好一些变量和图像的转换

  1. class DeepDream:
  2.     def __init__(self, image):
  3.         self.image = image
  4.         self.model = models.vgg16(pretrained=True)
  5.         if CUDA_ENABLED:
  6.             self.model = self.model.cuda()
  7.         self.modules = list(self.model.features.modules())
  8.         # vgg16 use 224x224 images
  9.         imgSize = 224
  10.         self.transformMean = [0.485, 0.456, 0.406]
  11.         self.transformStd = [0.229, 0.224, 0.225]
  12.         self.transformNormalise = transforms.Normalize(
  13.             mean=self.transformMean,
  14.             std=self.transformStd
  15.         )
  16.         self.transformPreprocess = transforms.Compose([
  17.             transforms.Resize((imgSize, imgSize)),
  18.             transforms.ToTensor(),
  19.             self.transformNormalise
  20.         ])
  21.         self.tensorMean = torch.Tensor(self.transformMean)
  22.         if CUDA_ENABLED:
  23.             self.tensorMean = self.tensorMean.cuda()
  24.         self.tensorStd = torch.Tensor(self.transformStd)
  25.         if CUDA_ENABLED:
  26.             self.tensorStd = self.tensorStd.cuda()
  27.     def toImage(selfinput):
  28.         return input * self.tensorStd + self.tensorMean

接着继承上面的类,定义正向传播与梯度更新的过程,这里使用了Adma来进行梯度的更新。

  1. class DeepDream(DeepDream):
  2.     def deepDream(self, image, layer, iterations, lr):
  3.         transformed = self.transformPreprocess(image).unsqueeze(0) # 转换后的图片
  4.         if CUDA_ENABLED:
  5.             transformed = transformed.cuda()
  6.         input = torch.autograd.Variable(transformed, requires_grad=True)
  7.         self.model.zero_grad()
  8.         optimizer = optim.Adam([input.requires_grad_()],lr=LR)
  9.         for _ in range(iterations):
  10.             optimizer.zero_grad()
  11.             out = input
  12.             for layerId in range(layer):
  13.                 out = self.modules[layerId + 1](out)
  14.             loss = -out.norm() # 让负的变小, 正的变大
  15.             loss.backward()
  16.             optimizer.step()
  17.             # input.data = input.data + lr * input.grad.data
  18.         input = input.data.squeeze()
  19.         input.transpose_(0,1)
  20.         input.transpose_(1,2)
  21.         input = self.toImage(input)
  22.         if CUDA_ENABLED:
  23.             input = input.cpu()
  24.         input = np.clip(input, 0, 1)
  25.         return Image.fromarray(np.uint8(input*255))

为了让结果更好,我们需要从一张小的图片进行反复迭代来生成最后的deep dream的图片。我在中间加了一些可视化的过程,会逐步打印出中间的图片,来查看一个变化的过程。

  1. class DeepDream(DeepDream):
  2.     def deepDreamRecursive(self, image, layer, iterations, lr, num_downscales):
  3.         if num_downscales > 0:
  4.             # scale down the image
  5.             image_small = image.filter(ImageFilter.GaussianBlur(2)) # 高斯模糊
  6.             small_size = (int(image.size[0]/2), int(image.size[1]/2))
  7.             if (small_size[0] == 0 or small_size[1] == 0):
  8.                 small_size = image.size
  9.             image_small = image_small.resize(small_size, Image.ANTIALIAS)
  10.             # run deepDreamRecursive on the scaled down image
  11.             image_small = self.deepDreamRecursive(image_small, layer, iterations, lr, num_downscales-1)
  12.             print('Num Downscales : {}'.format(num_downscales))
  13.             print('====Small Image=====')
  14.             pyplot.imshow(image_small)
  15.             pyplot.show()
  16.             # Scale up the result image to the original size
  17.             image_large = image_small.resize(image.size, Image.ANTIALIAS)
  18.             print('====Large Image=====')
  19.             pyplot.imshow(image_large)
  20.             pyplot.show()
  21.             # Blend the two image
  22.             image = ImageChops.blend(image, image_large, BLEND_ALPHA)
  23.             print('====Blend Image=====')
  24.             pyplot.imshow(image)
  25.             pyplot.show()
  26.         img_result = self.deepDream(image, layer, iterations, lr)
  27.         print(img_result.size)
  28.         img_result = img_result.resize(image.size)
  29.         print(img_result.size)
  30.         return img_result
  31.     def deepDreamProcess(self):
  32.         return self.deepDreamRecursive(self.image, LAYER_ID, NUM_ITERATIONS, LR, NUM_DOWNSCALES)

 进行生成

  1. # 导入图片
  2. IMAGE_PATH = 'face.jpg'
  3. img = Image.open(IMAGE_PATH)
  4. pyplot.imshow(img)
  5. pyplot.title("Image loaded from " + IMAGE_PATH)
PyTorch实现Deep Dream

进行生成最终的结果。我们看一下最后的结果。整个过程图片是由小变大。

  1. img_deep_dream = DeepDream(img).deepDreamProcess()
  2. pyplot.imshow(img_deep_dream)
  3. pyplot.title("Deep dream image")
PyTorch实现Deep Dream

最后,我们看一下最终生成图片的效果。首先是原始的图片。

PyTorch实现Deep Dream

然后是生成的图片。其实不是很好看。

PyTorch实现Deep Dream

关于deep dream,一个使用的地方,应该都很熟悉吧,deep learning书籍的封面就是使用这种技术进行生成的。

PyTorch实现Deep Dream

代码链接:Deep Dream的介绍

  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: