Bài 2: Deep Convolutional GAN (DCGAN) | Deep Learning cơ bản
 

Bài 2: Deep Convolutional GAN (DCGAN)

| Posted in GAN

Bài trước mình đã giới thiệu về GAN, cấu trúc mạng GAN và hướng dẫn dùng GAN để sinh các số trong bộ dữ liệu MNIST. Tuy nhiên mô hình của Generator và Discriminator đều dùng Neural Network. Trong khi ở bài CNN mình đã biết CNN xử lý dữ liệu ảnh tốt hơn và hiệu quả hơn rất nhiều so với Neural Network truyền thống. Vậy nên bài này mình sẽ hướng dẫn áp dụng CNN vào mô hình GAN bài trước, mô hình đấy gọi là Deep Convolutional GAN (DCGAN).

Bài toán: Dùng mạng GAN sinh ra các ảnh giống với dữ liệu trong CIFAR-10 dataset.

CIFAR-10 dataset bao gồm 60000 ảnh màu kích thước 32×32 thuộc 10 thể loại khác nhau. Mỗi thể loại có 6000 ảnh.

Dữ liệu cifar-10

Cấu trúc mạng

Nhắc lại bài trước 1 chút thì GAN gồm 2 mạng là generator và discriminator. Trong khi discriminator được train để phân biệt ảnh thật (trong dataset) và ảnh fake (do generator sinh ra), thì generator được train để đánh lừa discriminator. Ở bài trước thì cả generator và discriminator đều được xây bằng mạng neural network thông thường với các fully connected layer, bài này thì generator và discriminator được xây dựng bằng mô hình CNN với 2 layers chính là convolutional layer và transposed convolutional layer.

Generator

Mạng Generator nhằm mục đích sinh ảnh fake, input là noise vector kích thước 128 và output và ảnh fake cùng kích thước ảnh thật (32 * 32 *3)

Mô hình generator của DCGAN

Các layer trong mạng

  • Dense (fully-connected) layer: 128*1 -> 2048*1
  • Flatten chuyển từ vector về dạng tensor 3d, 2048*1 -> 2*2*512
  • Transposed convolution stride=2, kernel=256, 2*2*512 -> 4*4*256
  • Transposed convolution stride=2, kernel=128, 4*4*256 -> 8*8*128
  • Transposed convolution stride=2, kernel=64, 8*8*128 -> 16*16*64
  • Transposed convolution stride=2, kernel=3, 16*16*64 -> 32*32*3

Đầu tiên thì input noise (128) được dùng full-connected layer chuyển thành 2048 ( = 2*2*512). Số 2048 được chọn để reshape về dạng tensor 3d (2*2*512). Sau đó transposed convolution với stride = 2 được dùng để tăng kích thước tensor lên dần 4*4 -> 8*8 -> 16*16 -> 32*32. Cho tới khi kích thước tensor 32*32 (bằng đúng width, height của ảnh trong CIFAR-10 dataset) thì ta dùng 3 kernel để ra đúng shape của ảnh.

Mọi người để ý thấy là khi width, height tăng thì depth sẽ giảm, cũng giống như trong mạng CNN bình thường width, height giảm thì depth sẽ tăng.

Transposed convolution

Transposed convolution hay deconvolution có thể coi là phép toán ngược của convolution. Nếu như convolution với stride > 1 giúp làm giảm kích thước của ảnh thì transposed convolution với stride > 1 sẽ làm tăng kích thước ảnh. Ví dụ stride = 2 và padding = ‘SAME’ sẽ giúp gấp đôi width, height kích thước của ảnh.

Transposed convolution có 2 kiểu định nghĩa

Kiểu 1

Kiểu 1 được định nghĩa đơn giản hơn lấy từ sách Dive into deep learning. Ý tưởng đơn giản là transposed convolution là phép tính ngược của convolution.

Convolution s=1, p=0

Nếu như ở phép tính convolution thì 1 vùng kích thước 2*2 được nhân element-wise với kernel và tính tổng viết ra ở output thì ở phép tính transposed convolution mỗi phần tử ở input sẽ được nhân với kernel và ma trận kết quả cùng kích thước với kernel được viết vào output. Nếu các phần tử ở output viết đè lên nhau thì ta sẽ cộng dồn vào.

Transposed convolution với s=1, p=0

Stride trong transposed convolution được định nghĩa là số bước nhảy khi viết kết quả ra ma trận output

Transposed convolution với s=2, p=0

Với padding thì ta tính toán bình thường như với p=0 sau đó kết quả ta sẽ bỏ p hàng và cột ở 4 cạnh (trên, dưới, trái, phải)

Transposed convolution s=2, p=1

Kiểu 2

Kiểu định nghĩa thứ 2 thì phức tạp hơn nhưng lại có vẻ chuẩn và hay gặp hơn. Nguồn ở đây.

Ý nghĩa của stride và padding ở đây là khi ta thực hiện phép tính convolution trên output sẽ được kích thước giống input

Các bước thực hiện transposed convolution

Mọi người để ý là bước tính z để chèn 0 vào giữa hay tính lại padding p’ để thêm vào mục đích cuối cùng chỉ là để convolution trên output với s, p sẽ được input.

z = s – 1 = 0 hàng / cột chèn vào giữa, p’ = k – p – 1 = 2 padding input. Màu xanh dương là input, xanh lá cây đậm là output.

Ta thấy phép tính convolution với input 4*4 , kernel size 3*3 , s = 1, p = 0 thì output kích thước 2*2. Ngược lại phép tính transposed convolution : input là 2*2 , kernel size là 3*3 , s = 1, p = 0 thì output sẽ có kích thước 4*4.

Transposed convolution s=1,p=0

z = s – 1 = 1 hàng / cột chèn vào giữa, p’ = k – p – 1 = 1 padding input. Màu xanh dương là input, xanh lá cây đậm là output. Nếu mọi người check lại thì phép tính convolution với input 5*5, kernel size 3*3, s = 2, p = 1 sẽ được output kích thước 3*3.

Transposed convolution s=2, p=1

Discriminator

Mạng Discriminator nhằm mục đích phân biệt ảnh thật từ dataset và ảnh fake do Generator sinh ra, input là ảnh kích thước (32 * 32 *3), output là ảnh thật hay fake (binary classification)

Mô hình discriminator của DCGAN

Mô hình discriminator đối xứng lại với mô hình generator. Ảnh input được đi qua convolution với stride = 2 để giảm kích thước ảnh từ 32*32 -> 16*16 -> 8*8 -> 4*4 -> 2*2. Khi giảm kích thước thì depth tăng dần. Cuối cùng thì tensor shape 2*2*512 được reshape về vector 2048 và dùng 1 lớp fully connected chuyển từ 2048d về 1d.

Loss function được sử dụng giống như bài trước về GAN.

Tips

Đây là một số tips để build model và train DCGAN

  • Dùng ReLU trong generator trừ output layer
  • Output layer trong generator dùng tanh (-1, 1) và scale ảnh input về (-1,1) sẽ cho kết quả tốt hơn dùng sigmoid và scale ảnh về (0, 1) hoặc để nguyên ảnh.
  • Sử dụng LeakyReLU trong discriminator
  • Thay thế max pooling bằng convolution với stride = 2
  • Sử dụng transposed convolution để upsampling
  • Sử dụng batch norm từ output layer trong generator và input layer trong discriminator

Code

Code mọi người lấy ở đây.

Ảnh CIFAR-10 được scale về (-1, 1) để cùng scale với ảnh sinh ra bởi generator khi dùng tanh activation

def get_data():
    (X_train, y_train), (X_test, y_test) = cifar10.load_data()
    
    X_train = X_train.astype(np.float32)
    X_test = X_test.astype(np.float32)
    
    X_train = 2*(X_train/255)-1
    X_test = 2*(X_train/255)-1
    
    return X_train, X_test

Ở những epoch đầu tiên thì generator chỉ sinh ra noise

Ảnh sinh ra bởi generator sau 10 epochs

Tuy nhiên sau 150 epoch thì mạng đã học được thuộc tính của ảnh trong dữ liệu CIFAR-10 và có thể sinh ra được hình con chim, ô tô.

Ảnh sinh ra bởi generator sau 150 epochs


Deep Learning cơ bản ©2024. All Rights Reserved.
Powered by WordPress. Theme by Phoenix Web Solutions