基于gan网络的手写数字图像生成

举报
林中电弧 发表于 2021/11/12 11:54:19 2021/11/12
【摘要】 基于gan网络的手写数字图像生成,使用kreas框架

直接贴代码

import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential,Model,load_model
from keras.layers import Dropout, Conv2D, Dense,  LeakyReLU, Input,Reshape,  Flatten,  Conv2DTranspose
from keras.optimizers import adam_v2
import struct

os.environ["CUDA_VISIBLE_DEVICES"]="0"

def loadData_MNIST(path, kind='train'):
    labels_path = os.path.join(path,'%s-labels.idx1-ubyte'% kind)
    images_path = os.path.join(path,'%s-images.idx3-ubyte'% kind)
    with open(labels_path, 'rb') as lbpath:
        magic, n = struct.unpack('>II',lbpath.read(8))
        labels = np.fromfile(lbpath,dtype=np.uint8)
    with open(images_path, 'rb') as imgpath:
        magic, num, rows, cols = struct.unpack('>IIII',imgpath.read(16))
        images = np.fromfile(imgpath,dtype=np.uint8).reshape(len(labels),28,28,1)

    #由于源数据有些数据过大,会导致激活函数计算溢出,所以对数据集集体缩小,
    #由于图片数据每一位的值均为0-255之间,但统一除以255后发现当神经元个数达到一定数目或层数增加时还是会计算溢出,于是决定统一除以2550
    return (images-127.5)/127.5
#img_dataset为一个3维矩阵,数量*(64,64)的矩阵
# img_dataset=load_data()

def show_images(images,index = -1):
    """
    展示并保存图片
    :param images: 需要show的图片
    :param index: 保存图片名
    :return:
    """
    #定义一个图片
    plt.figure()

    for i, image in enumerate(images):
        #设置为55列显示
        ax = plt.subplot(5, 5, i+1)
        #关闭坐标轴
        plt.axis('off')
        plt.imshow(image)
    plt.savefig("data_%d.png"%index)
    plt.show()

# show_images(img_dataset[0:25],0)
# show_images(img_dataset[0: 25])
images=loadData_MNIST("data2")
show_images(images[0: 25])
#____________________________________________________

# noise的维度
noise_dim = 100
# 图片的shape
image_shape = (28,28,1)

Adam=adam_v2.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08)


def build_G():
    """
    构建生成器
    :return:
    """
    #model为生成模型
    model = Sequential()
    
    model.add(Input(shape=noise_dim))
    #(100)

    model.add(Dense(14*14*16))
    # Conv2D(1,3,padding='same')
    #(131072)
    
    model.add(LeakyReLU(0.2))
    model.add(Reshape((14,14,16)))
    #(32,32,128)

    #空间维数256SAME是在进行卷积前,在图像的周围补一圈0
    model.add(Conv2D(32,5,padding='same'))
    model.add(LeakyReLU(0.2))
    #(32,32,256)

    #出256,核4*4,stride就是在相邻元素之间添加stride-10元素
    #反卷积中如果padding为same的话则output_shape = input_shape * stride
    model.add(Conv2DTranspose(32,4,strides=2,padding='same'))
    model.add(LeakyReLU(0.2))
    #(64,64,256)

    model.add(Conv2D(32,5,padding='same'))
    model.add(LeakyReLU(0.2))
    #(64,64,256)

    model.add(Conv2D(32,5,padding='same'))
    model.add(LeakyReLU(0.2))
    #(64,64,256)
    
    model.add(Conv2D(1,7,activation='tanh',padding='same'))
    #(64,64,3)     
    
    return model

G = build_G()


def build_D():
    """
    构建判别器
    :return: 
    """
    model = Sequential()
    
    # 卷积层
    model.add(Conv2D(16,3,input_shape = image_shape))
    model.add(LeakyReLU(0.2))
    #[62,62,128]

    model.add(Conv2D(16,4, strides=2))
    model.add(LeakyReLU(0.2))
    #[30,30,128]

    # model.add(Conv2D(128,4, strides=2))
    # model.add(LeakyReLU(0.2))
    #[14,14,128]

    model.add(Conv2D(16,4, strides=2))
    model.add(LeakyReLU(0.2))
    #[6,6,128]
    
    model.add(Flatten())
    #[4608]

    model.add(Dropout(0.4))

    model.add(Dense(1,activation='sigmoid'))
    
    #损失选择交叉熵损失,是鼻主。
    model.compile(loss='binary_crossentropy',
              optimizer=adam_v2.Adam(learning_rate=0.0002, beta_1=0.5))
    return model
D = build_D()


def build_gan():
    """
    构建GAN网络
    :return:
    """
    # 冷冻判别器,也就是在训练的时候只优化G的网络权重,而对D保持不变
    D.trainable = False
    # GAN网络的输入
    gan_input = Input(shape=(noise_dim,))
    # GAN网络的输出
    gan_out = D(G(gan_input))
    # 构建网络
    gan = Model(gan_input,gan_out)
    # 编译GAN网络,使用Adam优化器,以及加上交叉熵损失函数(一般用于二分类)
    gan.compile(loss='binary_crossentropy',optimizer=adam_v2.Adam(learning_rate=0.0002, beta_1=0.5))
    return gan

GAN = build_gan()

#————————————————————————————————————————————————————————
def sample_noise(batch_size):
    """
    随机产生正态分布(01)的noise
    :param batch_size:
    :return: 返回的shape为(batch_size,noise)
    """
    return np.random.normal(size=(batch_size, noise_dim))

def smooth_pos_labels(y):
    """
    使得true label的值的范围为[0.8,1]
    :param y:
    :return:
    """
    return y - (np.random.random(y.shape) * 0.2)

def smooth_neg_labels(y):
    """
    使得fake label的值的范围为[0.0,0.3]
    :param y:
    :return:
    """
    return y + np.random.random(y.shape) * 0.3

def load_batch(data, batch_size,index):
    """
    按批次加载图片
    :param data: 图片数据集
    :param batch_size: 批次大小
    :param index: 批次序号
    :return:
    """
    return data[index*batch_size: (index+1)*batch_size]

#————————————————————————————————————————————————————————
def train(img_dataset,epochs=100, batch_size=64):
    """
    训练函数
    :param epochs: 训练的次数
    :param batch_size: 批尺寸
    :return:
    """
    # 判别器损失
    discriminator_loss = 0
    # 生成器损失
    generator_loss = 0
    
    # img_dataset.shape[0] / batch_size 代表这个数据可以分为几个批次进行训练
    n_batches = int(img_dataset.shape[0] / batch_size)
    
    for i in range(epochs):
        print("第{}轮训练开始".format(i))
        for index in range(n_batches):
            print(index)
            # 按批次加载数据
            x = load_batch(img_dataset, batch_size,index)
            # 产生noise
            noise = sample_noise(batch_size)
            # G网络产生图片
            generated_images = G.predict(noise)
            # 产生为1的标签
            y_real = np.ones(batch_size)
            # 将1标签的范围变成[0.8 , 1.0]
            y_real = smooth_pos_labels(y_real)
            # 产生为0的标签
            y_fake = np.zeros(batch_size)
            # 将0标签的范围变成[0.0 , 0.3]
            y_fake = smooth_neg_labels(y_fake)
            # 训练真图片loss
            d_loss_real = D.train_on_batch(x, y_real)
            # 训练假图片loss
            d_loss_fake = D.train_on_batch(generated_images, y_fake)

            discriminator_loss = d_loss_real + d_loss_fake
            # 产生为1的标签
            y_real = np.ones(batch_size)
            # 训练GAN网络,input = fake_img ,label = 1
            generator_loss = GAN.train_on_batch(noise, y_real)
        
        print('[Epoch {0}]. Discriminator loss : {1}. Generator_loss: {2}.'.format(i, discriminator_loss, generator_loss))

        # 每个epoch保存一次。
        if i%1 == 0:
            # 随机产生(25,100)的noise
            test_noise = sample_noise(25)
            # 使用G网络生成25张图偏
            test_images = G.predict(test_noise)
            # show 预测 img
            show_images(test_images,i)
        # GAN.save("/mymodle")


# %%
# print(int(img_dataset.shape[0] / 256))


# %%
train(images[:10000],epochs=100, batch_size=256)

# GAN=load_model("C:\\Users\\23502\\Documents\\codeProjects\\code_Py_learn\\上课\\大作业\\dcgan_anime_avatars-master\\文件\\my_model_gan")
# test_noise = sample_noise(25)
#             # 使用G网络生成25张图偏
# test_images = G.predict(test_noise)
# # show 预测 img
# show_images(test_images,10)
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。