【100 PyTorch exercises】 PyTorchを学ぼう 入門編 66~70問目

PyTorchの操作方法はNumpyの操作方法と似ています。

そのためNumpyが使用できれば同じような操作方法でPyTrochも扱えるという学習コストの低さが一つのメリットといえます。

しかし、多少の差異はどうしても存在します。

そこで、Numpyの練習に非常に役立つ「100 numpy exercises 」をPyTorchで書き換えることによって、PyTorchの操作方法を学ぶのと同時にNumpyとの類似点や相違点を学んでいきたいと思います。

github.com

PyTorchのコードだけでなくNumpyのコードもあわせて紹介していきます。

別記事に他の問題の解法も書いています。

次のリンクにまとめているので、他の問題もあわせて参考にしていただければと思います。

venoda.hatenablog.com




66. Considering a (w,h,3) image of (dtype=ubyte), compute the number of unique colors (★★☆)

「(dtype = ubyte)の(w、h、3)画像を考慮して、一意の色の数を計算してください」

PyTorch

w, h = 256, 256
I = torch.randint(0, 4, (h, w, 3))
colors = torch.unique(I.view(-1, 3), dim=0)
n = len(colors)
print(n)
# Output
64

Numpy

w, h = 256, 256
I = np.random.randint(0, 4, (h, w, 3)).astype(np.ubyte)
colors = np.unique(I.reshape(-1, 3), axis=0)
n = len(colors)
print(n)
# Output
64


67. Considering a four dimensions array, how to get sum over the last two axis at once? (★★★)

「4次元配列の最後の2つの軸の合計を一度に取得してください」

PyTorch

A = torch.randint(0, 10, (3, 4, 3, 4))
sum = A.sum(dim=(-2, -1))
print(sum)

sum = A.view(A.size()[:-2] + (-1, )).sum(dim=-1)
print(sum)
# Output
tensor([[47, 69, 46, 66],
        [68, 52, 49, 50],
        [76, 38, 61, 62]])
tensor([[47, 69, 46, 66],
        [68, 52, 49, 50],
        [76, 38, 61, 62]])

Numpy

A = np.random.randint(0,10,(3,4,3,4))
sum = A.sum(axis=(-2,-1))
print(sum)
  
sum = A.reshape(A.shape[:-2] + (-1,)).sum(axis=-1)
print(sum)
# Output
[[63 59 56 47]
 [63 68 50 71]
 [67 60 50 67]]
[[63 59 56 47]
 [63 68 50 71]
 [67 60 50 67]]




68. Considering a one-dimensional vector D, how to compute means of subsets of D using a vector S of same size describing subset indices? (★★★)

「1次元ベクトルDについて、サブセットインデックスを記述する同じサイズのベクトルSを使用して、Dのサブセットの平均を計算してください」

PyTorch

D = torch.distributions.uniform.Uniform(0, 1).sample([100])
S = torch.randint(0, 10, (100, ))
D_sums = torch.bincount(S, weights=D)
D_counts = torch.bincount(S)
D_means = D_sums / D_counts
print(D_means)
# Output
tensor([0.4601, 0.5256, 0.6136, 0.6511, 0.5553, 0.2704, 0.4001, 0.2308, 0.4230,
        0.6285])

Numpy

D = np.random.uniform(0, 1, 100)
S = np.random.randint(0, 10, 100)
D_sums = np.bincount(S, weights=D)
D_counts = np.bincount(S)
D_means = D_sums / D_counts
print(D_means)
# Output
[0.57597679 0.48310766 0.38572511 0.67786808 0.48981223 0.53382379
 0.6503257  0.43426519 0.34702275 0.4575979 ]


69. How to get the diagonal of a dot product? (★★★)

内積の対角の要素を取得してください」

PyTorch

A = torch.distributions.uniform.Uniform(0, 1, (5, 5)).sample([5, 5])
B = torch.distributions.uniform.Uniform(0, 1, (5, 5)).sample([5, 5])

# Slow version
torch.diag(torch.matmul(A, B))

# Fast version
torch.sum(A * B.T, dim=1)

# Faster version
torch.einsum("ij,ji->i", A, B)
# Output
tensor([1.0592, 1.2846, 1.0278, 0.4763, 1.1954])

Numpy

A = np.random.uniform(0, 1, (5, 5))
B = np.random.uniform(0, 1, (5, 5))

# Slow version
np.diag(np.dot(A, B))

# Fast version
np.sum(A * B.T, axis=1)

# Faster version
np.einsum("ij,ji->i", A, B)
# Output
array([0.96746301, 1.47904334, 1.58183947, 1.54715639, 1.87035922])




70. Consider the vector [1, 2, 3, 4, 5], how to build a new vector with 3 consecutive zeros interleaved between each value? (★★★)

「ベクトル[1、2、3、4、5]について、各値の間に3つの連続するゼロが交互に配置された新しいベクトルを作成してください」

PyTorch

Z = torch.tensor([1, 2, 3, 4, 5])
nz = 3
Z0 = torch.zeros(len(Z) + (len(Z) - 1) * (nz))
Z0[::nz+1] = Z
print(Z0)
# Output
tensor([1., 0., 0., 0., 2., 0., 0., 0., 3., 0., 0., 0., 4., 0., 0., 0., 5.])

Numpy

Z = np.array([1, 2, 3, 4, 5])
nz = 3
Z0 = np.zeros(len(Z) + (len(Z) - 1) * (nz))
Z0[::nz+1] = Z
print(Z0)
# Output
[1. 0. 0. 0. 2. 0. 0. 0. 3. 0. 0. 0. 4. 0. 0. 0. 5.]