当前位置: 首页 > 科技观察

GenerativeAdversarialNetworks-数据生成高级解决方案_2

时间:2023-03-13 13:00:31 科技观察

最近,数据科学界大力推广GenerativeAdversarialNetworks(简称GAN)。但是当你开始理解它们时,你马上就会明白为什么。GAN架构简直是一个天才的设计,主要是因为它“解锁”了现实世界数据生成和扩充的巨大潜力。在本文中,我将首先向您介绍GAN的基础知识,并向您展示如何使用Keras/Tensorflow库在Python环境中对其进行编程。概括来说,主要包括以下几项:机器学习算法中的GANGAN架构及其工作原理的直观解释以详细的Python示例演示如何从头构建GAN1.机器学习算法中的GAN即使是经验丰富的数据科学家也很容易迷失在数百种不同的机器学习算法中。为了总结这些算法,我对一些最常见的算法进行了分类,并创建了旭日图可视化。机器学习算法的分类Sunburst请注意,其中一些算法非常灵活,可以应用于不同的任务。因此,任何分类算法永远不会是最完美的分类算法。尽管如此,能够看到如此高层次的观点还是很重要的。注:原文中显示的图表是交互式的,只需点击不同类别的链接即可了解更多相应的提示。因此,本次翻译提供的静态图只能让你略感遗憾。你会发现GAN只是神经网络的一个子类,它本身又进一步包含了多个不同的子类,比如基础GAN(本文重点)、条件GAN(cGAN)、深度卷积GAN(DCGAN)等类型我将在以后的文章中介绍。2.GAN架构及其工作原理的直观解释生成对抗网络是将两个独立模型组合到一个架构中的深度学习机器。这两个组件是:GeneratorModelDiscriminatorModel这两个模型在零和博弈中相互竞争。生成器模型尝试生成与问题域中的数据样本相似的新数据样本。同时,鉴别器试图识别给定样本是假的(来自生成器)还是真实的(来自真实数据域)。生成器和鉴别器之间的竞争使它们成为对手,因此得名GAN。3.生成器模型首先,我们分析一下生成器模型,看看它是如何生成新的数据样本的。生成器模型示意图生成器模型从潜在空间中采样随机向量。这个空间服从高斯分布,维度由我们指定。由于我们使用随机向量作为神经网络的输入,因此随机向量成为该生成过程的种子数据。输入遵循网络的一个或多个隐藏层的标准路径。在简单的GAN架构的情况下,这将是一组密集连接的层,而深度卷积GAN(DCGAN)也包含卷积层。数据流入输出层,我们可以在输出层进行最终调整,以确保生成器输出数据中包含所需的形状,以提供给鉴别器。最后,我们可以使用这些假(生成)样本来测试和“愚弄”判别器。4.判别器模型接下来,让我们看看如何构建判别器模型。鉴别器模型鉴别器模型的输入是真实样本(从问题域中提取)和假样本(由生成器模型创建)的组合。数据通过具有一个或多个隐藏层的网络,与任何其他神经网络中的数据相同。3.一旦我们到达输出层,鉴别器就能够决定样本是真实的还是假的(生成的)。总之,鉴别器与标准神经网络分类模型没有什么不同。5.GANModelGenerativeAdversarialNetwork结合了相互竞争的生成器和判别器模型。下面的GAN架构图说明了这两个模型是如何相互关联的。GAN模型架构示意图如图所示。我们将假(生成)和真实样本数据输入鉴别器模型,该模型经过训练以区分这两种类型。随着鉴别器在区分真实数据和虚假数据方面变得越来越好,生成器模型的权重和偏差也会更新,以便生成更有说服力的虚假数据。该过程重复多次(根据指定的代数),直到生成器和鉴别器在其特定任务上做得更好。最后,在极限情况下,生成器模型的输出与实际输出无法区分,鉴别器模型收敛到0.5左右的中性预测。6.从头构建一个基于Python的GAN示例这个示例的目的是让您对GAN的工作原理有一个基本的了解。所以我们把它应用到一个简单的问题上。准备我们将使用以下库:用于数据生成和操作的Pandas、Numpy和Math库用于数据可视化的Matplotlib、Graphviz和Plotly(可选)Tensorflow/Keras用于构建神经网络首先,让我们导入库:#Tensorflow/Kerasfromtensorflowimportkeras#用于构建神经网络print('Tensorflow/Keras:%s'%keras.__version__)#Printversionfromkeras.modelsimportSequential#用于从keras组装神经网络模型。layersimportDense#给神经网络模型添加一些层fromtensorflow.keras.utilsimportplot_model#绘制模型图#数据操作importnumpyasnp#用于数据操作print('numpy:%s'%np.__version__)#PrintVersionimportpandasaspd#用于数据操作print('pandas:%s'%pd.__version__)#Printversionimportmath#用于生成真实数据(本例中指向一个圆圈)#可视化importmatplotlibimportmatplotlib.pyplotasplt#fordatavisualizationprint('matplotlib:%s'%matplotlib.__version__)#printversionimportgraphviz#显示模型图print('graphviz:%s'%graphviz.__version__)#printversionimportplotlyimportplotly.expressaspx#用于数据可视化print('plotly:%s'%plotly.__version__)#打印版本#othertoolsimportsysimportos#Assignthemaindirectorytoavariablemain_dir=os.path.dirname(sys.path[0])上面的代码会打印出本次使用的包的版本信息示例如下:Tensorflow/Keras:2.7.0numpy:1.21.4pandas:1.3.4matplotlib:3.5.1graphviz:0.19.1plotly:5.4.0接下来,我们将创建一个圆并获取其边缘(圆)上的点的坐标然后,我们GAN将通过训练生成器和鉴别器来“识别”和“生成”此类圆圈。#获取其边缘(圆周)上点的坐标defPointsInCircum(r,n=100):return[(math.cos(2*math.pi/n*x)*r,math.sin(2*math.pi/n*x)*r)forxinrange(0,n+1)]#保存组成一个半径为2的圆的一组实点的坐标circle=np.array(PointsInCircum(r=2,n=1000))#画图plt.figure(figsize=(15,15),dpi=400)plt.title(label='GAN生成器要学习的真实圆',loc='center')plt.scatter(circle[:,0],circle[:,1],s=5,color='black')plt.show()上面的代码会生成1000个点,画一个圆。从1000个点的圆中创建一个GAN模型现在,我们已经准备好数据了。接下来,让我们开始定义和组装我们的模型。我们将从生成器开始:#定义生成器模型defgenerator(latent_dim,n_outputs=2):model=Sequential(name="Generator")#Model#addlayersmodel.add(Dense(32,activation='relu',kernel_initializer='he_uniform',input_dim=latent_dim,name='Generator-Hidden-Layer-1'))#hiddenlayermodel.add(Dense(16,activation='relu',kernel_initializer='he_uniform',name='Generator-Hidden-Layer-2'))#Hiddenlayermodel.add(Dense(n_outputs,activation='linear',name='Generator-Output-Layer'))#输出层返回模型#Instantiationlatent_dim=3gen_model=generator(latent_dim)#显示模型汇总信息并绘制模型图gen_model.summary()plot_model(gen_model,show_shapes=True,show_layer_names=True,dpi=400)生成器模型图可以看到,我们的生成器有三个输入节点,自我们决定从3D潜在空间中绘制一个随机向量。请注意,我们可以自由选择潜在空间维度。同样,输出中显示了两个值,分别对应二维空间中一个点的x和y坐标。接下来,我们构建鉴别器模型:#构建鉴别器模型defdiscriminator(n_inputs=2):model=Sequential(name="Discriminator")#Model#addlayermodel.add(Dense(32,activation='relu',kernel_initializer='he_uniform',input_dim=n_inputs,name='Discriminator-Hidden-Layer-1'))#hiddenlayermodel.add(Dense(16,activation='relu',kernel_initializer='he_uniform',name='鉴别器-Hidden-Layer-2'))#Hiddenlayermodel.add(Dense(1,activation='sigmoid',name='Discriminator-Output-Layer'))#Outputlayer#编译模型model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])returnmodel#实例化dis_model=discriminator()#显示模型概要信息并绘制模型图dis_model.summary()plot_model(dis_model,show_shapes=True,show_layer_names=True,dpi=400)DiscriminatorModelGraph鉴别器输入有两个值,与生成器输出对齐。同时,鉴别器输出只是一个值,它告诉我们模型对数据真实/虚假的信心程度。接下来,我们将这两个模型结合起来创建一个GAN。下面代码中的一个关键细节是我们使判别器模型不可训练。我们这样做是因为,我们想使用真实和虚假(生成的)数据的组合分别训练鉴别器。稍后您将看到我们如何做到这一点。defdef_gan(generator,discriminator):#现阶段我们不想训练判别器权重。因此,使其不可训练discriminator.trainable=False#合并两个模型model=Sequential(name="GAN")#GAN模型model.add(generator)#添加生成器model.add(discriminator)#添加鉴别器#编译模型model.compile(loss='binary_crossentropy',optimizer='adam')returnmodel#实例化gan_model=def_gan(gen_model,dis_model)#显示模型汇总信息并绘制模型图gan_model.summary()plot_model(gan_model,show_shapes=True,show_layer_names=True,dpi=400)GAN模型图准备生成器和判别器的输入我们将创建三个简单的函数来辅助我们对两个模型进行数据采样和生成。第一个函数的作用是从圆上采样实点数据;第二个函数负责从潜在空间中提取随机向量;第三个函数负责将潜在变量传递给生成器模型以生成伪样本数据。#构造函数负责从我们的圆中收集随机点数据defreal_samples(n):#真实样本数据X=circle[np.random.choice(circle.shape[0],n,replace=True),:]#Classlabely=np.ones((n,1))returnX,y#在latentspace上生成点数据;我们将使用后续生成器的输入数据deflatent_points(latent_dim,n):#在latentspace上生成Point数据latent_input=np.random.randn(latent_dim*n)#重构形状:使其成为网络的批量输出latent_input=latent_input.reshape(n,latent_dim)returnlatent_input#使用生成器生成n个伪样本数据,结合类标签信息deffake_samples(generator,latent_dim,n):#在latent空间生成点latent_output=latent_points(latent_dim,n)#预测输出(例如生成伪样本数据)X=generator.predict(latent_output)#创建类标签y=np.zeros((n,1))returnX,y?模型训练和评估最后两个函数会帮助我们训练模型并以指定的时间间隔评估结果数据。首先,我们创建模型性能评估函数:defperformance_summary(epoch,generator,discriminator,latent_dim,n=100):#获取真实数据的样本x_real,y_real=real_samples(n)#在真实数据上评估判别器_,real_accuracy=discriminator.evaluate(x_real,y_real,verbose=1)#Getfake(generated)samplesx_fake,y_fake=fake_samples(generator,latent_dim,n)#Evaluatethediscriminatoronfake(generated)数据_,fake_accuracy=discriminator.evaluate(x_fake,y_fake,verbose=1)#Summarydiscriminatorperformanceprint("epochnumber:",epoch)print("DiscriminatorAccuracyonREALpoints:",real_accuracy)print("DiscriminatorAccuracyonFAKE(generated)points:",fake_accuracy)复制代码#Createa2Dscatterplottoshowrealandfake(generated)数据点plt.figure(figsize=(4,4),dpi=150)plt.scatter(x_real[:,0],x_real[:,1],s=5,color='black')plt.scatter(x_fake[:,0],x_fake[:,1],s=5,color='red')plt.show()可以看到,上面的函数评估鉴别器分别在真实和虚假(生成的)点对上。然后绘制二维散点图以显示点在二维平面上的位置。最后,训练函数如下:deftrain(g_model,d_model,gan_model,latent_dim,n_epochs=10001,n_batch=256,n_eval=1000):#我们训练判别器的批次将由一半真点和一半假点组成(generated)Pointhalf_batch=int(n_batch/2)#我们用手动的方式枚举世代(epochs)foriinrange(n_epochs):#TrainingDiscriminator#准备真实样本数据x_real,y_real=real_samples(half_batch)#Preparefalse(generated)sampledatax_fake,y_fake=fake_samples(g_model,latent_dim,half_batch)#使用真假样本训练判别器d_model.train_on_batch(x_real,y_real)d_model.train_on_batch(x_fake,y_fake)#生成器训练#从中得到latentspacePointsusedasgeneratorinputx_gan=latent_points(latent_dim,n_batch)#当我们生成假样本时,我们希望GAN生成器模型创建与真实样本相似的样本#因此,我们要传递与真实样本对应的标签,即y=1,not0.y_gan=np.ones((n_batch,1))#通过复合GAN模型训练生成器gan_model.train_on_batch(x_gan,y_gan)#在每个n_evalepochsif(i)%n_eval==0:performance_summary(i,g_model,d_model,latent_dim)和以前一样,我们通过传递一批50%真实和50%虚假(生成的)样本数据来分别训练鉴别器。同时,通过组合的GAN模型进行生成器训练。实验结果我们调用训练函数来显示上面一些实验的结果:#TrainGANmodeltrain(gen_model,dis_model,gan_model,latent_dim)下图是第0代(epoch)的输出:第0代完成后GAN性能3000代输出:3000代完成后的输出10000代输出:10000代完成后的输出我们可以看到生成器在每一步都有提升。然而,在10,000个epoch之后,鉴别器仍然表现良好,能够识别大多数真实样本和大多数假(生成)样本。因此,我们可以继续训练模型到接下来的10,000个epoch,以获得更好的结果。比较上述模型性能的另一种方法是查看真假点分布的汇总统计数据:#生成1000个假样本数据x_fake,y_fake=fake_samples(gen_model,latent_dim,1000)df_fake=pd.DataFrame(x_fake,columns=['x维度','y维度'])#1000个真实样本数据点x_real,y_real=real_samples(1000)df_real=pd.DataFrame(x_real,columns=['x维度','y维度'])#Displaysummarystatisticsprint("假(生成)点的分布统计")print(df_fake.describe())print("---------------------------------------")print("Distributionstatisticsofrealpoints")print(df_real.describe())真假(生成)点分布统计的比较以上实验数据清楚地表明分布差异比较小。7.结语希望在阅读本文后,您对GAN网络的工作原理有一个很好的理解。译者介绍朱宪忠,社区编辑,专家博主,讲师,潍坊某高校计算机教师,自由编程资深人士。早期专注于各种微软技术(编译成三本与ASP.NETAJX和Cocos2d-X相关的技术书籍)。/ESP32/RaspberryPi等物联网开发技术和Scala+Hadoop+Spark+Flink等大数据开发技术。原文链接:https://towardsdatascience.com/gans-generative-adversarial-networks-an-advanced-solution-for-data-generation-2ac9756a8a99