PyTorchにおけるTensor.scatter_reduce()の詳細解説:グラフニューラルネットワークとスパースデータ処理に役立つ新機能


torch.Tensor.scatter_reduce() は、PyTorchにおけるテンソル操作の一つであり、指定されたインデックスに基づいてソーステンソルからの値を散布し、指定された削減操作を使用して結果を累積します。この操作は、グラフニューラルネットワークやスパースデータ処理などのタスクでよく用いられます。

機能

  • オプションで、出力テンソルのサイズを指定できます。
  • 散布された値を "sum"、"prod"、"mean"、"amax"、"amin" などの削減操作を使用して累積します。
  • 特定のインデックスに基づいてソーステンソルからの値を散布します。

構文

torch.Tensor.scatter_reduce(dim, index, src, reduce, *, include_self=True)

引数

  • include_self (bool, optional): デフォルトは True で、この場合、散布操作の前に入力テンソル内の値も考慮されます。False に設定すると、入力テンソル内の値は考慮されません。
  • reduce (str): 使用する削減操作を指定します。
    • "sum": 各インデックスにおける値の合計を算出します。
    • "prod": 各インデックスにおける値の積を算出します。
    • "mean": 各インデックスにおける値の平均を算出します。
    • "amax": 各インデックスにおける値の最大値を算出します。
    • "amin": 各インデックスにおける値の最小値を算出します。
  • src (Tensor): 散布する値を含むソーステンソルです。
  • index (LongTensor): 散布するインデックスを指定するテンソルです。
  • dim (int): 散布と削減を行う次元を指定します。

出力

散布と削減操作の結果を含むテンソルを返します。出力テンソルのサイズは、入力テンソルと同じですが、指定された次元 dim のサイズは、index テンソルの最大値 + 1 になります。

以下の例では、index テンソルで指定されたインデックスに基づいてソーステンソルからの値を散布し、"sum" 操作を使用して結果を累積します。

import torch

# 入力テンソル
input = torch.tensor([1, 2, 3, 4, 5])

# インデックステンソル
index = torch.tensor([2, 0, 4])

# ソーステンソル
src = torch.tensor([3, 4, 5])

# 散布と削減
output = input.scatter_reduce(dim=0, index=index, src=src, reduce="sum")

print(output)

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

tensor([8, 6, 5])
  • この操作は、PyTorch 1.10 以降で使用できます。
  • torch.Tensor.scatter_reduce() は、torch.Tensor.scatter_()torch.Tensor.reduce() 操作を組み合わせたものです。


例 1: 異なる削減操作の使用

この例では、sumprodmeanamaxamin の各削減操作を使用して、ソーステンソルからの値を散布します。

import torch

# 入力テンソル
input = torch.tensor([1, 2, 3, 4, 5])

# インデックステンソル
index = torch.tensor([2, 0, 4])

# ソーステンソル
src = torch.tensor([3, 4, 5])

# 異なる削減操作を使用した散布と削減
output_sum = input.scatter_reduce(dim=0, index=index, src=src, reduce="sum")
output_prod = input.scatter_reduce(dim=0, index=index, src=src, reduce="prod")
output_mean = input.scatter_reduce(dim=0, index=index, src=src, reduce="mean")
output_amax = input.scatter_reduce(dim=0, index=index, src=src, reduce="amax")
output_amin = input.scatter_reduce(dim=0, index=index, src=src, reduce="amin")

print(output_sum)
print(output_prod)
print(output_mean)
print(output_amax)
print(output_amin)
tensor([8, 6, 5])
tensor([20])
tensor([2.6667])
tensor([5])
tensor([1])

例 2: include_self オプションの使用

この例では、include_self オプションを設定して、散布操作の前に入力テンソル内の値を考慮するかどうかを制御します。

import torch

# 入力テンソル
input = torch.tensor([1, 2, 3, 4, 5])

# インデックステンソル
index = torch.tensor([2, 0, 4])

# ソーステンソル
src = torch.tensor([3, 4, 5])

# `include_self=True` を使用した散布と削減
output_include_self = input.scatter_reduce(dim=0, index=index, src=src, reduce="sum", include_self=True)

# `include_self=False` を使用した散布と削減
output_exclude_self = input.scatter_reduce(dim=0, index=index, src=src, reduce="sum", include_self=False)

print(output_include_self)
print(output_exclude_self)
tensor([8, 6, 5])
tensor([5, 2, 0])

例 3: 出力テンソルのサイズの指定

この例では、output_size オプションを使用して、出力テンソルのサイズを指定します。

import torch

# 入力テンソル
input = torch.tensor([1, 2, 3, 4, 5])

# インデックステンソル
index = torch.tensor([2, 0, 4])

# ソーステンソル
src = torch.tensor([3, 4, 5])

# 出力テンソルのサイズを指定した散布と削減
output_size = torch.Size([10])
output = input.scatter_reduce(dim=0, index=index, src=src, reduce="sum", output_size=output_size)

print(output)
tensor([0, 0, 6, 0, 0, 0, 0, 0, 0, 5])


torch.scatter_() と torch.reduce() の組み合わせ

torch.Tensor.scatter_reduce() は、本質的に torch.scatter_()torch.reduce() 操作を組み合わせたものです。そのため、これらの操作を個別に使用することで、torch.Tensor.scatter_reduce() を代替することができます。

import torch

# 入力テンソル
input = torch.tensor([1, 2, 3, 4, 5])

# インデックステンソル
index = torch.tensor([2, 0, 4])

# ソーステンソル
src = torch.tensor([3, 4, 5])

# scatter_() を使用してソーステンソルを散布
output = input.scatter_(dim=0, index=index, src=src)

# reduce() を使用して結果を削減
output = output.reduce(dim=0, reduce="sum")

print(output)

このコードは、torch.Tensor.scatter_reduce() と同じ結果を出力します。

カスタム関数

より柔軟な制御が必要な場合は、torch.Tensor.scatter_reduce() の機能を再現するカスタム関数を作成することができます。

import torch

def scatter_reduce(input, dim, index, src, reduce):
    output = input.scatter_(dim=dim, index=index, src=src)
    return output.reduce(dim=dim, reduce=reduce)

# 入力テンソル
input = torch.tensor([1, 2, 3, 4, 5])

# インデックステンソル
index = torch.tensor([2, 0, 4])

# ソーステンソル
src = torch.tensor([3, 4, 5])

# カスタム関数を使用した散布と削減
output = scatter_reduce(input, dim=0, index=index, src=src, reduce="sum")

print(output)

PyTorch 以外にも、スパーステンソルやグラフニューラルネットワーク操作を扱うライブラリが存在します。これらのライブラリの中には、torch.Tensor.scatter_reduce() と同等の機能を提供するものがある可能性があります。

これらのライブラリの詳細については、それぞれのドキュメントを参照してください。

注意点

上記で紹介した代替方法は、それぞれ長所と短所があります。

  • カスタム関数: 柔軟性がありますが、実装が複雑になる場合があります。
  • torch.scatter_()torch.reduce() の組み合わせ: 最もシンプルで分かりやすい方法ですが、torch.Tensor.scatter_reduce() ほど効率的ではない場合があります。