你的GAN再不听话,就把它暴力肢解了吧,有用 | Demo · 代码

暴栗 发自 凹非寺
量子位 出品 | 公众号 QbitAI

640?wx_fmt=gif

这里有一只GAN,可以把尖耸的屋顶刷成圆的。

给天上的云换个姿势,一秒种起一棵树。

还可以,把草拔光。

640?wx_fmt=gif

 消除大法:触草木,尽死

MIT、IBM、港中大以及谷歌的科学家,用念力一组一组地控制了GAN的神经元,才支配了生成过程。

团队说,他们对GAN内在原理的了解程度,是前所未有的。所以,团队在一篇论文里,介绍了这种魔法。

现在,算法已开源,并有Demo可以玩,叫GANpaint。传送门见文底。

解锁GAN的隐藏原理,才能控制GAN

草,木,云,天,穹顶,砖瓦,房门......

每个元素,都对应GAN的其中一组神经元

只要激活某一组神经元,抑制其他神经元,就可以有选择地生成想要的元素。

长期以来,人类任由GAN胡乱涂鸦,不大去追究它们作画的原理。

640?wx_fmt=jpeg

 43.2万美元成交的GAN肖像,谁也不知道它是怎样学会画人

而GANpaint团队心思细腻,想要看清GAN的内部是如何运作,就有了这项研究:

每次激活不同的神经元,相当于把GAN肢解 (Dissect) 开来,让人一点一点去领会;

团队还提出了一个分析框架 (Analytical Framework) ,把肢解过程可视化,就像Demo展示的那样。

讲一下步骤。

640?wx_fmt=png

 找到每个神经元负责的物体,是把分割网络 (T. Xiao, et al, 2018) 和肢解方法 (D. Bau, et al, 2017) 结合,达成的

首先,把跟某个物体 (比如树) 相关的、可解释的GAN单元 (Interpretable GAN Units) 挑出来。通俗说来就是根据特征图,找到哪些神经元对应哪个物体。

然后,衡量这些单元对物体的影响力有多强,量化出来。也就是说,不只是相关 (Correlated) ,神经元要能控制物体的变化,才有用。

最终,考察这些单元与背景之间的上下文关系 (Contextual Relationship) 。研究要在一幅图里生成某种物体,怎样才能不突兀。

团队说,为了理解GAN的内在原理,而做的系统性分析,这还是史上第一次

640?wx_fmt=png

 43号单元,代表生成圆顶

还是刚才的栗子:要把尖顶变成圆顶,GAN要学习尖顶圆顶的特征,还要让生成的圆顶和原来的背景相处融洽。

而生成效果越自然,表示人类越发懂得控制GAN的神经元,也是理解GAN的工作原理了。

你也要试试么

想象,自己被追兵逼到一座古堡门前。你跑进了城堡,然后一秒把门GAN掉。安全。

640?wx_fmt=gif

然后,等追兵无功而返,再重新生成一道门跑出来。真是优秀的技能。

640?wx_fmt=gif

 这并不是什么城堡,但我真的GAN出一道门

再多的风景,就不一一列举了。

七个按钮,大家可以自己试试看,会不会生成什么惊喜。

毕竟,有人以为“去掉砖” (Brick x Remove) ,应该会是这样:

640?wx_fmt=gif

没有,不是我说的,不知道谁说的 (Twitter: @Jukkuden) 。

Demo传送门:
http://gandissect.res.ibm.com/ganpaint.html

代码传送门:
https://github.com/CSAILVision/GANDissect

论文传送门:
https://arxiv.org/pdf/1811.10597.pdf

年度评选申请

640?wx_fmt=jpeg

加入社群

量子位AI社群开始招募啦,欢迎对AI感兴趣的同学,在量子位公众号(QbitAI)对话界面回复关键字“交流群”,获取入群方式;


此外,量子位专业细分群(自动驾驶、CV、NLP、机器学习等)正在招募,面向正在从事相关领域的工程师及研究人员。


进专业群请在量子位公众号(QbitAI)对话界面回复关键字“专业群”,获取入群方式。(专业群审核较严,敬请谅解)

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复“招聘”两个字。

640?wx_fmt=jpeg

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我可以回答这个问题,以下是pytorch实现self attention gan代码: ```python import torch import torch.nn as nn import torch.nn.functional as F class SelfAttention(nn.Module): def __init__(self, in_dim): super(SelfAttention, self).__init__() self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1) self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1) self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1) self.gamma = nn.Parameter(torch.zeros(1)) def forward(self, x): batch_size, C, H, W = x.size() proj_query = self.query_conv(x).view(batch_size, -1, H*W).permute(, 2, 1) proj_key = self.key_conv(x).view(batch_size, -1, H*W) energy = torch.bmm(proj_query, proj_key) attention = F.softmax(energy, dim=-1) proj_value = self.value_conv(x).view(batch_size, -1, H*W) out = torch.bmm(proj_value, attention.permute(, 2, 1)) out = out.view(batch_size, C, H, W) out = self.gamma * out + x return out class Generator(nn.Module): def __init__(self, z_dim=100, image_size=64, conv_dim=64): super(Generator, self).__init__() self.image_size = image_size self.fc = nn.Linear(z_dim, (image_size//16)*(image_size//16)*8*conv_dim) self.conv1 = nn.ConvTranspose2d(8*conv_dim, 4*conv_dim, 4, 2, 1) self.conv2 = nn.ConvTranspose2d(4*conv_dim, 2*conv_dim, 4, 2, 1) self.conv3 = nn.ConvTranspose2d(2*conv_dim, conv_dim, 4, 2, 1) self.conv4 = nn.ConvTranspose2d(conv_dim, 3, 4, 2, 1) self.bn1 = nn.BatchNorm2d(8*conv_dim) self.bn2 = nn.BatchNorm2d(4*conv_dim) self.bn3 = nn.BatchNorm2d(2*conv_dim) self.bn4 = nn.BatchNorm2d(conv_dim) self.attn1 = SelfAttention(8*conv_dim) self.attn2 = SelfAttention(4*conv_dim) def forward(self, z): out = self.fc(z) out = out.view(-1, 8*self.conv_dim, self.image_size//16, self.image_size//16) out = F.relu(self.bn1(out)) out = F.relu(self.bn2(self.conv1(out))) out = self.attn1(out) out = F.relu(self.bn3(self.conv2(out))) out = self.attn2(out) out = F.relu(self.bn4(self.conv3(out))) out = torch.tanh(self.conv4(out)) return out class Discriminator(nn.Module): def __init__(self, image_size=64, conv_dim=64): super(Discriminator, self).__init__() self.conv1 = nn.Conv2d(3, conv_dim, 4, 2, 1) self.conv2 = nn.Conv2d(conv_dim, 2*conv_dim, 4, 2, 1) self.conv3 = nn.Conv2d(2*conv_dim, 4*conv_dim, 4, 2, 1) self.conv4 = nn.Conv2d(4*conv_dim, 1, 4, 1, ) self.bn1 = nn.BatchNorm2d(conv_dim) self.bn2 = nn.BatchNorm2d(2*conv_dim) self.bn3 = nn.BatchNorm2d(4*conv_dim) self.attn1 = SelfAttention(conv_dim) self.attn2 = SelfAttention(2*conv_dim) def forward(self, x): out = F.leaky_relu(self.conv1(x), .2) out = self.attn1(out) out = F.leaky_relu(self.bn2(self.conv2(out)), .2) out = self.attn2(out) out = F.leaky_relu(self.bn3(self.conv3(out)), .2) out = self.conv4(out) return out.view(-1, 1) ``` 希望能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值