回答編集履歴

1

2018/10/20 12:34

投稿

tiitoi
tiitoi

スコア21956

test CHANGED
@@ -1,39 +1,527 @@
1
- > 1. 画像読み込
2
-
3
- > 1. 1. Train 画像データ(正例負例) 入力
4
-
5
- > 1. 2. Test 画像データ(正例と負例)の入力
6
-
7
- > 1. 3. Train 画像データ水増し
8
-
9
-
10
-
11
- [ImageDataGenerator](https://keras.io/ja/preprocessing/image/) を使う
12
-
13
-
14
-
15
- > 2.データ処理;
16
-
17
- > 2.1. 2クラス分類処理を行うニューラルネットを構築
18
-
19
- > 2.2.Trainデータを使って学習データを作成
20
-
21
- > 2.3.作成した学習データに対し、Testデータを入力し、2クラス分類を実施
22
-
23
- > 3.結果出力;
24
-
25
- > 2.3.Testデータの正例と、2.3.にて出力した結果を比較して精度の算出
26
-
27
-
28
-
29
- モデルの構築は [過去の質問](https://teratail.com/questions/149156) を参照
30
-
31
-
32
-
33
- > 成果物;
34
-
35
- > 2クラス分類結果CSVファイル
36
-
37
-
38
-
39
- Python の CSV モジュールを使って、CSV で書き出せます。
1
+ > 画像読み込む際、画像の入ったフォルダを指定して
2
+
3
+ データを読み込むいうことをしたいですが、その場合はどうすればよろしいでしょうか。
4
+
5
+
6
+
7
+ 以下ようにすればよいです。
8
+
9
+ 1. glob.glob() でファイル一覧を取得する。
10
+
11
+ 2. PIL.Image.open() で画像読み込む
12
+
13
+
14
+
15
+ # 2クラス分類を Keras でやる手順
16
+
17
+
18
+
19
+ ## サンプルした使用するデータセット
20
+
21
+
22
+
23
+ [Kaggle Cats and Dogs Dataset](https://www.microsoft.com/en-us/download/details.aspx?id=54765)
24
+
25
+
26
+
27
+ 解凍すると、以下のようになっている。
28
+
29
+ ```
30
+
31
+ PetImages
32
+
33
+ ├── Cat: 猫の画像が入っている
34
+
35
+ └── Dog: 犬画像が入っている
36
+
37
+ ```
38
+
39
+
40
+
41
+ 画像を学習用とテスト用に分割する。
42
+
43
+
44
+
45
+ ```
46
+
47
+ '''
48
+
49
+ 以下のようなクラスごとにフォルダ分けされたディレクトリ構造を学習用、テスト用に分割する。
50
+
51
+
52
+
53
+ input_dirpath
54
+
55
+ ├── Cat
56
+
57
+ └── Dog
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+ dataset
66
+
67
+ ├── test
68
+
69
+ │   ├── cat
70
+
71
+ │   └── dog
72
+
73
+ └── train
74
+
75
+ ├── cat
76
+
77
+ └── dog
78
+
79
+ '''
80
+
81
+ import glob
82
+
83
+ import os
84
+
85
+ import shutil
86
+
87
+ from PIL import Image
88
+
89
+ from sklearn.model_selection import train_test_split
90
+
91
+
92
+
93
+ # dataset/train/dog/11702.jpg
94
+
95
+
96
+
97
+ input_dirpath = 'PetImages'
98
+
99
+ output_dirpath = 'dataset'
100
+
101
+
102
+
103
+ for sub_dirpath in glob.glob(os.path.join(input_dirpath, '*')):
104
+
105
+ class_name = os.path.basename(sub_dirpath).lower()
106
+
107
+
108
+
109
+ # 出力用のディレクトリを作成する。
110
+
111
+ train_dirpath = os.path.join(output_dirpath, 'train', class_name)
112
+
113
+ test_dirpath = os.path.join(output_dirpath, 'test', class_name)
114
+
115
+ os.makedirs(train_dirpath, exist_ok=True)
116
+
117
+ os.makedirs(test_dirpath, exist_ok=True)
118
+
119
+
120
+
121
+ # サブディレクトリ配下の画像パスを取得する。
122
+
123
+ img_paths = glob.glob(os.path.join(sub_dirpath, '*.jpg'))
124
+
125
+ print('class {}: {} images found.'.format(class_name, len(img_paths)))
126
+
127
+
128
+
129
+ # 画像パスを学習用、テスト用に分割する。
130
+
131
+ train_paths, test_paths = train_test_split(img_paths, test_size=0.2)
132
+
133
+ for img_paths, to_dirpath in zip([train_paths, test_paths], [train_dirpath, test_dirpath]):
134
+
135
+ for img_path in img_paths:
136
+
137
+ to_filepath = os.path.join(to_dirpath, os.path.basename(img_path))
138
+
139
+
140
+
141
+ try:
142
+
143
+ img = Image.open(img_path)
144
+
145
+ img.verify() # 画像が壊れていないかチェック
146
+
147
+ img._getexif() # exif の壊れていないかチェック
148
+
149
+ # 問題ない画像ファイルならコピー
150
+
151
+ shutil.copy(img_path, to_filepath)
152
+
153
+ # print('{} ---> {}'.format(img_path, to_filepath))
154
+
155
+ except Exception:
156
+
157
+ # 壊れた画像ファイルはスキップ
158
+
159
+ print('Invalid image found. {}'.format(img_path))
160
+
161
+ ```
162
+
163
+
164
+
165
+ ## 学習済みの ResNet-50 でモデルを作成する。
166
+
167
+
168
+
169
+ fine-tuning でやりたいので、ImageNet で学習済みの ResNet-50 のモデルのあとに全結合層をくっつけて、モデルを作成する。
170
+
171
+
172
+
173
+ ```
174
+
175
+ import numpy as np
176
+
177
+ from keras.applications.resnet50 import ResNet50, preprocess_input, decode_predictions
178
+
179
+ from keras.layers import Dense, Flatten
180
+
181
+ from keras.models import Model
182
+
183
+ from keras.preprocessing import image
184
+
185
+
186
+
187
+ num_classes = 2
188
+
189
+
190
+
191
+ # モデルを作成する。
192
+
193
+ # ----------------------------------
194
+
195
+
196
+
197
+ base_model = ResNet50(weights='imagenet', include_top=False,
198
+
199
+ input_shape=(224, 224, 3))
200
+
201
+ # ベースモデルのあとに分類用の全結合層を追加する。
202
+
203
+ x = base_model.output
204
+
205
+ x = Flatten()(x)
206
+
207
+ x = Dense(1000, activation='relu')(x)
208
+
209
+ output = Dense(num_classes, activation='softmax')(x)
210
+
211
+ model = Model(inputs=base_model.input, outputs=output)
212
+
213
+
214
+
215
+ # fine-tuning なので追加した層以外はフリーズする。(パラメータ更新しない)
216
+
217
+ for layer in base_model.layers:
218
+
219
+ layer.trainable = False
220
+
221
+
222
+
223
+ # モデルを可視化
224
+
225
+ from keras.utils import plot_model
226
+
227
+ # plot_model(model, to_file='model.png')
228
+
229
+
230
+
231
+ # モデルをコンパイルする。
232
+
233
+ model.compile(optimizer='rmsprop', loss='categorical_crossentropy',
234
+
235
+ metrics = ['accuracy'])
236
+
237
+ ```
238
+
239
+
240
+
241
+ ## ディレクトリからデータを読み込み、水増しするジェネレーターを作成する。
242
+
243
+
244
+
245
+ 以下のディレクトリ構造を想定している。
246
+
247
+
248
+
249
+ ```
250
+
251
+ dataset
252
+
253
+ ├── test
254
+
255
+ │   ├── cat
256
+
257
+ │   └── dog
258
+
259
+ └── train
260
+
261
+ ├── cat
262
+
263
+ └── dog
264
+
265
+ ```
266
+
267
+
268
+
269
+ [ImageDataGenerator](https://keras.io/ja/preprocessing/image/) でディレクトリから画像を読み込みつつ、水増しするジェネレーターを作成する。
270
+
271
+
272
+
273
+ ```
274
+
275
+ train_dirpath = 'dataset/train'
276
+
277
+ test_dirpath = 'dataset/test'
278
+
279
+ batch_size = 32
280
+
281
+ epochs = 10
282
+
283
+
284
+
285
+ # 学習用の画像生成器を作成する。
286
+
287
+ params = {'vertical_flip': True,
288
+
289
+ 'horizontal_flip': True,
290
+
291
+ 'brightness_range': [0.7, 1.0]}
292
+
293
+ # 学習用のジェネレーターを作成する。
294
+
295
+ train_datagen = image.ImageDataGenerator(
296
+
297
+ preprocessing_function=preprocess_input, **params)
298
+
299
+ train_gen = train_datagen.flow_from_directory(
300
+
301
+ train_dirpath, target_size=model.input_shape[1:3], batch_size=batch_size)
302
+
303
+
304
+
305
+ # テスト用の画像生成器を作成する。(テスト用は水増ししない)
306
+
307
+ test_datagen = image.ImageDataGenerator(preprocessing_function=preprocess_input)
308
+
309
+ # テスト用のジェネレーターを作成する。
310
+
311
+ test_gen = test_datagen.flow_from_directory(
312
+
313
+ test_dirpath, target_size=model.input_shape[1:3], batch_size=batch_size)
314
+
315
+ ```
316
+
317
+
318
+
319
+ ## 学習する。
320
+
321
+
322
+
323
+ ```python
324
+
325
+ # 学習する。
326
+
327
+ history = model.fit_generator(
328
+
329
+ train_gen,
330
+
331
+ steps_per_epoch=len(train_gen) / batch_size,
332
+
333
+ epochs=epochs,
334
+
335
+ validation_data=test_gen,
336
+
337
+ validation_steps=len(test_gen) / batch_size)
338
+
339
+ ```
340
+
341
+
342
+
343
+ ```
344
+
345
+ Found 24331 images belonging to 2 classes.
346
+
347
+ Found 8925 images belonging to 2 classes.
348
+
349
+ Epoch 1/10
350
+
351
+ 24/23 [==============================] - 10s 413ms/step - loss: 7.4179 - acc: 0.5208 - val_loss: 7.8353 - val_acc: 0.5139
352
+
353
+ Epoch 2/10
354
+
355
+ 24/23 [==============================] - 5s 188ms/step - loss: 6.2514 - acc: 0.6094 - val_loss: 4.3866 - val_acc: 0.7222
356
+
357
+ Epoch 3/10
358
+
359
+ 24/23 [==============================] - 5s 190ms/step - loss: 4.0494 - acc: 0.7435 - val_loss: 1.0163 - val_acc: 0.9340
360
+
361
+ Epoch 4/10
362
+
363
+ 24/23 [==============================] - 5s 219ms/step - loss: 3.1330 - acc: 0.7995 - val_loss: 1.2144 - val_acc: 0.9201
364
+
365
+ Epoch 5/10
366
+
367
+ 24/23 [==============================] - 5s 227ms/step - loss: 4.0351 - acc: 0.7487 - val_loss: 1.1573 - val_acc: 0.9236
368
+
369
+ Epoch 6/10
370
+
371
+ 24/23 [==============================] - 5s 215ms/step - loss: 3.3249 - acc: 0.7930 - val_loss: 1.0633 - val_acc: 0.9340
372
+
373
+ Epoch 7/10
374
+
375
+ 24/23 [==============================] - 5s 228ms/step - loss: 2.6396 - acc: 0.8346 - val_loss: 0.8395 - val_acc: 0.9479
376
+
377
+ Epoch 8/10
378
+
379
+ 24/23 [==============================] - 5s 225ms/step - loss: 2.5717 - acc: 0.8372 - val_loss: 1.1193 - val_acc: 0.9306
380
+
381
+ Epoch 9/10
382
+
383
+ 24/23 [==============================] - 5s 217ms/step - loss: 2.9105 - acc: 0.8190 - val_loss: 1.0074 - val_acc: 0.9375
384
+
385
+ Epoch 10/10
386
+
387
+ 24/23 [==============================] - 5s 216ms/step - loss: 2.5275 - acc: 0.8424 - val_loss: 1.3991 - val_acc: 0.9132
388
+
389
+ ```
390
+
391
+
392
+
393
+ ## 学習過程を可視化する。
394
+
395
+
396
+
397
+ ```
398
+
399
+ import matplotlib.pyplot as plt
400
+
401
+ fig, [ax1, ax2] = plt.subplots(1, 2, figsize=(8, 4))
402
+
403
+
404
+
405
+ epochs = np.arange(1, len(history.history['loss']) + 1)
406
+
407
+
408
+
409
+ # 各エポックの誤差の推移
410
+
411
+ ax1.set_title('loss')
412
+
413
+ ax1.plot(epochs, history.history['loss'], label='train')
414
+
415
+ ax1.plot(epochs, history.history['val_loss'], label='validation')
416
+
417
+ ax1.set_xticks(epochs)
418
+
419
+ ax1.legend()
420
+
421
+
422
+
423
+ # 各エポックの精度の推移
424
+
425
+ ax2.set_title('accuracy')
426
+
427
+ ax2.plot(epochs, history.history['acc'], label='train')
428
+
429
+ ax2.plot(epochs, history.history['val_acc'], label='validation')
430
+
431
+ ax2.set_xticks(epochs)
432
+
433
+ ax2.legend()
434
+
435
+
436
+
437
+ plt.show()
438
+
439
+ ```
440
+
441
+
442
+
443
+ ![イメージ説明](6edb4932990a76697570d01b948fda11.png)
444
+
445
+
446
+
447
+ ## テストデータを読み込む。
448
+
449
+
450
+
451
+ ```python
452
+
453
+ import glob
454
+
455
+ import os
456
+
457
+ from PIL import Image
458
+
459
+ from keras.preprocessing import image
460
+
461
+ from keras.utils import to_categorical
462
+
463
+
464
+
465
+ label_to_id = test_gen.class_indices
466
+
467
+ print(label_to_id) # {'cat': 0, 'dog': 1}
468
+
469
+
470
+
471
+ x = []
472
+
473
+ y = []
474
+
475
+ for path in glob.glob(os.path.join(test_dirpath, '*', '*.jpg')):
476
+
477
+ label = os.path.basename(os.path.dirname(path))
478
+
479
+ img = image.load_img(path, target_size=model.input_shape[1:3])
480
+
481
+ img = np.array(img)
482
+
483
+ img = preprocess_input(img)
484
+
485
+
486
+
487
+ x.append(img)
488
+
489
+ y.append(label_to_id[label])
490
+
491
+
492
+
493
+ x = np.array(x)
494
+
495
+ y = np.array(y)
496
+
497
+ print('x.shape', x.shape) # x.shape (8925, 224, 224, 3)
498
+
499
+ print('y.shape', y.shape) # y.shape (8925,)
500
+
501
+ ```
502
+
503
+
504
+
505
+ ## 学習したモデルでテストデータを推論し、精度を算出する。
506
+
507
+
508
+
509
+ ```
510
+
511
+ y_prob = model.predict(x)
512
+
513
+ y_classes = y_prob.argmax(axis=-1)
514
+
515
+
516
+
517
+ from sklearn.metrics import accuracy_score
518
+
519
+ accuracy = accuracy_score(y, y_classes)
520
+
521
+ print('accuracy: {:.2%}'.format(accuracy)) # accuracy: 92.45%
522
+
523
+ ```
524
+
525
+
526
+
527
+ 92% の精度が出ました。