今回はDeep Learningなどを用いた解析で、メモリに乗らないデータを扱う際にどのようにすればよいかを紹介します。
方法だけ知りたい人は、「はじめに」は読み飛ばしてください。
みんなのディープラーニング講座 ゼロからChainerとPythonで学ぶ深層学習の基礎
この記事は、少ないデータでいかにして精度を上げるかについて述べたものではありません。
分かりやすさのために、PCのDRAMを「メモリ」、GPUのVRAMを「GPUメモリ」としています。また、学習データ全体を「学習データセット」、1つの学習データを「学習データ」としています。
はじめに
メモリに載らないことによる学習への影響
Deep Learningはその性質上、大量のデータを用いて学習を行っています。学習データセットの容量が何百GBとなることもあります。そのため、128GBのメモリを用意したとしても、すべてのデータを読み出せないということもあります。
Deep Learningを扱っているとこの「データセットがメモリに載りきらない」ということはしばしばあります。私の経験上、以下の2つの事がよく発生しました。
- モデルがGPUメモリに載りきらない
- 学習データセットがメモリに載りきらない
「モデルがGPUに載りきらない」については、ミニバッチという手法を用いればその問題は多くの場合解決することが出来ます。
問題は学習データセットがメモリに載りきらないということです。
想定した学習ができなくなる
学習データセットがメモリに乗らなくても学習を無理矢理行わせることはできます。
それは、学習データセットを2つ(またはそれ以上)に分割し、1エポックの中で1つ目の学習データセットでの学習が終わったら、2つの目のデータセットを読みだして学習の続きをするという方法です。
しかしその方法を用いると、常に1つ目のデータセットは同じデータセット群でミニバッチがつくられるので2つ目のデータセットと同時に学習されることはありません。その為、学習データセットからランダムにミニバッチをつくっているとは言えず、学習時の偏りが発生しているかもしれません。
多くのモデルを回せなくなる
そして、学習データセットの容量が大きすぎることによる問題はもう一つあります。
それは、GPUメモリでは2つ分のモデルを載せる余裕があるのに、学習データセット容量が大きいためにメモリに2つ分の学習データセットを読み込めず、同時に2つのモデルを回せないということです。
この問題は、学習に時間がかかるDeep Learningには死活問題です。同時に2つ回すことが出来れば、倍の数のモデルを検討することができ、より良い成果を出せる可能性が上がるのです。
筆者が経験した問題
私も学生時代の研究で数十個のセンサから取得した波形を学習データとして、CNNを用いて、分類問題を扱っていました。精度を上げるためにデータ増強を行っていたのですが、64GBのメモリに学習データセットが載りきらないということが度々ありました。
精度を上げるためにデータ増強を行うとよくこのような問題にぶつかります。ちなみにDeep Learningにおけるデータ増強については別途記事を書く予定です。
前置きが長くなりましたが、次の章から私がDeep Learingで学習データがメモリ容量を超えた時にどのように対処したかを説明します。
メモリ容量を超えるデータを扱う方法
データを個別に分割する
「データを個別に分割」というのは単純に学習データセットとして1つのファイルにするのではなく、学習データごとに分割して保存するという方法です。
この方法は私が実際に用いた方法です。そして、画像データを扱うときによく用いられているような気がします。
学習データを個別に分割して保存し、epoch毎にそれぞれ読み込むことでメモリ容量を超えないように調整することが出来ます。
私はさらに、全ての学習データのファイル名だけが格納されたデータ(以下ファイル名データとします)を作成して、それを用いて、ミニバッチごとにどのデータを読み込むかを管理していました。
また、ファイル名データを用いることで学習データや検証データ、テストデータを分けるのも簡単にでき、モデルが回るかテストのため少量のデータを読み込むということもできます。
この「学習データセットをデータ毎に保存する」、「ファイル名データで読み込みを管理する」という方法を用いることのメリット・デメリットを以下にまとめました。
この方法を扱うことで、どんな容量のデータでも簡単に扱うことが出来ます。しかし、デメリットを考えるとDeep Learning専用のパソコン(私は「GPUマシン」と呼んでいます)を用意したほうが安定して運用できると思います。
実際、私が所属していた研究室はGTX1080tiを3つ載せたGPUマシンで解析を行っていました(私が作った)。このGPUマシンの作り方も記事にします。
データのbit数を下げる
これはデータに使用しているbit数を減らすことで、全体の容量を減らす方法です。
この方法は一番簡単なのですが、データの種類によってはbit数を下げることができなかったり、状況によっては学習の精度が低くなってしまうことがあるので気をつけてください。ここではpythonを用いたDeep Learningを想定しています。
pythonの場合、浮遊点少数(float型)は倍精度のため64bitになります。しかし、Deep Learningの精度において値を64bitまで扱う必要はなく、32bitないし16bitでもあまり精度が変わらないといわれています。
つまり、データの変数型を最大1/4に出来るということはデータ量も1/4に出来るということです。非常に簡単で効果的な方法です。
pythonの機械学習ライブラリであるTensorflowには16bit、32bitのfloat型やint型変数がサポートしているので、自分の環境に合ったbit数を選ぶといいと思います。
しかし、扱うデータの性質によっては問題が発生しかねないので、安易に16bitまで落とすのは気を付けたほうがいいと思います。
正直どちらかというと、pythonなどでは変数の型を意識しなくてよい分、無駄に変数のbit数が多くなって容量が増えてしまう場合があるので気を付けましょうということです。
バイナリデータ
データをバイナリ形式にすることで、データを選択的に途中まで読み込んで使用するという方法があります。
基本的にデータを読み込む際は始めから最後まで読み込む必要があると思いますが、バイナリ形式で保存されたデータは指定した場所から一部分だけ読み込むことが出来ます。
つまり、必要な分だけ読み込むことができるので、最小でepoch毎に読むということが出来ます。
しかし、完全にランダムな場所から読み込みたい場合、容量の大きなデータセットから1つ1つデータを読みだすことになるので、別々に学習データを保存したものを読み込みよりも遅くなることがあるので注意が必要です。
そもそも、メモリサイズを超えたデータを保存することはできないので、学習データセットがメモリを超えてしまう場合は対応できません(バイナリ形式なら途中まで保存して、追加書き込みで対応できる可能性も…検証はしていません)。
最後に
以上、メモリに(学習)データが載りきらない時の対処法について紹介しました。
今回は手法についての解説でしたが、筆者が研究で実際に使っていたpythonで作成したプログラムとその使い方を記事にする予定です(正直、このDeep Learning周りの内容を記事にしたくてブログを開設しました)。
どれも別段方難しいプログラムではないのですが、Deep Learningはもはや専門家だけが扱うものではありません。パッケージ化され、少しかじれば誰でもできるようになってきています。そのため、プログラミングやアルゴリズムを考えるのに慣れていない人を基準に記事をかくことは大切だと個人的には思っています。
正直、Deep Learningにおいて時間がかかって、面倒くさいのはデータ整形の部分なので、この記事やブログが少しでも役に立てばと思います。
逆に私自身もDeep Learningを扱ってたとはいえ、Deep Learning自体を研究していたわけではないのでこの件でもっといい方法があれば、その情報を頂けると幸いです。
コメント