シェルスクリプトマガジン

香川大学SLPからお届け!(Vol.70掲載)

著者:高嶋真輝

 今回は、本物に限りなく近いデータを生成できる「敵対的生成ネットワーク」(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')