Hadoop Conference Japan 2016
もともとは2月8日に開催されるHadoop Conference Japan 2016のセッションとしてこの話を応募したのですが、あえなく落選しました……(;_;) しかし、ありがたいことに復活戦のLightning Talkの投票では5位に選んでいただき、ランチタイムA会場でお話することになりました。ありがとうございます!
今回のスライドはここで公開しています。
とはいえ、5分のLTではこの内容をしっかりと伝えられる自信がないので、以下でスライド内容の詳しい解説をしたいと思います。また、2/13にGoogle東京オフィスで開かれるRejected HCJ 2016では、以下の内容をゆっくり普通のセッションとして発表する予定ですので、ご興味ある方はぜひどうぞ。
引用元
今回の元ネタはこちら。より詳しく知りたい方はこちらをごらんください。特にNIPS 2015でのJeff Deanのセッションはなかなかに踏み込んだ内容になってて、この熱い内容をわかりやすくまとめたい! という思いからこの記事を書いています。
- tensorflow.org
- TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems, Jeff Dean et al, tensorflow.org, 2015
- Large Scale Distributed Systems for Training Neural Networks, Jeff Dean and Oriol Vinyals, NIPS 2015
- Large Scale Distributed Large Networks, Jeff Dean et al, NIPS 2012
あらためて簡単に自己紹介ですが、
Googleにおいて機械学習やデータ処理プロダクトを担当するUSやUKのデベロッパーアドボケイト(エバンジェリスト)が集まるData & Analyticsというチームがあり、そのチームでTech Leadを担当しています。ここのところはTensorFlowやCloud Vision APIなどの機械学習プロダクトにフォーカスしています。
The Datacenter as a Computer
さて、TensorFlowの話に入る前に、私は必ず「The Datacenter as a Computer」の話から始めます。なぜなら、今回のメインテーマであるDistributed TensorFlowが本領を発揮するには、「データセンター内の数万台のサーバーを1台の大規模分散計算機として扱うためのさまざまな技術」が欠かせないからです。
Googleクラウドが他のクラウドベンダーと大きく異なる点は、このThe Datacenter as a Computerの考えが、データセンター建屋からサーバーハードウェア(自社製)、ネットワーク、そしてデータベースやファイルシステム、ミドルウェアのあらゆる部分に浸透しているところです。
おそらくこれからしばらくの間は、Googleは機械学習やディープラーニング分野でトップクラスのサービスを提供し続けられると思います。それはもちろん、Googleが抱えるきわめて優秀なソフトウェアエンジニアや研究者の能力に依るところが大きいのですが、もうひとつの理由は、彼らが書いたアルゴリズムを数百台、数千台という規模で大規模並列にスケールアウト実行できるインフラの存在にあります。
とりわけ、The Datacenter as a Computerの根幹を支えるのが、ネットワークです。
Googleがハードウェアから開発しているJupiterネットワークは、10GbEポートを10万ポート収容可能で、合計1.2 Pbpsのトラフィックをさばけます。Googleは世界最大規模のネットワークファブリックを開発するネットワークベンダーでもあるのです(一切外販していませんが:)。
で、残念ながらあまり詳細は書けませんが、数千台規模のサーバをあたかも1台の並列計算機のように使う上では、このJupiterはきわめて重要な役割を果たしています。
例えば、富士通の「京」、東工大のTSUBAMEのような近年のスーパーコンピュータのキモとなる部分は、多数の計算ノード間をむすぶ低遅延・高帯域のネットワークにありますが、おおざっぱに言えば、JupiterはGoogleデータセンターの数千台のサーバーをつないでスパコンのような使い方をするために十分な能力を提供します。その巨大なスパコンのようなものを使って大規模にスケールアウトする機械学習やビッグデータ処理を行えるのが、Googleのデータセンターです。
Google Brain
さて、肝心の機械学習の話に入ります。
Google Brainは、GoogleのシニアフェローであるJeff Dean(MapReduceやBigtableの生みの親。Google随一の分散系の研究者)が2011にスタートしたプロジェクトです。大規模なデータセットと計算機リソースを投入したディープラーニング技術の開発を目標としています。
とにかく大量の行列演算
ここではニューラルネットやディープラーニングの詳細については立ち入りません。丸山先生が最近まとめられたニューラル・ネットワーク+TensorFlow入門講座には、脳のニューロンの動きに始まり、それを行列演算で模倣する手法、そしてTensorFlowで記述するところまでが丁寧に解説されていますので、興味のある方はそちらをごらんください。
ニューラルネットの中身はさておき、システム屋的観点からその動作をおおざっぱに見てみますと、
例えば、ネコ画像のビットマップデータを入口となるベクトル(以下の図ではx)に入れておき、その後で数段〜数10段の行列演算を繰り返すと、出口となるベクトル(以下の図ではy)において、ネコに対応するいずれかの要素が0.98のような1に近い値になり、イヌやクルマに対応する要素は0に近くなります。
ニューラルネットは、そうした結果が得られるように機械が自分で学習する技術です。たくさんの学習データを入れながら、それに掛け合わせる重みの行列(上図のW)や加算するバイアス(上図のb)の値を上げ下げしてみて、いい感じに望みの結果が得られる方向に自動調整していく仕組みです。
ここでひとつだけ強調しておきたいのは、ニューラルネットやディープラーニングって結局は「とにかく大量の行列演算に帰結する」という点です。つまり、高校でも習ったベクトルや行列の積や和、あれをひたすら大量に繰り返します。
以下はGoogle Brainチームが2015年に公表したInceptionと呼ばれるディープラーニングのネットワークですが、
これもやはり、入り口に画像を入れると、出口側のベクトルの要素のどれかが高い値となって、認識結果が得られます。全体では40層程度のディープネットとなっています。なぜこのような深いネットワークを使うと従来手法よりも格段に高い精度の画像認識や音声認識を実現できるのか? という解説は専門書籍等にまかせるとして、やってることはひたすら行列演算です。
4年前から大規模サービスで本番投入
そしてGoogleは、このGoogle Brainチームの成果を4年ほど前から本番サービスに投入してきました。例えば、Google検索のランキング、Googleフォトの画像分類、Androidの音声認識、さらにはOCRや自然言語処理など。
すでにGoogle社内の20を超えるプロジェクトで利用されており、以下の図のようにその数は急増しています。
つまりGoogleにおいては、ディープラーニングはすでに「研究開発中のこれからの技術」ではなく「安定運用期に入り成熟した技術」です。数千万人・数億人のユーザーを抱えるサービスにおいて、そのデータセットを用いた大規模なモデル学習を継続的に行い、それで得たパラメータで画像認識や音声認識のサービスをスケーラブルかつ安定的に提供できる。そのための基盤とノウハウが整っています。
TensorFlowとは
このGoogle Brainチームの成果をオープンソースソフトウェアとして一般公開したものが、TensorFlowです。
(以下、TensorFlowについてすでにご存知の方は、次のDistributed TensorFlowセクションまで飛ばしても構いません)
Google Brainチームはこれまで、第一世代であるDistBeliefと呼ばれるフレームワークを用いて、上述したさまざまなディープラーニング技術の開発を進めてきました。そこで得た知見をもとに、とくに以下の点を改善すべく、第二世代としてTensorFlowが開発されました。
- DistBeliefは社内環境に依存しすぎていてオープンソース公開できない。MapReduceの時のように、ペーパーしか外に出せないのではオープンソースコミュニティに貢献できない
- Android等のモバイル環境でも使えるポータブルなフレームワークにしたい(とくに学習後の実行時)
TensorFlowは、「Google社内でもはや旧世代となった使い古し技術を外に出した」たぐいのものではありません。現在、社内で機械学習やディープラーニングに携わるたくさんのソフトウェアエンジニアが実際にTensorFlowを使って開発を進めています。ですから、例えばビジュアライズツールやデバッグ環境の使い勝手は、Googleエンジニア自ら実開発に耐えられる品質にがしがし直されていき、それがそのまま外部のデベロッパーとも共有されます。
一方で、TensorFlowはGoogleが持ちうるものをすべてさらけ出しているわけではありません。以下に説明するように、TensorFlowは「数値演算フレームワーク」に過ぎません。それを使ってどのような機械学習やディープラーニングのアルゴリズムを実装するかは、開発者まかせです。TensorFlowをダウンロードするとGoogleフォトで現在使われている画像認識ライブラリがそのままついてくる……わけではないのです。ただし、基本的な画像認識等のライブラリは豊富に提供されており、開発者はそれをベースに自分の用途にあったアルゴリズムを記述できます。
また、現在(2月8日)時点で一般公開されているTensorFlowは、1台のサーバーでしか動作しません。Google社内で実際に使われているような、複数台のサーバーに分散する使い方にはまだ対応していません。これについて詳しくは後述します。
TensorFlow = 多次元配列のデータフロー演算のフレームワーク
TensorFlowは英語読みでは「テンサーフロー」ですが、私は「テンソルフロー」と日本語読みしています。なぜなら、TensorFlowのTensorは数学で言う「テンソル」のことだからです。
高校の数学でベクトルや行列を習いますが、テンソルはあれの仲間です。
- ベクトル:1次元配列
- 行列:2次元配列
- テンソル:多次元配列
つまりTensorFlowって、「多次元配列を扱うデータフロー演算のフレームワーク」という意味です。じつはディープラーニングや機械学習に特化しているわけではなく、大量の数値演算や行列演算が必要なさまざまなHPC (High Performance Computing)用途に利用できます。例えば金融分野のモンテカルロ・シミュレーション等も、TensorFlowに乗るんじゃないかなーと期待しています。
TensorFlowでニューラルネットを書く
で、ディープラーニングやニューラルネットでは、
- 入力データに重み値の行列を掛ける
- さらにバイアス値を足す
- ReLUやソフトマックス等の活性化関数に通す
- 交差エントロピーを使いどれだけ間違ってるかを計算する
といった演算フロー(TensorFlowではグラフと呼ばれます)がしょっちゅう出てきます。
この計算をしたあと、間違いの量を減らすために、勾配降下法などのアルゴリズムを使って重みやバイアスの値(パラメータ)をいい感じに最適化していきます。
この最適化について、私はいつも「後輩君が先輩に繰り返し怒られながら、いいさじ加減での仕事のやり方を体得していく」って例えを思い浮かべます。コンピューターなのに、if-then-elseで書いたゼロイチの論理じゃなくて、たくさんの現実をふまえた上で「いいさじ加減」を自ら導き出すってのが、最近の機械学習やディープラーニングのパラダイムシフトと思います(ある意味、まったく異なるパラダイムのコンピューター言語と捉えることもできるんじゃないでしょうか)。
ともあれ。TensorFlowを使うと、こうした基本的なニューラルネットのグラフを、PythonまたはC++で以下のように記述できます。
ここで、
y = tf.nn.softmax(tf.matmul(x, W) + b)
という部分が、上述したグラフによるネットワークの定義。そのあとの、
step = tf.train.GradientDescentOptimizer(0.01).minimize(xent)
という部分が、「このネットワークに対して、勾配降下法を使って間違いを最小化するようパラメータを調整して」とTensorFlowに指示するコードです。
つづいて、ここまでのグラフ定義を使い、実際に学習を行います。
上記コードでは、TensorFlow実行環境とのセッションを開始し、100個の学習データを用いたモデル学習(ミニバッチ)を1000回繰り返しています。
こんな簡単なPythonコードで記述した1段のニューラルネットでも、手書き数字を91%程度の精度で認識できます。段数を増やせば、さらに精度を高められます。
今のディープラーニングは「たくさん試したもん勝ち」
このように、勾配降下法やら自動微分やら、数学的なむつかしいところはTensorFlowの中にカプセル化されてるので、私のように数学苦手人間でも見よう見まねでディープラーニングを試せてしまいます。
さらに言うと、現在のディープラーニングの面白いところは、その道の専門家にとっても意外に「行き当たりばったり」な方法で成果を出しているらしい、というところです。例えば、「ネットワークの段数は何段が最適なのか。ネットワーク設計の理論化は可能か」、「後段の隠れ層の個々の数値にはどのような意味(セマンティクス)があるのか」等々は、専門家の方でもよく分かってないようです。中で何が起きているのか不明な点も多いけど、とにかくいろいろなネットワークを設計してみては成果が出るか試してみる、を繰り返している。
また、画像認識や音声認識はがんがん研究されて成果が公開もされていますが、ちょっとそこから外れて、例えば「サーバーの大量のログから何らかのシグナルを抽出したい」とか「さまざまな属性をもとに広告のクリック率を最適化したい」といった手元への応用となると、確立された手法はちまたには出回っていません。そこで素人であっても、ともかく手持ちのデータでゆるふわに試してみると、何らかの面白い結果が出たり(出なかったり)すると期待されます。TensorFlowはそうしたアドホックな使い方ができるライブラリになっています。
TensorFlowを動かす
上述したTensorFlowのコードは、TensorFlowの実行環境上で実行できます。TensorFlowの使い方は、おおまかには「学習」と「実行」の2つのフェーズに分かれており、時間がかかるのは「学習」です。後輩君が先輩に怒られながら仕事を徐々に覚えていく、みたいなものですから、あっという間には終わりません。一方で、「実行(例えば画像を見せて認識結果を得る、など)」の方は計算量も少なく、結果はすぐに出てきます。
まず「学習」ですが、TensorFlowでは、以下の2種類の方法で学習を行えます。
- 1台のマシン上のCPUやGPUで学習
- 複数台のマシン上のCPUやGPUで学習
しかし先に述べたように、現時点で公開されているTensorFlowは、前者しかサポートしていません。
ニューラルネットは行列演算が主体なので、GPUを搭載したマシンであればCPUに比べてケタ違いに速い性能が得られますが、それでも1台のマシンのみを使った学習は、長い時間を要します。対象となるデータセットの量やアルゴリズムによっても大きく変化しますが、「GPU搭載マシンを数日回し続けた」「1か月ぶんまわした」という声をよく聞きます。これはTensorFlowを使っても、CaffeやTheano、Chainerといった他のディープラーニングのツールを使っても、大差はありません。TensorFlowはむしろ若干遅い部類に入ります。
では複数台のマシンを使えばいいだろう――という話になりますが、それについては次のセクションで。
つづいて「実行」ですが、こちらは学習で得られたパラメータに入力データを一回掛け合わせるだけなので、計算量は比較的小さく、さくっと出力が得られます。また、パラメータ自体は数10MB程度に収まるケースが多いので、モバイルデバイスに収めることも難しくありません。
TensorFlowの特長のひとつは、この学習から実行までをひとつのフレームワークでまかなえる点です。
実際に、TensorFlowのサンプルコードにはAndroidアプリの例も含まれています。例えば、クラウド環境のGPUサーバで学習したのち、パラメータをそのままAndroidアプリ上のTensorFlowに読み込んで実行に用いる、といった開発が簡単に行えます。
Distributed TensorFlow
さて、やっと本題のDistributed TensorFlowの話です。
先程も触れたように、いまディープラーニング開発を進めている方の多くは、1台のマシンにGPUを何枚か挿して、数時間〜数日をかけてがんばって学習している、という方法をとっています。
でも、そのやり方って実開発や実運用に使えるのでしょうか? 正直、きびしいでしょう。
そこで当然、GPUマシンを複数台使って、ディープラーニングの学習をスケールアウトさせよう、という試みが始まっています。例えばマイクロソフトは、つい最近以下のベンチマークを公開しました。
ここでは、マイクロソフトのディープラーニングツールCNTKを使って、4個のGPUを搭載したサーバを2台(合計でGPUが8個)用いた学習の結果が示されています。TensorFlow、圧倒的に負けてる……。
分散学習に求められる低遅延ネットワーク
多数のGPUマシンで数値演算のためのクラスタを組むのは、単純に「クラウドのGPUインスタンスをいくつか借りてTCP/IPで通信させればよい」というものではありません。なぜならGPUは、CPUやメモリとの間で数十〜数百nsの時間でデータのやり取りをしており、それでも遅いと言われる位です。そんなデータのやりとりを、数百usかかる(つまり1000倍遅い)TCP/IPネットワーク経由で行っても、スケールアウトしません。
そこで、クルマ向けの歩行者認識を研究されているデンソーIT Labさんでは、東工大のスーパーコンピュータTSUBAME2を借り、96個のGPUを使って分散学習をさせています。これにより、数十倍速くなったと報告されており、「これからは分散学習の時代だ」と主張されています。スパコンでディープラーニング、かっこよすぎます。
また、さくらインターネットさんは1月26日に、ディープラーニング分野で国内きっての実力を誇るPreferred Networksさんと共同で、ディープラーニングの並列学習のためのGPUクラスタによる「高火力コンピューティング」への取り組みを開始することを発表されました。今年夏ごろには稼働の予定だそうです。この高火力コンピューティングでも、スパコン構築によく用いられる低遅延のネットワーク技術であるInfiniBandを用いてクラスタが構築される予定です。
というように、ディープラーニング界隈では学習の分散化とそのための低遅延ネットワークの構築が実開発投入の最大の課題として認識されており、各社による競争の火ぶたが切って落とされています。
一方そのころGoogleは……。
すでに数百台規模のGPUにスケールアウト可能な分散学習を実開発に投入して何年かが経過しております。Google検索のランキングアルゴリズムに用いられるRankBrain事例では、TensorFlowを500台で動かして300倍の高速化を達成。Inceptionモデルによる画像認識も、50個のGPUで40倍の高速化が実現しています。このあいだ来日していたMike Schusterも言っていたように、Googleのデータセンターでは大規模な分散学習のために数千個規模でGPUが導入済みです。
いずれも、これからやりますよ、やってみたい、って言う研究事例ではなくて、すでに皆さんが毎日使っているGoogle検索やGoogleフォトに投入済みの実開発事例です。
そして、この規模の分散学習の安定稼働を実現できているのは、冒頭で紹介したJupiterネットワークの存在に依るところがきわめて大きいです。これについては後述します。
TensorFlowの真価は分散学習にあり
これらのGoogle社内事例では、数百のGPUへのスケールアウトに対応したDisributed TensorFlowが利用されています。TensorFlowの真価は、この分散学習の能力にあります。TensorFlowのペーパーを読んだ方ならお分かりかと思いますが、このペーパーではディープラーニングのアルゴリズムについてはほとんど論じられておらず、大半が「いかにして計算を分散させるか」という話になっています。
TensorFlowで記述したアルゴリズムは、上図左のように1台のマシン上で学習に利用できるだけでなく、コードをほとんど変えることなく大規模GPUクラスタでの分散学習にも利用できます(上図右)。ちょうどMapReduceと同じように、開発者は分散システムの面倒な部分についてあまり意識する必要はありません。
以下のような分散処理の詳細はDistributed TensorFlowの実行環境にお任せできます。
- 計算処理を個々のCPUやGPUに適切にスケジューリング
- 通信処理(ローカルのGPU間のデータ共有、リモートのCPU間のRPC、リモートのGPU間のRDMAなど)
- 通信時のデータ精度の最適化(32, 16, 8ビットの相互変換)
- 分散にともなう通信コストの推測と計測、それによるスケジューリングの最適化
- 障害時の再計算
よってTensorFlowを使う開発者は、分散環境の詳細のことを意識せずに「おまかせ」で使えます。加えて、「この部分は特定のGPUにピン止めして計算させたい」といったヒント(Device Constraints)を指定して、よりよい最適化が可能です。
モデル並列とデータ並列
さて、大規模なディープラーニングを複数台のマシンに分散させる方法としては、「モデル並列」と「データ並列」の2種類があります。
- モデル並列:パラメータを複数サーバに分割。学習データは共有する
- データ並列:学習データを複数サーバに分割。パラメータは共有する
これらのうち、Googleではおもにデータ並列が用いられています。画像認識のように数字がきちっと詰まっている密な行列の場合、通常は50ノードを用いたデータ並列によって10〜40倍の高速化が可能。自然言語処理のようにまばらな(スパース)行列の場合は、パラメータの並列性が高くなるため、1000を超えるノードに並列化も可能です。
また、データ並列でパラメータを共有する場合、パラメータサーバにおけるパラメータの更新を同期で行う(ロックする)か非同期で行う(ロックしない)かの選択が可能です。この2つの手法にはトレードオフがあって、
- 同期式:勾配降下法によるパラメータの最適化効率が高い
- 非同期式:ノード障害や遅延による学習の詰まりを避けられる
といったそれぞれの特性があります。
例えば以下のグラフは、同期式のデータ並列によるInceptionモデルの高速化の実例です。
ここでは、10ノードの場合で80時間かかる画像認識の学習が、50ノードでは20時間で済んでいることが分かります。つまり、およそ4倍の高速化です。
The Datacenter as a Computerふたたび
ここまで見てきたとおり、
- これからのディープラーニングの実用化競争では、分散学習がカギを握る
- 分散学習では、Googleの過去事例を見ると、データ並列が主流となりそう
という流れが理解できたかと思います。
ここで、システム屋的には「データ並列のパラメータサーバって、数百台のGPUマシンとの間で同期でデータを共有するって、かなりきびしくね?」と思われる方もいるでしょう。この部分で数百us単位の遅延やCPUネックが発生していると、データ並列はあまりスケールアウトしないことは容易に想像できます。
あまり多くは語れませんが、この部分こそが、The Datacenter as a Computerの思想と、それを支えるJupiterネットワークが本領を発揮するところです。データセンター内のたくさんの数のサーバを、あたかも1台の計算機のように使えてしまう仕組み。これがあるからこそ、大規模なデータ並列におけるパラメータサーバに集中する読み書きも、高IOPS・低遅延でさばけます。
じつはGoogle BigQueryのような、数十億行のビッグデータを数十秒で集計したりシャッフルできてしまう謎い技術も、Jupiterネットワークのおかげと言えます。つまり、TensorFlowという単体技術の性能だけではなく、Googleクラウドそのもののすごさが、BigQueryやディープラーニングのような氷山の一角として現れているのです。
Distributed TensorFlow公開のお知らせ
このDistributed TensorFlowですが、近々オープンソース公開される予定です。
また個人的には、今回紹介したGoogle社内における分散学習の環境を、より多くの外部の開発者の皆さんにもお使いいただけるような日が来るといいなと期待しています。
とりあえずは、現在のTensorFlowをお試しして、ここで紹介したようなTensorFlowの使いやすさをぜひ体感してみてください。
Disclaimer この記事は個人的なものです。ここで述べられていることは私の個人的な意見に基づくものであり、私の雇用者には関係はありません。