PyTorchの基礎(1):Tensorを学ぶ

スポンサーリンク
PyTorch
スポンサーリンク

PyTorchはオープンソースの機械学習フレームワークです。少ないコードで様々な機械学習を実装できます。また、GPUを使って高速な計算をすることができ、また、豊富なライブラリを持つことから、最も広く用いられている機械学習にのライブラリの一つです。今回、PyTorchのチュートリアルをベースにPyTorchを基本から学んでいきたいと思います。

Python Tutorials(英語版サイト)
PyTorchチュートリアル(日本語翻訳版)

Tensorとは

TensorはPyTorchで使われるデータ構造で、Numpyのndarrayと似た形状です。ただし、GPUを使った並列処理ができたり、ディープラーニングなどで重要な自動微分を取ることができたり、便利な性質を持ちます。PyTorchのTensorとNumpyのndarrayは相互変換が可能で、同じデータメモリを共有することもできます。

PyTorchと類似のNumpyを使うときは、それぞれをインポートして使用します。

import torch
import numpy as np

Tensorの作成

Tensorの作成例を示します。

# リストやシーケンスからのTensorの生成
L = [[1,2],[8,9]]
a = torch.Tensor(L)
# Tensor.dtypeでデータ型確認
print(a.dtype)
print(a)
torch.float32
tensor([[1., 2.],
        [8., 9.]])

Tensor.dtypeでデータ型を確認できます。Tensorのデフォルトのデータ型はfloat32です。

# 指定のサイズのTensor(中身はランダム)を生成
t1 = torch.empty(2,3)
print(t1)
tensor([[0.0000e+00, 1.0000e+00, 2.7597e-06],
        [1.0740e-05, 2.6426e+20, 4.2247e-05]])

※値はメモリ上のランダムな値

# 指定したサイズのゼロで埋めたTensorを生成
t2 = torch.zeros(4)
print(t2)
# 指定したサイズの1で埋めたTensorを生成
t3 = torch.ones(3,2)
print(t3)
tensor([0., 0., 0., 0.])
tensor([[1., 1.],
        [1., 1.],
        [1., 1.]])
# 指定したサイズの0~1の一様ランダムなTensorを生成
t4 = torch.rand(2,2)
print(t4)
# 指定したサイズの-1~1の正規分布に従うTensorを生成
t5 = torch.randn(4)
print(t5)
tensor([[0.7073, 0.0986],
        [0.9827, 0.8421]])
tensor([-1.3731, -0.4215,  0.3472,  0.3218])
# startからstep刻みでend未満の数列のTensorを生成
t6 = torch.arange(0,10,2)
print(t6)
# startからendまでstep等分の数列でTensorを生成
t7 = torch.linspace(0,1,20)
print(t7)
import math
t8 = torch.linspace(0, 2*math.pi,8)
print(t8)
tensor([0, 2, 4, 6, 8])
tensor([0.0000, 0.0526, 0.1053, 0.1579, 0.2105, 0.2632, 0.3158, 0.3684, 0.4211,
        0.4737, 0.5263, 0.5789, 0.6316, 0.6842, 0.7368, 0.7895, 0.8421, 0.8947,
        0.9474, 1.0000])
tensor([0.0000, 0.8976, 1.7952, 2.6928, 3.5904, 4.4880, 5.3856, 6.2832])

Tensorの形元(形)やデータ型の変換

Tensorの次元(形)はreshapeでおこないます。

# 1×16のTensorの次元を変換
b1 = torch.arange(16)
print(b1)
b2 = torch.reshape(b1,(4,4))
print(b2)
# -1はデータ数から8を自動補完
b3 = torch.reshape(b1,(2,-1))
print(b3)
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11],
        [12, 13, 14, 15]])
tensor([[ 0,  1,  2,  3,  4,  5,  6,  7],
        [ 8,  9, 10, 11, 12, 13, 14, 15]])
# Tensorの次元を確認
print(b3.size())
print(b3.shape)
# 0次元目の大きさ
print(b3.size(0))
# 1次元目の大きさ
print(b3.size(1))
torch.Size([2, 8])
torch.Size([2, 8])
2
8
# 次元数
print(b3.ndim)
2

データ型はdtypeで指定し、変更できる。

# 生成時に設定
c6 = torch.zeros(2,3, dtype=torch.int64)
print(c6.dtype)
# データ型の変換
c7 = torch.Tensor.type(c6,dtype=torch.float64)
print(c7.dtype)
# データ型とサイズの継承
c8 = torch.ones_like(c6)
print(c8)
print(c8.dtype)
torch.int64
torch.float64
tensor([[1, 1, 1],
        [1, 1, 1]])
torch.int64

Tensorの転置

Tensorはtransposeで転置したTensorを得ることができる。また、Tensor.Tでも転置したTensorを得ることができます。

# 転置
c1 = torch.Tensor([[1,2],[3,4]])
print(c1)
c2 = torch.transpose(c1,0,1)
print(c2)
print(c1.T)
tensor([[1., 2.],
        [3., 4.]])
tensor([[1., 3.],
        [2., 4.]])
tensor([[1., 3.],
        [2., 4.]])

transposeは任意の次元を入れ替えることができる。

c3 = torch.rand(2,3,4)
print(c3.shape)
# 0次元目と1次元目を入れ替え
c4 = torch.transpose(c1, 0, 1)
print(c4.shape)
# 1次元目と2次元目を入れ替え
c5 = torch.transpose(c1, 1, 2)
print(c5.shape)
torch.Size([2, 3, 4])
torch.Size([3, 2, 4])
torch.Size([2, 4, 3])

Tensorの演算

Tensorは各値の演算について示します。Tensorの演算は、
・+=*/などの演算子を用いる方法
・torch.add,torch.sub,torch.mul,torch.divなどの演算関数を用いる方法
・Tensor.add, Tensor.add_などのTensorのメソッドを用いる方法
などがあります。

# 演算子を用いた四則演算
x = torch.Tensor([[5,6],[8,10]])
y = torch.Tensor([[1,2],[3,4]])
z1 = x+y
z2 = x-y
z3 = x*y
z4 = x/y
print(z1)
print(z2)
print(z3)
print(z4)
tensor([[ 6.,  8.],
        [11., 14.]])
tensor([[4., 4.],
        [5., 6.]])
tensor([[ 5., 12.],
        [24., 40.]])
tensor([[5.0000, 3.0000],
        [2.6667, 2.5000]])
# 演算関数を用いた四則演算
x = torch.Tensor([[5,6],[8,10]])
y = torch.Tensor([[1,2],[3,4]])
z1 = torch.add(x,y)
z2 = torch.sub(x,y)
z3 = torch.mul(x,y)
z4 = torch.div(x,y)
print(z1)
print(z2)
print(z3)
print(z4)
tensor([[ 6.,  8.],
        [11., 14.]])
tensor([[4., 4.],
        [5., 6.]])
tensor([[ 5., 12.],
        [24., 40.]])
tensor([[5.0000, 3.0000],
        [2.6667, 2.5000]])

メソッドを使って演算する場合、元の値を保持する方法と値を書き換えるin-place操作をする方法があります。例えば、x.add(y)ではTensorのxにyを足した結果を返しますが、元のxは変わりません。一方で、x.add_(y)とアンダーバーを使ったメソッドでは、xの値は書き換わります。

# 演算メソッドを用いた四則演算
x = torch.Tensor([[5,6],[8,10]])
y = torch.Tensor([[1,2],[3,4]])
print(x.add(y))
print(x.sub(y))
print(x.mul(y))
print(x.div(y))
# xの値は変わらない
print(x)
tensor([[ 6.,  8.],
        [11., 14.]])
tensor([[4., 4.],
        [5., 6.]])
tensor([[ 5., 12.],
        [24., 40.]])
tensor([[5.0000, 3.0000],
        [2.6667, 2.5000]])
tensor([[ 5.,  6.],
        [ 8., 10.]])
# in-place処理をする演算メソッドを用いた四則演算
x = torch.Tensor([[5,6],[8,10]])
y = torch.Tensor([[1,2],[3,4]])
x.add_(y) # x+y
print(x)
x.mul_(y) # x*y
print(x)
x.sub_(y) # x-y
print(x)
x.div_(y) # x/y
print(x)
# yは不変
print(y)
tensor([[ 6.,  8.],
        [11., 14.]])
tensor([[ 6., 16.],
        [33., 56.]])
tensor([[ 5., 14.],
        [30., 52.]])
tensor([[ 5.,  7.],
        [10., 13.]])
tensor([[1., 2.],
        [3., 4.]])

Tensorの行列積

Tensorの行列式はtorch.matmul関数、またはtorch.mm関数で行うことができます。

x = torch.rand((2,3))
y = torch.rand((3,2))
print(x)
print(y)
tensor([[0.9107, 0.6812, 0.3674],
        [0.8000, 0.2388, 0.7749]])
tensor([[0.8742, 0.2070],
        [0.9954, 0.5732],
        [0.0333, 0.1516]])
# torch.matmul関数の場合
print(torch.matmul(x,y))
print(torch.matmul(y,x))
tensor([[1.4864, 0.6346],
        [0.9629, 0.4200]])
tensor([[0.9617, 0.6449, 0.4816],
        [1.3651, 0.8150, 0.8099],
        [0.1517, 0.0589, 0.1298]])
# torch.mm関数の場合
print(torch.mm(x,y))
print(torch.mm(y,x))
tensor([[1.4864, 0.6346],
        [0.9629, 0.4200]])
tensor([[0.9617, 0.6449, 0.4816],
        [1.3651, 0.8150, 0.8099],
        [0.1517, 0.0589, 0.1298]])

PyTorchのTensorとNumpyのndarrayの相互変換

Tensorからndarrayへの変換はTensorのnumpyメソッドを使います。一方、ndarrayからTensorへの変換はfrom_numpy関数を使います。

a = torch.Tensor([[1,2],[3,4]])
print(type(a))
# PyTorchのTensorからNumpyのndarrayへの変換
b = a.numpy()
print(type(b))
# NumpyのndarrayからPyTorchのTensorへの変換
c = torch.from_numpy(b)
print(type(c))

この場合、Tensorとndarrayは同じメモリを共有して使います。ですので、どちらかを変更した場合、もう一方も変更されます。それを避けるために、copyメソッドで新しいメモリのデータ構造を作る必要があります。

c[1][1] = 10
print(a)
print(b)
tensor([[ 1.,  2.],
        [ 3., 10.]])
[[ 1.  2.]
 [ 3. 10.]]
a = torch.Tensor([[1,2],[3,4]])
b = a.numpy().copy()
a[1][1] = 10
# bはaの変更の影響を受けない
print(b)
[[1. 2.]
 [3. 4.]]

Tensorのデバイス

Tensorは、CPUの他、GPU上で計算を行うことができます。デバイスは、torch.deviceクラスで表されます。CPUを表すデバイスはtorch.device(“cpu”)、GPUを表すデバイスはtorch.device(“cuda”)やtorch.device(“cuda:0”)と書きます。(0はGPUの番号)

# GPUが使えるか確認
torch.cuda.is_available()
True
 # デフォルトではCPU上でTensorを生成
d1 = torch.rand(3, 4)
print(d1.device) 
cpu
# GPUを指定してTensorを生成
d2 = torch.rand(3, 4, device=torch.device("cuda")) 
print(d2.device) 
cuda:0
# GPUが使える環境の時はGPUでTensorを生成
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 
d3 = torch.rand(3, 4, device = device) 
print(d3.device) 
cuda:0
PyTorch
スポンサーリンク
鷹の目週末プログラマー

コメント