PythonでGANを用いた画像生成プログラムを作っています。
教師データとしてMNISTデータセットを用い、偽の手書き数字画像を生成するのが目標です。
画像を生成するGeneratorは、ランダムなノイズベクトルから、UpSampling2DレイヤーまたはDeconvolution2D(Conv2DTranspose)レイヤー、Convolution2Dレイヤー、活性化関数(主にRelu)を6層ほど(何度か層を変えて試してみていますが拡大縮小したデータサイズを合わせるためにだいたい6層ほどでやっています)経て画像として出力します。
一方、本物の画像と生成画像を判別するDiscriminatorは、入力画像を数層のConvolution2Dレイヤーと活性化関数へ渡し、Dense(Affine)レイヤーを5層ほど経て判別結果を出力します。
本物・偽物を1,0で表現し、0~1の範囲のDiscriminatorの出力との差を使って損失関数を定義しています。(Kerasではbinary_crossentropyを用いています)
しかし何度実験してみても出来上がった画像はノイズのようなものばかりです。
(以下がいくつかの生成画像です,
上5つが外部ライブラリに頼らずに作ったもの, 下5つがKerasを用いて作ったもの)
===============================================
これまでに試してみたこととしては、
- 様々な組み合わせのハイパーパラメーターで学習する
- GeneratorとDiscriminatorのバランスを取る(それぞれの精度を加味しながら)
- Relu以外の活性化関数を使ってみる
- Batch Normalizationを使う
- レイヤーの組み合わせも様々に試す
- 画像分類などは問題なく作れる
インターネットで手当たり次第に調べたり、書籍で参考になりそうな情報を探したり、手を尽くしましたがなぜ全くうまくいかないのかわかりません。問題がレイヤーの組み方なのか、何か決定的に重要な処理を飛ばしてしまっているのか、損失関数などの評価の仕方が悪いのかも見当もつきません。
なにか見落としているポイントなどがありますでしょうか?PythonでGANを用いた画像生成プログラムを作っています。
教師データとしてMNISTデータセットを用い、偽の手書き数字画像を生成するのが目標です。
画像を生成するGeneratorは、ランダムなノイズベクトルから、UpSampling2DレイヤーまたはDeconvolution2D(Conv2DTranspose)レイヤー、Convolution2Dレイヤー、活性化関数(主にRelu)を6層ほど(何度か層を変えて試してみていますが拡大縮小したデータサイズを合わせるためにだいたい6層ほどでやっています)経て画像として出力します。
一方、本物の画像と生成画像を判別するDiscriminatorは、入力画像を数層のConvolution2Dレイヤーと活性化関数へ渡し、Dense(Affine)レイヤーを5層ほど経て判別結果を出力します。
本物・偽物を1,0で表現し、0~1の範囲のDiscriminatorの出力との差を使って損失関数を定義しています。(Kerasではbinary_crossentropyを用いています)
しかし何度実験してみても出来上がった画像はノイズのようなものばかりです。
(以下がいくつかの生成画像です,
上5つが外部ライブラリに頼らずに作ったもの, 下5つがKerasを用いて作ったもの)
===============================================
これまでに試してみたこととしては、
- 様々な組み合わせのハイパーパラメーターで学習する
- GeneratorとDiscriminatorのバランスを取る(それぞれの精度を加味しながら)
- Relu以外の活性化関数を使ってみる
- Batch Normalizationを使う
- レイヤーの組み合わせも様々に試す
- 画像分類などは問題なく作れる
インターネットで手当たり次第に調べたり、書籍で参考になりそうな情報を探したり、手を尽くしましたがなぜ全くうまくいかないのかわかりません。問題がレイヤーの組み方なのか、何か決定的に重要な処理を飛ばしてしまっているのか、損失関数などの評価の仕方が悪いのかも見当もつきません。
なにか見落としているポイントなどがありますでしょうか?
コード
Python
1import numpy as np 2from PIL import Image 3 4from keras.datasets import mnist 5from keras.layers import * 6from keras.models import * 7from keras.optimizers import * 8 9 10# --- プログレスバーを表示するクラス(学習自体には関係ありません) --------- 11class ProgressBar: 12 def __init__(self, entireJob): 13 self.job = entireJob 14 self.width = 40 15 def draw(self, progress): 16 print( ("\r["+"#"*int((progress+1)*self.width/self.job)+" "*(self.width-int((progress+1)*self.width/self.job) ) +"] %d/%d")%(progress+1,self.job), end="") 17 18 19# --- Generatorモデルの定義 ----------- 20class Generator: 21 def __init__(self): 22 layer0 = Input(shape=(1,1,100)) 23 24 layer1 = UpSampling2D(size=(3,3))(layer0) 25 layer1 = Conv2D( 26 filters=100, 27 kernel_size=(2,2), 28 strides=(1,1), 29 padding='same', 30 activation='relu' )(layer1) 31 layer1 = BatchNormalization()(layer1) 32 33 layer2 = UpSampling2D(size=(3,3))(layer1) 34 layer2 = Conv2D( 35 filters=100, 36 kernel_size=(2,2), 37 strides=(1,1), 38 padding='same', 39 activation='relu' )(layer2) 40 layer2 = BatchNormalization()(layer2) 41 42 layer3 = UpSampling2D(size=(2,2))(layer2) 43 layer3 = Conv2D( 44 filters=80, 45 kernel_size=(3,3), 46 strides=(1,1), 47 padding='valid', 48 activation='elu' )(layer3) 49 layer3 = BatchNormalization()(layer3) 50 51 layer4 = UpSampling2D(size=(2,2))(layer3) 52 layer4 = Conv2D( 53 filters=50, 54 kernel_size=(3,3), 55 strides=(1,1), 56 padding='same', 57 activation='elu' )(layer4) 58 layer4 = BatchNormalization()(layer4) 59 60 layer5 = UpSampling2D(size=(2,2))(layer4) 61 layer5 = Conv2D( 62 filters=20, 63 kernel_size=(4,4), 64 strides=(2,2), 65 padding='valid', 66 activation='elu' )(layer5) 67 layer5 = BatchNormalization()(layer5) 68 69 layer6 = Conv2D( 70 filters=1, 71 kernel_size=(4,4), 72 strides=(1,1), 73 padding='valid', 74 activation='tanh' )(layer5) 75 76 self.model = Model(layer0, layer6) 77 self.model.summary() 78 79# --- Discriminatorモデルの定義 ------- 80class Discriminator: 81 def __init__(self): 82 layer0 = Input(shape=(28,28,1)) 83 layer1 = Conv2D( 84 filters=5, 85 kernel_size=(3,3), 86 strides=(2,2), 87 padding='valid', 88 activation='elu' )(layer0) 89 layer1 = BatchNormalization()(layer1) 90 91 layer2 = Conv2D( 92 filters=10, 93 kernel_size=(3,3), 94 strides=(2,2), 95 padding='valid', 96 activation='elu' )(layer1) 97 layer2 = BatchNormalization()(layer2) 98 99 layer3 = Conv2D( 100 filters=5, 101 kernel_size=(3,3), 102 strides=(1,1), 103 padding='valid', 104 activation='relu' )(layer2) 105 layer3 = BatchNormalization()(layer3) 106 107 layer4 = Flatten()(layer3) 108 layer4 = Dense(units=30, activation='tanh')(layer4) 109 layer4 = BatchNormalization()(layer4) 110 111 layer5 = Dense(units=1, activation='sigmoid' )(layer4) 112 113 self.model = Model(layer0, layer5) 114 self.model.summary() 115 116 117 118class Main: 119 def __init__(self): 120 # --- Discriminatorの定義 ----------------- 121 self.discriminator = Discriminator().model 122 self.discriminator.compile( 123 optimizer=SGD(learning_rate=1e-4), 124 loss='binary_crossentropy', 125 metrics=['accuracy'] ) 126 127 # --- GeneratorとDiscriminatorを連結したモデルの定義 --- 128 self.generator = Generator().model 129 z = Input(shape=(1,1,100)) 130 img = self.generator(z) 131 self.discriminator.trainable = False # Discriminatorを更新しないよう設定 132 valid = self.discriminator(img) 133 self.combined = Model(z, valid) 134 self.combined.compile( 135 optimizer=Adam(learning_rate=1e-6), 136 loss='binary_crossentropy', 137 metrics=['accuracy'] ) 138 139 # --- MNISTデータセットの用意 --------------- 140 (x_train, t_train), (x_test, t_test) = mnist.load_data() 141 x_train = x_train.reshape(60000, 28, 28, 1) 142 x_test = x_test.reshape(10000, 28, 28, 1) 143 self.x_train = x_train.astype('float32') 144 self.x_test = x_test.astype('float32') 145 146 # --- 学習 ------------------------------------- 147 def _train(self, iteration, batch_size): 148 progress = ProgressBar(iteration) # プログレスバーを用意 149 for i in range(iteration): 150 z = np.random.uniform(-1,1,(batch_size//2,1,1,100)) # ノイズベクトルの生成 151 f_img = self.generator.predict(z) # f_img(fake_img)の生成 152 r_img = self.x_train[np.random.randint(0, 60000, batch_size//2)] # r_img(real_img)を読み込み 153 loss_d, acc_d = self.discriminator.train_on_batch(f_img, np.zeros((batch_size//2,1))) # Discriminatorの学習 154 loss_d_, acc_d_ = self.discriminator.train_on_batch(r_img, np.ones( (batch_size//2,1))) # acc_d = Discriminatorのaccuracy 155 acc_d += acc_d_ 156 157 z = np.random.uniform(-1,1,(batch_size,1,1,100)) # ノイズベクトルの生成 158 loss_g, acc_g = self.combined.train_on_batch(z, np.ones((batch_size,1))) # Generatorの学習 159 progress.draw(i) # プログレスバーの表示 160 print(" Accuracy=(%f,%f)"%(acc_g, acc_d/2), end="") 161 162 def train(self, iteration, batch_size, epoch): 163 for i in range(epoch): 164 print("Epoch %d/%d\n"%(i+1, epoch)) 165 self._train(iteration, batch_size) # _train()をepoch回繰り返します 166 167 # --- 学習が終わった時の確認用に一枚だけ画像を作ります ------- 168 def create_image(self): 169 z = np.random.uniform(-1,1,(1,1,1,100)) 170 img = self.generator.predict(z) 171 return img.reshape(1,28,28) 172 173 174if __name__ == "__main__": 175 main = Main() 176 main.train(iteration=1875, batch_size=32, epoch=1) 177 178 # --- 画像を表示 ----------------------- 179 img = main.create_image() 180 img = Image.fromarray(np.uint8(img.reshape(28,28) * 255)) 181 img.show() 182 img.save("gan_generated_img.png") 183
回答1件
あなたの回答
tips
プレビュー