将类信息添加到keras网络

Jos*_*mon 13 python conv-neural-network keras loss-function generative-adversarial-network

我试图找出如何使用Generative Adversarial Networks的数据集标签信息.我试图使用可在此处找到的条件GAN的以下实现.我的数据集包含两个不同的图像域(真实对象和草图),具有公共类信息(椅子,树,橙等).我选择了这种实现,它只将两个不同的域视为对应的不同"类"(列车样本X对应于真实图像,而目标样本y对应于草图图像).

有没有办法修改我的代码并考虑我整个架构中的类信息(椅子,树等)?我希望我的鉴别器能够预测我生成的图像来自生成器是否属于特定类,而不仅仅是它们是否真实.实际上,在当前架构中,系统学会在所有情况下创建类似的草图.

更新:鉴别器返回一个大小的张量1x7x7然后两者y_truey_pred在计算损失之前通过展平层:

def discriminator_loss(y_true, y_pred):
     BATCH_SIZE=100
     return K.mean(K.binary_crossentropy(K.flatten(y_pred), K.concatenate([K.ones_like(K.flatten(y_pred[:BATCH_SIZE,:,:,:])),K.zeros_like(K.flatten(y_pred[:BATCH_SIZE,:,:,:])) ]) ), axis=-1)
Run Code Online (Sandbox Code Playgroud)

以及鉴别器对发电机的损失功能:

def discriminator_on_generator_loss(y_true,y_pred):
     BATCH_SIZE=100
     return K.mean(K.binary_crossentropy(K.flatten(y_pred), K.ones_like(K.flatten(y_pred))), axis=-1)
Run Code Online (Sandbox Code Playgroud)

此外,我对输出1层的鉴别器模型的修改:

model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
#model.add(Activation('sigmoid'))
Run Code Online (Sandbox Code Playgroud)

现在鉴别器输出1层.如何相应修改上述损失函数?我应该有7而不是1,n_classes = 6用于预测真实和假对的+一类吗?

ben*_*che 7

建议的解决方案

重用您共享存储库中的代码,以下是一些建议的修改,以便在您的生成器和鉴别器上训练分类器(它们的架构和其他损失保持不变):

from keras import backend as K
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D

def lenet_classifier_model(nb_classes):
    # Snipped by Fabien Tanc - https://www.kaggle.com/ftence/keras-cnn-inspired-by-lenet-5
    # Replace with your favorite classifier...
    model = Sequential()
    model.add(Convolution2D(12, 5, 5, activation='relu', input_shape=in_shape, init='he_normal'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Convolution2D(25, 5, 5, activation='relu', init='he_normal'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Flatten())
    model.add(Dense(180, activation='relu', init='he_normal'))
    model.add(Dropout(0.5))
    model.add(Dense(100, activation='relu', init='he_normal'))
    model.add(Dropout(0.5))
    model.add(Dense(nb_classes, activation='softmax', init='he_normal'))

def generator_containing_discriminator_and_classifier(generator, discriminator, classifier):
    inputs = Input((IN_CH, img_cols, img_rows))
    x_generator = generator(inputs)

    merged = merge([inputs, x_generator], mode='concat', concat_axis=1)
    discriminator.trainable = False
    x_discriminator = discriminator(merged)

    classifier.trainable = False
    x_classifier = classifier(x_generator)

    model = Model(input=inputs, output=[x_generator, x_discriminator, x_classifier])

    return model


def train(BATCH_SIZE):
    (X_train, Y_train, LABEL_train) = get_data('train')  # replace with your data here
    X_train = (X_train.astype(np.float32) - 127.5) / 127.5
    Y_train = (Y_train.astype(np.float32) - 127.5) / 127.5
    discriminator = discriminator_model()
    generator = generator_model()
    classifier = lenet_classifier_model(6)
    generator.summary()
    discriminator_and_classifier_on_generator = generator_containing_discriminator_and_classifier(
        generator, discriminator, classifier)
    d_optim = Adagrad(lr=0.005)
    g_optim = Adagrad(lr=0.005)
    generator.compile(loss='mse', optimizer="rmsprop")
    discriminator_and_classifier_on_generator.compile(
        loss=[generator_l1_loss, discriminator_on_generator_loss, "categorical_crossentropy"],
        optimizer="rmsprop")
    discriminator.trainable = True
    discriminator.compile(loss=discriminator_loss, optimizer="rmsprop")
    classifier.trainable = True
    classifier.compile(loss="categorical_crossentropy", optimizer="rmsprop")

    for epoch in range(100):
        print("Epoch is", epoch)
        print("Number of batches", int(X_train.shape[0] / BATCH_SIZE))
        for index in range(int(X_train.shape[0] / BATCH_SIZE)):
            image_batch = Y_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE]
            label_batch = LABEL_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE]  # replace with your data here

            generated_images = generator.predict(X_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE])
            if index % 20 == 0:
                image = combine_images(generated_images)
                image = image * 127.5 + 127.5
                image = np.swapaxes(image, 0, 2)
                cv2.imwrite(str(epoch) + "_" + str(index) + ".png", image)
                # Image.fromarray(image.astype(np.uint8)).save(str(epoch)+"_"+str(index)+".png")

            # Training D:
            real_pairs = np.concatenate((X_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE, :, :, :], image_batch),
                                        axis=1)
            fake_pairs = np.concatenate(
                (X_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE, :, :, :], generated_images), axis=1)
            X = np.concatenate((real_pairs, fake_pairs))
            y = np.zeros((20, 1, 64, 64))  # [1] * BATCH_SIZE + [0] * BATCH_SIZE
            d_loss = discriminator.train_on_batch(X, y)
            print("batch %d d_loss : %f" % (index, d_loss))
            discriminator.trainable = False

            # Training C:
            c_loss = classifier.train_on_batch(image_batch, label_batch)
            print("batch %d c_loss : %f" % (index, c_loss))
            classifier.trainable = False

            # Train G:
            g_loss = discriminator_and_classifier_on_generator.train_on_batch(
                X_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE, :, :, :], 
                [image_batch, np.ones((10, 1, 64, 64)), label_batch])
            discriminator.trainable = True
            classifier.trainable = True
            print("batch %d g_loss : %f" % (index, g_loss[1]))
            if index % 20 == 0:
                generator.save_weights('generator', True)
                discriminator.save_weights('discriminator', True)
Run Code Online (Sandbox Code Playgroud)

理论细节

我认为对于有条件的GAN如何运作以及这些方案中的歧视者角色存在一些误解.

歧视者的角色

在GAN训练的最小 - 最大游戏[4]中,鉴别D器正在与发生器G(你实际关心的网络)进行对抗,这样在经过D仔细检查后,G就能更好地输出真实的结果.

为此,D训练分开来自样本的真实样本G; 而G被训练来欺骗D通过产生以下的目标分布现实的结果/结果.

注意:在条件GAN的情况下,即GAN将输入样本从一个域A(例如实际图片)映射到另一个域B (例如草图),D通常将堆叠在一起的样本对提供,并且必须区分"真实"对(来自A+对应目标样本的输入样本B和"假"对(来自A+对应输出的输入样本G) [1,2]

训练条件生成器D(而不是单纯训练G,只有L1/L2丢失,例如DAE)提高了采样能力G,迫使它输出清晰,逼真的结果,而不是试图平均分布.

尽管鉴别器可以有多个子网络来覆盖其他任务(参见下面的段落),但D应保留至少一个子网络/输出来覆盖其主要任务:分别从生成的样本中分析实际样本.要求D进一步回归进一步的语义信息(例如类)可能会干扰这个主要目的.

注意:D输出通常不是简单的标量/布尔值.通常有一个鉴别器(例如PatchGAN [1,2])返回一个概率矩阵,评估从其输入得到的真实补丁是多少.


有条件的GAN

以无人监督的方式训练传统GAN以从随机噪声矢量作为输入生成真实数据(例如图像).[4]

如前所述,条件GAN具有进一步的输入条件.沿着/代替噪声向量,它们从域中输入样本并从域A返回相应的样本B.A可以是完全不同的模态,例如B = sketch image同时A = discrete label; B = volumetric data同时A = RGB image,等[3]

这样的GAN也可以由多个输入来调节,例如A = real image + discrete labelwhile B = sketch image.介绍这些方法的着名工作是InfoGAN [5].它提出了如何在多个连续或离散输入(例如调节甘斯A = digit class + writing type,B = handwritten digit image),使用具有用于第二任务强制更先进的鉴别器G以最大化其调节输入和其相应的输出之间的互信息.


最大化cGAN的互信息

InfoGAN鉴别器有2个头/子网络来完成它的2个任务[5]:

  • 一个人D1做传统的真实/产生的歧视 - G必须最小化这个结果,即它必须愚弄,D1以便它不能分辨真实形式生成的数据;
  • 另一个头D2(也称为Q网络)试图回归输入A信息 - G必须最大化该结果,即它必须输出"显示"所请求的语义信息的数据(参见G条件输入及其输出之间的互信息最大化).

您可以在此处找到Keras实现,例如:https://github.com/eriklindernoren/Keras-GAN/tree/master/infogan.

通过使用提供的标签并最大化这些输入和G输出之间的互信息,一些工作正在使用类似的方案来改进对GAN生成的控制[6,7].基本思路总是一样的:

  • GB给出域的一些输入的情况下,训练生成域的元素A;
  • 训练D歧视"真实"/"假"结果 - G必须尽量减少这种情况;
  • 训练Q(例如分类器;可以共享层D)以估计样本的原始A输入B- G必须最大化这个).

包起来

在您的情况下,您似乎有以下培训数据:

  • 真实的图像 Ia
  • 相应的草图图像 Ib
  • 相应的班级标签 c

并且您希望训练一个生成器,G以便给定一个图像Ia及其类标签c,它会输出一个合适的草图图像Ib'.

总而言之,这是你拥有的大量信息,你可以监控你在条件图像和条件标签上的训练......灵感来自前面提到的方法[1,2,5,6,7],这里是一个使用所有这些信息来训练您的条件的可能方式G:

网络G:
  • 输入:Ia+c
  • 输出: Ib'
  • 架构:最新的(例如U-Net,ResNet,......)
  • 损失:Ib'&之间的L1/L2损失Ib,-D损失,Q损失
网络D:
  • 输入:Ia+ Ib(真实对),Ia+ Ib'(假对)
  • 输出:"假"标量/矩阵
  • 架构:最新的(例如PatchGAN)
  • 损失:对"假"估计的交叉熵
网络Q:
  • 输入:( Ib真实样本,用于训练Q),Ib'(假样本,反向传播时G)
  • 输出:( c'估计等级)
  • 架构:最新的(例如LeNet,ResNet,VGG,......)
  • 损失:c和之间的交叉熵c'
培训阶段:
  1. 训练D一批真正的对Ia+ Ib然后是一批假对Ia+ Ib';
  2. 训练Q一批真实样本Ib;
  3. 固定DQ重量;
  4. 训练G,将生成的输出传递Ib'给它们DQ通过它们反向传播.

注意:这是一个非常粗略的架构描述.我建议通过文献([1,5,6,7]作为一个良好的开端)来获得更多细节,也许是一个更精细的解决方案.


参考

  1. Isola,Phillip,et al."使用条件对抗网络进行图像到图像的转换." arXiv preprint(2017).http://openaccess.thecvf.com/content_cvpr_2017/papers/Isola_Image-To-Image_Translation_With_CVPR_2017_paper.pdf
  2. 朱俊彦等 "使用循环一致的对抗网络进行不成对的图像到图像转换." arXiv preprint arXiv:1703.10593(2017).http://openaccess.thecvf.com/content_ICCV_2017/papers/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.pdf
  3. 米尔扎,迈赫迪和西蒙奥辛德罗."有条件的生成对抗网." arXiv preprint arXiv:1411.1784(2014).https://arxiv.org/pdf/1411.1784
  4. Goodfellow,Ian,et al."生成对抗网." 神经信息处理系统的进展.2014. http://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf
  5. 陈曦等 "Infogan:通过最大化生成对抗网络的信息进行可解释的代表性学习." 神经信息处理系统的进展.2016. http://papers.nips.cc/paper/6399-infogan-interpretable-representation-learning-by-information-maximizing-generative-adversarial-nets.pdf
  6. Lee,Minhyeok和Junhee Seok."可控生成对抗网络".arXiv preprint arXiv:1708.00598(2017).https://arxiv.org/pdf/1708.00598.pdf
  7. Odena,Augustus,Christopher Olah和Jonathon Shlens."使用辅助分类器gans进行条件图像合成." arXiv preprint arXiv:1610.09585(2016).http://proceedings.mlr.press/v70/odena17a/odena17a.pdf