Generating a network-type description antagonistic

How nothing is the focus of AI research field. Most of the existing neural network is to identify and study existing problems, such as the animals learn the neural network to identify the picture of a cat or dog, with further research, currently able to do so that the network can not only identify objects in the picture but also let it learn how to create objects in the picture, with "creative" so that the value of AI technology has greatly improved.

Make a significant contribution in depth study "creative" is the brain researcher from the Google project team Goodfellow proposed article entitled "Generative Adversarial Networks" academic report, he proposes a particular network architecture, the network consists of two parts, the two parts form a confrontational relationship, a part called Generator, conducted by its "creation", for example, gives a portrait or some data, another part is called discrimator, it is the task of the former "create" inspection, the former the task is to create enough good quality output for examination by the latter, whose mission is to continuously improve its inspection capabilities in order to identify the given data is true or false.

We have to understand the network through a vivid metaphor. Imagine an artist he is good at fake Picasso, is a connoisseur, he can identify the authentic and fake track, the artist himself forged paintings connoisseur to recognize, if identified, he would sum up the experience to improve the ability to forge his continue to enhance the ability of forgery, until a connoisseur not identified so far, so the artist's ability to paint with Picasso makes no difference.

Let's get through the initial feelings of code practice, in order to lay a good foundation for the theory to grasp, we can learn how to construct a "painting" of the neural network. We use the data set provided by Google to do the training data network, data download link is:
https://storage.cloud.google.com/quickdraw_dataset/full/numpy_bitmap/camel.npy
First we need to load data into memory, code show as below:

import os
from os import walk
import numpy as np
def  load_data():
    path = "./data"
    txt_name_list = []
    for (dirpath, dirnames, filenames) in walk(path):
        for f in filenames:
            if f != '.DS_Store':
                txt_name_list.append(f)
                break
    slice_train = int(80000/len(txt_name_list))
    i = 0
    seed = np.random.randint(1, 10e6)
    
    for txt_name in txt_name_list:
        txt_path = os.path.join(path, txt_name)
        x = np.load(txt_path)
        x = (x.astype('float32') - 127.5) / 127.5
        x = x.reshape(x.shape[0], 28, 28, 1)
        
        y = [i] * len(x)
        np.random.seed(seed)
        np.random.shuffle(x)
        np.random.seed(seed)
        np.random.shuffle(y)
        x = x[:slice_train]
        y = y[:slice_train]
        if i != 0:
            xtotal = np.concatenate((x, xtotal), axis = 0)
            ytotal = np.concatenate((y, ytotal), axis = 0)
        else:
            xtotal = x
            ytotal = y
        i += 1
    return xtotal, ytotal
(x_train, y_train) = load_data()
import matplotlib.pyplot as plt
plt.imshow(x_train[200, :, :, 0], cmap = 'gray')

After running the above code following results were obtained:
image.png

This dataset comes from Google's Quick, Draw! It is the sum of hand-painted, our task is to train the network, it can generate a similar style of hand-painted sum. Next we want to construct two networks, two networks belonging to the nature of yin and yang is a relationship of mutual confrontation. One network called the creator, another network called the authenticator, creator task is to generate a network similar to the above image of a picture as possible, the task is to identify those who learn to recognize the characteristics of the above image, and then recognizes the input to the picture in the end it is there are still real picture generated by the picture structure, and therefore the relationship between the two networks is mutually game. On the one hand training algorithm to identify the picture's ability to identify growing, while training the creator-generated image as identified by the authenticator, the stronger the identification with the identification ability, creator internal feedback adjustment based authenticator parameters until after it is generated by identifying identification pictures keep his drawn out of the picture more and more like the real picture. The following figure shows the structure of the antagonistic generation networks identified by the authenticator consisting of:

adversarial.png

Next we look at the implementation code generated by the network:

class Model(tf.keras.Model):
    def  __init__(self):
        super(Model, self).__init__()
        self.layers = []
        self.weight_init = tf.keras.initializers.RandomNormal(mean = 0., stddev = 0.2) #用于初始化网络层参数
    def  get_activation(self, activation): #选定网络层的激活函数
        if  activation == 'leaky_relu':
            layer =  tf.keras.layers.LeakyReLU(alpha = 0.2)()
        else:
            layer = tf.keras.layers.Activation(activation)()
        return layer
     def  call(self, x):
        for layer in self.generator_layers:
            x = layer(x)
        return x    
          
class  Generator(Model):
    def  __init__(self, generator_params):
        super(Generator, self).__init__()
        self.generator_layers = []
        self.weight_init = tf.keras.initializers.RandomNormal
        self.generator_layers.append(tf.keras.layers.Dense(units = generator_params.generator_initial_dense_layer_size,
                                                           kernel_initializer = self.weight_init))
        if  generator_params.generator_batch_norm_momentun:
            self.generator_layers.append(
                tf.keras.layers.BatchNormalization(momentum = self.generator_batch_nrom_momentun)
            )
        self.generator_layers.append(self.get_activation(generator_params.generator_activation))

        self.generator_layers.append(tf.keras.layers.Reshape(generator_params.generator_initial_dense_layer_size))

        if generator_params.generator_dropout_rate:
            self.generator_layers.append(tf.keras.layers.Dropout(generator_params.generator_dropout_rate))
        for i in range(generator_params.n_layers_generator):
            if  generator_params.generator_upsample[i] == 2:
                '''
                UpSampling2D会将像素点在前后左右进行复制,例如:
                Input = [1,2
                         3,4]  经过计算后得:
                output = [1, 1, 2, 2
                          1, 1, 2, 2
                          3, 3, 4, 4,
                          3, 3, 4, 4]
                Conv2DTranspose同样会把输入扩展为原来的2倍,只不过新增加的像素点并不是直接复制而是
                通过训练后网络寻找出最合适的像素点值
                '''
                self.generator_layers.append(tf.keras.UpSampleing2D()) 
                self.generator_layers.append(
                    tf.keras.layers.Conv2D(filters = generator_params.generator_conv_filters[i],
                                           kernel_size = generator_params.generator_conv_kernel_size[i],
                                           padding = 'same',
                                           name = 'generator_conv_' + str(i),
                                           kernel_initializer = self.weight_init
                                           )
                )
            else:
                self.generator_layers.append(
                    tf.keras.layers.Conv2DTranspose(
                        filters = generator_params.generator_conv_filters[i],
                        kernel_size = generator_params.generator_conv_kernel_size[i],
                        padding = 'same',
                        strides = generator_params.generator_conv_strides[i],
                        name = "generator_conv_" + str(i),
                        kernel_initializer = self.weight_init
                    )
                )
            if  i < generator_params.n_layer_generator - 1:
                if  generator_batch_norm_momentum:
                    self.generator_layers.append(
                        tf.keras.layers.BatchNormalization(momentum = generator_params.generator_batch_norm_momentum)
                    )
                self.generator_layers.append(
                    self.get_activation(generator_params.generator_activation)
                )
            else: #最后生成图像的像素点值在[-1,1]之间后面会进一步把像素点值改为[0,1]之间
                self.generator_layers.append(
                    tf.keras.Activation('tanh')
                )    
          
        self.layers = self.generator_layers

Creator of the network receive high-dimensional key vector containing a given component, then the vector into a corresponding picture, later we will get the vector in the standard is too distributed, a task which means creator network actually learn the standard is too distribution each point is mapped to a picture of a given style. Next we look at the code to identify Network implementation:

class Discriminator(Model):
    def __init__(self, params):
        super(Discriminator, self).__init__()
        self.dsicriminator_layers = []
        self.weight_init = tf.keras.initializers.RandomNormal
        for i in range(params.n_layers_discriminator):
            self.dsicriminator_layers.append(
                tf.keras.layers.Conv2D(
                    filters = params.discriminator_conv_filters[i],
                    kernel_size = params.discriminator_conv_kernel_size[i],
                    strides = params.discriminator_conv_strides[i],
                    padding = 'same',
                    name = 'discriminator_conv_' + str(i),
                    kernel_initializer = self.weight_init
                )
            )
            if  params.discriminator_batch_norm_momentum and i > 0:
                self.discriminator_layers.append(
                    tf.keras.layers.BatchNormalization(momentum = params.discriminator_batch_norm_momentun)
                )
            self.discriminator_layers.append(self.get_activation(params.discrimator_activation))
            if  params.discriminator_dropout_rate:
                self.discriminator_layers.append(
                    tf.keras.layers.Dropout(rate = params.discriminator_dropout_rate)
                )
        self.discriminator_layers.append(
            tf.keras.layers.Flatten()
        )        
        self.discriminator_layers.append(
            tf.keras.layers.Dense(units = 2, activation = 'softmax', 
                                  kernel_initializer = self.weight_init)#计算输入数据为真或假的概率
        )
        self.discriminator_layers.append(
            tf.argmax
        )

        self.layers = self.discriminator_layers

Network picture identification receiving a corresponding two-dimensional array, and then given a 0 or 1 indicates that the input picture is a true picture, let's connect the two networks for training:

class GAN():
     def  __init__(self, discrimiator_params, generator_params, z_dim):
         self.d_losses = []
         self.g_losses = []
         self.epoch = 0
         self.z_dim = z_dim  #关键向量的维度
         #设置生成者和鉴别者网络的优化函数
         self.discriminator_optimizer = tf.train.AdamOptimizer(discriminator_params.learning_rate)
         self.generator_optimizer = tf.train.AdamOptimizer(generator_params.learning_rate)
         generator_params.n_layers_generator = len(generator_params.generator_conv_filters)
         self.generator = Generator(generator_params)
         discriminator_params.n_layers_discriminator = len(discriminator_params.discriminator_conv_filters)
         self.discriminator = Discriminator(discriminator_params)
         self.build_adversarial()
   
    def  train_discriminator(self, x_train, batch_size, using_generator):
        '''
        训练鉴别师网络,它的训练分两步骤,首先是输入正确图片,让网络有识别正确图片的能力。
        然后使用生成者网络构造图片,并告知鉴别师网络图片为假,让网络具有识别生成者网络伪造图片的能力
        '''
        valid = np.ones((batch_size, 1))
        fake = np.zeros((batch_size, 1))
        if using_generator:#使用数据加载器
            true_imgs = next(x_train)[0] #读入图片数据
            if true_imgs.shape[0] != batch_size:
                true_imgs = next(x_train)[0]
        else:#之间从文件系统读取训练数据
            idx = np.random.randint(0, x_train.shape[0], batch_size)
            true_imgs = x_train[idx]
        noise = np.random.normal(0, 1, (batch_size, self.z_dim))
        gen_imgs = self.generator(noise) #让生成者网络根据关键向量生成图片
        real_accuracy = tfe.metrics.Accuracy()  #计算网络识别正确图片的成功率
        fake_accuracy = tfe.metrics.Accuracy() #计算网络识别构造图片的成功率
        
        with tf.GradientTape(watch_accessed_variables=False) as tape: #只修改鉴别者网络的内部参数
            tape.watch(self.discriminator.trainable_variables)
            d_loss_real = tf.keras.losses.BinaryCrossentropy(y_true = valid, self.discriminator(true_imgs))
        grads = tape.gradients(d_loss_real, self.discriminator.trainable_variables)
        self.discriminator_optimizer.apply_gradients(zip(grads, self.discriminator.trainbale_variables)) #改进鉴别者网络内部参数
        d_acc_real = real_accuracy(labels = valid, predictions = self.discriminator(true_imgs)).result().numpy() #计算训练后网络识别真图片的正确率
        
        with tf.GradientTape(watch_accessed_variables=False) as tape: #只修改鉴别者网络的内部参数
            tape.watch(self.discriminator.trainable_variables)
            d_loss_fake = tf.keras.losses.BinaryCrossentropy(y_true = fake,
                                                             y_pred = self.discriminator(gen_imgs))
        grads = tape.gradients(d_loss_fake, self.discriminator.trainbale_variables)
        self.discriminator_optimizer.apply_gradients(ziep(grads, self.discriminator.trainable_variables))
        d_acc_fake = fake_accuracy(labels = fake, predictions = self.discriminator(gen_imgs)).result().numpy() #计算鉴别者网络识别虚假图片的正确率
        
        d_loss = 0.5*(d_loss_real + d_loss_fake)
        d_acc = 0.5 * (d_acc_fake + d_acc_real)

        return [d_loss, d_loss_real, d_loss_fake, d_acc, d_acc_real, d_acc_fake]

    def  train_generator(self, batch_size): #训练生成者网络
        '''
        生成者网络训练的目的是让它生成的图像尽可能通过鉴别者网络的审查
        '''
        valid = np.ones((batch_size, 1)) #希望生成的图片尽可能多通过鉴别者网络的鉴定
        noise = np.random.normal(0, 1, (batch_size, self.z_dim)) #随机生成关键向量
        with tf.GradientTape(watch_accessed_variables=False) as tape: #只能修改生成者网络的内部参数不能修改鉴别者网络的内部参数
            tape.watch(self.generator.trainbale_variables)
            gen_imgs = self.generator(noise) #生成伪造的图片
            verify_results = self.discriminator(gen_imgs)
            verify_loss = tf.keras.keras.BinaryCrossentropy(y_true = valid,
                                                            y_pred = verify_results)
        grads = tape.gradients(verify_loss, self.generator.trainable_variables) #调整生成者网络内部参数使得它生成的图片尽可能通过鉴别者网络的识别
        self.generator_optimizer.apply_gradients(zip(grads, self.generator.trainable_variables))
        pass_accuracy = tfe.metrics.Accuracy() #计算生成者网络能通鉴定的成功率
        gen_imgs = self.generator(noise)
        verify_results = self.discriminator(gne_imgs)
        accuracy = pass_accuracy(labels = valid, predictions = verify_results).result().numpy()#检验训练后生成者网络的成功率
        return verify_loss, accuracy
    def  train(self, x_train, batch_size, epochs, run_folder, print_every_n_batches = 50,
               using_generator = False):#启动训练流程
         for  epoch in range(self.epoch, self.epoch + epoches):
             d = self.train_discriminator(x_train, batch_size, using_generator)
             g = self.train_generator(batch_size)
             print("%d [D loss: (%.3f)(R %.3f, F %.3f)] [D acc: (%.3f)(%.3f, %.3f)] [G loss: %.3f] [G acc: %.3f]" % 
                   (epoch, d[0], d[1], d[2], d[3], d[4], g[0], g[1]))
             if epoch % print_every_n_batches == 0:
                 self.sample_images(run_folder) #将生成者构造的图像绘制出来
                 self.save_model(run_folder) #存储两个网络的内部参数
            self.epoch + 1
    def  sample_images(self, run_folder): #绘制生成者构建的图像
        r, c = 5,5
        noise = np.random.normal(0, 1, (r * c, self.z_dim)) #构建关键向量
        gen_imgs = self.generator(noise)
        gen_imgs = 0.5 * (gen_imgs + 1) 
        gen_imgs = np.clip(gen_imgs, 0, 1) #将图片像素点转换到[0,1]之间
        fig, axs = plt.subplots(r, c, figsize = [15, 15])
        cnt = 0

        for i in range(r):
            for j in range(c):
                axs[i, j].imshow(np.squeeze(gen_imgs[cnt, :,:,:]), cmap = 'gray')
                axs[i,j].axis('off')
                cnt += 1
        fig.savefig(os.path.join(run_folder, 'images/sample%d.png' % self.epoch))
        plt.close()
    def  save_model(self, run_folder): #保持网络内部参数
        self.discriminator.save_weights(os.path.join(run_folder, 'discriminator.h5'))
        self.generator.save_weights(os.path.join(run_folder, 'generator.h5'))
    def  load_model(self, run_folder):
        self.discriminator.load_weights(os.path.join(run_folder, 'discriminator.h5'))
        self.generator.load_weights(os.path.join(run_folder, 'generator.h5'))

From the code point of view, the training process two different networks. Authenticator network need to enter two kinds of pictures, one is the real picture, it is to learn to recognize Photos Features grasp the true picture of the characteristics, the other is the creator of the network structure of the picture, it is to train internal parameters so that the generated Network configuration photo identification is false. Network training generated rather special, it must be combined with identification by the network to be trained, it receives from the first key is too vector distribution, and then outputs an image, then the image is input to the network authenticator, the results of which are given in accordance with adjust the internal parameters, it is possible to adjust the parameters so that the result of the identification by the network output is true, we should note that in training producer network, there must be frozen internal parameters to identify those networks, but also in training if creator change the internal parameters of the authenticator, then the whole exercise will not converge.

Since the training process confrontational generation networks is more complex, it is necessary that focused on the individual, so this section of code is given only to achieve the network, the next section we look at how effective training two networks.

A more detailed explanation and code debugging during the presentation, click the link

For more technical information, including operating systems, compilers, interview algorithms, machine learning, artificial intelligence, please take care of my public number:
Write pictures described here

Published 346 original articles · won praise 290 · Views 400,000 +

Guess you like

Origin blog.csdn.net/tyler_download/article/details/104362952