「PyTorch入門 1. テンソル」¶

菅間修正済み 2025/05/15

【原題】TENSORS

【原著】 Suraj Subramanian、Seth Juarez 、Cassie Breviu 、Dmitry Soshnikov、Ari Bornstein

【元URL】https://pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html

【翻訳】電通国際情報サービスISID AIトランスフォーメーションセンター 小川 雄太郎

【日付】2021年03月20日

【チュトーリアル概要】

本チュートリアルでは、PyTorchの基本データ型である、Tensor(テンソル)について解説を行います。

テンソル:Tensors¶

テンソルは特殊なデータ構造で、配列や行列によく似ています。

PyTorchではテンソル型の変数を使用して、モデルの入力と出力、そしてモデルのパラメータを表現します。

テンソルはNumPyのndarraysに似ていますが、違いとしてGPUや他のハードウェアアクセラレータ上で動作させることができます。

テンソルとNumPyの配列は基本的には同じメモリを共有することができるため、2つの型間での変換時にはデータをコピーする必要がありません。

テンソルはその他に、自動微分に最適化されています(この点については、後ほど5. 自動微分にて、詳しく説明します)。

NumPyのndarraysに慣れている人は、Tensor APIをすぐに使いこなせると思います。

そうでない場合には、本チュートリアルを通してぜひ習得してください。

In [ ]:
import torch
import numpy as np

テンソルの初期化¶

テンソルは様々な手法で初期化できます。

以下に例を示します。

データから直接テンソルに変換

データから直接テンソルを作ることができます。

その際、データ型は自動的に推測されます。

In [ ]:
data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)

NumPy arrayからテンソルに変換

テンソルとNumpy arraysは相互に変換可能です。

In [ ]:
np_array = np.array(data)
x_np = torch.from_numpy(np_array)

他のテンソルから作成

他のテンソルから新しいテンソルを作成する場合、明示的に上書きされない限り、引数のテンソルのプロパティ(形状、データ型)を保持します。

In [ ]:
x_ones = torch.ones_like(x_data) # x_dataの特性(プロパティ)を維持
print(f"Ones Tensor: \n {x_ones} \n")

x_rand = torch.rand_like(x_data, dtype=torch.float) # x_dataのdatatypeを上書き更新
print(f"Random Tensor: \n {x_rand} \n")
Ones Tensor: 
 tensor([[1, 1],
        [1, 1]]) 

Random Tensor: 
 tensor([[0.1634, 0.9357],
        [0.3695, 0.1511]]) 

ランダム値や定数のテンソルの作成

shapeは、テンソルの次元を示すタプルです。

以下の例では、shapeからテンソルのサイズを決めています。

In [ ]:
shape = (2,3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")
Random Tensor: 
 tensor([[0.8638, 0.0139, 0.6148],
        [0.6302, 0.3649, 0.0683]]) 

Ones Tensor: 
 tensor([[1., 1., 1.],
        [1., 1., 1.]]) 

Zeros Tensor: 
 tensor([[0., 0., 0.],
        [0., 0., 0.]])

テンソルの属性変数¶

テンソルは属性変数として、その形状、データの型、保存されているデバイスを保持しています。

In [ ]:
tensor = torch.rand(3,4)

print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")
Shape of tensor: torch.Size([3, 4])
Datatype of tensor: torch.float32
Device tensor is stored on: cpu

テンソルの操作¶

PyTorchでは、算術、線形代数、行列操作(転置、インデックス、スライス)など、100種類以上のテンソル演算が可能です。

種々操作の詳細はこちら )をご覧ください。

各操作はGPU上で実行可能です(一般的にCPUの場合より高速です)。

Google Colaboratoryを使用している場合は、GPUを使用できるように設定してください。

(Runtime > Change runtime type > GPU)

デフォルトではテンソルはCPU上で作られます。

そのため、明示的に、.toメソッドを使用して、テンソルをGPU上へと移動させます。

大きなテンソルをデバイス間でコピーすると、時間とメモリの面でコストがかかる点にご注意ください。

In [ ]:
# GPUが使用可能であれば、GPU上にテンソルを移動させる
if torch.cuda.is_available():
  tensor = tensor.to('cuda')

テンソル操作の中からいくつかを試してみましょう。

NumPy APIに慣れていれば、Tensor APIも簡単に使えるようになると思います。

numpy-likeなindexingとslicing:

In [ ]:
tensor = torch.ones(4, 4)
print('First row: ',tensor[0])
print('First column: ', tensor[:, 0])
print('Last column:', tensor[..., -1])
tensor[:,1] = 0
print(tensor)
First row:  tensor([1., 1., 1., 1.])
First column:  tensor([1., 1., 1., 1.])
Last column: tensor([1., 1., 1., 1.])
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

テンソルの結合

torch.catを使用することで、テンソルを特定の次元に沿って結合させることができます(詳細はこちらをご覧ください)。

torch.catとは微妙に異なるテンソル結合演算であるtorch.stackも確認しておいてください。

In [ ]:
t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)
tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
        [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])

算術演算

In [ ]:
# 2つのテンソル行列のかけ算です。 y1, y2, y3 は同じ結果になります。
y1 = tensor @ tensor.T
y2 = tensor.matmul(tensor.T)

y3 = torch.rand_like(tensor)
torch.matmul(tensor, tensor.T, out=y3)


# こちらは、要素ごとの積を求めます。 z1, z2, z3 は同じ値になります。
z1 = tensor * tensor
z2 = tensor.mul(tensor)

z3 = torch.rand_like(tensor)
torch.mul(tensor, tensor, out=z3)
Out[ ]:
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]])

1要素のテンソル

1要素のテンソル(テンソルの全要素を足し算する等をした結果生まれます)を扱う場合には、.item()を使用することでPythonの数値型変数に変換できます。

In [ ]:
agg = tensor.sum()
agg_item = agg.item()
print(agg_item, type(agg_item))
12.0 <class 'float'>

インプレース操作

演算結果をオペランドに格納する演算をインプレースと呼びます。

メソッドの最後、接尾辞として操作名に、 _ が付きます。

例えば、x.copy_(y), x.t_()であり、xの内容そのものを更新します。

In [ ]:
print(tensor, "\n")
tensor.add_(5)
print(tensor)
tensor([[1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.],
        [1., 0., 1., 1.]]) 

tensor([[6., 5., 6., 6.],
        [6., 5., 6., 6.],
        [6., 5., 6., 6.],
        [6., 5., 6., 6.]])

【注意】

インプレース操作はメモリを節約できますが、演算履歴が失われてしまうため、微分を計算する際には問題となります。

そのため、そのような微分を求める場面ではインプレース操作の使用は推奨されていません。


NumPyとの変換¶

CPU上のテンソルとNumpy arraysは同じメモリを共有することができ、相互変換が容易です。

Tensor to NumPy array

In [ ]:
t = torch.ones(5)
print(f"t: {t}")
n = t.numpy()
print(f"n: {n}")
t: tensor([1., 1., 1., 1., 1.])
n: [1. 1. 1. 1. 1.]

この際、テンソルが変化すると、Numpy側も変化します。

In [ ]:
t.add_(1)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]

NumPy array to Tensor

In [ ]:
n = np.ones(5)
t = torch.from_numpy(n)

NumPy arrayの変化はテンソル側にも反映されます。

In [ ]:
np.add(n, 1, out=n)
print(f"t: {t}")
print(f"n: {n}")
t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]

以上。