質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2508閲覧

DCGANでノイズ画像しか生成されない

tomoki_fab

総合スコア25

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/05/24 03:58

編集2020/05/24 05:33

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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2020/05/24 04:03

コピペで動くコードを記載できますか?
tomoki_fab

2020/05/24 05:41 編集

返信ありがとうございます! Python3で、 kerasとpillowのインストールが必要です。 プログレスバーの表示などいくらか余計なものもついていますが、よろしくおねがいします。
tomoki_fab

2020/05/24 05:33

本当ですね、すみません。 修正しました。
tiitoi

2020/05/24 05:45

ありがとうございます。今、GPU 使える環境がないので、試すのが明日とかになってしまうかもしれないです。
tomoki_fab

2020/05/24 06:02

わざわざありがとうございます、よろしくおねがいします。
guest

回答1

0

ベストアンサー

とりあえず、一番の問題はわかりました。
MNIST の画像は画素値が [0, 255] のままモデルに流すのではなく、[-1, 1] の範囲に正規化してから流す必要があります。

画素値は [0, 255] の整数なので、以下の手順で [-1, 1] の float に変換します。

  1. float に変換
  2. 127.5 で減算して、範囲を [-127.5, 127.5] にする
  3. 127.5 で除算して、範囲を [-1, 1] にする

python

1def get_data(): 2 '''MNIST から入力データを作成する。 3 ''' 4 (x_train, y_train), (x_test, y_test) = mnist.load_data() 5 6 # 学習データとテストデータを合わせる。 7 x_samples = np.concatenate([x_train, x_test]) 8 # 各画素の範囲を [0, 255] から [-1, 1] に変換する。 9 x_samples = (x_samples.astype(np.float32) - 127.5) / 127.5 10 # チャンネル分の次元を追加する。 (N, H, W) -> (N, H, W, C) 11 x_samples = x_samples[..., np.newaxis] 12 13 return x_samples

1000イテレーション時の画像
イメージ説明

5000イテレーション時の画像
イメージ説明

検証したコード

上記問題に気づくまでにあれこれ試行錯誤したので、モデルや最適化手法とかも変えてしまいましたが、とりあえず現状うまくいったコードを以下に貼ります。

python

1import numpy as np 2from PIL import Image 3 4# tensorflow の keras を使ってますが、keras を使う場合は tensorflow. を消してください 5from tensorflow.keras.datasets import mnist 6from tensorflow.keras.layers import * 7from tensorflow.keras.models import * 8from tensorflow.keras.optimizers import * 9from IPython.display import display 10 11# --- プログレスバーを表示するクラス(学習自体には関係ありません) --------- 12class ProgressBar: 13 def __init__(self, entireJob): 14 self.job = entireJob 15 self.width = 40 16 def draw(self, progress): 17 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="") 18 19 20# Generator 21class Generator: 22 def __init__(self): 23 model = Sequential() 24 25 model.add(Dense(1024, input_dim=100)) 26 model.add(BatchNormalization()) 27 model.add(Activation('tanh')) 28 29 model.add(Dense(7 * 7 * 128)) 30 model.add(BatchNormalization()) 31 model.add(Activation('tanh')) 32 33 model.add(Reshape((7, 7, 128))) 34 35 model.add(UpSampling2D(size=(2, 2))) 36 model.add(Conv2D(64, 5, padding='same')) 37 model.add(BatchNormalization()) 38 model.add(Activation('tanh')) 39 40 model.add(UpSampling2D(size=(2, 2))) 41 model.add(Conv2D(1, 5, padding='same')) 42 model.add(Activation('tanh')) 43 44 self.model = model 45 46# --- Discriminatorモデルの定義 ------- 47class Discriminator: 48 def __init__(self): 49 model = Sequential() 50 51 model.add(Conv2D(64, 5, padding='same', input_shape=(28, 28, 1))) 52 model.add(LeakyReLU(0.2)) 53 model.add(Conv2D(64, 2, strides=2, padding='same')) 54 55 model.add(Conv2D(128, (5, 5))) 56 model.add(LeakyReLU(0.2)) 57 model.add(Conv2D(128, 2, strides=2, padding='same')) 58 59 model.add(Flatten()) 60 model.add(Dense(1024)) 61 model.add(LeakyReLU(0.2)) 62 63 model.add(Dense(1, activation='sigmoid')) 64 65 self.model = model 66 67def get_data(): 68 '''MNIST から入力データを作成する。 69 ''' 70 71 (x_train, y_train), (x_test, y_test) = mnist.load_data() 72 73 # 学習データとテストデータを合わせる。 74 x_samples = np.concatenate([x_train, x_test]) 75 # 各画素の範囲を [0, 255] から [-1, 1] に変換する。 76 x_samples = (x_samples.astype(np.float32) - 127.5) / 127.5 77 # チャンネル分の次元を追加する。 (N, H, W) -> (N, H, W, C) 78 x_samples = x_samples[..., np.newaxis] 79 80 return x_samples 81 82class Main: 83 def __init__(self): 84 # Generator を作成する。 85 self.generator = Generator().model 86 # Discriminator を作成する。 87 self.discriminator = Discriminator().model 88 # DCGAN モデルを作成する。 89 z = Input(shape=100) 90 img = self.generator(z) 91 self.discriminator.trainable = False # Discriminatorを更新しないよう設定 92 valid = self.discriminator(img) 93 self.combined = Model(z, valid) 94 self.combined.compile( 95 optimizer="adam", 96 loss='binary_crossentropy', 97 metrics=['accuracy'] ) 98 self.combined.summary() 99 100 # Discriminator をコンパイルする。 101 self.discriminator.trainable = True 102 self.discriminator.compile( 103 optimizer="adam", 104 loss='binary_crossentropy', 105 metrics=['accuracy'] ) 106 # --- MNISTデータセットの用意 --------------- 107 self.x_train = get_data() 108 109 # --- 学習 ------------------------------------- 110 def _train(self, iteration, batch_size): 111 progress = ProgressBar(iteration) # プログレスバーを用意 112 for i in range(iteration): 113 z_batch = np.random.uniform(-1,1,(batch_size,100)) # ノイズベクトルの生成 114 f_img = self.generator.predict(z_batch) # f_img(fake_img)の生成 115 r_img = self.x_train[np.random.randint(0, len(self.x_train), batch_size)] # r_img(real_img)を読み込み 116 117 # 偽物のデータと本物のデータをあわせる 118 x_batch = np.concatenate([f_img, r_img]) 119 # Discriminator の学習ラベルは偽物のデータでは 0、本物のデータでは1 120 y_batch = np.array([0] * batch_size + [1] * batch_size) 121 122 loss_d, acc_d = self.discriminator.train_on_batch(x_batch, y_batch) # Discriminatorの学習 123 124 z_batch = np.random.uniform(-1,1,(batch_size,100)) # ノイズベクトルの生成 125 # Generator のラベルは 1 126 y_batch =np.array([1] * batch_size) 127 128 self.discriminator.trainable = False 129 loss_g, acc_g = self.combined.train_on_batch(z_batch, y_batch) # Generatorの学習 130 self.discriminator.trainable = True 131 progress.draw(i) # プログレスバーの表示 132 print(" Accuracy=(%f,%f)"%(acc_g, acc_d/2), end="") 133 134 if i % 1000 == 0: 135 display(main.create_image()) 136 137 def train(self, iteration, batch_size, epoch): 138 for i in range(epoch): 139 print("Epoch %d/%d\n"%(i+1, epoch)) 140 self._train(iteration, batch_size) # _train()をepoch回繰り返します 141 142 def create_image(self): 143 # 100枚の画像を生成する。 144 z = np.random.uniform(-1,1,(100, 100)) 145 images = main.generator.predict(z) 146 147 images = images * 127.5 + 127.5 # [-1, 1] -> [0, 255] 148 149 # 画像を正方形に並べる。 150 n, h, w, c = images.shape 151 cols = int(np.sqrt(n)) 152 rows = int(np.ceil(n / cols)) 153 image = np.zeros((rows * h, cols * w), dtype=images.dtype) 154 155 for i, img in enumerate(images): 156 r = i // cols 157 c = i % cols 158 image[r * h:(r + 1) * h, c * w:(c + 1) * w] = img[..., 0] 159 image = image.astype(np.uint8) 160 image = Image.fromarray(image) 161 162 return image 163 164 165main = Main() 166main.train(iteration=5000, batch_size=32, epoch=1)

投稿2020/05/25 14:15

編集2020/05/25 14:19
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomoki_fab

2020/05/26 01:19

ありがとうございます! ご指摘の通り画像データを変換する過程を飛ばしてしまっていました。 また、どうやら問題はそこだけではなかったようで、作り直して頂いたコードと比較して試行錯誤してみたところ、Generatorのノイズベクトルの入力をはじめにDenseレイヤーに通すことで大幅に改善しました。 まだ送っていただいたコードほどの性能のものを自分では再現できませんが、引き続きコードを熟読して参考にさせていただきます。 とても丁寧な手ほどきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問