2017-10-10 91 views
0

我用来在Keras中设计我的GAN。但是,对于特定需求,我想将我的代码调整为Tensorflow。大多数甘斯实现与Tensorflow的使用类的GAN然后为鉴别功能和发电机用Python类在Tensorflow中构建GAN

其中给出的东西,看起来像这样:

class MyGAN(): 
    def __init__(self): 
     # various initialisation 

    def generator(self, n_examples): 
     ### do some business and return n_examples generated. 

     return G_output 

    def discrimintator(self, images): 
     ### do some business with the images 

     return D_Prob, D_logits 

哪个,事实上完全没问题。不过,我更喜欢每个部分[MyGAN,Generator,Discriminator]都是完全独立的类的设计。您只初始化了主文件:MyGAN,它由其自己处理。它允许我更简单的代码组织和相对简单的代码阅读。

但是,我在一些设计模式上挣扎,我可以使用“输入”图层,它允许我从给定数据集的Discriminator真实数据和发生器生成的假数据切换。短短几行与Keras 伪代码暴露的想法:

class Generator(object): 

    def __init__(self, latent_shape): 

     gen_input = Input(shape=latent_shape, name='generator_input') 

     #### ====== do some business ====== #### 

     gen_output = Activation('tanh', name='generator_output')(previous_layer) 

     self.model = Model(gen_input, gen_output) 

class Discriminator(object): 

    def __init__(self): 

     disc_input = Input(shape=self.input_shape, name='discriminator_input') 

     #### ====== do some business ====== #### 

     disc_output = Activation('sigmoid', name='discriminator_output')(previous_layer) 

     # Model definition with Functional API 
     self.model = Model(disc_input, disc_output) 

class MyGAN(object): 

    def __init__(self): 

     ########## GENERATOR ########## 

     # We create the optimizer for G 
     g_optim = Adam(lr=2e-4, beta_1=0.5) 

     self.generator = Generator(latent_shape=(100,))   
     self.generator.model.compile(loss='binary_crossentropy', optimizer=g_optim) 

     ########## DISCRIMINATOR ########## 

     We create the optimizer for D 
     d_optim = Adam(lr=2e-4, beta_1=0.5) 

     self.discriminator = Discriminator() 
     self.discriminator.model.compile(loss='binary_crossentropy', optimizer=d_optim, metrics=['accuracy']) 

     ########## FULL GAN ########## 

     # create an Input Layer for the complete GAN 
     gan_input = Input(shape=self.latent_shape) 

     # link the input of the GAN to the Generator 
     G_output = self.generator.model(gan_input) 

     For the combined model we will only train the generator => We do not want to backpropagate D while training G 
     self.discriminator.model.trainable = False 

     # we retrieve the output of the GAN 
     gan_output = self.discriminator.model(G_output) 

     # we construct a model out of it. 
     self.fullgan_model = Model(gan_input, gan_output) 
     self.fullgan_model.compile(loss='binary_crossentropy', optimizer=g_optim, metrics=['accuracy']) 

    def train_step(self, batch): 

     ## Train Generator First ## 

     noise = #### Generate some noise with the size: 2*batch (D is trained twice)   
     loss, acc = self.fullgan_model.train_on_batch(noise, np.ones(noise.shape[0])) 

     ## Train Discriminator Then ## 

     self.discriminator.model.trainable = True 

     generated_images = ### Generate samples with G with same size as batch 

     d_loss_fake, d_acc_fake = self.discriminator.model.train_on_batch(
       generated_images, 
       np.zeros(generated_images.shape[0]) 
      ) 
     d_loss_real, d_acc_real = self.discriminator.model.train_on_batch(
      X, 
      np.ones(X.shape[0]) 
     ) 

     d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) 
     d_acc = 0.5 * np.add(d_acc_real, d_acc_fake) 

     self.discriminator.model.trainable = False 

我的问题很简单,我怎么能再现这样的代码结构Tensorflow?我有一些想法,但我不说服了与任何这些:

我可以用一个tf.Variable然后用负载函数执行过程中进行分配。问题是:对于每个培训步骤,似乎需要为每个网络(D和G)执行两个sess.run()。这显然是低效的...

  • 对于发电机:

    • 1:其中G生成数据与sess.run()呼叫
    • 2:用sess.run()呼叫
    • 3装载在d中的数据:计算与所述损失另一个sess.run()致电
    • 4:最后反向传播G与最后一个sess.run()
  • 对于鉴别:

    • 1:其中G生成数据与sess.run()呼叫
    • 2:计算用于假数据损失:用sess.run()呼叫
    • 3装载在d中的数据用sess.run()呼叫
    • 4:计算用于真实数据的丢失与sess.run()呼叫
    • 5:最后backpropagate d与最后sess.run()

对我来说这只是看起来显然效率不高,我也没有更好的主意。我当然可以使用占位符,它可以用feed_dict“隐藏”加载操作,但不会真正影响性能(我试过)。

我的目标是以下内容:

  • 直接连接g至d,并能避免调用G,只是具有G和d直接相连。

  • 在从G或数据批处理中获取数据时,能够“切换D”。这将允许我以避免从GPU/CPU的数据传输=>节省时间

+0

不能将G的输出连接到D的第一个“图层”吗?看起来你可以把东西自由地连接起来,就好像它们是树枝一样(这看起来正是keras所做的),你可以运行最后一个输出,它会考虑整个网络,或者你可以运行一个中间输出,它只考虑网络 –

+0

这是正确的,但是如何设计D从G和真实数据中随时切换?问题不在于连接G和D.这是关于切换入口点的问题 –

回答

0

你可以达到你想要使用纯功能的方法,并重新申请使用变量的作用域网络的设计结构。例如,这个代码片段设置网络的真正/假冒的部分:

with variable_scope.variable_scope(generator_scope) as gen_scope: 
    generated_data = generator_fn(generator_inputs) 
with variable_scope.variable_scope(discriminator_scope) as dis_scope: 
    discriminator_gen_outputs = discriminator_fn(generated_data, 
               generator_inputs) 
with variable_scope.variable_scope(dis_scope, reuse=True): 
    discriminator_real_outputs = discriminator_fn(real_data, generator_inputs) 

考虑使用TensorFlow's TFGAN以避免重现GAN基础设施。 These examples演示如何使用TFGAN创建各种GAN(使用,以及使用内置功能)。

+1

虽然此链接可能回答问题,最好在这里包括答案的重要部分,并提供参考链接。如果链接页面更改,则仅链接答案可能会失效。 - [来自评论](/ review/low-quality-posts/18093589) – aaron