なぜこんな問題に直面したのか?
現在、会社の自己啓発プロジェクトの一環として、機械学習初心者数人で、kaggleのcassava classificationのプロジェクトにトライしております。
pythonはここ一年でようやく慣れてきましたが、画像データを取り扱うのは初めてでなかなか不慣れなことが多いです。
同プロジェクトでCNNについての輪講を実施したので、使ってみようと思っていたのですが、
MemoryError
('Д')
大量の画像データなんて扱ったことないし、所詮数値データなんだからnumpyに直してしまえば全部読み込めるだろうと思っていたのですが、2万枚というレベルになるとなかなか厳しそうですよね。ということで、自分なりに考えたり調べたりした結果を共有しようと思います。
実際にはどのくらいのサイズになるのか?
ざっくり全部展開するとどのくらいになるのか計算してみます。
項目 | 値 |
---|---|
画像サイズ | 800x600 |
枚数 | 21,397枚 |
チャンネル数 | 3 |
各要素の値の範囲 | 0-255(8bit) |
$$
600\times 800\times 21397\times 3\times 1[byte] \approx 30[GB]
$$
え?さすがに重たすぎる??ダウンロードしても2GB程度なのに??
と思ったのですが、jpg画像ファイルは圧縮がかかっていたりサイズ調整がなされていることで実際のサイズよりは小さくなっているようです。それにしてもちょっと重すぎる感じがしますが、本題とは関係ないのでいったん保留。
ということで、すべての画像を数値としてメモリに保持するのは困難であるようです。
kerasの公式ドキュメントに従う
- modelクラスのメソッドを使用する(train_on_batchとtest_on_batch)
- modelクラスのメソッドを使用する(fit_generator)
ImageDataGeneratorクラスの存在に頼る
kaggleのnotebookランキングを見ているとどうもImageDataGeneratorなるものがあるようです。詳しくはこちらに。簡単に言えば、一つ一つ画像を加工して取り出してくれるものです。こんな感じで使います。引数はここに
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
featurewise_center = False,
samplewise_center = False,
featurewise_std_normalization = False,
samplewise_std_normalization = False,
zca_whitening = False,
rotation_range = 45,
width_shift_range = 0.2,
height_shift_range = 0.2,
horizontal_flip = False,
vertical_flip = False,
validation_split = 0.2
)
画像を切り取る
意外とこれをやってるnotebookがたくさんありました。切り取るサイズはまちまちでしたが、256や512など2の累乗が割と多かった気がします。しかも縦横同サイズが多いです。しかし正方形でなければいけないという決まりもないので自由にってかんじですね。(https://teratail.com/questions/200002)
精度向上のメモ
画像認識は結局、転移学習が強いらしいです。
あらかじめパラメータも設定してもらってるので、かなり楽できそうですね。
ただし、パラメータ数が莫大なので注意(68万とかあるらしい)。
今回はefficientnetというやつを使いました。
https://qiita.com/omiita/items/83643f78baabfa210ab1
使い方は簡単。kaggleにもともとインポートされてないのでnotebook上で以下の記述をする。
!pip install git+https://github.com/qubvel/efficientnet
notebook上の記述は単純でよい。またmodelはB0~B7まである。
from efficientnet.keras import EfficientNetB0
model = EfficientNetB0(include_top = False, weights = None,input_shape = (TARGET_SIZE, TARGET_SIZE, 3))
model = model.output
この後プーリング層や全結合層をくっつけてあげるといい精度を出せるみたい。
参考
https://aotamasaki.hatenablog.com/entry/2018/08/27/124349
https://developers.wonderpla.net/entry/2017/10/24/110000
https://www.haya-programming.com/entry/2017/02/09/190512
https://nonbiri-tereka.hatenablog.com/entry/2016/01/03/230429