teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

2018/10/20 12:34

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -1,20 +1,264 @@
1
- > 1. 画像読み込み
2
- > 1. 1. Train 画像データ(正例と負例) の入力
3
- > 1. 2. Test 画像データ(正例と負例)の入
1
+ > 画像を読み込む際、画像の入ったフォルダを指定して
4
- > 1. 3. Train 画像のデータ水増
2
+ データを読み込むということをたいのですが、その場合はどうすればよろしいでしょうか。
5
3
 
4
+ 以下のようにすればよいです。
5
+ 1. glob.glob() でファイル一覧を取得する。
6
- [ImageDataGenerator](https://keras.io/ja/preprocessing/image/) を使う
6
+ 2. PIL.Image.open() で画像読み込む
7
7
 
8
- > 2.データ処理;
9
- > 2.1. 2クラス分類処理行うニューラルネットを構築
8
+ # 2クラス分類を Keras でやる手順
10
- > 2.2.Trainデータを使って学習データを作成
11
- > 2.3.作成した学習データに対し、Testデータを入力し、2クラス分類を実施
12
- > 3.結果出力;
13
- > 2.3.Testデータの正例と、2.3.にて出力した結果を比較して精度の算出
14
9
 
15
- モデルの構築は [過去の質問](https://teratail.com/questions/149156) 参照
10
+ ## サンプルした使用するデータセット
16
11
 
17
- > 成果物;
18
- > 2クラス分類結果のCSVファイル
12
+ [Kaggle Cats and Dogs Dataset](https://www.microsoft.com/en-us/download/details.aspx?id=54765)
19
13
 
14
+ 解凍すると、以下のようになっている。
15
+ ```
16
+ PetImages
17
+ ├── Cat: 猫の画像が入っている
18
+ └── Dog: 犬の画像が入っている
19
+ ```
20
+
21
+ 画像を学習用とテスト用に分割する。
22
+
23
+ ```
24
+ '''
25
+ 以下のようなクラスごとにフォルダ分けされたディレクトリ構造を学習用、テスト用に分割する。
26
+
27
+ input_dirpath
28
+ ├── Cat
29
+ └── Dog
30
+
31
+
32
+
33
+ dataset
34
+ ├── test
35
+ │   ├── cat
36
+ │   └── dog
37
+ └── train
38
+ ├── cat
39
+ └── dog
40
+ '''
41
+ import glob
42
+ import os
43
+ import shutil
44
+ from PIL import Image
45
+ from sklearn.model_selection import train_test_split
46
+
47
+ # dataset/train/dog/11702.jpg
48
+
49
+ input_dirpath = 'PetImages'
50
+ output_dirpath = 'dataset'
51
+
52
+ for sub_dirpath in glob.glob(os.path.join(input_dirpath, '*')):
53
+ class_name = os.path.basename(sub_dirpath).lower()
54
+
55
+ # 出力用のディレクトリを作成する。
56
+ train_dirpath = os.path.join(output_dirpath, 'train', class_name)
57
+ test_dirpath = os.path.join(output_dirpath, 'test', class_name)
58
+ os.makedirs(train_dirpath, exist_ok=True)
59
+ os.makedirs(test_dirpath, exist_ok=True)
60
+
61
+ # サブディレクトリ配下の画像パスを取得する。
62
+ img_paths = glob.glob(os.path.join(sub_dirpath, '*.jpg'))
63
+ print('class {}: {} images found.'.format(class_name, len(img_paths)))
64
+
65
+ # 画像パスを学習用、テスト用に分割する。
66
+ train_paths, test_paths = train_test_split(img_paths, test_size=0.2)
67
+ for img_paths, to_dirpath in zip([train_paths, test_paths], [train_dirpath, test_dirpath]):
68
+ for img_path in img_paths:
69
+ to_filepath = os.path.join(to_dirpath, os.path.basename(img_path))
70
+
71
+ try:
72
+ img = Image.open(img_path)
73
+ img.verify() # 画像が壊れていないかチェック
74
+ img._getexif() # exif の壊れていないかチェック
75
+ # 問題ない画像ファイルならコピー
76
+ shutil.copy(img_path, to_filepath)
77
+ # print('{} ---> {}'.format(img_path, to_filepath))
78
+ except Exception:
79
+ # 壊れた画像ファイルはスキップ
80
+ print('Invalid image found. {}'.format(img_path))
81
+ ```
82
+
83
+ ## 学習済みの ResNet-50 でモデルを作成する。
84
+
85
+ fine-tuning でやりたいので、ImageNet で学習済みの ResNet-50 のモデルのあとに全結合層をくっつけて、モデルを作成する。
86
+
87
+ ```
88
+ import numpy as np
89
+ from keras.applications.resnet50 import ResNet50, preprocess_input, decode_predictions
90
+ from keras.layers import Dense, Flatten
91
+ from keras.models import Model
92
+ from keras.preprocessing import image
93
+
94
+ num_classes = 2
95
+
96
+ # モデルを作成する。
97
+ # ----------------------------------
98
+
99
+ base_model = ResNet50(weights='imagenet', include_top=False,
100
+ input_shape=(224, 224, 3))
101
+ # ベースモデルのあとに分類用の全結合層を追加する。
102
+ x = base_model.output
103
+ x = Flatten()(x)
104
+ x = Dense(1000, activation='relu')(x)
105
+ output = Dense(num_classes, activation='softmax')(x)
106
+ model = Model(inputs=base_model.input, outputs=output)
107
+
108
+ # fine-tuning なので追加した層以外はフリーズする。(パラメータ更新しない)
109
+ for layer in base_model.layers:
110
+ layer.trainable = False
111
+
112
+ # モデルを可視化
113
+ from keras.utils import plot_model
114
+ # plot_model(model, to_file='model.png')
115
+
116
+ # モデルをコンパイルする。
117
+ model.compile(optimizer='rmsprop', loss='categorical_crossentropy',
118
+ metrics = ['accuracy'])
119
+ ```
120
+
121
+ ## ディレクトリからデータを読み込み、水増しするジェネレーターを作成する。
122
+
123
+ 以下のディレクトリ構造を想定している。
124
+
125
+ ```
126
+ dataset
127
+ ├── test
128
+ │   ├── cat
129
+ │   └── dog
130
+ └── train
131
+ ├── cat
132
+ └── dog
133
+ ```
134
+
135
+ [ImageDataGenerator](https://keras.io/ja/preprocessing/image/) でディレクトリから画像を読み込みつつ、水増しするジェネレーターを作成する。
136
+
137
+ ```
138
+ train_dirpath = 'dataset/train'
139
+ test_dirpath = 'dataset/test'
140
+ batch_size = 32
141
+ epochs = 10
142
+
143
+ # 学習用の画像生成器を作成する。
144
+ params = {'vertical_flip': True,
145
+ 'horizontal_flip': True,
146
+ 'brightness_range': [0.7, 1.0]}
147
+ # 学習用のジェネレーターを作成する。
148
+ train_datagen = image.ImageDataGenerator(
149
+ preprocessing_function=preprocess_input, **params)
150
+ train_gen = train_datagen.flow_from_directory(
151
+ train_dirpath, target_size=model.input_shape[1:3], batch_size=batch_size)
152
+
153
+ # テスト用の画像生成器を作成する。(テスト用は水増ししない)
154
+ test_datagen = image.ImageDataGenerator(preprocessing_function=preprocess_input)
155
+ # テスト用のジェネレーターを作成する。
156
+ test_gen = test_datagen.flow_from_directory(
157
+ test_dirpath, target_size=model.input_shape[1:3], batch_size=batch_size)
158
+ ```
159
+
160
+ ## 学習する。
161
+
162
+ ```python
163
+ # 学習する。
164
+ history = model.fit_generator(
165
+ train_gen,
166
+ steps_per_epoch=len(train_gen) / batch_size,
167
+ epochs=epochs,
168
+ validation_data=test_gen,
169
+ validation_steps=len(test_gen) / batch_size)
170
+ ```
171
+
172
+ ```
173
+ Found 24331 images belonging to 2 classes.
174
+ Found 8925 images belonging to 2 classes.
175
+ Epoch 1/10
176
+ 24/23 [==============================] - 10s 413ms/step - loss: 7.4179 - acc: 0.5208 - val_loss: 7.8353 - val_acc: 0.5139
177
+ Epoch 2/10
178
+ 24/23 [==============================] - 5s 188ms/step - loss: 6.2514 - acc: 0.6094 - val_loss: 4.3866 - val_acc: 0.7222
179
+ Epoch 3/10
180
+ 24/23 [==============================] - 5s 190ms/step - loss: 4.0494 - acc: 0.7435 - val_loss: 1.0163 - val_acc: 0.9340
181
+ Epoch 4/10
182
+ 24/23 [==============================] - 5s 219ms/step - loss: 3.1330 - acc: 0.7995 - val_loss: 1.2144 - val_acc: 0.9201
183
+ Epoch 5/10
184
+ 24/23 [==============================] - 5s 227ms/step - loss: 4.0351 - acc: 0.7487 - val_loss: 1.1573 - val_acc: 0.9236
185
+ Epoch 6/10
186
+ 24/23 [==============================] - 5s 215ms/step - loss: 3.3249 - acc: 0.7930 - val_loss: 1.0633 - val_acc: 0.9340
187
+ Epoch 7/10
188
+ 24/23 [==============================] - 5s 228ms/step - loss: 2.6396 - acc: 0.8346 - val_loss: 0.8395 - val_acc: 0.9479
189
+ Epoch 8/10
190
+ 24/23 [==============================] - 5s 225ms/step - loss: 2.5717 - acc: 0.8372 - val_loss: 1.1193 - val_acc: 0.9306
191
+ Epoch 9/10
192
+ 24/23 [==============================] - 5s 217ms/step - loss: 2.9105 - acc: 0.8190 - val_loss: 1.0074 - val_acc: 0.9375
193
+ Epoch 10/10
194
+ 24/23 [==============================] - 5s 216ms/step - loss: 2.5275 - acc: 0.8424 - val_loss: 1.3991 - val_acc: 0.9132
195
+ ```
196
+
197
+ ## 学習過程を可視化する。
198
+
199
+ ```
200
+ import matplotlib.pyplot as plt
201
+ fig, [ax1, ax2] = plt.subplots(1, 2, figsize=(8, 4))
202
+
203
+ epochs = np.arange(1, len(history.history['loss']) + 1)
204
+
205
+ # 各エポックの誤差の推移
206
+ ax1.set_title('loss')
207
+ ax1.plot(epochs, history.history['loss'], label='train')
208
+ ax1.plot(epochs, history.history['val_loss'], label='validation')
209
+ ax1.set_xticks(epochs)
210
+ ax1.legend()
211
+
212
+ # 各エポックの精度の推移
213
+ ax2.set_title('accuracy')
214
+ ax2.plot(epochs, history.history['acc'], label='train')
215
+ ax2.plot(epochs, history.history['val_acc'], label='validation')
216
+ ax2.set_xticks(epochs)
217
+ ax2.legend()
218
+
219
+ plt.show()
220
+ ```
221
+
222
+ ![イメージ説明](6edb4932990a76697570d01b948fda11.png)
223
+
224
+ ## テストデータを読み込む。
225
+
226
+ ```python
227
+ import glob
228
+ import os
229
+ from PIL import Image
230
+ from keras.preprocessing import image
231
+ from keras.utils import to_categorical
232
+
233
+ label_to_id = test_gen.class_indices
234
+ print(label_to_id) # {'cat': 0, 'dog': 1}
235
+
236
+ x = []
237
+ y = []
238
+ for path in glob.glob(os.path.join(test_dirpath, '*', '*.jpg')):
239
+ label = os.path.basename(os.path.dirname(path))
240
+ img = image.load_img(path, target_size=model.input_shape[1:3])
241
+ img = np.array(img)
242
+ img = preprocess_input(img)
243
+
244
+ x.append(img)
245
+ y.append(label_to_id[label])
246
+
247
+ x = np.array(x)
248
+ y = np.array(y)
249
+ print('x.shape', x.shape) # x.shape (8925, 224, 224, 3)
250
+ print('y.shape', y.shape) # y.shape (8925,)
251
+ ```
252
+
20
- Python の CSV ジュールを使ってCSV で書きせます。
253
+ ## 学習したでテストデータ推論し精度を算出す
254
+
255
+ ```
256
+ y_prob = model.predict(x)
257
+ y_classes = y_prob.argmax(axis=-1)
258
+
259
+ from sklearn.metrics import accuracy_score
260
+ accuracy = accuracy_score(y, y_classes)
261
+ print('accuracy: {:.2%}'.format(accuracy)) # accuracy: 92.45%
262
+ ```
263
+
264
+ 92% の精度が出ました。