Independentクラスを使いこなす!多変量確率分布の表現とサンプル生成


torch.distributions.independent.Independent は、PyTorchの "Probability Distributions" モジュールにおけるクラスで、複数の独立した確率分布を表現するためのものです。

このクラスは、以下の2つの役割を果たします。

  1. バッチ次元をイベント次元として再解釈: 1つの確率分布を複数回複製し、それぞれを独立した確率変数として扱います。
  2. パラメータベクトルの次元を拡張: 複数の確率分布に対応するパラメータを保持します。

利点

Independent を使用することで、以下の利点が得られます。

  • 計算効率: 独立した確率分布を個別に処理するよりも効率的に計算できます。
  • 柔軟性: 異なる種類の確率分布を組み合わせることができます。
  • 多次元確率分布を簡単に表現: 複数の独立した確率変数からなる多次元確率分布を、1つの確率分布クラスで表現できます。

使用方法

Independent クラスは以下の引数を受け取ります。

  • event_dim: イベント次元を指定する整数。デフォルトは1です。
  • base_distribution: 複製する基となる確率分布クラス

具体的な使用方法は以下の通りです。

import torch
from torch.distributions import Independent, Normal

# 単変量正規分布を2回複製
base_distribution = Normal(torch.tensor([0.0]), torch.tensor([1.0]))
independent_distribution = Independent(base_distribution, event_dim=1)

# サンプルを生成
samples = independent_distribution.sample()
print(samples)

この例では、base_distribution は単変量正規分布を表し、event_dim=1 を指定することで、2つの独立した確率変数として扱われます。

例:多変量正規分布

Independent を使って、以下の多変量正規分布を表現できます。

mean = torch.tensor([1.0, 2.0])
covariance = torch.tensor([[1.0, 0.5], [0.5, 1.0]])

base_distribution = MultivariateNormal(mean, covariance)
independent_distribution = Independent(base_distribution)

# サンプルを生成
samples = independent_distribution.sample()
print(samples)

この例では、base_distribution は多変量正規分布を表し、Independent を使用することで、2つの次元を持つ独立した確率変数として扱われます。



多変量正規分布からのサンプリング

import torch
from torch.distributions import Independent, MultivariateNormal

# 多変量正規分布のパラメータを設定
mean = torch.tensor([1.0, 2.0])
covariance = torch.tensor([[1.0, 0.5], [0.5, 1.0]])

# 独立した確率分布を作成
base_distribution = MultivariateNormal(mean, covariance)
independent_distribution = Independent(base_distribution)

# バッチサイズを指定
batch_size = 10

# サンプルを生成
samples = independent_distribution.sample(sample_shape=(batch_size,))
print(samples)

このコードを実行すると、以下の出力が得られます。

tensor([[ 1.2000,  1.8000],
       [ 0.8000,  2.3000],
       [ 1.5000,  1.1000],
       [ 1.9000,  0.7000],
       [ 2.1000,  2.4000],
       [ 1.6000,  1.3000],
       [ 0.9000,  2.0000],
       [ 1.4000,  1.5000],
       [ 2.2000,  0.5000],
       [ 1.7000,  1.9000]])

以下のコードは、Independent を使って、Beta分布とガンマ分布を組み合わせた確率分布からサンプリングする方法を示しています。

import torch
from torch.distributions import Independent, Beta, Gamma

# Beta分布のパラメータを設定
alpha = torch.tensor([2.0, 3.0])
beta = torch.tensor([4.0, 5.0])

# ガンマ分布のパラメータを設定
concentration = torch.tensor([1.0, 2.0])
rate = torch.tensor([3.0, 4.0])

# Beta分布を作成
beta_distribution = Beta(alpha, beta)

# ガンマ分布を作成
gamma_distribution = Gamma(concentration, rate)

# 独立した確率分布を作成
independent_distribution = Independent(beta_distribution)
mixture_distribution = Independent(gamma_distribution)

# バッチサイズを指定
batch_size = 10

# サンプルを生成
samples = mixture_distribution.sample(sample_shape=(batch_size,))
print(samples)
tensor([[ 0.2992,  0.7059],
       [ 0.7413,  0.2851],
       [ 0.4098,  0.5547],
       [ 0.8811,  0.1477],
       [ 0.6152,  0.3392],
       [ 0.5307,  0.4403],
       [ 0.1988,  0.7847],
       [ 0.3171,  0.6749],
       [ 0.9221,  0.0845],
       [ 0.4923,  0.5077]])

これらの例は、Independent を使って様々な確率分布を表現できることを示しています。

  • Independent クラスは、ベイズ統計モデルの構築にもよく使用されます。
  • Independent クラスは、Mixture クラスと組み合わせて、混合分布を表現するのにも役立ちます。


以下に、「Independent」の代替となる可能性のあるものをいくつか紹介します。

単一の確率分布を複数回複製

最も単純な代替方法は、base_distribution を複数回複製することです。

import torch
from torch.distributions import Normal

base_distribution = Normal(torch.tensor([0.0]), torch.tensor([1.0]))
num_samples = 10

samples = []
for _ in range(num_samples):
  samples.append(base_distribution.sample())

samples = torch.stack(samples)

この方法は、柔軟性に欠けますが、簡単な状況であれば有効です。

torch.distributions.ProductDistribution を使用する

ProductDistribution クラスは、複数の確率分布の積を表現するために使用できます。

import torch
from torch.distributions import ProductDistribution, Normal

base_distribution1 = Normal(torch.tensor([0.0]), torch.tensor([1.0]))
base_distribution2 = Normal(torch.tensor([1.0]), torch.tensor([2.0]))

product_distribution = ProductDistribution([base_distribution1, base_distribution2])

# サンプルを生成
samples = product_distribution.sample(sample_shape=(10,))
print(samples)

この方法は、Independent クラスよりも柔軟性が高く、複数の異なる種類の確率分布を組み合わせることができます。

カスタム確率分布クラスを作成する

より複雑な状況では、カスタム確率分布クラスを作成することが必要になる場合があります。

import torch
import torch.distributions as dist

class MyIndependentDistribution(dist.Distribution):

  def __init__(self, base_distribution):
    super().__init__(batch_shape=base_distribution.batch_shape + (1,))
    self.base_distribution = base_distribution

  def rsample(self, sample_shape=torch.Size([])):
    return self.base_distribution.rsample(sample_shape + self.batch_shape)

  def log_prob(self, value):
    return self.base_distribution.log_prob(value.view(-1, self.base_distribution.event_shape[0]))

base_distribution = Normal(torch.tensor([0.0]), torch.tensor([1.0]))
my_independent_distribution = MyIndependentDistribution(base_distribution)

# サンプルを生成
samples = my_independent_distribution.sample(sample_shape=(10,))
print(samples)

この方法は、最も柔軟性がありますが、実装には時間がかかります。

最適な代替方法の選択

最適な代替方法は、具体的な状況によって異なります。

  • 高度なカスタマイズが必要: カスタム確率分布クラスを作成
  • 柔軟性が必要: ProductDistribution を使用する
  • シンプルかつ高速な方法が必要: 単一の確率分布を複数回複製

各方法の長所と短所を比較検討し、状況に合った方法を選択することが重要です。

  • 複雑な確率分布を扱う場合は、ベイズ統計ライブラリを使用すると便利かもしれません。
  • 上記以外にも、状況によっては他のライブラリを使用することもできます。