[Paddle学习笔记][05][对抗生成网络]

说明:

生成对抗网络(Generative Adversarial Network [1],简称GAN)是非监督式学习的一种方法,通过让两个神经网络相互博弈的方式进行学习。本例程使用DCGAN网络和MNIST数据集生成数字字符。


实验代码:

import paddle
import paddle.fluid as fluid
import numpy as np

import math
import matplotlib.pyplot as plt
%matplotlib inline

# 全局变量
use_cuda = 1 # 是否使用GPU
batch_size = 128 # 每批读取数据
epoch_num = 20 # 训练迭代周期
noise_size = 100 # 噪声维度

# 判别网络
def D(image):
    # 输入图像: N*C*H*W=N*1*28*28, H/W=(H/W-F+2*P)/S+1, 网络层数: 4
    image = fluid.layers.reshape(x=image, shape=[-1, 1, 28, 28])
    
    conv_pool_1 = fluid.nets.simple_img_conv_pool( # 输出: N*64*12*12
        input=image, num_filters=64, filter_size=5, act='leaky_relu',
        pool_size=2, pool_stride=2, param_attr='conv_pool_1_w', bias_attr='conv_pool_1_b')
    conv_pool_2 = fluid.nets.simple_img_conv_pool( # 输出: N*128*4*4
        input=conv_pool_1, num_filters=128, filter_size=5, act='leaky_relu',
        pool_size=2, pool_stride=2, param_attr='conv_pool_2_w', bias_attr='conv_pool_2_b')
    bn1 = fluid.layers.batch_norm(
        input=conv_pool_2, act='leaky_relu', name='bn1',
        param_attr='bn1_w', bias_attr='bn1_b', moving_mean_name='bn1_m', moving_variance_name='bn1_v')
    fc1 = fluid.layers.fc(                         # 输出: N*1024
        input=bn1, size=1024, act=None,
        param_attr='fc1_w', bias_attr='fc1_b')
    bn2 = fluid.layers.batch_norm(
        input=fc1, act='leaky_relu', name='bn2',
        param_attr='bn2_w', bias_attr='bn2_b', moving_mean_name='bn2_m', moving_variance_name='bn2_v')
    
    # 输出标签: 1为真实图像,0为虚假图像
    logit = fluid.layers.fc(                       # 输出: N*1
        input=bn2, size=1, act='sigmoid',
        param_attr='fc2_w', bias_attr='fc2_b')
    
    return logit

# 生成网络
def G(noise):
    # 输入噪声: N*100, 网络层数: 4
    fc3 = fluid.layers.fc(                     # 输出: N*2048
        input=noise, size=2048, act=None,
        param_attr='fc3_w', bias_attr='fc3_b')
    bn3 = fluid.layers.batch_norm(
        input=fc3, act='relu', name='bn3',
        param_attr='bn3_w', bias_attr='bn3_b', moving_mean_name='bn3_m', moving_variance_name='bn3_v')
    fc4 = fluid.layers.fc(                     # 输出: N*6272
        input=bn3, size=6272, act=None,
        param_attr='fc4_w', bias_attr='fc4_b')
    bn5 = fluid.layers.batch_norm(
        input=fc4, act='relu', name='bn5',
        param_attr='bn5_w', bias_attr='bn5_b', moving_mean_name='bn5_m', moving_variance_name='bn5_v')
    
    reshape = fluid.layers.reshape(x=bn5, shape=[-1, 128, 7, 7])
    
    deconv1 = fluid.layers.conv2d_transpose(   # 输出: N*128*14*14
        input=reshape, output_size=[14, 14], 
        num_filters=128, filter_size=5, stride=2, padding=2, dilation=1, act='relu',
        param_attr='deconv1_w', bias_attr='deconv1_b')
    deconv2 = fluid.layers.conv2d_transpose(   # 输出: N*1*28*28
        input=deconv1, output_size=[28, 28], 
        num_filters=1, filter_size=5, stride=2, padding=2, dilation=1, act='tanh',
        param_attr='deconv2_w', bias_attr='deconv2_b')
    
    # 输出图像
    image = fluid.layers.reshape(x=deconv2, shape=[-1, 784])
    
    return image

# 显示图像
def show_image(total_image):
    n = int(math.ceil(math.sqrt(total_image.shape[0])))
    total_image = total_image.reshape((n, n, 28, 28)).transpose((0, 2, 1, 3)).reshape((n*28, n*28))
    fig= plt.figure(figsize=(8, 8))
    plt.axis('off')
    plt.imshow(total_image, cmap='Greys_r', vmin=-1, vmax=1)
    plt.show(fig)

# 训练模型
def train():
    # 读取数据
    train_reader = paddle.batch(
        paddle.reader.shuffle(paddle.dataset.mnist.train(), buf_size=60000),
        batch_size=batch_size)
    
    # 配置训练判别网络
    d_program = fluid.Program() # 获取判别网络
    with fluid.program_guard(d_program):
        # 输入图像
        d_image = fluid.data(name='image', shape=[None, 784], dtype='float32') # 输入图像: N*1*28*28
        d_label = fluid.data(name='label', shape=[None, 1], dtype='float32')   # 图像标签: N*1
        
        # 判别图像
        d_logit = D(d_image)
        
        # 计算损失
        d_loss = fluid.layers.sigmoid_cross_entropy_with_logits(x=d_logit, label=d_label)
        d_avg_loss = fluid.layers.mean(d_loss)
        
    # 配置训练生成网络
    dg_program = fluid.Program() # 获取判别生成网络
    with fluid.program_guard(dg_program):
        # 输入噪声
        g_noise = fluid.data(name='noise', shape=[None, noise_size], dtype='float32')               # 输入噪声: N*100
        noise_shape = fluid.layers.shape(g_noise)
        g_label = fluid.layers.fill_constant(value=1.0, shape=[noise_shape[0], 1], dtype='float32') # 图像标签: N*1
        
        # 生成图像
        g_image = G(g_noise)
        
        # 克隆生成网络
        g_program = dg_program.clone()
        g_program_test = dg_program.clone(for_test=True)
        
        # 判别图像
        dg_logit = D(g_image)
        
        # 计算损失
        dg_loss = fluid.layers.sigmoid_cross_entropy_with_logits(x=dg_logit, label=g_label)
        dg_avg_loss = fluid.layers.mean(dg_loss)
    
    # 配置优化方法
    optimizer = fluid.optimizer.Adam(learning_rate=0.0002) #Adam算法
    
    d_parameters = [p.name for p in d_program.global_block().all_parameters()]
    optimizer.minimize(loss=d_avg_loss, parameter_list=d_parameters) # 最小化判别网络平均损失值
    
    g_parameters = [p.name for p in g_program.global_block().all_parameters()]
    optimizer.minimize(loss=dg_avg_loss, parameter_list=g_parameters) # 最小化生成网络平均损失值

    # 启动程序
    place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() # 获取执行设备
    exe = fluid.Executor(place) # 获取执行程序
    exe.run(fluid.default_startup_program()) # 运行启动程序
    
    # 训练模型
    for epoch in range(epoch_num):
        for batch, train_data in enumerate(train_reader()):
            # 准备训练数据
            if len(train_data) != batch_size:
                continue
            
            real_images = np.array(list(map(lambda x: x[0], train_data))).reshape(-1, 784).astype('float32')
            real_labels = np.ones(shape=[real_images.shape[0], 1], dtype='float32')
            
            fake_noises = np.random.uniform(low=-1.0, high=1.0, size=[batch_size, noise_size]).astype('float32')
            fake_labels = np.zeros(shape=[real_images.shape[0], 1], dtype='float32')

            # 生成虚假图像
            fake_images = exe.run(
                program=g_program, 
                feed={'noise': fake_noises}, 
                fetch_list=[g_image])[0]
     
            # 训练判别模型:判断虚假图片为假的损失
            d_avg_loss_fake = exe.run(
                program=d_program,
                feed={'image': fake_images, 'label': fake_labels},
                fetch_list=[d_avg_loss])[0][0]
            
            # 训练判别模型:判断真实图片为真的损失
            d_avg_loss_real = exe.run(
                program=d_program,
                feed={'image': real_images, 'label': real_labels},
                fetch_list=[d_avg_loss])[0][0]
            
            # 计算判别损失
            d_avg_loss_n = d_avg_loss_fake + d_avg_loss_real
     
            # 训练生成模型
            for i in range(2):
                noise = np.random.uniform(low=-1.0, high=1.0, size=[batch_size, noise_size]).astype('float32')
                dg_avg_loss_n = exe.run(
                    program=dg_program,
                    feed={'noise': noise},
                    fetch_list=[dg_avg_loss])[0][0]

            # 显示生成图像
            if batch % 10 == 0:
                # 获取生成图像
                noise = np.random.uniform(low=-1.0, high=1.0, size=[batch_size, noise_size]).astype('float32')
                generate_images = exe.run(
                    program=g_program_test,
                    feed={'noise': noise},
                    fetch_list=[g_image])[0]
                
                total_image = np.concatenate([real_images, generate_images])
                
                # 显示生成图像 
                print("Epoch: {0}, Batch: {1}, D AVG Loss: {2}, DG AVG Loss: {3}".format(epoch, batch, d_avg_loss_n, dg_avg_loss_n))
                show_image(total_image)

# 主函数
if __name__ == "__main__":
    train()

 


 

实验结果:

8行为训练集字符,后8行为生成字符

Epoch: 19, Batch: 460, D AVG Loss: 1.1578519344329834, DG AVG Loss: 0.6636089086532593

参考资料:

https://www.paddlepaddle.org.cn/documentation/docs/zh/user_guides/cv_case/gan/README.cn.html

 

 

 

posted @ 2020-06-22 20:20  盛夏夜  阅读(246)  评论(0编辑  收藏  举报