はじめに
「敵対的生成ネットワーク(GAN: Generative Adversarial Networks)」は、
ディープラーニングの生成モデルの一種であり、
与えたデータから本物と偽物を見分けるように複数の学習器を用いて学習することで、
新たな画像の生成や画風の変更などができる。
このGANモデルは、Generator(生成器)とDiscriminator(識別器)のニューラルネットワーク部に大別される。
生成器では、インプットデータ(ex. ノイズ)から
本物のデータに近い偽物を作ることを目指して、学習を進めていく。
また、識別器では、生成器が作成した偽物を本物のデータと区別するために、学習を行う。
今回、GANモデル(教師なし学習)による手書き文字(7を使用)
の画像生成がやってみた。
中間層に、全結合ネットワークだけでなく、
畳み込みニューラルネットワーク(CNN)を使ってるので、
正式には、DCGAN (Deep Convolutional GAN)の分類かもしれないけど。
関連パッケージのインストール・ロード
library(keras)
source("https://gist.githubusercontent.com/kumeS/41fed511efb45bd55d468d4968b0f157/raw/b7205c6285422e5166f70b770e1e8674d65f5ea2/DL_plot_modi_v1.2.R")
ministデータセットをダウンロードする
minist <- dataset_mnist()
str(minist)
trainx <- minist$train$x
trainy <- minist$train$y
str(trainx)
7のみのデータを抽出して、アレイ形式に変換してノーマライズする
trainx7 <- trainx[trainy==7,,]
par(mfrow=c(8,8), mar=rep(0,4))
for(n in 1:64){plot(as.raster(trainx7[n,,], max=255))}
quartz.save("Fig_01.png", type = "png")
par(mfrow=c(1,1))
trainX <- array_reshape(trainx7,
c(nrow(trainx7), 28, 28,1))
trainX <- trainX/255
str(trainX)
生成器モデル (1)
Generatorモデル (生成器モデル)の作成(1)
l <- 28
input <- layer_input(shape=l)
gen <- input %>%
layer_dense(unit=32*14*14) %>%
layer_activation_leaky_relu() %>%
layer_reshape(target_shape = c(14,14,32)) %>%
layer_conv_2d(filters = 32,
kernel_size = 5,
padding = "same") %>%
layer_activation_leaky_relu() %>%
layer_conv_2d_transpose(filters = 32,
kernel_size = 4,
strides = 2,
padding = "same") %>%
layer_activation_leaky_relu() %>%
layer_conv_2d(filters = 1,
kernel_size = 5,
activation = "tanh",
padding = "same")
Generator <- keras_model(input, gen)
Generator
Discriminatorモデル (識別器モデル)の作成(1)
shape <- c(28, 28, 1)
input0 <- layer_input(shape=shape)
dis <- input0 %>%
layer_conv_2d(filters = 64,
kernel_size = 4) %>%
layer_activation_leaky_relu() %>%
layer_flatten() %>%
layer_dropout(rate = 0.3) %>%
layer_dense(units = 1,
activation = "sigmoid")
Discriminator <- keras_model(input0, dis)
Discriminator
モデルのコンパイル(1)
Discriminator %>% compile(optimizer="rmsprop",
loss="binary_crossentropy")
Discriminator$trainable
freeze_weights(Discriminator)
Discriminator$trainable
input <- layer_input(shape=l)
gan <- input %>% Generator %>% Discriminator
GAN <- keras_model(input, gan)
GAN %>% compile(optimizer="rmsprop",
loss="binary_crossentropy")
plot_model_modi(Generator)
plot_model_modi(Discriminator)
plot_model_modi(GAN)
モデルのトレーニング (事前準備 + 実行)
b <- 50
dir <- "gan_img"
dir.create(dir)
start <- 1
dloss <- NULL
gloss <- NULL
for(i in 1:120){
noise <- matrix(rnorm(b*l),
nrow=b,
ncol=l)
fake <- predict(Generator, noise)
stop <- start + b -1
real <- trainX[start:stop,,,]
real <- array_reshape(real, c(nrow(real), 28,28,1))
rows <- nrow(real)
both <- array(0, dim=c(rows*2, dim(real)[-1]))
both[1:rows,,,] <- fake
both[(rows+1):(rows*2),,,] <- real
Labels <- rbind(matrix(runif(b, 0.9, 1),
nrow=b,
ncol=1),
matrix(runif(b, 0, 0.1),
nrow=b,
ncol=1)
)
dloss[i] <- Discriminator %>% train_on_batch(both, Labels)
fakeAsReal <- array(runif(b, 0, 0.1), dim=c(b,1))
gloss[i] <- GAN %>% train_on_batch(noise, fakeAsReal)
par(mfrow=c(7,7), mar=rep(0,4), omi=c(0,0,0.5,0))
for(n in 1:49){
f <- fake[n,,,]
dim(f) <- c(28, 28)
plot(as.raster(((f-min(f))/max(f-min(f)))*255, max=255))
}
mtext(side = 3, line=1, outer=T, cex=2,
text = paste0("i = ", i))
quartz.save(file.path(dir, paste0("f_", formatC(i, width = 4, flag = "0"), ".png")),
type = "png")
start <- start + b
}
ここで、train_on_batch関数は、1batchのサンプルでのシングル勾配更新またはモデル評価する関数である
画像生成の結果をgifアニメーションとして可視化(1)
system(paste0("convert -delay 20 -loop 10 ./", dir, "/*.png ./Fig_03_20ms.gif"))
Lossの結果を可視化する
par(mfrow=c(1,1))
x <- 1:120
plot(x, dloss, col="red", type="l",
ylim=c(0,3), xlab="Interations",
ylab="Loss")
lines(x, gloss, col="black", type="l")
legend("topright", legend=c("Discriminator", "GAN Loss"),
col=c("red", "black"), lwd=1)
quartz.save("Fig_04.png", type = "png")
GANの改善モデルでの実行
次に、少し改善したモデルで実行してみる。
各モデルに、layer_conv_2dレイヤーを1つずつ追加した。
生成器モデル (2)
Generatorモデル (生成器モデル)の作成(2)
l <- 28
input <- layer_input(shape=l)
gen <- input %>%
layer_dense(unit=32*14*14) %>%
layer_activation_leaky_relu() %>%
layer_reshape(target_shape = c(14,14,32)) %>%
layer_conv_2d(filters = 32,
kernel_size = 5,
padding = "same") %>%
layer_activation_leaky_relu() %>%
layer_conv_2d_transpose(filters = 32,
kernel_size = 4,
strides = 2,
padding = "same") %>%
layer_activation_leaky_relu() %>%
layer_conv_2d(filters = 64,
kernel_size = 5,
padding = "same") %>%
layer_activation_leaky_relu() %>%
layer_conv_2d(filters = 1,
kernel_size = 5,
activation = "tanh",
padding = "same")
Generator <- keras_model(input, gen)
Generator
Discriminatorモデル (識別器モデル)の作成(2)
shape <- c(28, 28, 1)
input0 <- layer_input(shape=shape)
dis <- input0 %>%
layer_conv_2d(filters = 64,
kernel_size = 4) %>%
layer_activation_leaky_relu() %>%
layer_conv_2d(filters = 64,
kernel_size = 4,
strides = 2) %>%
layer_activation_leaky_relu() %>%
layer_flatten() %>%
layer_dropout(rate = 0.3) %>%
layer_dense(units = 1,
activation = "sigmoid")
Discriminator <- keras_model(input0, dis)
Discriminator
モデルのコンパイル(2)
Discriminator %>% compile(optimizer="rmsprop",
loss="binary_crossentropy")
Discriminator$trainable
freeze_weights(Discriminator)
Discriminator$trainable
input <- layer_input(shape=l)
gan <- input %>% Generator %>% Discriminator
GAN <- keras_model(input, gan)
GAN %>% compile(optimizer="rmsprop",
loss="binary_crossentropy")
モデルのトレーニング (事前準備 + 再実行)
b <- 50
dir <- "gan_img2"
dir.create(dir)
start <- 1
dloss <- NULL
gloss <- NULL
for(i in 1:120){
noise <- matrix(rnorm(b*l),
nrow=b,
ncol=l)
fake <- predict(Generator, noise)
stop <- start + b -1
real <- trainX[start:stop,,,]
real <- array_reshape(real, c(nrow(real), 28,28,1))
rows <- nrow(real)
both <- array(0, dim=c(rows*2, dim(real)[-1]))
both[1:rows,,,] <- fake
both[(rows+1):(rows*2),,,] <- real
Labels <- rbind(matrix(runif(b, 0.9, 1),
nrow=b,
ncol=1),
matrix(runif(b, 0, 0.1),
nrow=b,
ncol=1)
)
dloss[i] <- Discriminator %>% train_on_batch(both, Labels)
fakeAsReal <- array(runif(b, 0, 0.1), dim=c(b,1))
gloss[i] <- GAN %>% train_on_batch(noise, fakeAsReal)
par(mfrow=c(7,7), mar=rep(0,4), omi=c(0,0,0.5,0))
for(n in 1:49){
f <- fake[n,,,]
dim(f) <- c(28, 28)
plot(as.raster(((f-min(f))/max(f-min(f)))*255, max=255))
}
mtext(side = 3, line=1, outer=T, cex=2,
text = paste0("i = ", i))
quartz.save(file.path(dir, paste0("f_", formatC(i, width = 4, flag = "0"), ".png")),
type = "png")
start <- start + b
}
画像生成の結果をgifアニメーションとして可視化(2)
system(paste0("convert -delay 20 -loop 10 ./", dir, "/*.png ./Fig_05_20ms.gif"))
Lossの結果を可視化する
par(mfrow=c(1,1))
x <- 1:120
plot(x, dloss, col="red", type="l",
ylim=c(0,3), xlab="Interations",
ylab="Loss")
lines(x, gloss, col="black", type="l")
legend("topright", legend=c("Discriminator", "GAN Loss"),
col=c("red", "black"), lwd=1)
quartz.save("Fig_06.png", type = "png")
参考資料
本記事は、Dr. Bharatendra Raiが提供するYouTubeチャネル内の
「Generative Adversarial Networks (GANs) with R」の実行スクリプトを参考に作成した。
Generative Adversarial Networks (GANs) with R | 1. Introduction & Overview - YouTube
clean-copy-of-onenote.hatenablog.com
www.imagazine.co.jp