在秦朝末期,奸臣赵高一手遮天,为了显示自己的权势与力量,他在众人面前指着一头鹿说那是马,大家畏惧赵高的权势,明知那是鹿却不得不配合赵高说那是马,这就是经典成语”指鹿为马“的出处。
在光天化日之下,罔顾事实强行将A说成B,除非你有权有势,别人都依附于你,你才有可能做得到,要不然大家都会认为你傻逼。例如像我这样的平头百姓在大街上指着一个五大三粗,满脸胡渣子的大男人说那是个窈窕大美女,你会不会觉得我傻逼呢?在现代人工智能技术的加持下,我还真有指鹿为马,指男为女的”超能力“。
本节我们介绍一种功能强大的对抗性网络叫CycleGAN,它的特点是能将物体A平和的转变为物体B,例如下图就是CycleGAN的功能实现:
从上图可以看到,训练好的网络能将马变成斑马,将苹果与橘子互换,当然我们要实现更强大的功能,那就是男人与女人互换。CycleGAN的实现比前面介绍的对抗性网络在结构和算法上要复杂很多,首先它有两个生成者网络和鉴别者网络,因为我们想把物体A变成B,那么网络必须有识别和生成物体A和B的能力,因此CycleGAN要使用一组生成者和鉴别者网络来识别和生成物体A,使用第二组生成者和鉴别者网络识别和生成物体B,这点跟我们前面描述的对抗性网络一样,因此CycleGAN有如下结构特点:
不同之处在于两组网络要把自己掌握的信息与对方沟通,这样两组网络能共同掌握物体A和B的特性,这也是Cycle的由来。接下来是CycleGAN的算法关键所在,如下图所示:
从上图可见,两个生成者网络互相交互形成一个循环。由于第一个生成者网络Generator_AB用于接收图片A然后产出图片B,第二个生成者网络Generator_BA接收图片B然后生成图片A,如果第一个网络生成的图片B质量足够好,那么将它伪造的图片B输出给第二个生成者网络,后者生伪造的图片A就应该能获得好质量,因此判断第一个网络生成结果好坏的标准之一就是将它生成的结果用于第二个网络,看看后者能不能得到好结果,因此这就形成一个循环。
同理第二个生成者网络接收图片B后伪造图片A,如果它伪装出A的质量足够好,那么将它伪装的结果输入到第一个生成者网络,后者伪装出的图片B质量就应该足够好,于是这又形成一个循环。
这种循环训练的好处在于两个生成者网络能使用各自对相应图片的识别能力去训练另一个网络。例如一开始算法使用大量真实图片A来训练Generator_AB,于是它就掌握了物体A的内在特征,当Generator_BA将其伪装的图片A输入到Generator_AB,如此就形成了一条输入链,信息由Generator_BA—>Generator_AB,在训练时信息会反向传导变成Generator_AB->Generator_BA,于是前者就把自己对物体A特征的掌握和识别传导给后者,这样后者就能改进自己的构造能力,提升它伪造的图片质量,同理算法也可以形成Generator_AB—>Generator_BA的闭环,让后者伪装的图片A质量越来越好。
网络还有第二个循环,那就是对于接收图片B伪装图片A的生成者网络Generator_BA而言,算法要让它接收图片A,然后伪造的图片A质量也要足够好,其过程如下图所示:
该循环训练流程本质上是让网络Generator_AB和Generator_BA也学会识别图片A和B的特征,这样才有利于网络去提升他们伪造的图片质量。接下来我们看看算法代码的部分实现,首先是对训练数据的加载:
celeba_train = tfds.load(name="celeb_a", data_dir = '/content/drive/My Drive/tfds_celeba',split="train") #data_dir指向数据存储路径
celeba_test = tfds.load(name="celeb_a", data_dir = '/content/drive/My Drive/tfds_celeba',split="test")
assert isinstance(celeba_train, tf.data.Dataset)
import matplotlib.pyplot as plt
for data in celeba_train.take(1): #利用take接口获取数据
print(data) #数据其实是Dict对象,它包含了数据的所有相关属性
print(data["attributes"]["Male"])
plt.imshow(data['image'])
首先我们使用Tensorflow提供的数据集接口加载Celeba人脸图像数据,然后将图片分为男女两个类别,上面代码运行后所得结果如下: