Google Cloud Storage に画像データを置くときは TFRecord を使った方が良さそうという教訓
これは TensorFlow Advent Calendar 2017 の 1 日目の記事です。
もちろん主張したいことはタイトルの通りです。
順を追って、かつドラマチックに説明していきましょう。
TFRecord って何?
TensorFlow 用のデータフォーマットです。 詳しくはこのあたりを見ると良いと思います。
今回重要なポイントは複数の画像ファイルを 1 つの TFRecord に詰め込むことが可能という点です。
TFRecord を使うデメリット
実は僕は TFRecord 別に使わなくても良いんじゃね派でした。 なので、まずはデメリットから挙げておきましょう。
- バイナリファイルなので人間が目で見てデータを確認できない
- 何かデータに手を加えたくなったときに、ごっそり作り直しになるので大変面倒臭い
僕は両方とも結構重大な問題だと思っていたのですが、それでも TFRecord を使おうと思うような事件が起こったのです。
今まで画像データをどう扱っていたか
画像を適当なストレージ(僕は Google Cloud Storage を使っていました)に置いて、以下のような CSV ファイルをセットで作成していました。
image,label gs://hoge/1.jpg,0 gs://hoge/2.jpg,1 gs://hoge/3.jpg,1 gs://hoge/1.jpg,0 ...
この CSV ファイルを逐次的に読み込んで、さらに書かれている画像とラベルも逐次的に読み込んでキューに入れて...という処理を学習の裏で複数スレッドで回します。
こうすることで学習に使う画像データが大量にあってもメモリに載せずに処理できますし、学習を走らせるスレッドはキューからデータを取り出していけば I/O の処理を待つ必要もなくなります。
事件
ちょっと大きめのデータで回してやろうと思って、 60 GB 分くらいの jpg を Cloud Storage にコピーしていたときのことでした。
何気なく Cloud Storage の課金表を見て、コピーはクラス A のオペレーションで課金対象であることに気付きます。
「えーっと、今 Regional のバケットに 2000 万枚くらいの画像をコピーしようとしてるから、 0.05$ x 2000 で 100$...」
え!?この処理完了したら 100$ 掛かるの!?
慌てて処理を中断しました。
コピーは 1 回きりなのでまだしも、学習をするときに読み込みの処理があるので 1 epoch ごとに結構なお金が持っていかれる計算になります。
このあたりの課金は普通に使っていたらそんなに意識しなくても良いかもしれませんが、機械学習などで大量のデータを扱うときにはきちんと計算をした方が良いでしょう。
まあ 2000 万個のファイルをコピーしようとした方が悪いと言われたらぐうの音も出ません。
どうすれば良いのか
TFRecord の出番です。
TFRecord ならば複数の画像ファイルを 1 つのファイルにまとめることができます。
こうして僕は画像ファイルはバラで扱うのではなく TFRecord で扱うことを夜空に誓ったのでした。
その他 TFRecord の方が良さそうな場面
単純に読み込みが速くなるので、データをキューに入れていく処理が勾配の計算などに追いついていない場合は TFRecord の方が良いと思います。
このあたりはちゃんと検証していないので、実際に TFRecord を使わないとデータ読み込みが追いつかなかったというケースを持っている人がいたら教えてください。
つまり結論は
- Cloud Storage を使う場合はデータのファイル数を程々で抑えた方が課金の面で良い
- なので大量の画像ファイルをそのまま扱うのは危険で、TFRecord に複数ファイル詰めるようにした方が良さそう
ということです。
ただ、データの読み込み周りは情報が少なくて何がベストプラクティスなのかよくわからないので、詳しい人がいたら教えて頂けると嬉しいです。
余談
最初は某記事に敬意を表してタイトルを
Google Cloud Storage で危うく 10 万円くらい溶かしそうになった人の顔
とする予定だったのですが、さすがに Google に怒られる気がしたのでやめておきました。