GANPictureGen

通过简单的图片生成模型,了解GAN的工作过程

#coding=utf-8
from PIL import Image
from keras.models import Sequential
from keras.layers import Dense,Activation,BatchNormalization,Reshape,UpSampling2D,\
    Conv2D,MaxPooling2D,Flatten
import numpy as  np
from keras.optimizers import SGD
from keras.datasets import mnist
import math

# 定义生成器模型
def Generator_model():
    # 下面搭建生成器的架构,首先导入序贯模型
    model = Sequential()
    # 添加一个全连接层,输入为100维向量,输出为1024维
    model.add(Dense(input_dim=100, output_dim=1024))
    # 添加一个激活函数tanh
    model.add(Activation('tanh'))
    # 添加一个全连接层,输出维128×7×7维度
    model.add(Dense(128*7*7))
    # 添加一个批量归一化层,该层在每个batch上将前一层的激活值重新规范化,即使得其输出均值接近于0,标准差接近于1
    model.add(BatchNormalization())
    model.add(Activation('tanh'))
    # Reshape层用来将输入shape转换为特定的shape
    model.add(Reshape((7,7,128),input_shape=(128,7,7)))
    # 2维上采样层,即将数据的行和列分别重复2次
    model.add(UpSampling2D(size=(2,2)))
    # 添加一个2维卷积层,卷积核大小维5×5,激活函数为tanh,共64个卷积核,并采用padding使图像尺寸保持不变
    model.add(Conv2D(64,(5,5),padding='same'))
    model.add(Activation('tanh'))
    model.add(UpSampling2D(size=(2,2)))
    # 卷积核设为1即输出图像的维度
    model.add(Conv2D(1,(5,5),padding='same'))
    model.add(Activation('tanh'))
    return model

# 定义判别器模型
def Discriminator_model():
    model=Sequential()
    # 添加二维卷积层,卷积核大小为5×5,激活函数为tanh,
    model.add(
        Conv2D(64,(5,5),
        padding='same',
        input_shape=(28,28,1))
    )
    model.add(Activation('tanh'))
    #添加最大池化层,pool_size取(2,2)使得图片在原来维度上变为一半
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Conv2D(128,(5,5)))
    model.add(Activation('tanh'))
    #卷积层过渡到全连接层
    model.add(Flatten())
    model.add(Dense(1024))
    model.add(Activation('tanh'))
    #一个节点进行二值分类
    model.add(Dense(1))
    model.add(Activation('sigmoid'))
    return model

#将生成器和判别器连结成为GAN模型
def GAN_model(g,d):
    model=Sequential()
    #先添加Generator,再令Discriminator不可训练(即固定d)
    model.add(g)
    d.trainable=False
    model.add(d)
    return model

#生成图片进行拼接
def Combine_image(generated_images):
    num = generated_images.shape[0]#图片数目
    width = int(math.sqrt(num))
    height = int(math.ceil(float(num)/width))
    shape = generated_images.shape[1:3]#图片形状取其1-3维,第一维是num
    image = np.zeros((height*shape[0],width*shape[1]),
                     dtype = generated_images.dtype)
    for index,img in enumerate(generated_images):
        i = int(index/width)
        j = index%width
        image[i*shape[0]:(i+1)*shape[0],j*shape[1]:(j+1)*shape[1]]=img[:,:,0]
    return image

#训练GAN
def Train(Batch_size):
    (X_train,y_train),(X_test,y_test)=mnist.load_data()
    #归一化
    X_train = (X_train.astype(np.float32)-127.5)/127.5
    X_train = X_train[:,:,:,None]
    x_test = X_test[:,:,:,None]
    #将定义好的Generator和Discriminator赋值给特定变量
    g = Generator_model()
    d = Discriminator_model()
    g.load_weights('generator_weight',True)
    d.load_weights('discriminator_weight',True)
    d_on_g = GAN_model(g,d)
    #利用SGD优化器
    d_optim = SGD(lr=0.001,momentum=0.9,nesterov=True)
    g_optim = SGD(lr=0.001,momentum=0.9,nesterov=True)
    #对G、D和GAN进行编译
    g.compile(loss='binary_crossentropy', optimizer="SGD")
    d_on_g.compile(loss='binary_crossentropy', optimizer=g_optim)
    #前一个架构再固定D的情况下训练了G,故此处需先设置D为可训练
    d.trainable = True
    d.compile(loss='binary_crossentropy',optimizer=d_optim)
    for epoch in range(30):
        print("Epoch is",epoch)
        #计算一个epoch所需要的迭代次数。
        print("Number of batches is ",int(X_train.shape[0]/Batch_size))

        #一个epoch内进行迭代训练
        for index in range(int(X_train.shape[0]/Batch_size)):
            # 随机生成均匀分布,上下边界为1和-1,输出Batch_size×100个样本
            noise = np.random.uniform(-1,1,size=(Batch_size,100))
            #抽取一个批量的真实照片
            image_batch = X_train[index * Batch_size:(index + 1) * Batch_size]
            #生成的图片使用G对随机噪声进行推断
            generated_images = g.predict(noise, verbose=0)

            #每经过100次迭代输出一张生成的图片
            if index % 100 == 0:
                image = Combine_image(generated_images)
                #逆归一化
                image = image * 127.5 + 127.5
                Image.fromarray(image.astype(np.uint8)).save(
                    "./GAN_Picture_train/" + str(epoch) + "_"+ str(index) + ".png"
                )

            #将真实的图片和生成的图片以数组的形式拼接再一起,真实图片在上,生成图片在下
            X = np.concatenate((image_batch,generated_images))
            #生成真假标签,即一个包含两倍批量大小的列表,前一个批量均为1,代表真,后一个批量均为0,代表生成图片
            y = [1] * Batch_size + [0] * Batch_size

            #判别器的损失;在一个batch的数据上进行一次参数更新
            d_loss = d.train_on_batch(X,y)
            print("batch %d d_loss : %f" % (index,d_loss))
            #随机生成均匀分布噪声
            noise = np.random.uniform(-1,1,(Batch_size,100))
            #固定D
            d.trainable = False
            #计算生成器损失;在一个batch的数据上进行一次参数更新
            g_loss = d_on_g.train_on_batch(noise,[1]*Batch_size)
            #令D可训练
            d.trainable = True
            print("batch %d g_loss : %f" %(index,g_loss))
            #每100次迭代保存一次G和D的权重
            if index%100 == 9:
                g.save_weights('generator_weight',True)
                d.save_weights('discriminator_weight',True)

#产生图片
def Generate(Batch_size,nice=False):
    #调用Generator
    g = Generator_model()
    g.compile(loss='binary_crossentropy',optimizer="SGD")
    #加载权重
    g.load_weights('generator_weight')
    if nice:
        d = Discriminator_model()
        d.compile(loss='binary_crossentropy',optimizer="SGD")
        d.load_weights('disriminator_weight')
        noise = np.random.uniform(-1,1,(Batch_size*20,100))
        generated_images = g.predict(noise,verbose=1)
        d_pret = d.predict(generated_images,verbose=1)
        #产生0到Batch_size*20的数,步长为1
        index =np.arange(0,Batch_size*20)
        #转换形状
        index.resize((Batch_size*20,1))
        pre_with_index =list(np.append(d_pret,index,axis=1))#axis=1表示沿着行向量的方向
        pre_with_index.sort(key=lambda x:x[0],reverse=True)#reverse=True表示升序;key=lambda x:x[0]指明所根据的字段进行排序
        nice_images = np.zeros((Batch_size,)+generated_images.shape[1:3],dtype=np.float32)
        nice_images = nice_images[:,:,:,None]
        for i in range(Batch_size):
            idx = int(pre_with_index[i][1])
            nice_images[i,:,:,0] = generated_images[idx,:,:,0]
        image = Combine_image(nice_images)
    else:
        #随机生成正态分布噪声
        noise = np.random.uniform(-1, 1, (Batch_size, 100))
        generated_images = g.predict(noise, verbose=0)
        image = Combine_image(generated_images)
    image = image*127.5+127.5
    #保存图片
    Image.fromarray(image.astype(np.uint8)).save(
        "./GAN_Picture/Generate_image3.png"
    )
Train(50)
Generate(100)

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201016211524931.png

0%