TensorFlow : Extend : TensorFlow アーキテクチャ (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 04/01/2017
* 本ページは、TensorFlow の本家サイトの Extend – TensorFlow Architecture を翻訳した上で
適宜、補足説明したものです:
https://www.tensorflow.org/extend/architecture
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
私たちは TensorFlow をラージ・スケール分散トレーニングと推論のために設計しましたが、新しい機械学習モデルとシステムレベルの最適化の実験をサポートするに十分に柔軟でもあります。
このドキュメントはスケールと柔軟性の組み合わせを可能にするシステム・アーキテクチャについて説明します。貴方が計算グラフ、演算、そしてセッションのような TensorFlow プログラミング・コンセプトについて基本的な知識があることを仮定しています。これらのトピックへの序論については TensorFlow で始めましょう を見てください。分散 TensorFlow についての幾らかの知識もまた手助けとなります。
このドキュメントは、現在の API ではサポートされていない何某かの方法で TensorFlow を拡張することを望む開発者、TensorFlow のために最適化することを望むハードウェア技術者、スケーリングと分散で動作する機械学習システムの実装者、あるいは TensorFlow 内部を見ることを望む任意の人のためのものです。読んだ後にはコア TensorFlow コードを読んで変更するに十分なほど TensorFlow アーキテクチャを良く理解するはずです。
概要
TensorFlow ランタイムはクロスプラットフォーム・ライブラリです。Figure 1 はその概略的なアーキテクチャを図示しています。C API は異なる言語のユーザレベル・コードをコア・ランタイムから分離します。
Figure 1
このドキュメントは次の層にフォーカスします :
- クライアント :
- 計算をデータフロー・グラフとして定義する。
- session を使用してグラフ実行を初期化する。
- 分散マスター
- Session.run() への引数で定義されるように、グラフから特定のサブグラフを切り取る。
- サブグラフを異なるプロセスとデバイスで動作する複数のピースに分割する。
- ワーカー・サービスへグラフ・ピースを分散させる。
- ワーカー・サービスによるグラフ・ピース実行を初期化する。
- ワーカー・サービス (各タスクのために一つ)
- 利用可能なハードウェア (CPU, GPU, etc.) に適当なカーネル実装を使用してグラフ演算の実行をスケジュールする。
- 他のワーカーサービスへ/から演算結果を送る/受け取る。
- カーネル実装
- 個々のグラフ演算のために計算を実行する。
Figure 2 はこれらのコンポーネントの相互作用を図示しています。”/job:worker/task:0″ と “/job:ps/task:0″ は両者ともワーカーサービスのタスクです。”PS” は “パラメータ・サーバ” を表します : モデルのパラメータを保持して更新する責任を持つタスクです。他のタスクはパラメータを最適化する動作をしている時にこれらのパラメータに更新を送ります。タスク間の仕事の特定の分担は必要ではありませんが、分散トレーニングでは一般的です。
Figure 2
分散マスターとワーカー・サービスは分散 TensorFlow でのみ存在することに注意してください。TensorFlow のシングル-プロセス版は、分散マスターが行なう全てを行ないながらローカルプロセスでデバイスと通信するのみという特別な Session 実装を含みます。
次のセクションではコア TensorFlow 層をより詳細に説明してサンプル・グラフの処理を通り抜けます。
クライアント
ユーザは、計算グラフを構築するクライアント TensorFlow プログラムを書きます。このプログラムは個々の演算を直接構成することもできますし Estimators API のような便利なライブラリを使用してニューラルネットワーク層と他の高位抽象を構成することもできます。TensorFlow は複数のクライアント言語をサポートし、私たちは Python と C++ を優先してきました、何故ならば内部ユーザがこれらの言語に最も精通しているからです。特徴がより確立された時には、典型的にはそれらを C++ に移植し、その結果ユーザは全てのクライアント言語から最適化された実装にアクセスできます。トレーニング・ライブラリの多くは依然として Python-only ですが、C++ は効率的な推論をサポートします。
クライアントは session を作成します、これはグラフ定義を分散マスターに tf.GraphDef protocol buffer として送ります。クライアントがグラフのノードあるいはノード群を評価する時、その評価は分散マスターへの呼び出しのトリガーとなり計算を初期化します。
Figure 3 では、クライアントはグラフを構築します、これは重み (w) を特徴ベクトル (x) に適用し、バイアス項 (b) を加算しそして結果を変数 (s) に保存します。
Figure 3
コード
分散マスター
分散マスター :
- クライアントから要求されたノードを評価するために必要なサブグラフを得るためにグラフを切り取り、
- 関係する各デバイスのためにグラフ・ピースを得るためにグラフを分割し、そして
- 後続のステップで再利用できるようにこれらのピースをキャッシュします。
マスターはステップのための計算全体を見るので、それは共通部分式除去 (common subexpression elimination) と定数畳み込み (constant folding) のような標準的な最適化を提供します。そしてそれはタスクのセットに渡って最適化されたサブグラフの実行を調整します。
Figure 4
Figure 5 はサンプル・グラフの可能な分割を示しています。分散マスターはモデル・パラメータをグループ化します、パラメータ・サーバ上にそれらを一緒に置くためにです。
Figure 5
グラフ・エッジは分割によりカットされ、分散マスターは send と receive ノードを挿入して分散タスク間で情報を渡します (Figure 6)。
Figure 6
分散マスターはそしてグラフ・ピースを分散タスクへ送ります。
Figure 7
コード
ワーカー・サービス
各タスクのワーカー・サービスは :
- マスターからのリクエストを処理し、
- ローカル・サブグラフを含む演算のためのカーネル実行をスケジュールし、そして
- タスク間の直接通信を調整します。
大きなグラフを小さなオーバーヘッドで実行するためにワーカーサービスを最適化します。現在の実装では秒毎に何万ものサブグラフが実行可能で、迅速な、きめ細かい訓練ステップを行なうための数多くのレプリカを有効にします。ワーカー・サービスはカーネルをローカルデバイスにディスパッチして可能な時にはカーネルを並列に実行します、例えば複数の CPU コアあるいは GPU ストリームを使用することによってです。
Send と Recv 演算は送信元と送信先のデバイスタイプの各ペアのために特化します :
- ローカル CPU と GPU デバイス間の転送は cudaMemcpyAsync() API を使用して計算とデータ転送をオーバーラップさせます。
- 2つのローカル GPU 間の転送は peer-to-peer DMA を使用し、ホスト CPU 経由の高価なコピーを回避します。
タスク間の転送のためには、TensorFlow は複数プロトコルを使用し、以下を含みます :
- gRPC over TCP.
- RDMA over Converged Ethernet.
マルチ-GPU 通信のための NVIDIA’s NCCL のための予備的サポートも持ちます (tf.contrib.nccl 参照)。
Figure 8
コード
カーネル実装
ランタイムは 200 標準演算以上を含み、数学的、配列操作、制御フロー、そして状態管理演算を含みます。これらの演算の各々は様々なデバイスに最適化されたカーネル実装を持つことができます。演算カーネルの多くは Eigen::Tensor を使用して実装されています、これはマルチコア CPU と GPU のための効率的な並列コードを生成するために C++ テンプレートを使用します ; けれども、私たちは cuDNN のようなライブラリも自在に使用しそこではより効率的なカーネル実装が可能です。更にまた 量子化 も実装しました、これはモバイルデバイスと高スループットなデータセンター・アプリケーションのような環境でより高速な推論を可能にします、そして量子化された計算を高速化するために gemmlowp 低精度行列ライブラリを使用します。
サブ計算を演算の合成として表現することは難しくあるいは非効率で、ユーザは C++ で書かれた効率的な実装を提供する追加のカーネルを登録できます。例えば、ReLU と Sigmoid 活性化関数とそれらの該当する勾配のような、あるパフォーマンス・クリティカルな演算のための貴方自身の融合カーネルを登録することを推奨しています。XLA コンパイラ は自動カーネル融合の実験的な実装を持ちます。
コード
以上