TensorFlow : ZhuSuan Tutorials : ZhuSuan の基本概念 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/13/2018
* 本ページは、ZhuSuan サイトの Tutorials : Basic Concepts in ZhuSuan を翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
ZhuSuan Tutorials : ZhuSuan の基本概念
Distribution と StochasticTensor
確率分布は有向グラフィカルモデル (ベイジアン・ネットワーク) を構築するための主要コンポーネントです。ZhuSuan はそれらのための 2 つの抽象層を提供します : Distribution と StochasticTensor で、これらは初心者には少し混乱させるかもしれません。それの定義と関係をここで明確にします。
Distribution
Distribution クラスは様々な確率分布のための基底クラスで、バッチ入力をサポートし、サンプルのバッチを生成し、そして与えられた値のバッチで確率を評価します。
総ての利用可能な分布のリストはこれらのページで見つかります :
これらの分布は次のように ZhuSuan からアクセス可能です (例えば、単変量正規分布) :
>>> import zhusuan as zs >>> a = zs.distributions.Normal(mean=0., logstd=0.)
Distribution のための典型的な入力は batch_shape + input_shape のようなものです。そこでは input_shape は非バッチ入力パラメータの shape を表します ; batch_shape は幾つの独立的入力が分布に供給されるかを表します。一般に、分布は入力のためにブロードキャスティングをサポートします。
サンプルは distribution オブジェクトの sample() メソッドを呼び出すことにより生成できます。shape は ([n_samples] + )batch_shape + value_shape です。最初の追加軸は渡された n_samples が None (by default) のときに限り省略されます、その場合には一つのサンプルが生成されます。value_shape は distribution の非バッチ value shape です。単変量分布については、その value_shape は [] です。
単変量分布 (Normal) の例です :
>>> import tensorflow as tf >>> _ = tf.InteractiveSession() >>> b = zs.distributions.Normal([[-1., 1.], [0., -2.]], [0., 1.]) >>> b.batch_shape.eval() array([2, 2], dtype=int32) >>> b.value_shape.eval() array([], dtype=int32) >>> tf.shape(b.sample()).eval() array([2, 2], dtype=int32) >>> tf.shape(b.sample(1)).eval() array([1, 2, 2], dtype=int32) >>> tf.shape(b.sample(10)).eval() array([10, 2, 2], dtype=int32)
多変量分布 (OnehotCategorical) の例です :
>>> c = zs.distributions.OnehotCategorical([[0., 1., -1.], ... [2., 3., 4.]]) >>> c.batch_shape.eval() array([2], dtype=int32) >>> c.value_shape.eval() array([3], dtype=int32) >>> tf.shape(c.sample()).eval() array([2, 3], dtype=int32) >>> tf.shape(c.sample(1)).eval() array([1, 2, 3], dtype=int32) >>> tf.shape(c.sample(10)).eval() array([10, 2, 3], dtype=int32)
確率変数のバッチが単一の事象にグループ化されるケースがあり、それらの確率は一緒に計算できます。これは (0 がデフォルトの) group_ndims 引数を設定することにより達成されます。batch_shape の軸の最後の group_ndims 数は単一事象にグループ化されます。例えば、Normal(…, group_ndims=1) はその batch_shape を最後の軸を単一事象に設定します、i.e. identity 共分散行列を持つ多変量 Normal。
対数確率密度 (質量) 関数は与えられた値を distribution オブジェクトの log_prob() メソッドに渡すことにより評価できます。その場合、与えられた Tensor は shape (… + )batch_shape + value_shape にブロードキャスト可能であるべきです。返された Tensor は shape (… + )batch_shape[:-group_ndims] を持ちます。例えば :
>>> d = zs.distributions.Normal([[-1., 1.], [0., -2.]], 0., ... group_ndims=1) >>> d.log_prob(0.).eval() array([-2.83787704, -3.83787727], dtype=float32) >>> e = zs.distributions.Normal(tf.zeros([2, 1, 3]), 0., ... group_ndims=2) >>> tf.shape(e.log_prob(tf.zeros([5, 1, 1, 3]))).eval() array([5, 2], dtype=int32)
StochasticTensor
Distribution が確率分布のための基本的な機能を提供する一方で、それらで計算グラフを直接構築することは依然として手間がかかります、何故ならばそれらはベイジアン・ネットワークにおける確率ノードとしての内側の再利用性を認識しないからです : ひとたび distribution からサンプリングすれば、downroot グラフをそれを観測することを望むときに再利用する方法はありません。
この挑戦に対応するために、ZhuSuan は distributions の上に構築されたもう一つの抽象を提供します。それは StochasticTensor です。zhusuan.distributions の利用可能な総ての distributions に対して、対応する StochasticTensor があり、これは zs.Normal によりアクセスできます (例えば、単変量 Normal StochasticTensor)。それらのリストは このページ 上です。
StochasticTensor は BayesianNet コンテキストのもとでのみ構築可能です。それらのインスタンスは Tensor-like で、それは tensorflow プリミティブを使用してベイジアン・ネットワークの透過的な構築を可能にします。使用方法の例については BayesianNet セクションを見てください。
Note: StochasticTensor を望むとき zs.Normal を使用して Distribution を望むとき zs.distributions.Normal を使用します。
BayesianNet
BayesianNet クラスは ZhuSuan におけるモデル構築をベイジアン・ネットワーク (有向グラフィカルモデル) としてサポートするコンテキスト・クラスです。BayesianNet は 2 つの種類のノードを持つ DAG を表します :
- 決定論的ノード、任意の tensorflow 演算から構成されます。
- 確率ノード (= Stochastic nodes)、StochasticTensor で構築されます。
BayesianNet コンテキストを始めるためには :
import zhusuan as zs with zs.BayesianNet() as model: # build the model
ベイジアン線形回帰の例 :
\[
\begin{align}\begin{aligned}w \sim N(0, \alpha^2 I)\\y \sim N(w^Tx, \beta^2)\end{aligned}\end{align}
\]
import tensorflow as tf import zhusuan as zs def bayesian_linear_regression(x, alpha, beta): with zs.BayesianNet() as model: w = zs.Normal('w', mean=0., logstd=tf.log(alpha) y_mean = tf.reduce_sum(tf.expand_dims(w, 0) * x, 1) y = zs.Normal('y', y_mean, tf.log(beta)) return model
ネットワークの任意の確率ノードを観測するために、BayesianNet を構築するとき (name, Tensor) ペアの辞書マッピングを渡します。これは観測された値を対応する StochasticTensor に割り当てます。例えば :
def bayesian_linear_regression(observed, x, alpha, beta): with zs.BayesianNet(observed=observed) as model: w = zs.Normal('w', mean=0., logstd=tf.log(alpha) y_mean = tf.reduce_sum(tf.expand_dims(w, 0) * x, 1) y = zs.Normal('y', y_mean, tf.log(beta)) return model model = bayesian_linear_regression({'w': w_obs}, ...)
は w を観測されるものとして設定します。結果として y_mean は w のサンプルの代わりに w の観測値 (w_obs) から計算されます。上の関数を異なる観測引数で呼び出すと BayesianNet を異なる観測でインスタンス化します、これは確率的グラフィカル・モデルについて一般的な挙動です。
Note: 渡された観測は StochasticTensor と同じ型と shape を持たなければなりません。
もしこの関数で作成された tensorflow Variable があれば、それを再利用することを望むかもしれません。ZhuSuan はこれを行なう簡単な方法を提供します。関数に単にデコレータを追加できます :
@zs.reuse(scope="model") def bayesian_linear_regression(observed, x, alpha, beta): ...
詳細のためには reuse() を見てください。
コンストラクション後、BayesianNet はネットワーク上の query をサポートします :
# get samples of random variable y following generative process # in the network model.outputs('y') # because w is observed in this case, its observed value will be # returned model.outputs('w') # get local log probability values of w and y, which returns # log p(w) and log p(y|w, x) model.local_log_prob(['w', 'y']) # query many quantities at the same time model.query('w', outputs=True, local_log_prob=True)
以上