質問編集履歴

2

疑問点を修正しました

2020/12/26 05:31

投稿

kentaro189
kentaro189

スコア0

test CHANGED
@@ -1 +1 @@
1
- KerasによるData Augmentation方法
1
+ DCGANによる半教師あり学習実装
test CHANGED
@@ -2,9 +2,7 @@
2
2
 
3
3
 
4
4
 
5
- GANを使用した半教師あり学習により、MNITSの教師あり画像を100枚使用しただけで精度90%の汎化性能を達成するべく、
5
+ GANを使用した半教師あり学習により、MNITSの教師あり画像を100枚使用しただけで精度90%の汎化性能を達成するべく、コード作成に取り組んでおります。
6
-
7
- コード作成に取り組んでおります。
8
6
 
9
7
 
10
8
 
@@ -14,11 +12,11 @@
14
12
 
15
13
 
16
14
 
17
- 一方、実際の精度は60-70%程度で向上せず、過学習発生しいる可能性があるため、
15
+ 一方、実際の精度は60-70%程度で向上せず、原因なのか頭を悩ませおります。
18
-
16
+
19
- Data Augmentationによる画像の水増しを試してみたいと思っているのですが、自分のコードの場合、
17
+ 過学習が発生してい可能性があるため、とりあえず画像の水増しなども実装してみたのですが、やはり汎化精度が向上しません。
20
-
18
+
21
- どのように実装すればよいのかわからず困ております。
19
+ もし何かわかる方がいらっしゃいましたらアドバイス頂けると大変助かります。
22
20
 
23
21
 
24
22
 
@@ -676,15 +674,7 @@
676
674
 
677
675
 
678
676
 
679
- ネットで検索したところ、ImageDataGeneratorを使用するのがよいというアイデアはあるのですが、
680
-
681
- いかんせんコードを書き始めて2か月のド素人のため、どのように当てはめればよいのかアドバイス頂けると大変助かります。
682
-
683
-
684
-
685
- kerasのImageDataGeneratorを使用して、(Class:Dataset内に)見よう見まねで以下のコードを追加してみたのですが、
677
+ 補足情報に載したGitHubコード(とあるDCGANに関する書籍のサンプルコードです)の単純なコピペではうまくいかなかったため、kerasのImageDataGeneratorを使用して、(Class:Dataset内に)以下のコードを追加してみたのですが、汎化精度が向上しませんでした。
686
-
687
- 汎化精度が向上しませんでした。水増しの方法が誤っているのか、そもそも他に原因があるのか、もしわかる方がいらっしゃればアドバイス頂けると大変助かります。
688
678
 
689
679
 
690
680
 

1

日本語がいまいちでしたので、現状が分かるように修正しました。また、追加で試したこと(コード)を書き足しています。

2020/12/26 05:31

投稿

kentaro189
kentaro189

スコア0

test CHANGED
File without changes
test CHANGED
@@ -2,668 +2,674 @@
2
2
 
3
3
 
4
4
 
5
+ GANを使用した半教師あり学習により、MNITSの教師あり画像を100枚使用しただけで精度90%の汎化性能を達成するべく、
6
+
5
- ここ質問の内容を詳しく書いてください
7
+ コード作成取り組んでおります
6
-
7
- (例)PHP(CakePHP)で●●なシステムを作っています。
8
+
8
-
9
- ■■な機能を実装中に以下のエラーメッセージが発生しました。
9
+
10
10
 
11
11
 
12
12
 
13
13
  ### 発生している問題・エラーメッセージ
14
14
 
15
+
16
+
15
- GANを使用した半教師あり学習によりMNITS教師あり画像を100枚使用しただけで精度90%の汎化能を達成すコードを作成しております。
17
+ 一方実際の精度は60-70%程度で向上せず、過学習が発生している可能があため、
16
-
18
+
17
- 一方、精度は60-70%程度で向上せず、過学習が発生している可能性があるため、Data Augmentationによる画像の水増しを試してみたいと思っているのですが、自分のコードの場合、どのように実装すればよいのかわからず困っております。
19
+ Data Augmentationによる画像の水増しを試してみたいと思っているのですが、自分のコードの場合、
20
+
21
+ どのように実装すればよいのかわからず困っております。
22
+
23
+
24
+
25
+ ### 該当のソースコード
26
+
27
+
28
+
29
+ ```Python
30
+
31
+ import matplotlib.pyplot as plt
32
+
33
+ %matplotlib inline
34
+
35
+ import numpy as np
36
+
37
+
38
+
39
+ from keras import backend as K
40
+
41
+ from keras.datasets import mnist
42
+
43
+ from keras.layers import Activation, BatchNormalization, Concatenate, Dense, Dropout, Flatten, Input, Lambda, Reshape
44
+
45
+ from keras.layers.advanced_activations import LeakyReLU
46
+
47
+ from keras.layers.convolutional import Conv2D, Conv2DTranspose
48
+
49
+ from keras.models import Model, Sequential
50
+
51
+ from keras.optimizers import Adam
52
+
53
+ from keras.utils import to_categorical
54
+
55
+ from keras.preprocessing.image import ImageDataGenerator
56
+
57
+
58
+
59
+ ## モデルの入力次元の定義
60
+
61
+ img_rows = 28
62
+
63
+ img_cols = 28
64
+
65
+ channels = 1
66
+
67
+
68
+
69
+ #入力画像の解像度
70
+
71
+ img_shape = (img_rows, img_cols, channels)
72
+
73
+
74
+
75
+ #Generatorに入力するノイズベクトルzのサイズ
76
+
77
+ z_dim = 100
78
+
79
+
80
+
81
+ #データセット内のクラスの数
82
+
83
+ num_classes = 10
84
+
85
+
86
+
87
+ ##訓練と検証のためのデータの設定 num_labeledで指定された枚数の画像のみを使用(残りはラベルなしとして使用)
88
+
89
+ class Dataset:
90
+
91
+ def __init__(self, num_labeled):
92
+
93
+
94
+
95
+ # 訓練用に使用するラベル付き画像の数
96
+
97
+ self.num_labeled = num_labeled
98
+
99
+
100
+
101
+ # MNISTデータのDL
102
+
103
+ (self.x_train, self.y_train), (self.x_test, self.y_test) = mnist.load_data()
104
+
105
+
106
+
107
+ def preprocess_imgs(x):
108
+
109
+ # [0, 255] のグレースケール画素値を [-1, 1]の値に変換する
110
+
111
+ x = (x.astype(np.float32) - 127.5) / 127.5
112
+
113
+ # xの画像の次元を横幅×縦幅×チャンネル数に拡張する
114
+
115
+ x = np.expand_dims(x, axis=3)
116
+
117
+ return x
118
+
119
+
120
+
121
+ def preprocess_labels(y):
122
+
123
+ return y.reshape(-1, 1)
124
+
125
+
126
+
127
+ # 訓練データ
128
+
129
+ self.x_train = preprocess_imgs(self.x_train)
130
+
131
+ self.y_train = preprocess_labels(self.y_train)
132
+
133
+
134
+
135
+ # テストデータ
136
+
137
+ self.x_test = preprocess_imgs(self.x_test)
138
+
139
+ self.y_test = preprocess_labels(self.y_test)
140
+
141
+
142
+
143
+ def batch_labeled(self, batch_size):
144
+
145
+ # ラベル付き画像とそのラベルをランダムに取り出してバッチをつくる
146
+
147
+ idx = np.random.randint(0, self.num_labeled, batch_size)
148
+
149
+ imgs = self.x_train[idx]
150
+
151
+ labels = self.y_train[idx]
152
+
153
+
154
+
155
+   datagen = ImageDataGenerator(rotation_range = 50)
156
+
157
+ g = datagen.flow(imgs, labels, batch_size, shuffle=False)
158
+
159
+ imgs, labels = g.next()
160
+
161
+
162
+
163
+ return imgs, labels
164
+
165
+
166
+
167
+ def batch_unlabeled(self, batch_size):
168
+
169
+ # ラベルなし画像をランダムに取り出してバッチをつくる
170
+
171
+ idx = np.random.randint(self.num_labeled, self.x_train.shape[0],batch_size)
172
+
173
+ imgs = self.x_train[idx]
174
+
175
+ return imgs
176
+
177
+
178
+
179
+ def training_set(self):
180
+
181
+ x_train = self.x_train[range(self.num_labeled)]
182
+
183
+ y_train = self.y_train[range(self.num_labeled)]
184
+
185
+ return x_train, y_train
186
+
187
+
188
+
189
+ def test_set(self):
190
+
191
+ return self.x_test, self.y_test
192
+
193
+
194
+
195
+ ## ラベル付き訓練データの数の指定
196
+
197
+
198
+
199
+ num_labeled = 100
200
+
201
+
202
+
203
+ dataset = Dataset(num_labeled)
204
+
205
+
206
+
207
+ ## 生成器(Generator)の実装
208
+
209
+
210
+
211
+ def build_generator(z_dim):
212
+
213
+
214
+
215
+ model = Sequential()
216
+
217
+
218
+
219
+ # 入力を全結合により7×7×256のテンソルに変形する
220
+
221
+ model.add(Dense(256 * 7 * 7, input_dim=z_dim))
222
+
223
+ model.add(Reshape((7, 7, 256)))
224
+
225
+
226
+
227
+ # 転置畳み込み層により14x14x128のテンソルに変形する(転置畳み込みにより、幅と高さを拡大する代わりに深さを小さくできる⇔普通の畳み込みと逆)
228
+
229
+ model.add(Conv2DTranspose(128, kernel_size=3, strides=2, padding='same'))
230
+
231
+
232
+
233
+ # Batch normalization(バッチ正規化)
234
+
235
+ model.add(BatchNormalization())
236
+
237
+
238
+
239
+ # Leaky ReLU による活性化
240
+
241
+ model.add(LeakyReLU(alpha=0.01))
242
+
243
+
244
+
245
+ # 転置畳み込み層により14x14x64のテンソルに変形する
246
+
247
+ model.add(Conv2DTranspose(64, kernel_size=3, strides=1, padding='same'))
248
+
249
+
250
+
251
+ # Batch normalization (バッチ正規化)
252
+
253
+ model.add(BatchNormalization())
254
+
255
+
256
+
257
+ # Leaky ReLU による活性化
258
+
259
+ model.add(LeakyReLU(alpha=0.01))
260
+
261
+
262
+
263
+ # 転置畳み込み層により28x28x1のテンソルに変形する
264
+
265
+ model.add(Conv2DTranspose(1, kernel_size=3, strides=2, padding='same'))
266
+
267
+
268
+
269
+ # tanhによる活性化を行った出力層(tanhにすることでよりはっきりした画像になる)
270
+
271
+ model.add(Activation('tanh'))
272
+
273
+
274
+
275
+ return model
276
+
277
+
278
+
279
+ ## 識別機(Discriminator)の実装
280
+
281
+
282
+
283
+ def build_discriminator_net(img_shape):
284
+
285
+
286
+
287
+ model = Sequential()
288
+
289
+
290
+
291
+ # 畳み込み層により14x14x32のテンソルに変形する
292
+
293
+ model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=img_shape, padding='same'))
294
+
295
+
296
+
297
+ # Leaky ReLU による活性化
298
+
299
+ model.add(LeakyReLU(alpha=0.01))
300
+
301
+
302
+
303
+ # 畳み込み層により7x7x64のテンソルに変形する
304
+
305
+ model.add(Conv2D(64, kernel_size=3, strides=2, input_shape=img_shape, padding='same'))
306
+
307
+
308
+
309
+ # Batch normalization (バッチ正規化)
310
+
311
+ model.add(BatchNormalization())
312
+
313
+
314
+
315
+ # Leaky ReLU による活性化
316
+
317
+ model.add(LeakyReLU(alpha=0.01))
318
+
319
+
320
+
321
+ # 畳み込み層により3x3x128のテンソルに変形する
322
+
323
+ model.add(Conv2D(128, kernel_size=3, strides=2, input_shape=img_shape, padding='same'))
324
+
325
+
326
+
327
+ # Batch normalization (バッチ正規化)
328
+
329
+ model.add(BatchNormalization())
330
+
331
+
332
+
333
+ # Leaky ReLU による活性化
334
+
335
+ model.add(LeakyReLU(alpha=0.01))
336
+
337
+
338
+
339
+ # ドロップアウト
340
+
341
+ model.add(Dropout(0.5))
342
+
343
+
344
+
345
+ # テンソルを一列に変形する
346
+
347
+ model.add(Flatten())
348
+
349
+
350
+
351
+ # num_classesニューロンへの全結合層
352
+
353
+ model.add(Dense(num_classes))
354
+
355
+
356
+
357
+ return model
358
+
359
+
360
+
361
+ ## 教師あり部分のSGAN識別機の実装
362
+
363
+
364
+
365
+ def build_discriminator_supervised(discriminator_net):
366
+
367
+
368
+
369
+ model = Sequential()
370
+
371
+
372
+
373
+ model.add(discriminator_net)
374
+
375
+
376
+
377
+ # ソフトマックスによる活性化により、本物のクラスの中のどれに該当するのか推定確率を出力
378
+
379
+ model.add(Activation('softmax'))
380
+
381
+
382
+
383
+ return model
384
+
385
+
386
+
387
+ ## 教師なし部分のSGAN識別機の実装
388
+
389
+
390
+
391
+ def build_discriminator_unsupervised(discriminator_net):
392
+
393
+
394
+
395
+ model = Sequential()
396
+
397
+
398
+
399
+ model.add(discriminator_net)
400
+
401
+
402
+
403
+ def predict(x):
404
+
405
+ # 本物のクラスごとの確率分布を、本物か偽物かの2値の確率に変換する
406
+
407
+ prediction = 1.0 - (1.0 /(K.sum(K.exp(x), axis=-1, keepdims=True) + 1.0))
408
+
409
+ return prediction
410
+
411
+
412
+
413
+ # 本物か偽物かを出力する
414
+
415
+ model.add(Lambda(predict))
416
+
417
+
418
+
419
+ return model
420
+
421
+
422
+
423
+ ## モデル構築
424
+
425
+
426
+
427
+ def build_gan(generator, discriminator):
428
+
429
+
430
+
431
+ model = Sequential()
432
+
433
+
434
+
435
+ # 生成器と識別器を結合する
436
+
437
+ model.add(generator)
438
+
439
+ model.add(discriminator)
440
+
441
+
442
+
443
+ return model
444
+
445
+
446
+
447
+ # 教師ありと教師なしで共有される層
448
+
449
+ discriminator_net = build_discriminator_net(img_shape)
450
+
451
+
452
+
453
+ # 教師あり学習のための識別機をコンパイルする
454
+
455
+ discriminator_supervised = build_discriminator_supervised(discriminator_net)
456
+
457
+ discriminator_supervised.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer=Adam())
458
+
459
+
460
+
461
+ # 教師なし学習のための識別機をコンパイルする
462
+
463
+ discriminator_unsupervised = build_discriminator_unsupervised(discriminator_net)
464
+
465
+ discriminator_unsupervised.compile(loss='binary_crossentropy', optimizer=Adam())
466
+
467
+
468
+
469
+ # 生成器の作成
470
+
471
+ generator = build_generator(z_dim)
472
+
473
+
474
+
475
+ # 生成器の訓練中は識別機のパラメータは定数
476
+
477
+ discriminator_unsupervised.trainable = False
478
+
479
+
480
+
481
+ # 生成器の訓練を行うため、識別機のパラメータを固定したGANモデルを構築し、コンパイルする
482
+
483
+ gan = build_gan(generator, discriminator_unsupervised)
484
+
485
+ gan.compile(loss='binary_crossentropy', optimizer=Adam())
486
+
487
+
488
+
489
+ ''''''''''''''''''''''
490
+
491
+ SGAN訓練アルゴリズムの実装
492
+
493
+
494
+
495
+ ①教師あり識別機の訓練
496
+
497
+
498
+
499
+ ラベリングされた本物のデータからランダムにサンプルを取り出し、ミニバッチを作成
500
+
501
+ このミニバッチからロスを計算し、誤差逆伝播によってパラメータθを更新
502
+
503
+ ②生成器の訓練
504
+
505
+
506
+
507
+ ラベルのない本物データからランダムにミニバッチを作成
508
+
509
+ ここからロスを計算し、2値分類の誤差逆伝播によってθを更新
510
+
511
+ ノイズベクトルzから偽サンプルのミニバッチを作成
512
+
513
+ このミニバッチからもロスを計算し、2値分類の誤差逆伝播によってθを更新
514
+
515
+ ③生成器の訓練
516
+
517
+
518
+
519
+ ノイズベクトルzから偽の生成サンプルからなるミニバッチを作成
520
+
521
+ このミニバッチからロスを計算し、2値分類の誤差逆伝播によってθを更新
522
+
523
+ '''''''''''''''''''''''
524
+
525
+
526
+
527
+ supervised_losses = []
528
+
529
+ iteration_checkpoints = []
530
+
531
+
532
+
533
+
534
+
535
+ def train(iterations, batch_size, sample_interval):
536
+
537
+
538
+
539
+ # 本物の画像のラベル: すべて1
540
+
541
+ real = np.ones((batch_size, 1))
542
+
543
+
544
+
545
+ # 偽物の画像のラベル: すべて0
546
+
547
+ fake = np.zeros((batch_size, 1))
548
+
549
+
550
+
551
+ #識別機の訓練
552
+
553
+ for iteration in range(iterations):
554
+
555
+
556
+
557
+ # ラベル付きデータの取得
558
+
559
+ imgs, labels = dataset.batch_labeled(batch_size)
560
+
561
+
562
+
563
+ # ワンホットエンコードされたラベル
564
+
565
+ labels = to_categorical(labels, num_classes=num_classes)
566
+
567
+
568
+
569
+ # ラベルなしデータの取得
570
+
571
+ imgs_unlabeled = dataset.batch_unlabeled(batch_size)
572
+
573
+
574
+
575
+ # 偽画像のバッチ作成
576
+
577
+ z = np.random.normal(0, 1, (batch_size, z_dim))
578
+
579
+ gen_imgs = generator.predict(z)
580
+
581
+
582
+
583
+ # ラベル付き本物データによる訓練
584
+
585
+ d_loss_supervised, accuracy = discriminator_supervised.train_on_batch(imgs, labels)
586
+
587
+
588
+
589
+ # ラベルなしの本物サンプルによる訓練
590
+
591
+ d_loss_real = discriminator_unsupervised.train_on_batch(imgs_unlabeled, real)
592
+
593
+
594
+
595
+ # 偽のサンプルによる訓練
596
+
597
+ d_loss_fake = discriminator_unsupervised.train_on_batch(gen_imgs, fake)
598
+
599
+
600
+
601
+ d_loss_unsupervised = 0.5 * np.add(d_loss_real, d_loss_fake)
602
+
603
+
604
+
605
+ # 生成器の訓練
606
+
607
+
608
+
609
+ # 偽画像のバッチ作成
610
+
611
+ z = np.random.normal(0, 1, (batch_size, z_dim))
612
+
613
+ gen_imgs = generator.predict(z)
614
+
615
+
616
+
617
+ # 生成器の訓練
618
+
619
+ g_loss = gan.train_on_batch(z, np.ones((batch_size, 1)))
620
+
621
+
622
+
623
+ if (iteration + 1) % sample_interval == 0:
624
+
625
+
626
+
627
+ # 生成器の教師ありの分類損失を、訓練後にプロットするために保存しておく
628
+
629
+ supervised_losses.append(d_loss_supervised)
630
+
631
+ iteration_checkpoints.append(iteration + 1)
632
+
633
+
634
+
635
+ # 訓練の進捗を出力
636
+
637
+ print("%d [D loss supervised: %.4f, acc.: %.2f%%] [D loss unsupervised: %.4f] [G loss: %f]" % (iteration + 1, d_loss_supervised, 100 * accuracy, d_loss_unsupervised, g_loss))
638
+
639
+
640
+
641
+ # ハイパーパラメータの設定
642
+
643
+ iterations = 8000
644
+
645
+ batch_size = 32
646
+
647
+ sample_interval = 800
648
+
649
+
650
+
651
+ # SGANを指定した回数だけ反復訓練させる
652
+
653
+ train(iterations, batch_size, sample_interval)
654
+
655
+
656
+
657
+ x, y = dataset.test_set()
658
+
659
+ y = to_categorical(y, num_classes=num_classes)
660
+
661
+
662
+
663
+ # テストデータの分類データの測定
664
+
665
+ _, accuracy = discriminator_supervised.evaluate(x, y)
666
+
667
+ print("Test Accuracy: %.2f%%" % (100 * accuracy))
18
668
 
19
669
 
20
670
 
21
671
  ```
22
672
 
23
- エラーメッセージ
24
-
25
- ```
26
-
27
-
28
-
29
- ### 該当のソースコード
30
-
31
-
32
-
33
- ```Python
34
-
35
- import matplotlib.pyplot as plt
36
-
37
- %matplotlib inline
38
-
39
- import numpy as np
40
-
41
-
42
-
43
- from keras import backend as K
44
-
45
- from keras.datasets import mnist
46
-
47
- from keras.layers import Activation, BatchNormalization, Concatenate, Dense, Dropout, Flatten, Input, Lambda, Reshape
48
-
49
- from keras.layers.advanced_activations import LeakyReLU
50
-
51
- from keras.layers.convolutional import Conv2D, Conv2DTranspose
52
-
53
- from keras.models import Model, Sequential
54
-
55
- from keras.optimizers import Adam
56
-
57
- from keras.utils import to_categorical
58
-
59
-
60
-
61
- ## モデルの入力次元の定義
62
-
63
- img_rows = 28
64
-
65
- img_cols = 28
66
-
67
- channels = 1
68
-
69
-
70
-
71
- #入力画像の解像度
72
-
73
- img_shape = (img_rows, img_cols, channels)
74
-
75
-
76
-
77
- #Generatorに入力するノイズベクトルzのサイズ
78
-
79
- z_dim = 100
80
-
81
-
82
-
83
- #データセット内のクラスの数
84
-
85
- num_classes = 10
86
-
87
-
88
-
89
- ##訓練と検証のためのデータの設定 num_labeledで指定された枚数の画像のみを使用(残りはラベルなしとして使用)
90
-
91
- class Dataset:
92
-
93
- def __init__(self, num_labeled):
94
-
95
-
96
-
97
- # 訓練用に使用するラベル付き画像の数
98
-
99
- self.num_labeled = num_labeled
100
-
101
-
102
-
103
- # MNISTデータのDL
104
-
105
- (self.x_train, self.y_train), (self.x_test, self.y_test) = mnist.load_data()
106
-
107
-
108
-
109
- def preprocess_imgs(x):
110
-
111
- # [0, 255] のグレースケール画素値を [-1, 1]の値に変換する
112
-
113
- x = (x.astype(np.float32) - 127.5) / 127.5
114
-
115
- # xの画像の次元を横幅×縦幅×チャンネル数に拡張する
116
-
117
- x = np.expand_dims(x, axis=3)
118
-
119
- return x
120
-
121
-
122
-
123
- def preprocess_labels(y):
124
-
125
- return y.reshape(-1, 1)
126
-
127
-
128
-
129
- # 訓練データ
130
-
131
- self.x_train = preprocess_imgs(self.x_train)
132
-
133
- self.y_train = preprocess_labels(self.y_train)
134
-
135
-
136
-
137
- # テストデータ
138
-
139
- self.x_test = preprocess_imgs(self.x_test)
140
-
141
- self.y_test = preprocess_labels(self.y_test)
142
-
143
-
144
-
145
- def batch_labeled(self, batch_size):
146
-
147
- # ラベル付き画像とそのラベルをランダムに取り出してバッチをつくる
148
-
149
- idx = np.random.randint(0, self.num_labeled, batch_size)
150
-
151
- imgs = self.x_train[idx]
152
-
153
- labels = self.y_train[idx]
154
-
155
- return imgs, labels
156
-
157
-
158
-
159
- def batch_unlabeled(self, batch_size):
160
-
161
- # ラベルなし画像をランダムに取り出してバッチをつくる
162
-
163
- idx = np.random.randint(self.num_labeled, self.x_train.shape[0],batch_size)
164
-
165
- imgs = self.x_train[idx]
166
-
167
- return imgs
168
-
169
-
170
-
171
- def training_set(self):
172
-
173
- x_train = self.x_train[range(self.num_labeled)]
174
-
175
- y_train = self.y_train[range(self.num_labeled)]
176
-
177
- return x_train, y_train
178
-
179
-
180
-
181
- def test_set(self):
182
-
183
- return self.x_test, self.y_test
184
-
185
-
186
-
187
- ## ラベル付き訓練データの数の指定
188
-
189
-
190
-
191
- num_labeled = 100
192
-
193
-
194
-
195
- dataset = Dataset(num_labeled)
196
-
197
-
198
-
199
- ## 生成器(Generator)の実装
200
-
201
-
202
-
203
- def build_generator(z_dim):
204
-
205
-
206
-
207
- model = Sequential()
208
-
209
-
210
-
211
- # 入力を全結合により7×7×256のテンソルに変形する
212
-
213
- model.add(Dense(256 * 7 * 7, input_dim=z_dim))
214
-
215
- model.add(Reshape((7, 7, 256)))
216
-
217
-
218
-
219
- # 転置畳み込み層により14x14x128のテンソルに変形する(転置畳み込みにより、幅と高さを拡大する代わりに深さを小さくできる⇔普通の畳み込みと逆)
220
-
221
- model.add(Conv2DTranspose(128, kernel_size=3, strides=2, padding='same'))
222
-
223
-
224
-
225
- # Batch normalization(バッチ正規化)
226
-
227
- model.add(BatchNormalization())
228
-
229
-
230
-
231
- # Leaky ReLU による活性化
232
-
233
- model.add(LeakyReLU(alpha=0.01))
234
-
235
-
236
-
237
- # 転置畳み込み層により14x14x64のテンソルに変形する
238
-
239
- model.add(Conv2DTranspose(64, kernel_size=3, strides=1, padding='same'))
240
-
241
-
242
-
243
- # Batch normalization (バッチ正規化)
244
-
245
- model.add(BatchNormalization())
246
-
247
-
248
-
249
- # Leaky ReLU による活性化
250
-
251
- model.add(LeakyReLU(alpha=0.01))
252
-
253
-
254
-
255
- # 転置畳み込み層により28x28x1のテンソルに変形する
256
-
257
- model.add(Conv2DTranspose(1, kernel_size=3, strides=2, padding='same'))
258
-
259
-
260
-
261
- # tanhによる活性化を行った出力層(tanhにすることでよりはっきりした画像になる)
262
-
263
- model.add(Activation('tanh'))
264
-
265
-
266
-
267
- return model
268
-
269
-
270
-
271
- ## 識別機(Discriminator)の実装
272
-
273
-
274
-
275
- def build_discriminator_net(img_shape):
276
-
277
-
278
-
279
- model = Sequential()
280
-
281
-
282
-
283
- # 畳み込み層により14x14x32のテンソルに変形する
284
-
285
- model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=img_shape, padding='same'))
286
-
287
-
288
-
289
- # Leaky ReLU による活性化
290
-
291
- model.add(LeakyReLU(alpha=0.01))
292
-
293
-
294
-
295
- # 畳み込み層により7x7x64のテンソルに変形する
296
-
297
- model.add(Conv2D(64, kernel_size=3, strides=2, input_shape=img_shape, padding='same'))
298
-
299
-
300
-
301
- # Batch normalization (バッチ正規化)
302
-
303
- model.add(BatchNormalization())
304
-
305
-
306
-
307
- # Leaky ReLU による活性化
308
-
309
- model.add(LeakyReLU(alpha=0.01))
310
-
311
-
312
-
313
- # 畳み込み層により3x3x128のテンソルに変形する
314
-
315
- model.add(Conv2D(128, kernel_size=3, strides=2, input_shape=img_shape, padding='same'))
316
-
317
-
318
-
319
- # Batch normalization (バッチ正規化)
320
-
321
- model.add(BatchNormalization())
322
-
323
-
324
-
325
- # Leaky ReLU による活性化
326
-
327
- model.add(LeakyReLU(alpha=0.01))
328
-
329
-
330
-
331
- # ドロップアウト
332
-
333
- model.add(Dropout(0.5))
334
-
335
-
336
-
337
- # テンソルを一列に変形する
338
-
339
- model.add(Flatten())
340
-
341
-
342
-
343
- # num_classesニューロンへの全結合層
344
-
345
- model.add(Dense(num_classes))
346
-
347
-
348
-
349
- return model
350
-
351
-
352
-
353
- ## 教師あり部分のSGAN識別機の実装
354
-
355
-
356
-
357
- def build_discriminator_supervised(discriminator_net):
358
-
359
-
360
-
361
- model = Sequential()
362
-
363
-
364
-
365
- model.add(discriminator_net)
366
-
367
-
368
-
369
- # ソフトマックスによる活性化により、本物のクラスの中のどれに該当するのか推定確率を出力
370
-
371
- model.add(Activation('softmax'))
372
-
373
-
374
-
375
- return model
376
-
377
-
378
-
379
- ## 教師なし部分のSGAN識別機の実装
380
-
381
-
382
-
383
- def build_discriminator_unsupervised(discriminator_net):
384
-
385
-
386
-
387
- model = Sequential()
388
-
389
-
390
-
391
- model.add(discriminator_net)
392
-
393
-
394
-
395
- def predict(x):
396
-
397
- # 本物のクラスごとの確率分布を、本物か偽物かの2値の確率に変換する
398
-
399
- prediction = 1.0 - (1.0 /(K.sum(K.exp(x), axis=-1, keepdims=True) + 1.0))
400
-
401
- return prediction
402
-
403
-
404
-
405
- # 本物か偽物かを出力する
406
-
407
- model.add(Lambda(predict))
408
-
409
-
410
-
411
- return model
412
-
413
-
414
-
415
- ## モデル構築
416
-
417
-
418
-
419
- def build_gan(generator, discriminator):
420
-
421
-
422
-
423
- model = Sequential()
424
-
425
-
426
-
427
- # 生成器と識別器を結合する
428
-
429
- model.add(generator)
430
-
431
- model.add(discriminator)
432
-
433
-
434
-
435
- return model
436
-
437
-
438
-
439
- # 教師ありと教師なしで共有される層
440
-
441
- discriminator_net = build_discriminator_net(img_shape)
442
-
443
-
444
-
445
- # 教師あり学習のための識別機をコンパイルする
446
-
447
- discriminator_supervised = build_discriminator_supervised(discriminator_net)
448
-
449
- discriminator_supervised.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer=Adam())
450
-
451
-
452
-
453
- # 教師なし学習のための識別機をコンパイルする
454
-
455
- discriminator_unsupervised = build_discriminator_unsupervised(discriminator_net)
456
-
457
- discriminator_unsupervised.compile(loss='binary_crossentropy', optimizer=Adam())
458
-
459
-
460
-
461
- # 生成器の作成
462
-
463
- generator = build_generator(z_dim)
464
-
465
-
466
-
467
- # 生成器の訓練中は識別機のパラメータは定数
468
-
469
- discriminator_unsupervised.trainable = False
470
-
471
-
472
-
473
- # 生成器の訓練を行うため、識別機のパラメータを固定したGANモデルを構築し、コンパイルする
474
-
475
- gan = build_gan(generator, discriminator_unsupervised)
476
-
477
- gan.compile(loss='binary_crossentropy', optimizer=Adam())
478
-
479
-
480
-
481
- ###########################
482
-
483
- SGAN訓練アルゴリズムの実装
484
-
485
-
486
-
487
- ①教師あり識別機の訓練
488
-
489
-
490
-
491
- ラベリングされた本物のデータからランダムにサンプルを取り出し、ミニバッチを作成
492
-
493
- このミニバッチからロスを計算し、誤差逆伝播によってパラメータθを更新
494
-
495
- ②生成器の訓練
496
-
497
-
498
-
499
- ラベルのない本物データからランダムにミニバッチを作成
500
-
501
- ここからロスを計算し、2値分類の誤差逆伝播によってθを更新
502
-
503
- ノイズベクトルzから偽サンプルのミニバッチを作成
504
-
505
- このミニバッチからもロスを計算し、2値分類の誤差逆伝播によってθを更新
506
-
507
- ③生成器の訓練
508
-
509
-
510
-
511
- ノイズベクトルzから偽の生成サンプルからなるミニバッチを作成
512
-
513
- このミニバッチからロスを計算し、2値分類の誤差逆伝播によってθを更新
514
-
515
- #############################
516
-
517
-
518
-
519
-
520
-
521
- supervised_losses = []
522
-
523
- iteration_checkpoints = []
524
-
525
-
526
-
527
-
528
-
529
- def train(iterations, batch_size, sample_interval):
530
-
531
-
532
-
533
- # 本物の画像のラベル: すべて1
534
-
535
- real = np.ones((batch_size, 1))
536
-
537
-
538
-
539
- # 偽物の画像のラベル: すべて0
540
-
541
- fake = np.zeros((batch_size, 1))
542
-
543
-
544
-
545
- #識別機の訓練
546
-
547
- for iteration in range(iterations):
548
-
549
-
550
-
551
- # ラベル付きデータの取得
552
-
553
- imgs, labels = dataset.batch_labeled(batch_size)
554
-
555
-
556
-
557
- # ワンホットエンコードされたラベル
558
-
559
- labels = to_categorical(labels, num_classes=num_classes)
560
-
561
-
562
-
563
- # ラベルなしデータの取得
564
-
565
- imgs_unlabeled = dataset.batch_unlabeled(batch_size)
566
-
567
-
568
-
569
- # 偽画像のバッチ作成
570
-
571
- z = np.random.normal(0, 1, (batch_size, z_dim))
572
-
573
- gen_imgs = generator.predict(z)
574
-
575
-
576
-
577
- # ラベル付き本物データによる訓練
578
-
579
- d_loss_supervised, accuracy = discriminator_supervised.train_on_batch(imgs, labels)
580
-
581
-
582
-
583
- # ラベルなしの本物サンプルによる訓練
584
-
585
- d_loss_real = discriminator_unsupervised.train_on_batch(imgs_unlabeled, real)
586
-
587
-
588
-
589
- # 偽のサンプルによる訓練
590
-
591
- d_loss_fake = discriminator_unsupervised.train_on_batch(gen_imgs, fake)
592
-
593
-
594
-
595
- d_loss_unsupervised = 0.5 * np.add(d_loss_real, d_loss_fake)
596
-
597
-
598
-
599
- # 生成器の訓練
600
-
601
-
602
-
603
- # 偽画像のバッチ作成
604
-
605
- z = np.random.normal(0, 1, (batch_size, z_dim))
606
-
607
- gen_imgs = generator.predict(z)
608
-
609
-
610
-
611
- # 生成器の訓練
612
-
613
- g_loss = gan.train_on_batch(z, np.ones((batch_size, 1)))
614
-
615
-
616
-
617
- if (iteration + 1) % sample_interval == 0:
618
-
619
-
620
-
621
- # 生成器の教師ありの分類損失を、訓練後にプロットするために保存しておく
622
-
623
- supervised_losses.append(d_loss_supervised)
624
-
625
- iteration_checkpoints.append(iteration + 1)
626
-
627
-
628
-
629
- # 訓練の進捗を出力
630
-
631
- print("%d [D loss supervised: %.4f, acc.: %.2f%%] [D loss unsupervised: %.4f] [G loss: %f]" % (iteration + 1, d_loss_supervised, 100 * accuracy, d_loss_unsupervised, g_loss))
632
-
633
-
634
-
635
- # ハイパーパラメータの設定
636
-
637
- iterations = 8000
638
-
639
- batch_size = 32
640
-
641
- sample_interval = 800
642
-
643
-
644
-
645
- # SGANを指定した回数だけ反復訓練させる
646
-
647
- train(iterations, batch_size, sample_interval)
648
-
649
-
650
-
651
- x, y = dataset.test_set()
652
-
653
- y = to_categorical(y, num_classes=num_classes)
654
-
655
-
656
-
657
- # テストデータの分類データの測定
658
-
659
- _, accuracy = discriminator_supervised.evaluate(x, y)
660
-
661
- print("Test Accuracy: %.2f%%" % (100 * accuracy))
662
-
663
-
664
-
665
- ```
666
-
667
673
 
668
674
 
669
675
  ### 試したこと
@@ -676,7 +682,17 @@
676
682
 
677
683
 
678
684
 
685
+ 追記:kerasのImageDataGeneratorを使用して、(Class:Dataset内に)見よう見まねで以下のコードを追加してみたのですが、
686
+
687
+ 汎化精度が向上しませんでした。水増しの方法が誤っているのか、そもそも他に原因があるのか、もしわかる方がいらっしゃればアドバイス頂けると大変助かります。
688
+
689
+
690
+
691
+ datagen = ImageDataGenerator(rotation_range = 50)
692
+
693
+ g = datagen.flow(imgs, labels, batch_size, shuffle=False)
694
+
679
- ここに問題に対して試したことを記載してください。
695
+ imgs, labels = g.next()
680
696
 
681
697
 
682
698