Advertisement

1.4半监督生成对抗网络(SGAN)

阅读量:

SGAN是一种半监督生成对抗网络,结合生成器和鉴别器进行训练。其核心在于利用少量标签数据和大量无标签数据进行学习,通过生成器生成伪样本和鉴别器区分真伪样本,同时鉴别器需对真实样本进行多分类以提高准确性。SGAN的鉴别器不仅用于二分类(真伪区分),还用于多分类(类别预测),通过监督学习提升生成器的逼真度。实验结果表明,SGAN在训练集上达到了100%的分类准确率,在测试集上获得了89%的精度。

1.SGAN简介

半监督学习仅用于为训练数据集的一小部分分配类别标签。数据内部的潜在结构为半监督学习提供了基础,使其能够从标注数据集中抽取小样本,并对未知样例进行精确分类。

要使半监督学习有效,标签数据和无标签数据必须来自相同分布。

半监督生成对抗网络是一种生成对抗网络,其分类器为多分类器,不仅能够区分正反两类,而是能够识别N+1类,其中N为训练数据集的类别数,生成模块生成的假样本属于特定类别。

相对于其他生成对抗网络,SGAN的核心关注点是鉴别器。在训练过程中,该网络最终目标是成为仅依赖部分标签数据的半监督分类器,其性能表现与全监督分类器相近,即每个样本都带有标签的半监督分类器。

1.2架构图

生成器负责将随机噪音转换为伪样本;鉴别器接收有标签的真实图像(x,y)、无标签的真实图像(x)以及生成器生成的伪图像(x*)。首先使用sigmoid函数区分真伪,接着采用softmax进行类别划分。

2.代码实现

2.1导入声明

复制代码
 %matplotlib inline

    
  
    
 import matplotlib.pyplot as plt
    
 import numpy as np
    
  
    
 from keras import backend as K
    
  
    
 from keras.datasets import mnist
    
 from keras.layers import (Activation, BatchNormalization, Concatenate, Dense,
    
                       Dropout, Flatten, Input, Lambda, Reshape)
    
 from keras.layers.advanced_activations import LeakyReLU
    
 from keras.layers.convolutional import Conv2D, Conv2DTranspose
    
 from keras.models import Model, Sequential
    
 from keras.optimizer_v2 import adam as Adam
    
 from tensorflow.keras.utils import to_categorical

2.2模型输入维度

复制代码
 img_rows = 28

    
 img_cols = 28
    
 channels = 1
    
  
    
 # 输入图像维度
    
 img_shape = (img_rows, img_cols, channels)
    
  
    
 # 噪声向量的大小,用作生成器的输入
    
 z_dim = 100
    
  
    
 # 数据集中类别的数量
    
 num_classes = 10

2.3数据集

此处采用的是MNIST数据集,该数据集总共包含有50000张图片,每张图片都带有标签。但其中仅选取一部分图片用于训练,其余图片则假设没有标签。

复制代码
 class Dataset:

    
     def __init__(self, num_labeled):
    
  
    
     # 训练中使用的有标签图像的数量
    
     self.num_labeled = num_labeled
    
  
    
     # 加载MINST数据集
    
     (self.x_train, self.y_train), (self.x_test,
    
                                    self.y_test) = mnist.load_data()
    
  
    
     def preprocess_imgs(x):
    
         # 灰度像素值从[0,255]缩放到[-1,1]
    
         x = (x.astype(np.float32) - 127.5) / 127.5
    
         # 将图像尺寸扩展到宽*高*通道数
    
         x = np.expand_dims(x, axis=3)
    
         return x
    
  
    
     def preprocess_labels(y):
    
         return y.reshape(-1, 1)
    
  
    
     # 训练数据
    
     self.x_train = preprocess_imgs(self.x_train)
    
     self.y_train = preprocess_labels(self.y_train)
    
  
    
     # 测试数据
    
     self.x_test = preprocess_imgs(self.x_test)
    
     self.y_test = preprocess_labels(self.y_test)
    
  
    
     def batch_labeled(self, batch_size):
    
    #获取随机批量有标签图像及其标签
    
     idx = np.random.randint(0, self.num_labeled, batch_size)
    
     imgs = self.x_train[idx]
    
     labels = self.y_train[idx]
    
     return imgs, labels
    
  
    
     def batch_unlabeled(self, batch_size):
    
     # 获取随机批量的无标签图像
    
     idx = np.random.randint(self.num_labeled, self.x_train.shape[0],
    
                             batch_size)
    
     imgs = self.x_train[idx]
    
     return imgs
    
  
    
     def training_set(self):
    
     x_train = self.x_train[range(self.num_labeled)]
    
     y_train = self.y_train[range(self.num_labeled)]
    
     return x_train, y_train
    
  
    
     def test_set(self):
    
     return self.x_test, self.y_test
    
  
    
 # 要使用的有标签样本的数量
    
 num_labeled = 100
    
  
    
 dataset = Dataset(num_labeled)

2.4生成器

此处的生成器网络与DCGAN网络具有相同的结构,通过转置卷积层,将低维的随机噪声向量映射到高维的空间,从而生成与目标图像尺寸(28281)一致的图像。

复制代码
 def build_generator(z_dim):

    
  
    
     model = Sequential()
    
  
    
     # 通过一个全连接层改变输入为一个7*7*256的张量
    
     model.add(Dense(256 * 7 * 7, input_dim=z_dim))
    
     model.add(Reshape((7, 7, 256)))
    
  
    
     # 转置卷积层,张量从7*7*256变为14*14*128
    
     model.add(Conv2DTranspose(128, kernel_size=3, strides=2, padding='same'))
    
  
    
     # 批归一化
    
     model.add(BatchNormalization())
    
  
    
     # Leaky ReLU 的激活函数
    
     model.add(LeakyReLU(alpha=0.01))
    
  
    
     # 转置卷积层,张量从14*14*128变为14*14*64
    
     model.add(Conv2DTranspose(64, kernel_size=3, strides=1, padding='same'))
    
  
    
     # 拟归一化
    
     model.add(BatchNormalization())
    
  
    
     # Leaky ReLU 的激活函数
    
     model.add(LeakyReLU(alpha=0.01))
    
  
    
     #转置卷积层,张量从14*14*64变为28*28*1
    
     model.add(Conv2DTranspose(1, kernel_size=3, strides=2, padding='same'))
    
  
    
     # 带有tanh激活函数的输出层
    
     model.add(Activation('tanh'))
    
  
    
     return model

2.5鉴别器

有着双重目标:

区别真实样本和伪样本。(使用sigmoid函数)

对于真实样本,还要对其标签进行分类。(使用softmax函数)

2.5.1核心鉴别网络

添加一个dropout,通过在训练过程中随机丢弃神经元来防止过拟合。

复制代码
 def build_discriminator_net(img_shape):

    
  
    
     model = Sequential()
    
  
    
     # 卷积层,张量从28*28*1变成14*14*32
    
     model.add(
    
     Conv2D(32,
    
            kernel_size=3,
    
            strides=2,
    
            input_shape=img_shape,
    
            padding='same'))
    
  
    
     # Leaky ReLU 的激活函数
    
     model.add(LeakyReLU(alpha=0.01))
    
  
    
     # 卷积层,张量从14*14*32到7*7*64
    
     model.add(
    
     Conv2D(64,
    
            kernel_size=3,
    
            strides=2,
    
            input_shape=img_shape,
    
            padding='same'))
    
  
    
     # 批归一化
    
     model.add(BatchNormalization())
    
  
    
     # Leaky ReLU 激活函数
    
     model.add(LeakyReLU(alpha=0.01))
    
  
    
     # 卷积层,张量从7*7*64变成3*3128
    
     model.add(
    
     Conv2D(128,
    
            kernel_size=3,
    
            strides=2,
    
            input_shape=img_shape,
    
            padding='same'))
    
  
    
     # 批归一化
    
     model.add(BatchNormalization())
    
  
    
     # Leaky ReLU 激活函数
    
     model.add(LeakyReLU(alpha=0.01))
    
  
    
     # Droupout正则
    
     model.add(Dropout(0.5))
    
  
    
     # 将张量展平
    
     model.add(Flatten())
    
  
    
     # 于unm_classes神经元完全连接的层
    
     model.add(Dense(num_classes))
    
  
    
     return model

2.5.2有监督的多分类鉴定器

复制代码
 def build_discriminator_supervised(discriminator_net):

    
  
    
     model = Sequential()
    
  
    
     model.add(discriminator_net)
    
  
    
     # Softmax 激活函数, 输出真实类别的预测概率分布
    
     model.add(Activation('softmax'))
    
  
    
     return model

2.5.3无监督的二分类鉴定器

复制代码
 def build_discriminator_unsupervised(discriminator_net):

    
  
    
     model = Sequential()
    
  
    
     model.add(discriminator_net)
    
  
    
     def predict(x):
    
     # 将真实类别的分布转换为二元真——假概率
    
     prediction = 1.0 - (1.0 /
    
                         (K.sum(K.exp(x), axis=-1, keepdims=True) + 1.0))
    
     return prediction
    
  
    
     
    
     model.add(Lambda(predict))
    
  
    
     return model

2.6构建模型

复制代码
 def build_gan(generator, discriminator):

    
  
    
     model = Sequential()
    
  
    
     # 结合生成器和鉴定器模型
    
     model.add(generator)
    
     model.add(discriminator)
    
  
    
     return model

鉴定器

复制代码
  
    
 # 核心鉴定器网络:在有监督和无监督中共享
    
 discriminator_net = build_discriminator_net(img_shape)
    
  
    
 #构建有监督鉴定器
    
 discriminator_supervised = build_discriminator_supervised(discriminator_net)
    
 discriminator_supervised.compile(loss='categorical_crossentropy',
    
                              metrics=['accuracy'],
    
                              optimizer=Adam.Adam())
    
  
    
 # 构建无监督鉴定器
    
 discriminator_unsupervised = build_discriminator_unsupervised(discriminator_net)
    
 discriminator_unsupervised.compile(loss='binary_crossentropy',
    
                                optimizer=Adam.Adam())
复制代码
 # 构建生成器

    
 generator = build_generator(z_dim)
    
  
    
 # 生成器训练时保持鉴定器参数不变
    
 discriminator_unsupervised.trainable = False
    
  
    
 # 构建固定参数的鉴别器,以训练生成器
    
 # 鉴别器使用无监督版本
    
 gan = build_gan(generator, discriminator_unsupervised)
    
 gan.compile(loss='binary_crossentropy', optimizer=Adam.Adam())

2.7训练

复制代码
 supervised_losses = []

    
 iteration_checkpoints = []
    
  
    
  
    
 def train(iterations, batch_size, sample_interval):
    
  
    
     # 真实图像的标签:全为1
    
     real = np.ones((batch_size, 1))
    
  
    
     # 伪图像的标签:全为0
    
     fake = np.zeros((batch_size, 1))
    
  
    
     for iteration in range(iterations):
    
  
    
     # -------------------------
    
     #  训练鉴定器
    
     # -------------------------
    
  
    
     # 获得标签样本
    
     imgs, labels = dataset.batch_labeled(batch_size)
    
  
    
     # 独热编码标签
    
     labels = to_categorical(labels, num_classes=num_classes)
    
  
    
     # 获得无标签样本
    
     imgs_unlabeled = dataset.batch_unlabeled(batch_size)
    
  
    
     # 生成一批伪图像
    
     z = np.random.normal(0, 1, (batch_size, z_dim))
    
     gen_imgs = generator.predict(z)
    
  
    
     # 训练有标签的真实样本
    
     d_loss_supervised, accuracy = discriminator_supervised.train_on_batch(imgs, labels)
    
  
    
     #训练无标签的真实样本
    
     d_loss_real = discriminator_unsupervised.train_on_batch(
    
         imgs_unlabeled, real)
    
  
    
     # 训练伪样本
    
     d_loss_fake = discriminator_unsupervised.train_on_batch(gen_imgs, fake)
    
  
    
     d_loss_unsupervised = 0.5 * np.add(d_loss_real, d_loss_fake)
    
  
    
     # ---------------------
    
     #  训练生成器
    
     # ---------------------
    
  
    
     # 生成一批次假图像
    
     z = np.random.normal(0, 1, (batch_size, z_dim))
    
     gen_imgs = generator.predict(z)
    
  
    
     # 训练生成器
    
     g_loss = gan.train_on_batch(z, np.ones((batch_size, 1)))
    
  
    
     if (iteration + 1) % sample_interval == 0:
    
  
    
         # 保存鉴别器的有监督分类损失,以便绘制损失曲线
    
         supervised_losses.append(d_loss_supervised)
    
         iteration_checkpoints.append(iteration + 1)
    
  
    
         # 输出训练过程
    
         print(
    
             "%d [D loss supervised: %.4f, acc.: %.2f%%] [D loss unsupervised: %.4f] [G loss: %f]"
    
             % (iteration + 1, d_loss_supervised, 100 * accuracy,
    
                d_loss_unsupervised, g_loss))

2.8. 训练模型

复制代码
 # 设置超参数

    
 iterations = 8000
    
 batch_size = 32
    
 sample_interval = 800
    
  
    
  
    
 train(iterations, batch_size, sample_interval)

2.9画出鉴定器的监督损失

复制代码
 losses = np.array(supervised_losses)

    
  
    
  
    
 plt.figure(figsize=(15, 5))
    
 plt.plot(iteration_checkpoints, losses, label="Discriminator loss")
    
  
    
 plt.xticks(iteration_checkpoints, rotation=90)
    
  
    
 plt.title("Discriminator – Supervised Loss")
    
 plt.xlabel("Iteration")
    
 plt.ylabel("Loss")
    
 plt.legend()

2.10.模型训练和测试准确率

复制代码
 x, y = dataset.training_set()

    
 y = to_categorical(y, num_classes=num_classes)
    
  
    
 # 在测试集上计算分类准确率
    
 _, accuracy = discriminator_supervised.evaluate(x, y)
    
 print("Training Accuracy: %.2f%%" % (100 * accuracy))

此处生成的结果是100%的数据(SGAN在训练过程中仅使用了100个有标签的样本进行有监督训练,这可能完全记住了训练数据集)

复制代码
 x, y = dataset.test_set()

    
 y = to_categorical(y, num_classes=num_classes)
    
  
    
 # 计算在测试集上的精度
    
 _, accuracy = discriminator_supervised.evaluate(x, y)
    
 print("Test Accuracy: %.2f%%" % (100 * accuracy))

达到了89%

全部评论 (0)

还没有任何评论哟~