ImageNetから取得した画像でデータセットを作って、分類してみた。
同じコードで、何故かうまく行く時と、そうでない時があって原因はよくわからない。1
notebookはこちら:https://gist.github.com/juntaki/263d9c43c0509c6610bdf95a59867e99
データのダウンロード
ImageNetで検索したURLリストを適当な場所に保存したら、画像をダウンロードする。
容量が異常に小さいものや、テキストファイルは失敗しているので捨てる。
cat ../urllist | xargs wget -T1
画像読み込み
Kerasに渡すにはRGB画像なら、[3(RGB), 50(縦), 50(横)]のようにする必要がある。
Image.open()で来たものは[50,50,3]となっているため、transpose()で順序を変更している。
引数は、[0,1,2]を[2,0,1]にするという意味。
im_reading = np.array( Image.open(i).resize((50,50)))
im_reading = im_reading.transpose(2,0,1)
データセット作成
さらに、Kerasに入力するには、[サンプル、3,50,50(RGB画像)]のnp.arrayにしなければならないので、
空の配列にappendしていく形でデータセットを作成した。pythonのarrayと違って、最初に行列サイズを定義してやる必要がある。また、画像のdtypeはuint8なので、unsignedで揃えないとimshow()でうまく画像として表示できなくなる(学習だけなら支障はなさそうだが)2。
image = np.empty((0,3,50,50), dtype=np.uint8)
...
image = np.append(image, [im_reading], axis=0)
画像表示
入れ替えた順序を戻すと、表示できる。
plt.imshow( image[number].transpose(1,2,0) )
データセット分割
scikit-learnにデータセットをトレーニング用とテスト用に分割する関数がある。
データセットは順番にappendしているので前後で綺麗にわかれてしまっているが、この関数を通せばランダムにピックアップして分割してくれる。
from sklearn.cross_validation import train_test_split
data_train, data_test, labels_train, labels_test = train_test_split(image, result, test_size=0.10, random_state=10)
モデルの定義と学習
モデルの中身はコンボリューション層とMaxpoolingを適当に重ねてみたもの。
model = Sequential()
model.add(Convolution2D(96, 3, 3, border_mode="same", activation="relu" ,input_shape=(3, 50, 50) ))
model.add(Convolution2D(96, 3, 3, border_mode="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Convolution2D(96, 3, 3, border_mode="same", activation="relu"))
model.add(Convolution2D(96, 3, 3, border_mode="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Convolution2D(96, 3, 3, border_mode="same", activation="relu"))
model.add(Convolution2D(96, 3, 3, border_mode="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation("relu"))
model.add(Dense(10))
model.add(Activation("relu"))
model.add(Dense(2))
model.add(Activation("sigmoid"))
#model.summary()
model.compile(loss='binary_crossentropy', optimizer="adadelta", metrics=['accuracy'])
結果
2クラスの単純な分類だが、適当に選んだラベル付き画像を読み込んで、90%の精度を出せた。