آشنایی کامل با پایتورچ
آگوست 16, 2023تنسور چیست
آگوست 18, 2023یادگیری تنسور در پایتورچ
تانسورها
تانسورها یک ساختار داده تخصصی هستند که بسیار شبیه به آرایه ها و ماتریس ها هستند. در PyTorch، ما از تانسورها برای رمزگذاری ورودی ها و خروجی های یک مدل و همچنین پارامترهای مدل استفاده می کنیم. تانسورها شبیه درایههای نامپای( NumPy ) هستند، با این تفاوت که تانسورها میتوانند روی پردازندههای گرافیکی یا سایر سختافزارهای تخصصی برای سرعت بخشیدن به محاسبات اجرا شوند. اگر با ndarray ها آشنا هستید، با Tensor API درست در خانه خواهید بود. در غیر این صورت، این راهنمای سریع API را دنبال کنید.
import torch
import numpy as np
راه اندازی تانسور
تانسورها را می توان به روش های مختلفی مقداردهی اولیه کرد. به نمونه های زیر دقت کنید :
مستقیماً از داده ها
تانسورها را می توان مستقیماً از داده ها ایجاد کرد. نوع داده به طور خودکار استنباط می شود.
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
از یک آرایه NumPy
تانسورها را می توان از آرایه های NumPy ایجاد کرد (و بالعکس – Bridge with NumPy را ببینید).
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
از تانسور دیگر:
تانسور جدید خصوصیات (شکل، نوع داده) تانسور آرگومان را حفظ می کند، مگر اینکه به صراحت لغو شود.
x_ones = torch.ones_like(x_data) # retains the properties of x_data
print(f"Ones Tensor: \n {x_ones} \n")
x_rand = torch.rand_like(x_data, dtype=torch.float) # overrides the datatype of x_data
print(f"Random Tensor: \n {x_rand} \n")
out :
Ones Tensor:
tensor([[1, 1],
[1, 1]])
Random Tensor:
tensor([[0.8823, 0.9150],
[0.3829, 0.9593]])
با مقادیر تصادفی یا ثابت:
به شکل چند تایی (تاپل ) از ابعاد تانسور است. در توابع زیر، ابعاد تانسور خروجی را تعیین می کند.
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.3904, 0.6009, 0.2566],
[0.7936, 0.9408, 0.1332]])
Ones Tensor:
tensor([[1., 1., 1.],
[1., 1., 1.]])
Zeros Tensor:
tensor([[0., 0., 0.],
[0., 0., 0.]])
ویژگی های تانسور
ویژگی های تانسور شکل، نوع داده و دستگاهی که در آن ذخیره می شوند را توصیف می کند.
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
عملیات تانسور
بیش از 100 عملیات تانسور، از جمله جابجایی، نمایه سازی، برش، عملیات ریاضی، جبر خطی، نمونه برداری تصادفی و موارد دیگر به طور جامع در اینجا توضیح داده شده است.
هر یک از آنها را می توان روی GPU (با سرعت های معمولی بالاتر از CPU) اجرا کرد. اگر از Colab استفاده می کنید، با رفتن به Edit > Notebook Settings، یک GPU اختصاص دهید.
# We move our tensor to the GPU if available
if torch.cuda.is_available():
tensor = tensor.to('cuda')
print(f"Device tensor is stored on: {tensor.device}")
Device tensor is stored on: cuda:0
برخی از عملیات های لیست را امتحان کنید. اگر با NumPy API آشنا هستید، می توانید از Tensor API استفاده کنید.
نمایه سازی و برش معمولی مانند ناپای
tensor = torch.ones(4, 4)
tensor[:,1] = 0
print(tensor)
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
اتصال تانسورها
میتوانید از torch.cat برای الحاق دنبالهای از تانسورها در یک بعد معین استفاده کنید. همچنین به torch.stack مراجعه کنید، تانسور دیگری که به عملیات متصل میشود که به طور ماهرانهای با torch.cat متفاوت است.
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.]])
ضرب تانسورها
# This computes the element-wise product
print(f"tensor.mul(tensor) \n {tensor.mul(tensor)} \n")
# Alternative syntax:
print(f"tensor * tensor \n {tensor * tensor}")
tensor.mul(tensor)
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
tensor * tensor
tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])
این ضرب ماتریس بین دو تانسور را محاسبه می کند
print(f"tensor.matmul(tensor.T) \n {tensor.matmul(tensor.T)} \n")
# Alternative syntax:
print(f"tensor @ tensor.T \n {tensor @ tensor.T}")
tensor.matmul(tensor.T)
tensor([[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]])
tensor @ tensor.T
tensor([[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]])
عملیات در محل
عملیاتی که پسوند _ دارند در جای خود هستند. به عنوان مثال: x.copy_(y)، x.t_()، را x را تغییر خواهد داد.
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 میتوانند مکانهای حافظه underlying خود را به اشتراک بگذارند و تغییر یکی، دیگری را تغییر میدهد.
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 منعکس می شود.
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 به Tensor
n = np.ones(5)
t = torch.from_numpy(n)
تغییرات در آرایه NumPy در تانسور منعکس می شود.
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.]