PyTorchでTensor要素を散布的に追加する:scatter_add関数と代替方法を徹底解説
この関数は、以下の引数を取ります。
src
(Tensor): 追加する要素の値index
(LongTensor): 追加する要素のインデックスdim
(int): 要素を追加する次元input
(Tensor): 入力テンソル
scatter_add
関数は、以下の出力を返します。
Tensor
: 入力テンソルと同じ形状の出力テンソル
例
以下の例では、scatter_add
関数を使用して、1 次元テンソルに値を追加する方法を示します。
import torch
# 入力テンソルを作成する
input = torch.tensor([1, 2, 3, 4, 5])
# 追加する要素のインデックスを作成する
index = torch.tensor([2, 4])
# 追加する要素の値を作成する
src = torch.tensor([3, 5])
# scatter_add 関数を実行する
output = input.scatter_add(0, index, src)
# 出力テンソルを出力する
print(output)
このコードを実行すると、以下の出力が得られます。
tensor([1, 2, 5, 4, 8])
上記の例では、index
テンソルによって、input
テンソルの 2 番目の要素と 4 番目の要素が選択されます。src
テンソルによって、これらの要素にそれぞれ 3 と 5 が追加されます。
scatter_add 関数の詳細
scatter_add
関数は、以下のオプション引数もサポートしています。
dim_size
(int, optional):dim
次元の出力テンソルのサイズ。指定されていない場合は、input
テンソルのサイズが使用されます。out
(Tensor, optional): 出力テンソル。指定されていない場合は、新しいテンソルが作成されます。
scatter_add 関数の使用例
scatter_add
関数は、以下のタスクに使用できます。
- 集計データの更新
- ヒストグラムの更新
- スパーステンソルの更新
1 次元テンソルへの要素の追加
この例では、1 次元テンソルに値を追加する方法を示します。
import torch
# 入力テンソルを作成する
input = torch.tensor([1, 2, 3, 4, 5])
# 追加する要素のインデックスを作成する
index = torch.tensor([2, 4])
# 追加する要素の値を作成する
src = torch.tensor([3, 5])
# scatter_add 関数を実行する
output = input.scatter_add(0, index, src)
# 出力テンソルを出力する
print(output)
tensor([1, 2, 5, 4, 8])
2 次元テンソルへの要素の追加
import torch
# 入力テンソルを作成する
input = torch.tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 追加する要素のインデックスを作成する
index = torch.tensor([[1, 0],
[2, 2]])
# 追加する要素の値を作成する
src = torch.tensor([10, 20, 30])
# scatter_add 関数を実行する
output = input.scatter_add(1, index, src)
# 出力テンソルを出力する
print(output)
tensor([[1, 12, 3],
[4, 5, 6],
[7, 8, 30]])
スパーステンソルの更新
この例では、スパーステンソルを更新する方法を示します。
import torch
from scipy.sparse import coo_matrix
# スパーステンソルを作成する
data = [1, 2, 3]
rows = [0, 1, 2]
cols = [0, 2, 1]
sp_tensor = coo_matrix((data, (rows, cols)), shape=(3, 3))
# Tensorに変換する
tensor = torch.from_numpy(sp_tensor.toarray())
# 追加する要素のインデックスを作成する
index = torch.tensor([1, 2])
# 追加する要素の値を作成する
src = torch.tensor([10, 20])
# scatter_add 関数を実行する
output = tensor.scatter_add(1, index, src)
# スパーステンソルに変換する
sp_output = sp_tensor.from_scipy_sparse_matrix(output)
# スパーステンソルを出力する
print(sp_output)
(0, 0) 1.0
(0, 2) 10.0
(1, 0) 2.0
(1, 1) 0.0
(1, 2) 3.0
(2, 0) 3.0
(2, 1) 0.0
(2, 2) 20.0
この例では、ヒストグラムを更新する方法を示します。
import torch
# ヒストグラムを作成する
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
hist, _ = torch.histogram(torch.tensor(data))
# 更新するビンインデックスを作成する
index = torch.tensor([3, 5])
# 更新値を作成する
values = torch.tensor([5, 2])
# scatter_add 関数を実行する
hist = hist.scatter_add(0, index, values)
# ヒストグラムを出力する
print(hist)
tensor([0, 0, 0, 5, 2, 3, 0, 0, 0, 1])
手動ループ
最も基本的な代替手段は、手動ループを使用して要素を散布的に追加することです。 これは単純ですが、時間がかかり、コードが冗長になる可能性があります。
import torch
def scatter_add_manual(input, dim, index, src):
output = input.clone()
for i, j, v in zip(index, index, src):
output[i, j] += v
return output
# 入力テンソルを作成する
input = torch.tensor([1, 2, 3, 4, 5])
# 追加する要素のインデックスを作成する
index = torch.tensor([2, 4])
# 追加する要素の値を作成する
src = torch.tensor([3, 5])
# 手動ループでscatter_addを実行する
output = scatter_add_manual(input, 0, index, src)
# 出力テンソルを出力する
print(output)
tensor([1, 2, 5, 4, 8])
torch.index_add
torch.index_add
関数は、指定されたインデックス位置の要素にテンソルを追加します。 これは scatter_add
よりも汎用性が高く、テンソルだけでなくスカラー値も追加できます。
import torch
# 入力テンソルを作成する
input = torch.tensor([1, 2, 3, 4, 5])
# 追加する要素のインデックスを作成する
index = torch.tensor([2, 4])
# 追加する要素の値を作成する
src = torch.tensor([3, 5])
# index_add 関数を実行する
output = input.index_add(0, index, src)
# 出力テンソルを出力する
print(output)
tensor([1, 2, 5, 4, 8])
torch.bincount
torch.bincount
関数は、ヒストグラムを計算するために使用できます。 これは、ヒストグラムを更新する必要がある場合に便利です。
import torch
# ヒストグラムを作成する
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
counts = torch.bincount(torch.tensor(data))
# 更新するビンインデックスを作成する
index = torch.tensor([3, 5])
# 更新値を作成する
values = torch.tensor([5, 2])
# countsを散布的に追加する
counts = counts.scatter_add_(0, index, values)
# ヒストグラムを出力する
print(counts)
tensor([0, 0, 0, 5, 2, 3, 0, 0, 0, 1])
NumPy
PyTorch テンソルを NumPy 配列に変換し、NumPy 関数を使用して要素を散布的に追加してから、PyTorch テンソルに戻すこともできます。 これは、特に小さなテンソルを扱う場合に役立ちます。
import torch
import numpy as np
# 入力テンソルを作成する
input = torch.tensor([1, 2, 3, 4, 5])
# 追加する要素のインデックスを作成する
index = torch.tensor([2, 4]).numpy()
# 追加する要素の値を作成する
src = torch.tensor([3, 5]).numpy()
# NumPy配列に変換する
input_array = input.numpy()
# NumPyでscatter_addを実行する
input_array[index] += src
# PyTorch テンソルに戻す
output = torch.from_numpy(input_array)
# 出力テンソルを出力する
print(output)
tensor([1, 2, 5, 4, 8])