文章目录

  • 前言
  • 1 DeepDream原理
  • 2 DeepDream算法流程
  • 3 PyTorch实现DeepDream
  • 4 全部代码(详细注释)

前言

  卷积神经网络取得了突破性进展,效果也非常理想,但是卷积神经网络的学习过程难以从理论上难以解释,因此被不少人诟病。因此可视化其的学习过程十分重要,DeepDream 模型的目的也正是如此。DeepDearm 模型在2015年由谷歌提出,理论基础是2013年所提出的《Visualizing and Understanding Convolutional Neural Networks》,该文章提出了使用梯度上升的方法可视化网络每一层的特征,即用一张噪声图像输入网络,反向更新的时候不更新网络权重,而是更新初始图像的像素值,以这种训练图像的方式可视化网络。深度学习领域奠基性的经典教材《深度学习》的封面就是使用 DeepDream 模型生成的。

1 DeepDream原理

  DeepDream 为了说明CNN学习到的各特征的意义,将采用放大处理的方式。具体来说就是使用梯度上升的方法可视化网络每一层的特征,即用一张噪声图像输入网络,但反向更新的时候不更新网络权重,而是更新初始图像的像素值,以这种“训练图像”的方式可视化网络。此外输入图像也可以是一些正常的图片,这样的话就是生成背景图像之类的。
  DeepDream 如何放大图像特征?比如:有 一个网络学习了分类猫和狗的任务,给这个网络一张云的图像,这朵云可能比较像狗,那么机器提取的特征可能也会像狗。假设对应一个特征最后输入概率为[0.6,0.4],0.6表示为狗的概率,0.4则表示为猫的概率,那么采用L2L_2L2​范数可以很好达到放大特征的效果。对于这样一个特征,L2=x12+x22L_2 = x_1^{2} + x_2^{2}L2​=x12​+x22​,若x1x_1x1​ 越大,x2x_2x2​越小,则L2L_2L2​越大,所以只需要最大化L2L_2L2​就能保证当x1x_1x1​ > x1x_1x1​的时候, 迭代的轮数越多x1x_1x1​越大,x2x_2x2​越小,所以图像就会越来越像狗。每次迭代相当 于计算L2L_2L2​范数,然后用梯度上升的方法调整图像。优化的就不再是优化权重参数,而是特征值或像素点,因此,构建损失函数时,不使用通常的交叉熵,而是最大化特征值的L2范数。使图像经过网络之后提取的特征更像网络隐含的特征。具体实现的时候还要通过多尺度、随机 移动等方法获取比较好的结果。

2 DeepDream算法流程

  使用基本图像,它输入到预训练的CNN。并正向传播到特定层。
  为了更好地理解该层学到了什么,我们需要最大化通过该层激活值。这里要解释一下什么是激活值,激活值表示属于某类的概率大小,比如说二分类问题中,用[0,1]表示两类的标签,我们规定当神经网络的输出大于0就被分类到1(100% 被激活),小于0就分到0(没有被激活),所以在此情况下激活值只有100%或者0%,但是我们在平常的多分类任务中希望它可以是0%~100%的任意值。激活值越大,激活程度越高,对于分类,也就意味着它属于这一类的概率越大。DeepDream 以该层输出为梯度,然后在输入图像上完成渐变上升,以最大化该层的激活值。不过,光这样做并不能产生好的图像。为了提高训练质量,需要使用一些技术使得到的图像更好。通常可以进行高斯模糊以使图像更平滑,使用多尺度(又称为八度)的图像进行计算。先连续缩小输入图像,然后,再逐步放大,并将结果合并为一个图像输出。

  先对图像连续做二次等比例缩小,该比例是1.5,之所以要缩小,图像缩小是为了让图像的像素点调整后所得结果图案能显示的更加平滑,过程主要是抑制了图像的高频成分,放大了低频成分。缩小二次后,把图像每个像素点当作参数,对它们求偏导,这样就可以知道如何调整图像像素点能够对给定网络层的输出产生最大化的刺激。

3 PyTorch实现DeepDream

  本次实现是取 VGG19 模型为预训练模型,将获取的特征最大化之后展示在一张普通的图像上,本次使用的是梵高的星空图。为了训练更加有效,还使用对图像进行不同大小的缩放处理。
1) 下载预训练模型。VGG19 模型包括了三种不同的模块,第一个是特征提取模块 (features) ,一共有36层,第二个是池化层 (avgpool) ,只有一层,第三个是分类层 (classifier) ,一共有6层。

vgg = models.vgg19(pretrained = True).to(device)
modulelist = list(vgg.features.modules())

2) 函数 prod 主要功能是传入输入图像,正 向传播到 VGG19 的指定层(如第8层或第32层等),然后,用梯度上升更新输入图像的特征值。

def prod(image, feature_layers, iterations, lr, transform, device, vgg, modulelist) :input = transform(image).unsqueeze(0)input = input.to(device).requires_grad_(True)vgg.zero_grad()for i in range(iterations) :out = inputfor j in range(feature_layers) :out = modulelist[j + 1](out)loss = out.norm()loss.backward()with torch.no_grad() :input += lr * input.gradinput = input.squeeze()# input = input.transpose(0, 1)# input = input.transpose(1, 2)input = input.permute(1, 2, 0)input = np.clip(deprocess(input, device).detach().cpu().numpy(), 0, 1)image = Image.fromarray(np.uint8(input * 255))return image

3) 函数 deep_dream_vgg 是一个递归函数,多次缩小图像,然后调用函数 prod 。接着再放大结果,并与按一定比例图像混合在一起,最终得到与输入图像相同大小的输出图像。

def deep_dream_vgg(image, feature_layers, iterations, lr, transform, device, vgg, modulelist, octave_scale = 2, num_octaves = 100) :if num_octaves > 0 :image1 = image.filter(ImageFilter.GaussianBlur(2))if (image1.size[0] / octave_scale < 1 or image1.size[1] / octave_scale < 1) :size = image1.sizeelse :size = (int(image1.size[0] / octave_scale), int(image1.size[1] / octave_scale))image1 = image1.resize(size, Image.ANTIALIAS)image1 = deep_dream_vgg(image1, feature_layers, iterations, lr, transform, device, vgg, modulelist, octave_scale, num_octaves - 1)size = (image.size[0], image.size[1])image1 = image1.resize(size, Image.ANTIALIAS)image = ImageChops.blend(image, image1, 0.6)# PIL.ImageChops.blend(image1, image2, alpha)# out = image1 * (1.0 - alpha) + image2 * alphaimg_result = prod(image, feature_layers, iterations, lr, transform, device, vgg, modulelist)img_result = img_result.resize(image.size)return img_result

4 全部代码(详细注释)

import torch
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image, ImageFilter, ImageChops
from torchvision import models
from torchvision import transforms#下载图片
def load_image(path) :img = Image.open(path)return img#因为在图像处理过程中有归一化的操作,所以要"反归一化"
def deprocess(image, device):image = image * torch.tensor([0.229, 0.224, 0.225], device = device) + torch.tensor([0.485, 0.456, 0.406], device = device)return image#传入输入图像,正 向传播到VGG19的指定层,然后,用梯度上升更新 输入图像的特征值。
def prod(image, feature_layers, iterations, lr, transform, device, vgg, modulelist) :input = transform(image).unsqueeze(0)         #对图像进行resize,转成tensor和归一化操作,要增加一个维度,表示一个样本,[1, C, H, W]input = input.to(device).requires_grad_(True) #对图片进行追踪计算梯度vgg.zero_grad()                               #梯度清零for i in range(iterations) :out = inputfor j in range(feature_layers) :          #遍历features模块的各层out = modulelist[j + 1](out)          #以上一层的输出特征作为下一层的输入特征loss = out.norm()                         #计算特征的二范数loss.backward()                           #反向传播计算梯度,其中图像的每个像素点都是参数with torch.no_grad() :input += lr * input.grad              #更新原始图像的像素值input = input.squeeze()                       #训练完成后将表示样本数的维度去除# 交互维度# input = input.transpose(0, 1)# input = input.transpose(1, 2)input = input.permute(1, 2, 0)                #维度转换,因为tensor的维度是(C, H, W),而array是(H, W, C)input = np.clip(deprocess(input, device).detach().cpu().numpy(), 0, 1)#将像素值限制在(0, 1)之间image = Image.fromarray(np.uint8(input * 255))#将array类型的图像转成PIL类型图像,要乘以255是因为转成tensor时函数自动除以了255return image#多次缩小图像,然后调用函数 prod。接着在放大结果,并与按一定比例图像混合在一起,最终得到与输入 图像相同大小的输出图像。
#octave_scale参数决定了有多少个尺度的图像, num_octaves参数决定一共有多少张图像
#octave_scale和num_octaves两个参数的选定对生成图像的影响很大。
def deep_dream_vgg(image, feature_layers, iterations, lr, transform, device, vgg, modulelist, octave_scale = 2, num_octaves = 100) :if num_octaves > 0 :image1 = image.filter(ImageFilter.GaussianBlur(2))#高斯模糊if (image1.size[0] / octave_scale < 1 or image1.size[1] / octave_scale < 1) :#当图像的大小小于octave_scale时图像尺度不再变化size = image1.sizeelse :size = (int(image1.size[0] / octave_scale), int(image1.size[1] / octave_scale))image1 = image1.resize(size, Image.ANTIALIAS)#缩小图片image1 = deep_dream_vgg(image1, feature_layers, iterations, lr, transform, device, vgg, modulelist, octave_scale, num_octaves - 1)#递归size = (image.size[0], image.size[1])image1 = image1.resize(size, Image.ANTIALIAS)#放大图像image = ImageChops.blend(image, image1, 0.6) #按一定比例将图像混合在一起# PIL.ImageChops.blend(image1, image2, alpha)# out = image1 * (1.0 - alpha) + image2 * alphaimg_result = prod(image, feature_layers, iterations, lr, transform, device, vgg, modulelist)img_result = img_result.resize(image.size)return img_resultif __name__ == '__main__':#对图像进行预处理tranform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(), #将PIL类型转成tensor类型,注意再次过程中像素值已经转到了[0, 1]之间,方式是除以255transforms.Normalize(mean = [0.485, 0.456, 0.406], #归一化std = [0.229, 0.224, 0.225])])device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")vgg = models.vgg19(pretrained = True).to(device) modulelist = list(vgg.features.modules())#要注意网络层转成列表元素之后,第一个元素是全部的网络层,下标从1开始迭代网络层,这也是后面是modulelist[j + 1]的原因night_sky = load_image('starry_night.jpg')night_sky_30 = deep_dream_vgg(night_sky, 36, 6, 0.2, tranform, device, vgg, modulelist)plt.imshow(night_sky_30)plt.show()

运行结果:
输入图像:

VGG19 的第10层学习的特征:

VGG19 的第20层学习的特征:
VGG19 的第30层学习的特征:

  VGG19 预训练模型是基于ImageNet大数据集训练的模型,该数据集共有1000个类别。从上面的结果可以看出,越靠近顶部的层,其激活值表现就越全面或抽象,如像某些类别(比如狗)的图案。

机器学习(十二) DeepDearm模型相关推荐

  1. 「超级干货大放送」机器学习十二种经典模型实例

    目录 实例一:线性回归波士顿房价 实例二:KNN实现电影分类 实例三:基于线性回归预测波士顿房价 ​ 实例四:sklearn完成逻辑回归鸢尾花分类 实例五:支持向量机完成逻辑回归鸢尾花分类 实例六:使 ...

  2. [Python人工智能] 三十二.Bert模型 (1)Keras-bert基本用法及预训练模型

    从本专栏开始,作者正式研究Python深度学习.神经网络及人工智能相关知识.前一篇文章结合文本挖掘介绍微博情感分类知识,包括数据预处理.机器学习和深度学习的情感分类.这篇文章将开启新的内容--Bert ...

  3. 入门机器学习(十二)--课后作业解析-偏差与方差(Python 实现)

    在本次作业中,我们要完成的是预测水库水位的变化预测大坝流出的水量.已知特征为水库的水位,要预测的y是大坝流出的水量. 编程作业 5 - 偏差和方差 这次练习我们将会看到如何使用课上的方法改进机器学习算 ...

  4. [WebGL入门]十二,模型数据和顶点属性

    注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:].另外.鄙人webgl研究还不够深入,一些专业词语.假设翻译有误.欢迎大家指 ...

  5. 机器学习(十二)——感知器算法

    感知器算法是一种可以直接得到线性判别函数的线性分类方法,它是基于样本线性可分的要求下使用的 线性可分与线性不可分 算法流程 感知器作为人工神经网络中最基本的单元,有多个输入和一个输出组成.虽然我们的目 ...

  6. [Python人工智能] 三十四.Bert模型 (3)keras-bert库构建Bert模型实现微博情感分析

    从本专栏开始,作者正式研究Python深度学习.神经网络及人工智能相关知识.前一篇文章开启了新的内容--Bert,首先介绍Keras-bert库安装及基础用法及文本分类工作.这篇文章将通过keras- ...

  7. 感谢十二年的陪伴——分享回归,不忘初心(Eastmount博客总结及未来规划)

    曾记否,2021年4月28日,为了更好地从事科研和学习,当时给所有读者群发了我在CSDN唯一的私信,感谢大家十年的陪伴,短暂消失,不负青春.当时也收到了很多博友的鼓励与祝福,感恩. 是啊!很难想象读博 ...

  8. [Python从零到壹] 十二.机器学习之回归分析万字总结全网首发(线性回归、多项式回归、逻辑回归)

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  9. Spark机器学习实战 (十二) - 推荐系统实战

    0 相关源码 将结合前述知识进行综合实战,以达到所学即所用.在推荐系统项目中,讲解了推荐系统基本原理以及实现推荐系统的架构思路,有其他相关研发经验基础的同学可以结合以往的经验,实现自己的推荐系统. 1 ...

最新文章

  1. css那些事儿2 经典两列布局
  2. Mine Sweeper II
  3. SpringBoot-视图解析与模板引擎
  4. 【英语学习】【Level 07】U07 Stories of my Life L2 I actually did it!
  5. 在hibernate框架中配置显示sql语句
  6. 基础入门_Python-模块和包.Gevent异步服务类实现多姿势WEB实时展示?
  7. java 怎么获取object的数据_自学java,想将来从事大数据工作,现实吗?怎么学?...
  8. Integer与int的种种比较你知道多少?
  9. 测试理论基础(思维导图)
  10. c语言 复制到编辑页面 乱码,富文本编辑器的复制word到浏览器发生乱码(vue+wangEditor)...
  11. php 忽略 deprecated,php升级后使用deprecated函数报错的解决方法
  12. Sql Server排序规则(转)
  13. Codeforces Round #727 (Div. 2) B. Love Song
  14. 树莓派3B+ wifi 5G连接
  15. SiT5357:±0.1~±0.25ppm超高精度Stratum 3温补振荡器TCXO,60-220MHz
  16. Classification分类学习
  17. bugku 0和1的故事 用Excel完成
  18. RK3399平台开发系列讲解(PCI/PCI-E)5.51、PCIE EP模式软件架构
  19. 2021计算机二级抽考的是,2021年计算机二级office考试将采用2016版本软件
  20. html设置文本边框为透明,透明框中的文本

热门文章

  1. 解密百信银行架构:如何构建全云系统
  2. sublime text3 破解版下载
  3. iOS游戏反外挂方案解析
  4. 图谱实战 | 知识图谱在美团搜索酒旅场景认知中的应用
  5. 人脸识别-arcsoft
  6. 错误:System.Data.MetadataException: 无法加载指定的元数据资源。
  7. Maven连同关联依赖一起打包成可执行jar
  8. python弹钢琴_flash钢琴自动弹奏之Python实现
  9. 医信“十三五”系列教材定稿会暨技能大赛筹备会在京召开
  10. 使用记事本保存的html乱码,电脑中记事本保存的文本文档显示乱码的解决办法...