著者:高嶋真輝
今回は、本物に限りなく近いデータを生成できる「敵対的生成ネットワーク」(Generative Adversarial Networks)という機械学習の技術と、「Fashion-MNIST」という服飾画像のデータセットを用いて、靴の画像生成に挑戦します。
シェルスクリプトマガジン Vol.70は以下のリンク先でご購入できます。
図3 各種ライブラリをインポートするためのコード
1 2 3 4 5 6 7 8 9 10 |
%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 モデルの入力次元を設定するためのコード
1 2 3 4 5 |
img_rows = 28 #画像の横軸 img_cols = 28 #画像の縦軸 channels = 1 #画像のチャンネル数(モノクロは「1」、カラーは「3」) img_shape = (img_rows, img_cols, channels) z_dim = 100 #ノイズベクトルの次元数 |
図5 生成器のモデルを構築する関数を定義するためのコード
1 2 3 4 5 6 7 8 9 10 11 12 |
# 生成器モデル構築(画像形状情報: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 生成器のモデルを構築する関数を定義するためのコード
1 2 3 4 5 6 7 8 9 10 11 12 |
# 識別器モデル構築(画像形状情報: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のシステムモデルを構築する関数を定義するためのコード
1 2 3 4 5 6 |
# GANモデル構築関数 def ganBuilder(generator, discriminator): model = Sequential() model.add(generator) model.add(discriminator) return model |
図12 学習モデルをコンパイルするためのコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 識別器モデル作成(入力形状: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 損失などのデータを格納する変数を定義するためのコード
1 2 3 |
losses = [] accuracies = [] iteration_checkpoints = [] |
図14 学習用データを準備するためのコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 訓練用データの抽出 (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 学習処理用の関数を定義するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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 画像の表示と保存をする関数を定義するコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 画像生成と表示 # (学習済み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') |