В этой статье мы узнаем, как построить GAN с нуля, используя слои свертки. Для демонстрации и быстрой работы мы будем использовать набор данных Fashion MNIST. И после того, как вы его выучите, то же самое вы можете сделать и с лицами. Прежде чем вдаваться в подробности, я хочу, чтобы вы подумали: можем ли мы использовать глубокое обучение для создания чего-то из ничего? Чтобы ответить на этот вопрос, мы собираемся внедрить GAN и увидеть результаты своими глазами.
GAN — это объединение двух нейронных сетей: генератора и дискриминатора. генератор создает новые экземпляры данных, а другой, дискриминатор, оценивает их подлинность; то есть дискриминатор решает, принадлежит ли каждый экземпляр данных, которые он просматривает, фактическому набору обучающих данных или нет. Теперь давайте реализуем и посмотрим сами.
Сначала загрузите следующие основные зависимости
- Tensorflow (я тестировал 1.12)
- Керас
- Панды
- OpenCV
Теперь вы можете начать с открытия блокнота Jupyter и начать вводить каждый фрагмент кода в блокноте.
(x_train,y_train), (x_test, y_test) = fashion_mnist.load_data()#We next normalize the imagesx_train = (x_train.astype(np.float32) - 127.5)/127.5
Теперь у нас есть данные для обучения,содержащие 60 тысяч изображений формы (28 x 28 x 1). Итак, нам нужно создать Генератор, который принимает изображения этой конкретной формы.
def create_discriminator(): discriminator=Sequential() discriminator.add(Dense(units=512,input_dim=28*28)) #discriminator.add(Conv2D(64, (3,3), strides =(1,1), padding ='same', input_shape = [28,28,1])) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dropout(0.3)) #discriminator.add(Flatten()) discriminator.add(Dense(units=512)) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dropout(0.3)) discriminator.add(Dense(units=256)) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dense(units=1, activation='sigmoid')) discriminator.compile(loss='binary_crossentropy', optimizer=adam_optimizer()) return discriminator d =create_discriminator() d.summary() #Summary of the GeneratorLayer (type) Output Shape Param # ================================================================= conv2d_3 (Conv2D) (None, 10, 10, 64) 640 _________________________________________________________________ batch_normalization_3 (Batch (None, 10, 10, 64) 256 _________________________________________________________________ leaky_re_lu_13 (LeakyReLU) (None, 10, 10, 64) 0 _________________________________________________________________ conv2d_4 (Conv2D) (None, 4, 4, 32) 18464 _________________________________________________________________ batch_normalization_4 (Batch (None, 4, 4, 32) 128 _________________________________________________________________ leaky_re_lu_14 (LeakyReLU) (None, 4, 4, 32) 0 _________________________________________________________________ flatten_3 (Flatten) (None, 512) 0 _________________________________________________________________ dense_15 (Dense) (None, 512) 262656 _________________________________________________________________ leaky_re_lu_15 (LeakyReLU) (None, 512) 0 _________________________________________________________________ dense_16 (Dense) (None, 1024) 525312 _________________________________________________________________ leaky_re_lu_16 (LeakyReLU) (None, 1024) 0 _________________________________________________________________ dense_17 (Dense) (None, 784) 803600 ================================================================= Total params: 1,611,056 Trainable params: 1,610,864 Non-trainable params: 192
Мы создали Генератор, который состоит из двух сверточных слоев, за которыми следуют два плотных слоя. Последний плотный слой имеет форму (28x28), так что мы можем реконструировать его обратно в изображения, как в наборе данных.
Затем мы создаем дискриминатор, который будет определять, являются ли изображения, созданные Генератором, поддельными или реальными. Если дискриминатор предсказывает, что эти изображения являются поддельными, то генератор изменяет свой вес до тех пор, пока не сможет обмануть дискриминатор. Так Генератор научится создавать изображения из шумов.
def create_discriminator(): discriminator=Sequential() discriminator.add(Dense(units=512,input_dim=28*28)) #discriminator.add(Conv2D(64, (3,3), strides =(1,1), padding ='same', input_shape = [28,28,1])) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dropout(0.3)) #discriminator.add(Flatten()) discriminator.add(Dense(units=512)) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dropout(0.3)) discriminator.add(Dense(units=256)) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dense(units=1, activation='sigmoid')) discriminator.compile(loss='binary_crossentropy', optimizer=adam_optimizer()) return discriminator d =create_discriminator() d.summary()
Мы создали Генератор и Дискриминатор. Затем мы объединяем их обоих для создания GAN. В приведенном ниже коде мы объединяем два модуля и обучаем их.
def create_gan(discriminator, generator): discriminator.trainable=False img_shape=(28, 28, 1) gan_input = Input(img_shape) x = generator(gan_input) gan_output= discriminator(x) gan= Model(inputs=gan_input, outputs=gan_output) gan.compile(loss='binary_crossentropy', optimizer=adam_optimizer()) return gan
Теперь давайте обучим GAN, объединив Генератор с Дискриминатором.
generator= create_generator() discriminator= create_discriminator() gan = create_gan(discriminator, generator) batch_size = 128 Epochs = 300 for epcs in range(1, Epochs ): print("Epoch Number %d" %epcs) for _ in tqdm(range(batch_size)): #generate random noise of shape 28*28 noise= np.random.normal(0,1, [batch_size, 28,28,1]) # Now predict the noise by feeding it to generator generated_images = generator.predict(noise) # Take real images from the Fashion MNIST image_batch =x_train[np.random.randint (low=0,high=x_train.shape[0],size=128)] # The discriminator accepts vector of dimension 784 image_batch = image_batch.reshape(-1,28*28) #We concate both real and fake images X= np.concatenate([image_batch, generated_images]) # We Next assign label to X y_discriminator=np.zeros(2*batch_size) # First images are true, so we label them 1 y_discriminator[:batch_size]=1 #Pretrain discriminator on fake and real data discriminator.trainable=True discriminator.train_on_batch(X, y_discriminator) # We trick the noises to be real noise= np.random.normal(0,1, [batch_size, 28,28,1]) y_label = np.ones(batch_size) discriminator.trainable=False # Let us train the GAN gan.train_on_batch(noise, y_label)
После завершения обучения вы можете предсказать Генератор на основе шума.
# feed the noises to the generator and predict them generated_images = generator.predict(noise)#we are going to see the first image i.e at index 0 x =generated_images[0].reshape(28,28)# Let us plot the image plt.imshow(x, cmap ="Greys")
Ниже приведены изображения, сгенерированные из шумов, и теперь вы можете начать тестирование на своих собственных изображениях.