後藤弘茂のWeekly海外ニュース
第3世代のディープラーニングプロセッサはモデル圧縮技術が鍵
2020年7月17日 06:55
プルーニングは第3世代のディープラーニングプロセッサの重要技術
ディープラーニングプロセッサは、まだ進化の途上にあり、人類進化にたとえるなら、現在は猿人から原人に進化したばかりの段階にある。ホモサピエンスレベルへの進化には、まだワンステップ以上が必要となる。
2018年のプロセッサ学会「Hot Chips」のチュートリアルで、MIT(Massachusetts Institute of Technology)のSong Han氏(Assistant Professor, MIT EECS)は、ディープラーニングプロセッサの進化のスライドを示した。Han氏は、元スタンフォード大学でNVIDIAなどと共同で行なった「Deep Compression」の研究の中心人物だった。
Han氏のスライドで示された原人の項目の技術は「SW/HW Co-design: Compression before Acceleration」だ。つまり、ニューラルネットワークのモデル圧縮と、それに対応したハードウェアアーキテクチャが、第3世代のディープラーニングプロセッサの技術項目となっている。モデル圧縮技術は、猿人から原人への進化と同程度の重要なステップという認識だ。
ディープラーニングのモデルの圧縮にはいくつか方法がある。NVIDIAがスタンフォード大学などと共同研究したDeep Compressionでは、「プルーニング(Pruning:刈り込み)」、「量子化(Quantization)」、「ウェイトシェアリング(Weight Sharing:重み共有)」、「ハフマン符号化(Huffman Coding)」が研究されていた。
プルーニングでは重要度の低いパラメータを削除する。量子化では、たとえば32-bit浮動小数点から8-bit整数などにパラメータのビット数を下げる。ウェイトシェアリングでは、ウェイトを共有することで、ウェイトパラメータの量を減らす。プルーニングとウェイトシェアリングでパラメータの数を減らし、量子化でパラメータのビット数を減らし、パラメータの符号化でデータ圧縮を行なう。
こうした圧縮技術によって、パラメータとそのデータ量を削減し、必要なメモリ量やメモリ帯域、演算量や演算精度を下げて、消費電力やチップの規模を小さくする。それも、ディープラーニングの処理精度を落とさずに。
一連の圧縮技術のなかでもプルーニングはもっとも重要だ。それは、パラメータ数を劇的に減らすことができる可能性があるからだ。また、パラメータを減らすことで、メモリ量だけでなく演算量も減らすことができる。パラメータ数を10分の1やそれ以上に減らすと、その分、消費電力が減り性能が向上する。プロセッサ側からすると、アーキテクチャの対応だけで、性能を劇的に伸ばすことができる魅力的な技術だ。
トレーニングでスパース化してインファレンスで実行
基本的な事項を抑えておくと、ニューラルネットワークには、トレーニング(学習)とインファレンス(推論)の2つのフェイズがある。トレーニングでは大量の学習データを使ってニューラルネットワークモデルに学習をさせる。インファレンスではトレーニング済みのニューラルネットワークで認識を行なう。
たとえば、大量の動物の写真を使ったトレーニングで動物種を学習させたネットワークを作る。すると、インファレンスでは、ネコの写真を入力されると、ネコと推論する。プルーニングは、基本的にはインファレンスで効果を発揮するが、トレーニングでの最適化が必要となる。
では、この2つのフェイズの間で、プルーニングはどうやって行なうのか。まず、トレーニングフェイズで、学習済みのフル接続のネットワークを作る。このときは、まだ、デンスネットワークだ。
次に、学習済みのデンスネットワークをプルーニングして、重要度が低いウェイトやノードを削除する。そして、プルーニング済みのスパースネットワークを、さらに再トレーニングして、ネットワークを完成させる。再トレーニングを省くこともできるが、その場合は精度が低下する。
一般的には、学習済みのネットワークのウェイトパラメータのうち、絶対値が小さい値を0値にする。0値化することで、ネットワークから削除できるようにする。ウェイトの分布を見ると、ほとんどの値が0近くに分布している。しかし、絶対値の大きなウェイトしか、モデル精度に寄与しない。絶対値の小さなパラメータを0に落としてもインファレンス精度に大きな影響が出ないとされる。また、ウェイトの絶対値の総和でチャネルごとプルーニングする手法もある。
実際には0値化できるパラメータが多い
これをパラメータのマトリックスとしてビジュアル化すると、下のスライドのようになる。ウェイトパラメータのうち正の値が赤、負の値が青、プルーニングされた0値が黒で示されている。左がデンスネットワークで、パラメータ群は赤か青の値を持っている。それに対して、一定の絶対値でプルーニングを行なったのが右の2つの図で、値が小さいパラメータは0値化され黒になっている。
上のスライドで黒が大半を占めることでわかるとおり、プルーニングしたスパースネットワークは、多くの0値パラメータを含んでいる。インデックスをつけて0値のパラメータを削除することで、パラメータデータを圧縮する。圧縮したプルーニング済みのスパースネットワークは、元のデンスネットワークより大幅にサイズが小さくなる。モデルサイズが小さくなるため、インファレンスを行なうときに効率的になる。
サイズが小さくなったネットワークモデルは、より小さなメモリに収まるため、メモリ量が少なくて済み、メモリからの読み出しも少なく、メモリアクセスの消費電力が下がる。また、演算量も減るため、演算の消費電力が下がるだけでなく、性能が上がり、インファレンスのレイテンシが短くなる。トレーニングでプルーニングを行なうことで、インファレンスがアクセラレートされる仕組みだ。ちなみに、プルーニングでトレーニングもアクセラレートするというアイデアもあるが、これは、まだ研究段階だ。
プルーニングへのハードウェア対応
トレーニングでプルーニングを行なう段階では、ハードウェアの特殊な対応は必要とされていない。GPUなどの汎用のプロセッサでトレーニングして、ソフトウェア的にプルーニングでパラメータを間引くことができる。
しかし、インファレンスフェイズは異なる。プルーニングの効果をインファレンス時に引き出すには、ハードウェアの対応が望ましい。とくにプルーニングの粒度が小さくなり、値のばらつきに規則性が少なくなると、ハードウェアが対応しないかぎり、プルーニングによる圧縮の効果を十分に活かすことができない。粒度が大きい場合は、ハードウェアの対応がなくてもいい。
プルーニングのスパースネットワークへのハードウェア対応には、いくつかのステップがある。スパースにして圧縮したネットワークは、ハードウェアのサポートがない場合、メモリ上でデンスネットワークに展開してプロセッサに読み込まなければならない。
しかし、メモリレベルでスパースに対応している場合、圧縮されたスパースネットワークをプロセッサのなかに直接読み込むことができる。その場合は、モデルに必要なメモリ量と、メモリ読み込み量が削減され、電力消費と必要メモリ量が抑えられる。
場合によっては、オンチップのメモリに圧縮されたパラメータをすべて収めることも可能になる。メモリレベルだけの対応の場合は、読み込んだスパースネットワークは、プロセッサの内部で逐次に展開されて、削除されていた値は、0値としてデンスネットワークと同じように実行される。
コンピュートレベルでスパースネットワークに対応する場合は、メモリでのサポートに加えて、読み込んだスパースのパラメータ群のうち、プルーニングで0値化されたパラメータの演算がスキップされる。無駄な演算がスキップされるため、省電力制御を行なえば電力消費が抑えられる。スキップするだけなので、演算ユニットがマトリックス演算(GEMM:General Matrix Multiply)に最適化されていても、演算時のハードウェアの制御は容易だ。
演算レベルでスパースネットワークに対応する場合は、さらに進んだサポートとなる。演算スパーシティ対応では、読み込んだ圧縮されたスパースパラメータは、そのまま演算ユニットアレイで実行される。圧縮されたネットワークでは、しきい値以下のパラメータは0値化されて削除されており、パラメータ数が減っている。そのため、実行する演算ユニットアレイ側に空きができる。
そこで、圧縮されたスパースマトリックスをハードウェアで制御することで、演算ユニットアレイの空いた演算ユニットに、別なロウのパラメータの演算を割り当てる。空きユニットを効率よく使って、性能を引き上げる。演算を単純にスキップする場合と比べると、演算ユニットを無駄なく稼働させることができる。制御は複雑になるが、その分、性能と電力効率が向上する。
実際のプロセッサでのプルーニング対応
プルーニングへのハードウェア対応自体は、すでにインファレンス専用のディープラーニングプロセッサの世界には浸透している。たとえば、Armのマシンラーニング(ML)専用プロセッサIP「Arm MLプロセッサ(Machine Learning Processor)」は、プルーニングにハードウェア対応している。NVIDIAが、SoC「Xavier」に組み込んだディープラーニングアクセラレータコア「NVDLA(NVIDIA Deep Learning Accelerator)」も同様だ。また、Centaur Technologyが発表した新しいx86 SoC「CHA」に内蔵されるディープラーニングアクセラレータ「Ncore」もメモリレベルだがスパースに対応する。
インファレンスの研究チップを見ると、スパースネットワークへのハードウェア対応は、すでに一般的だ。スタンフォード大学やNVIDIAなどの「EIE(Efficient Inference Engine)」と「ESE(Efficient Speech Recognition Engine」、MIT(Massachusetts Institute of Technology)やNVIDIAなどの「SCNN」や「Eyeriss v2」、Princeton大学の「SPRING」、Michigan大学やNVIDIA、MITの「Stitch-X」、KAISTの「Centaur」、Toronto大学の「Cnvlutin」など、多数の研究が発表されている。企業ではNVIDIAが絡む研究が多い。
ただし、NVIDIAの実際の商用製品であるAmpereアーキテクチャでのプルーニング対応は、インファレンス向けに最適化したディープラーニングプロセッサでの対応とは多少異なる。一言で言えば、インファレンス向けのプロセッサの研究チップは、リソースを投入してプルーニング効率を追求する傾向が強い。それに対して、NVIDIAのAmpereはプルーニングのためのリソースを慎重に抑えて、プルーニング効率は2倍までに留める。
NVIDIAは、制御ロジックやインデクシングを複雑にすることで、汎用のプロッッサとしての、トレーニング性能やニューラルネットワーク以外の性能を削がないように気をつけている。その一方で、スパーシティへのハードウェア対応は、メモリやコンピュートレベルではなく、演算レベルのサポートへと踏み込んでおり、電力効率を高める。NVIDIAの対応は、汎用性の高いプロセッサでのプルーニング対応の今後を示すかもしれない。
重要となるプルーニングの粒度と構造
プルーニングのハードウェア対応を考える場合に重要な要素は、スパースネットワークの粒度(Granularity)と構造(Structure)だ。粒度が大きく構造に規則性があれば、ハードウェアでの対応は容易になる。また、インデクシングのオーバーヘッドも小さくなり、その分、データ圧縮の比率が高まる。粒度が非常に大きく規則的な場合は、ハードウェアのサポートがなくても、スパースネットワークによって効率が上げられる。
プルーニングで0値化するパラメータが規則性なく分布しているのが「Unstructured Sparsity(非構造化)」とか「Irregular sparsity(イレギュラー)」と呼ばれるスパースネットワークだ。それに対して、0値パラメータの分布が規則性を持つスパースネットワークを、「Structured Sparsity(構造化)」とか「Regular sparsity(レギュラー)」と呼ぶ。多くのケースでは、スパース性は非構造化となる。
粒度では、0値が細かく分布しているスパースネットワークを「Fine-Grained Sparsity(細粒度)」や「0-D」と呼ぶ。粒度の小さなFine-Grained Sparsityの場合には、規則性としては基本は非構造(Unstructured)だが、構造化(Structured)にすることも可能だ。
一方、粒度が大きい場合は基本的に規則性のあるStructured Sparsityで、粒度としては「Coarse-Grained Sparsity(粗粒度)」と総称するが、さまざまな粒度のレベルがある。0値がロウに並ぶ場合は「Vector Level Sparsity」や「1-D」と呼ばれる。
ベクタではなく、一定のブロック単位の場合は「Block Sparsity」と呼ばれる。ブロックが大きく、マトリックスのすべてのパラメータが0値となる場合は「Kernel Level Sparsity」や「2-D」と呼ばれる。さらに大きな場合は「Filter Level Sparsity」、「Channel Sparsity」、「3-D」となる。CNNでフィルタやチャネルごとプルーニングされるようなケースだ。
スパースネットワークのインデックスオーバーヘッド
粒度と規則性は、スパースな行列を、どうやって圧縮するか、どうやってインデックスをつけるか、インデックスのオーバーヘッドがどの程度で、圧縮がどれだけ効率的か、という点にも大きく関係する。
スパースネットワークの圧縮方法では「Compressed Sparse Row (CSR)」フォーマットなどが一般的だ。CSRではポインタでカラムインデックスの頭を指定して、カラムインデックスにロウのバリッドな値の位置を指定する。CSRなら、規則性のない非構造化(Unstructured)な、細粒度(Fine-Grained)のスパースマトリックスも格納できる。しかし、CSRをそのまま適用すると、インデックスのオーバーヘッドが非常に大きくなってしまう。
とくに、圧縮したニューラルネットワークの場合、パラメータを量子化していると、値自体のビット数が小さいので、インデックスのビット分のオーバーヘッドが無視できない。また、プルーニングによる圧縮の比率が小さい場合もオーバーヘッドが大きくなる。たとえば、各要素が8-bitで、50%しか圧縮できない場合は、CSRなどのフォーマットではオーバーヘッドで圧縮が相殺されてしまう。そのため、モデル圧縮では、インデックスの仕組みも重要になる。
下のGTCでのBaiduのスライドでは、一定のブロック単位の大きな粗粒度(Coarse-Grained)で、規則的な構造化(Structured)があれば、ブロックに合わせてオーバーヘッドが小さくした「Block Sparse Row (BSR)」などの圧縮フォーマットを使うことができるとしている。しかし、柔軟性を持たせて細粒度(Fine-Grained)のスパーシティのままでインデックスのオーバーヘッドを減らすためには、インデックスの持たせ方などに工夫が必要となる。これは、後述するNVIDIAのAmpereのプルーニングの重要なポイントとなっている。
プルーニングでは、ニューロンに当たるノード自体が削除されるケースがある。シナプス結合の重みをエミュレートしたウェイトの値が小さい場合に、プルーニングで0値化される。プルーニングによってシナプス結合が消えることは、ネットワーク上でのウェイトの0値化で表される。シナプスが散発的に刈り込まれる場合は、0値もマトリックス上でばらつく。
しかし、大きな範囲でネットワークの消滅も発生する。たとえば、あるニューロンから次のニューロンへのアウトプットのシナプスがすべて消滅すると、そのニューロン自体が意味を持たなくなる。すると、消えたニューロンにつながる部分のサブネットワークをごそっと削ることが可能になる。人工ニューラルネットワークでは、これは一群のノードがプルーニングで削られることを意味する。マトリックス上の一定の範囲のウェイト(重み)が、すべて0値化されることになる。すると、ブロックのスパーシティが産まれる。