著者:高嶋真輝
今回は、本物に限りなく近いデータを生成できる「敵対的生成ネットワーク」(Generative Adversarial Networks)という機械学習の技術と、「Fashion-MNIST」という服飾画像のデータセットを用いて、靴の画像生成に挑戦します。
シェルスクリプトマガジン Vol.70は以下のリンク先でご購入できます。![]()
![]()
図3 各種ライブラリをインポートするためのコード
%matplotlib inline
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import fashion_mnist
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Flatten, Reshape, LeakyReLU
from tensorflow.keras.optimizers import Adam
from google.colab import drive
図4 モデルの入力次元を設定するためのコード
img_rows = 28 #画像の横軸
img_cols = 28 #画像の縦軸
channels = 1 #画像のチャンネル数(モノクロは「1」、カラーは「3」)
img_shape = (img_rows, img_cols, channels)
z_dim = 100 #ノイズベクトルの次元数
図5 生成器のモデルを構築する関数を定義するためのコード
# 生成器モデル構築(画像形状情報:tuple, 入力ノイズベクトル次元数:int)
def generatorBuilder(img_shape, z_dim):
model = Sequential()
# 全結合層(ノード数:int, 入力の形状(第1層のときのみ):z_dim(int))
model.add(Dense(128, input_dim=z_dim))
# LeakyReLUによる活性化(alpha=負の場合の傾き:double)
model.add(LeakyReLU(alpha = 0.2))
# 出力層(全結合層)と活性化(ノード数:int, activation = :活性化関数(string))
model.add(Dense(28*28*1, activation="tanh"))
# 整形(整形後の形状:img_shape(tuple))
model.add(Reshape(img_shape))
return model
図9 生成器のモデルを構築する関数を定義するためのコード
# 識別器モデル構築(画像形状情報:tuple(rows:int,cols:int,channels:int)
def discliminatorBuilder(img_shape):
model = Sequential()
# データを並べる(第1層なので入力の形状:img_shape(tuple))
model.add(Flatten(input_shape=img_shape))
# 全結合層(ノード数:int)
model.add(Dense(128))
# LeakyReLUによる活性化(alpha= : double)
model.add(LeakyReLU(alpha = 0.01))
#出力層と活性化(ノード数:int, activation = :活性化関数(string))
model.add(Dense(1, activation="sigmoid"))
return model
図11 GANのシステムモデルを構築する関数を定義するためのコード
# GANモデル構築関数
def ganBuilder(generator, discriminator):
model = Sequential()
model.add(generator)
model.add(discriminator)
return model
図12 学習モデルをコンパイルするためのコード
# 識別器モデル作成(入力形状:img_shape(tuple))
discriminator = discliminatorBuilder(img_shape)
# 識別器コンパイル
# (loss = :損失関数, optimizer = :最適化手法, metrics = :評価関数)
discriminator.compile(loss = "binary_crossentropy",
optimizer=Adam(),
metrics=['accuracy'])
# 生成器モデル作成(出力形状:img_shape(tuple), 入力形状:z_dim(int))
generator = generatorBuilder(img_shape, z_dim)
discriminator.trainable = False # 識別器モデルの学習停止
# GANモデル作成(生成器モデル:generator, 識別器モデル:discriminator)
gan = ganBuilder(generator, discriminator)
# GANコンパイル:(loss = :損失関数, optimizer = :最適化手法)
gan.compile(loss = "binary_crossentropy",
optimizer = Adam())
図13 損失などのデータを格納する変数を定義するためのコード
losses = []
accuracies = []
iteration_checkpoints = []
図14 学習用データを準備するためのコード
# 訓練用データの抽出
(trainData, trainLabel), (_, _) = fashion_mnist.load_data()
trainData = trainData / 127.5 - 1.0
trainData = np.expand_dims(trainData, axis=3)
# 真画像ラベル作成
batch_size = 128
real = np.ones((batch_size, 1))
# 偽画像ラベル作成
fake = np.zeros((batch_size, 1))
# 靴のデータの抜き出し
# trainLabelは、5がサンダル、7がスニーカ、9がブーツ
trainData = trainData.tolist()
trainShoes = []
for i in range(len(trainLabel)):
if trainLabel[i] in [5,7,9]:
trainShoes.append(trainData[i])
図15 学習処理用の関数を定義するコード
def train(iterations, batch_size, sample_interval):
for iteration in range(iterations):
# 真画像群の作成
idx = np.random.randint(0, len(trainShoes), batch_size)
imgs = [trainShoes[i] for i in idx]
imgs = np.asarray(imgs)
# 生成画像群の作成
# ランダムノイズ作成(正規分布の平均値:float, 標準偏差:float, 形状:tuple)
z = np.random.normal(0,1,(batch_size, z_dim))
# 生成画像の取得
gen_imgs = generator.predict(z)
# 識別器訓練:真偽のそれぞれで実施
d_loss_real = discriminator.train_on_batch(imgs, real)
d_loss_fake = discriminator.train_on_batch(gen_imgs, fake)
# 損失と正確さを計算(2損失の合算を半分にする)
d_loss, accuracy = 0.5 * np.add(d_loss_real, d_loss_fake)
## 生成画像群の作成(GAN学習用)
z = np.random.normal(0,1,(batch_size, z_dim))
g_loss = gan.train_on_batch(z, real)
if (iteration + 1) % sample_interval == 0:
# 記録と出力
losses.append((d_loss, g_loss))
accuracies.append(100.0 * accuracy)
iteration_checkpoints.append(iteration + 1)
print("%d [D loss: %f, acc: %.2f%%][G loss: %f]" %
(iteration + 1, d_loss, 100.0*accuracy, g_loss))
## 学習済みgeneratorを渡す(iteration+1は保存に使う)
showSample(generator, iteration+1)
図16 画像の表示と保存をする関数を定義するコード
# 画像生成と表示
# (学習済みgenerator:TensorFlowSequential, 画像表示用の行, 列:int)
def showSample(generator, iteration, img_grid_rows=4, img_grid_cols=4):
z = np.random.normal(0, 1, (img_grid_rows*img_grid_cols, z_dim))
gen_imgs = generator.predict(z) # 画像生成
gen_imgs = 0.5 * gen_imgs + 0.5 # 画素値を[0, 1]でスケーリング
#画像の表示領域の確保(画像表示の行, 列, 画像サイズ, 表示画像の行と列を共有)
fig,axs = plt.subplots(img_grid_rows,
img_grid_cols,
figsize=(4,4),
sharey=True,
sharex=True)
cnt = 0
#画像の表示
for i in range(img_grid_rows):
for j in range(img_grid_cols):
axs[i, j].imshow(gen_imgs[cnt, :, :, 0], cmap='gray')
axs[i,j].axis('off')
cnt += 1
# 現在のfigをGoogleドライブのMy Driveに保存
fig.savefig('./gdrive/My Drive/'+str(iteration)+'FMShoesfig.png')