PyTorch Day 03: Tensor Operations

📑 فهرست مطالب
- بررسی اجمالی موضوعات
-
عملیات پایه تانسور
-
عملیات در محل در مقابل عملیات خارج از محل
-
فعالیت های عملی
- منابع
- اهداف یادگیری
- نتایج مورد انتظار
- نکاتی برای موفقیت
- نکات پیشرفته و بهترین شیوه ها
- خلاصه جامع
- حرکت رو به جلو
- تشویق نهایی
1. بررسی اجمالی موضوعات
عملیات پایه تانسور
درک و انجام عملیات تانسور اصلی مانند جمع، تفریق، ضرب و تقسیم ضروری است. این عملیات نه تنها در محاسبات ریاضی اساسی هستند، بلکه ستون فقرات آموزش شبکه عصبی و دستکاری داده ها را نیز تشکیل می دهند.
عملیات در محل در مقابل عملیات خارج از محل
PyTorch دو نوع عملیات ارائه می دهد:
- عملیات خارج از محل: این عملیات یک تانسور جدید ایجاد می کند و تانسور اصلی را تغییر نمی دهد.
- عملیات در محل: این عملیات مستقیماً تانسور اصلی را تغییر می دهد که می تواند منجر به صرفه جویی در حافظه شود اما ممکن است پیامدهایی برای محاسبات گرادیان داشته باشد.
امروز، ما هر دو نوع را بررسی می کنیم، تفاوت های آنها را درک می کنیم و یاد می گیریم که چه زمانی از هر کدام استفاده کنیم.
2. عملیات پایه تانسور
بیایید چهار عمل تانسور اصلی را بررسی کنیم: جمع، تفریق، ضرب و تقسیم. برای هر کدام توضیحات مفصل و نمونه کد ارائه خواهیم کرد.
2.1. اضافه
اضافه عنصر:
با افزودن دو تانسور هم شکل، یک تانسور جدید ایجاد می شود که در آن هر عنصر مجموع عناصر مربوطه از تانسورهای ورودی است.
import torch
# Creating two tensors of the same shape
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])
# Element-wise addition
z = x + y
print("Addition (x + y):", z) # Output: tensor([5, 7, 9])
اضافه پخش شده:
هنگامی که تانسورهای شکل های مختلف درگیر هستند، PyTorch قوانین پخش را برای اجرای اضافه اعمال می کند.
# Tensor shapes: x is (3, 1), y is (1, 4)
x = torch.ones(3, 1)
y = torch.ones(1, 4)
# Broadcasted addition
z = x + y
print("Broadcasted Addition (x + y):\n", z)
# Output:
# tensor([[2., 2., 2., 2.],
# [2., 2., 2., 2.],
# [2., 2., 2., 2.]])
2.2. تفریق
تفریق بر حسب عنصر:
تفریق یک تانسور از دیگری با همان شکل.
# Element-wise subtraction
z = y - x
print("Subtraction (y - x):", z) # Output: tensor([3, 3, 3])
تفریق پخش شده:
# Using tensors from previous example
z = y - x
print("Broadcasted Subtraction (y - x):\n", z)
# Output:
# tensor([[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]])
2.3. ضرب
ضرب عنصری:
ضرب دو تانسور هم شکل.
# Element-wise multiplication
z = x * y
print("Multiplication (x * y):", z) # Output: tensor([4, 10, 18])
ضرب ماتریس:
برای تانسورهای دو بعدی (ماتریس)، ضرب از قوانین ضرب ماتریس پیروی می کند.
# Creating two matrices
A = torch.tensor([[1, 2], [3, 4]])
B = torch.tensor([[5, 6], [7, 8]])
# Matrix multiplication using torch.mm
C = torch.mm(A, B)
print("Matrix Multiplication (A.mm(B)):\n", C)
# Output:
# tensor([[19, 22],
# [43, 50]])
ضرب المان در مقابل ماتریس:
# Element-wise multiplication using *
C_element = A * B
print("Element-wise Multiplication (A * B):\n", C_element)
# Output:
# tensor([[ 5, 12],
# [21, 32]])
2.4. بخش
تقسیم بندی عنصری:
تقسیم یک تانسور بر دیگری با همان شکل.
# Element-wise division
z = y / x
print("Division (y / x):", z) # Output: tensor([4., 5., 6.])
بخش مدیریت با صفر:
PyTorch تقسیم بر صفر را با بازگشت کنترل می کند inf
یا nan
.
# Creating tensors with zero
x = torch.tensor([1.0, 0.0, 3.0])
y = torch.tensor([4.0, 5.0, 6.0])
# Division
z = y / x
print("Division with Zero (y / x):", z) # Output: tensor([4.0000, inf, 2.0000])
3. عملیات در محل در مقابل عملیات خارج از محل
درک تفاوت بین عملیات در محل و خارج از محل برای مدیریت کارآمد حافظه و جلوگیری از عوارض جانبی ناخواسته، به ویژه در طول آموزش مدل، بسیار مهم است.
3.1. عملیات خارج از محل
تعریف:
عملیات خارج از محل یک تانسور جدید بدون تغییر تانسورهای اصلی درگیر در عملیات ایجاد می کند.
مثال:
x = torch.tensor([1, 2, 3], dtype=torch.float32)
y = torch.tensor([4, 5, 6], dtype=torch.float32)
# Out-of-place addition
z = x + y
print("Out-of-Place Addition (z = x + y):", z) # Output: tensor([5., 7., 9.])
print("Original x:", x) # x remains unchanged
# Output: tensor([1., 2., 3.])
3.2. عملیات در محل
تعریف:
عملیات درجا مستقیماً تانسور اصلی را اصلاح میکند و با ایجاد نکردن تانسور جدید، حافظه را ذخیره میکند.
نحو:
در PyTorch، عملیات در محل با زیرخط (_
) در انتهای نام متد.
مثال:
x = torch.tensor([1, 2, 3], dtype=torch.float32)
# In-place addition
x.add_(2)
print("In-Place Addition (x.add_(2)):", x) # Output: tensor([3., 4., 5.])
مزایا:
- کارایی حافظه: با اجتناب از ایجاد تانسورهای جدید، استفاده از حافظه را کاهش می دهد.
- عملکرد: می تواند منجر به محاسبات سریعتر در سناریوهای خاص شود.
معایب:
- عوارض جانبی بالقوه: تانسور اصلی را اصلاح می کند، که در صورت استفاده از تانسور اصلی در جای دیگری می تواند منجر به عواقب ناخواسته شود.
- مفاهیم Autograd: عملیات در محل می تواند با محاسبات گرادیان تداخل داشته باشد، به خصوص اگر تانسور در نمودار محاسباتی درگیر باشد.
3.3. چه زمانی از کدام استفاده کنیم
احتیاط: هنگام استفاده از عملیات در محل، به ویژه هنگام کار با تانسورهایی که نیاز به گرادیان دارند، همیشه مراقب باشید. اگر مقادیر مورد نیاز برای محاسبه گرادیان را بازنویسی کنند، تغییرات در محل میتوانند منجر به خطا در حین انتشار پسانداز شوند.
4. فعالیت های عملی
برای تقویت درک خود از عملیات تانسور، در تمرینات عملی زیر شرکت کنید.
4.1. آزمایش با عملیات پایه
هدف: انجام و مشاهده اثرات عملیات پایه تانسور.
مراحل:
-
ایجاد دو تانسور:
import torch # Creating tensors x = torch.tensor([10, 20, 30], dtype=torch.float32) y = torch.tensor([1, 2, 3], dtype=torch.float32)
-
انجام عملیات حسابی:
# Addition add = x + y print("Addition:", add) # Output: tensor([11., 22., 33.]) # Subtraction subtract = x - y print("Subtraction:", subtract) # Output: tensor([ 9., 18., 27.]) # Multiplication multiply = x * y print("Multiplication:", multiply) # Output: tensor([10., 40., 90.]) # Division divide = x / y print("Division:", divide) # Output: tensor([10., 10., 10.])
-
ضرب ماتریس:
# Creating matrices A = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32) B = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32) # Matrix multiplication using torch.mm C = torch.mm(A, B) print("Matrix Multiplication (A.mm(B)):\n", C) # Output: # tensor([[19., 22.], # [43., 50.]])
4.2. درک عملیات در محل
هدف: بین عملیات در محل و خارج از محل تفاوت قائل شوید و اثرات آنها را درک کنید.
مراحل:
-
مثال عملیات خارج از محل:
x = torch.tensor([1, 2, 3], dtype=torch.float32) y = torch.tensor([4, 5, 6], dtype=torch.float32) # Out-of-place addition z = x + y print("Out-of-Place Addition (z = x + y):", z) # Output: tensor([5., 7., 9.]) print("Original x:", x) # Output: tensor([1., 2., 3.])
-
مثال عملیات در محل:
x = torch.tensor([1, 2, 3], dtype=torch.float32) # In-place addition x.add_(5) print("In-Place Addition (x.add_(5)):", x) # Output: tensor([6., 7., 8.])
-
مفاهیم Autograd:
# Creating tensors with requires_grad=True a = torch.tensor([2.0, 3.0], requires_grad=True) b = torch.tensor([4.0, 5.0], requires_grad=True) # Out-of-place operation c = a + b print("c (Out-of-Place):", c) # Output: tensor([6., 8.], grad_fn=
) # In-place operation a.add_(1) print("a after In-Place Addition:", a) # Output: tensor([3., 4.], requires_grad=True) # Attempting backward pass try: c.backward(torch.tensor([1.0, 1.0])) except RuntimeError as e: print("Error during backward pass:", e)توضیح:
عملیات در محل تانسور را اصلاح می کندa
، که بخشی از نمودار محاسباتی برایc
. این می تواند محاسبات گرادیان را مختل کند، که منجر به خطا در هنگام عبور به عقب می شود.
4.3. ترکیب عملیات
هدف: چندین عملیات تانسور را برای انجام محاسبات پیچیده ترکیب کنید.
مراحل:
-
عملیات زنجیره ای:
x = torch.tensor([1, 2, 3, 4], dtype=torch.float32) y = torch.tensor([5, 6, 7, 8], dtype=torch.float32) # Chain of operations: ((x + y) * x) / y z = ((x + y) * x) / y print("Chained Operations:", z) # Output: tensor([ 1.2000, 2.3333, 3.5000, 4.8000])
-
استفاده از توابع داخلی:
# Element-wise square z = x.pow(2) print("Element-wise Square:", z) # Output: tensor([ 1., 4., 9., 16.]) # Element-wise exponential z = x.exp() print("Element-wise Exponential:", z) # Output: tensor([ 2.7183, 7.3891, 20.0855, 54.5982])
-
اعمال عملیات در محل در زنجیره:
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True) # In-place multiplication x.mul_(2) print("In-Place Multiplication (x.mul_(2)):", x) # Output: tensor([2., 4., 6.], requires_grad=True) # Computing loss loss = x.sum() loss.backward() print("Gradients:", x.grad) # Output: tensor([1., 1., 1.])
توجه: در مورد عملیات در محل محتاط باشید زیرا می توانند مقادیر مورد نیاز برای محاسبه گرادیان را بازنویسی کنند.
5. منابع
درک خود را با منابع زیر تقویت کنید:
-
اسناد و راهنماهای رسمی:
-
کتاب و مطالب خواندنی:
- “یادگیری عمیق با PyTorch” توسط الی استیونز، لوکا آنتیگا و توماس ویهمان: بینشها و پروژههای عملی.
- “برنامه نویسی PyTorch برای یادگیری عمیق” توسط Ian Pointer: راهنمای استفاده از PyTorch برای وظایف یادگیری عمیق.
- “شبکه های عصبی و یادگیری عمیق” توسط مایکل نیلسن: در دسترس آنلاین.
-
دوره ها و سخنرانی های آنلاین:
-
انجمن و پشتیبانی:
-
ابزارها و برنامه های افزودنی:
- تجسم:
- بهینه سازی عملکرد:
- اشکال زدایی و پروفایل:
6. اهداف آموزشی
تا پایان روز 3، شما باید بتوانید:
-
انجام عملیات پایه تانسور:
- جمع، تفریق، ضرب و تقسیم بر حسب عنصر را اجرا کنید.
- درک و اعمال ضرب ماتریس و عملیات عنصری.
-
تمایز بین عملیات در محل و خارج از محل:
- تفاوت های نحوی را بشناسید.
- مفاهیم هر نوع بر روی حافظه و محاسبات گرادیان را درک کنید.
-
اعمال عملیات پیشرفته:
- عملیات تانسور چندگانه زنجیره ای
- از توابع داخلی PyTorch برای محاسبات پیچیده استفاده کنید.
-
مدیریت ویژگی های تانسور در طول عملیات:
- قبل از انجام عملیات، مطمئن شوید که تانسورها روی دستگاه صحیح (CPU/GPU) قرار دارند.
- تبدیل نوع داده را به طور موثر مدیریت کنید.
7. نتایج مورد انتظار
در پایان روز 3، شما خواهید داشت:
- تسلط بر عملیات پایه تانسور: تانسورها را با استفاده از جمع، تفریق، ضرب و تقسیم به خوبی اجرا و دستکاری کنید.
- درک انواع عملیات: درک روشنی از عملیات در محل در مقابل عملیات خارج از محل و موارد استفاده مناسب از آنها.
- مهارت های محاسباتی پیشرفته: توانایی ترکیب چندین عملیات برای انجام محاسبات پیچیده ضروری برای آموزش شبکه عصبی.
- آماده برای موضوعات پیشرفته: پایه ای محکم در دستکاری های تانسور، راه را برای کاوش های عمیق تر در معماری شبکه های عصبی و مکانیسم های آموزشی هموار می کند.
8. نکاتی برای موفقیت
- تمرین عملی: به همراه مثال های ارائه شده به صورت فعال کدنویسی کنید. تکرار کد درک شما را تقویت می کند.
- آزمایش: قطعه کد را تغییر دهید تا نتایج متفاوتی را مشاهده کنید. برای بررسی سناریوهای مختلف، مقادیر تانسور، اشکال و انواع داده را تغییر دهید.
- تجسم نتایج: از عبارات چاپی یا ابزارهای تجسم برای مشاهده نتایج عملیات تانسور خود استفاده کنید.
- آموخته های خود را مستند کنید: یک دفترچه یادداشت یا سند دیجیتالی برای ثبت مفاهیم کلیدی، تکه کدها و اطلاعات بینش نگه دارید.
- وقتی گیر کرده اید کمک بخواهید: از انجمن ها و منابع انجمن برای حل هر گونه چالشی که با آن روبرو می شوید استفاده کنید.
9. نکات پیشرفته و بهترین شیوه ها
-
اهرم شتاب GPU:
- **Ensure All Tensors Are on the Same Device:** Prevent runtime errors by maintaining consistency in tensor devices.
-
مدیریت کارآمد حافظه:
- از عملیات در محل به میزان کم استفاده کنید: در حالی که آنها حافظه را ذخیره می کنند، می توانند نمودار محاسباتی را پیچیده کنند.
-
تانسورها را در صورت لزوم جدا کنید:
y = z.detach()
جدا کردن تانسور آن را از نمودار محاسباتی حذف می کند و از محاسبات گرادیان جلوگیری می کند.
-
اجتناب از دام های رایج:
- قوانین پخش را بشناسید: از سازگاری ابعاد تانسور برای جلوگیری از نتایج غیرمنتظره اطمینان حاصل کنید.
-
مدیریت ردیابی گرادیان: محتاط باشید با
requires_grad=True
برای مدیریت اینکه کدام تانسورها باید گرادیان ها را ردیابی کنند.
-
بهینه سازی عملکرد:
- عملیات دسته ای: برای استفاده از محاسبات موازی، عملیات را روی دستهای از دادهها انجام دهید.
- به حداقل رساندن انتقال داده ها: تعداد دفعاتی که تانسورها بین CPU و GPU جابه جا می شوند را کاهش دهید تا عملکرد را افزایش دهید.
-
خوانایی و نگهداری کد:
- از نام های متغیر توصیفی استفاده کنید: وضوح کد را با نامگذاری معنی دار تانسورها افزایش دهید.
- مدولار کردن کد: عملیات پیچیده را به عملکردهای کوچکتر و قابل استفاده مجدد تقسیم کنید.
-
ادغام با سایر کتابخانه ها:
-
تبدیل یکپارچه بین PyTorch و NumPy:
# From Tensor to NumPy np_array = x.cpu().numpy() # From NumPy to Tensor tensor_from_np = torch.from_numpy(np_array).to(device)
-
- **Interoperability with Pandas:**
```python
import pandas as pd
df = pd.DataFrame(np_array)
tensor_from_df = torch.tensor(df.values).to(device)
```
-
استفاده از توابع داخلی:
-
توابع تجمع:
torch.sum
،torch.mean
،torch.max
و غیره -
عملیات آماری:
torch.std
،torch.var
و غیره -
مثال:
x = torch.tensor([1.0, 2.0, 3.0, 4.0]) total = torch.sum(x) average = torch.mean(x) maximum = torch.max(x) print("Sum:", total, "Mean:", average, "Max:", maximum)
-
توابع تجمع:
-
اجرای عملیات سفارشی:
- گسترش عملکرد PyTorch: در صورت نیاز توابع سفارشی را برای دستکاری های تخصصی تانسور ایجاد کنید.
10. خلاصه جامع
امروز، شما به دنیای ضروری کاوش کرده اید عملیات تانسور در PyTorch. در اینجا خلاصه ای از آنچه را پوشش داده ایم آورده ایم:
این درک جامع از عملیات تانسور، پایه ای محکم برای ساخت و آموزش شبکه های عصبی، پیش پردازش داده ها، و وظایف یادگیری عمیق پیشرفته تر ایجاد می کند.
11. حرکت رو به جلو
با درک قوی از عملیات تانسور، اکنون آماده هستید تا به مؤلفه حیاتی بعدی PyTorch بروید: Autograd و تمایز خودکار. این به شما امکان می دهد تا نحوه محاسبه گرادیان ها را که برای آموزش شبکه های عصبی اساسی است، درک کنید.
موضوعات آینده:
- روز 4: PyTorch Autograd و تمایز خودکار
-
روز پنجم: ساخت شبکه های عصبی با
torch.nn
-
روز ششم: بارگذاری و پیش پردازش داده ها با
torch.utils.data
- روز هفتم: حلقه های آموزشی و استراتژی های بهینه سازی
متعهد بمانید، به تمرین ادامه دهید و برای کاوش عمیق تر در مکانیک هایی که مدل های یادگیری عمیق را قدرتمند می کند آماده شوید!
12. تشویق نهایی
تبریک بابت تکمیل روز 3 از سفر استادی PyTorch شما! شما گامهای مهمی در درک و دستکاری تانسورها برداشتهاید، همان پایهای که مدلهای یادگیری عمیق بر آن ساخته شدهاند. به یاد داشته باشید، ثبات کلیدی است – به تمرین، آزمایش و کشف قابلیتهای گسترده PyTorch ادامه دهید.
چالش ها را به عنوان فرصت هایی برای یادگیری و رشد در آغوش بگیرید. از منابع و جوامعی که در دسترس شماست استفاده کنید و در صورت نیاز در جستجوی کمک دریغ نکنید. فداکاری و تلاش شما راه را برای تسلط بر یادگیری عمیق و هوش مصنوعی هموار می کند.
به کار عالی ادامه دهید و بیایید این سفر هیجان انگیز را با هم ادامه دهیم!
📄 ضمیمه
نمونه قطعه کد
برای تقویت یادگیری خود، در اینجا چند قطعه کد نمونه وجود دارد که مفاهیم مورد بحث امروز را در بر می گیرد.
1. انجام عملیات پایه تانسور
import torch
# Creating tensors
x = torch.tensor([10, 20, 30], dtype=torch.float32)
y = torch.tensor([1, 2, 3], dtype=torch.float32)
# Addition
add = x + y
print("Addition:", add) # Output: tensor([11., 22., 33.])
# Subtraction
subtract = x - y
print("Subtraction:", subtract) # Output: tensor([ 9., 18., 27.])
# Multiplication
multiply = x * y
print("Multiplication:", multiply) # Output: tensor([10., 40., 90.])
# Division
divide = x / y
print("Division:", divide) # Output: tensor([10., 10., 10.])
2. عملیات در محل در مقابل عملیات خارج از محل
import torch
# Out-of-Place Operation
x = torch.tensor([1, 2, 3], dtype=torch.float32)
y = torch.tensor([4, 5, 6], dtype=torch.float32)
z = x + y
print("Out-of-Place Addition (z = x + y):", z) # Output: tensor([5., 7., 9.])
print("Original x:", x) # Output: tensor([1., 2., 3.])
# In-Place Operation
x.add_(5)
print("In-Place Addition (x.add_(5)):", x) # Output: tensor([6., 7., 8.])
3. ضرب ماتریس
import torch
# Creating matrices
A = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
B = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)
# Matrix multiplication using torch.mm
C = torch.mm(A, B)
print("Matrix Multiplication (A.mm(B)):\n", C)
# Output:
# tensor([[19., 22.],
# [43., 50.]])
4. مثال پخش
import torch
# Creating tensors with different shapes
x = torch.ones(3, 1)
y = torch.ones(1, 4)
# Broadcasted addition
z = x + y
print("Broadcasted Addition (x + y):\n", z)
# Output:
# tensor([[2., 2., 2., 2.],
# [2., 2., 2., 2.],
# [2., 2., 2., 2.]])
5. دست زدن به بخش صفر
import torch
# Creating tensors with zero
x = torch.tensor([1.0, 0.0, 3.0])
y = torch.tensor([4.0, 5.0, 6.0])
# Division
z = y / x
print("Division with Zero (y / x):", z) # Output: tensor([4.0000, inf, 2.0000])
📌 سوالات متداول (سؤالات متداول)
Q1: تفاوت بین در محل چیست (add_()
) و خارج از محل (add()
) عملیات؟
A1:
-
عملیات خارج از محل (
add()
): اینها یک تانسور جدید بدون تغییر تانسورهای اصلی ایجاد می کنند.x = torch.tensor([1, 2, 3], dtype=torch.float32) y = torch.tensor([4, 5, 6], dtype=torch.float32) z = x + y # z is a new tensor
-
عملیات در محل (
add_()
): اینها مستقیماً تانسور اصلی را تغییر می دهند و با ایجاد نکردن تانسور جدید در حافظه صرفه جویی می کنند.x = torch.tensor([1, 2, 3], dtype=torch.float32) x.add_(5) # x is modified to [6, 7, 8]
Q2: آیا عملیات در محل می تواند با محاسبات گرادیان در autograd تداخل داشته باشد؟
A2: بله. عملیات در محل می تواند مقادیر مورد نیاز برای محاسبات گرادیان را بازنویسی کند، که منجر به خطا در طول انتشار پس زمینه می شود. ضروری است که از عملیات در محل با احتیاط استفاده کنید، به خصوص در مورد تانسورهایی که دارند requires_grad=True
.
Q3: پخش در PyTorch چگونه کار می کند؟
A3: پخش به PyTorch اجازه می دهد تا با گسترش خودکار تانسور کوچکتر برای مطابقت با شکل تانسور بزرگتر، عملیات روی تانسورهای اشکال مختلف را انجام دهد. ابعاد باید با رعایت قوانین خاص سازگار باشند:
- اگر تانسورها دارای ابعاد متفاوتی هستند، شکل تانسور کوچکتر را با یکها وصل کنید تا هر دو شکل طول یکسانی داشته باشند.
- برای هر بعد، اندازه ها یا باید برابر باشند یا یکی از آنها باید یکی باشد.
Q4: چگونه یک تانسور را به آرایه NumPy تبدیل کنم و بالعکس؟
A4:
-
تانسور به NumPy:
x = torch.tensor([1, 2, 3], dtype=torch.float32) np_array = x.numpy()
-
NumPy به Tensor:
import numpy as np np_array = np.array([4, 5, 6]) x = torch.from_numpy(np_array)
توجه: تانسور و آرایه NumPy حافظه یکسانی دارند. اصلاح یکی بر دیگری تأثیر می گذارد.
Q5: اگر یک عملیات در محل روی تانسوری انجام دهم که به گرادیان نیاز دارد، چه اتفاقی میافتد؟
A5: انجام عملیات در محل بر روی تانسورهایی که به گرادیان نیاز دارند، میتواند نمودار محاسباتی را مختل کند و منجر به خطاهای زمان اجرا در طول گذر به عقب شود. به عنوان مثال:
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x * 2
x.add_(1) # In-place operation
z = y.sum()
z.backward() # This will raise an error
پیغام خطا:
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
🧠 Deep Dive: Understanding Broadcasting
پخش یک ویژگی قدرتمند است که به PyTorch اجازه می دهد تا عملیات را روی تانسورهای اشکال مختلف به طور موثر انجام دهد. در اینجا یک نگاه دقیق تر است:
قوانین پخش:
- ** با شروع از ابعاد انتهایی (یعنی سمت راست)، اندازه هر بعد را بین دو تانسور مقایسه کنید.
- **اگر ابعاد مساوی باشد یا یکی از آنها 1 باشد، تانسورها برای پخش سازگار هستند.
- **اگر تانسورها دارای ابعاد متفاوتی هستند، شکل تانسور کوچکتر را با تانسورهایی که طول هر دو یکسان باشد، قرار دهید.
مثال:
import torch
# Tensor A: shape (3, 1)
A = torch.tensor([[1], [2], [3]], dtype=torch.float32)
# Tensor B: shape (1, 4)
B = torch.tensor([[4, 5, 6, 7]], dtype=torch.float32)
# Broadcasting A and B to shape (3, 4)
C = A + B
print("Broadcasted Addition (A + B):\n", C)
# Output:
# tensor([[5., 6., 7., 8.],
# [6., 7., 8., 9.],
# [7., 8., 9., 10.]])
توضیح:
- تانسور A با تکرار ستون تک آن در چهار ستون به (3، 4) تغییر شکل مییابد.
- تانسور B با تکرار یک ردیف آن در سه ردیف به (3، 4) تغییر شکل مییابد.
- افزودن به صورت عنصر بر روی تانسورهای پخش شده انجام می شود.
📝 تمرین تمرین: اجرای پخش سفارشی
هدف: یک تابع سفارشی که رفتار پخش PyTorch را برای اضافه کردن تقلید می کند، پیاده سازی کنید.
مراحل:
-
تعریف تابع:
import torch def custom_broadcast_add(x, y): """ Adds two tensors with broadcasting. """ # Get the shapes x_shape = x.shape y_shape = y.shape # Determine the maximum number of dimensions max_dims = max(len(x_shape), len(y_shape)) # Prepend ones to the shape of the smaller tensor x_shape = (1,) * (max_dims - len(x_shape)) + x_shape y_shape = (1,) * (max_dims - len(y_shape)) + y_shape # Compute the broadcasted shape broadcast_shape = [] for x_dim, y_dim in zip(x_shape, y_shape): if x_dim == y_dim: broadcast_shape.append(x_dim) elif x_dim == 1: broadcast_shape.append(y_dim) elif y_dim == 1: broadcast_shape.append(x_dim) else: raise ValueError("Shapes are not compatible for broadcasting.") # Expand tensors to the broadcasted shape x_expanded = x.view(x_shape).expand(*broadcast_shape) y_expanded = y.view(y_shape).expand(*broadcast_shape) # Perform element-wise addition return x_expanded + y_expanded
-
تست تابع:
# Creating tensors A = torch.tensor([[1], [2], [3]], dtype=torch.float32) # Shape: (3,1) B = torch.tensor([4, 5, 6, 7], dtype=torch.float32) # Shape: (4,) # Using custom broadcasting addition C = custom_broadcast_add(A, B) print("Custom Broadcasted Addition (A + B):\n", C) # Output: # tensor([[5., 6., 7., 8.], # [6., 7., 8., 9.], # [7., 8., 9., 10.]])
-
مقایسه با پخش PyTorch:
# Using PyTorch's built-in broadcasting C_pytorch = A + B print("PyTorch Broadcasted Addition (A + B):\n", C_pytorch) # Output should match the custom implementation
نتیجه:
هم عملکرد سفارشی و هم پخش داخلی PyTorch نتیجه یکسانی را ایجاد می کنند و درک مکانیک پخش را نشان می دهند.
📌 سوالات متداول (سؤالات متداول)
Q1: چرا برخی از عملیات تانسور نیاز به یک شکل تانسور دارند؟
A1: عملیات عنصری مانند جمع، تفریق، ضرب و تقسیم نیاز به تانسورها دارند که شکل یکسانی داشته باشند تا اطمینان حاصل شود که هر عنصر مربوطه به درستی عمل میکند. هنگامی که تانسورها دارای اشکال مختلف هستند، قوانین پخش برای سازگاری شکل آنها اعمال می شود.
Q2: اهمیت خط زیر چیست (_
) در عملیات در محل؟
A2: در PyTorch، متدهایی که عملیات در محل را انجام می دهند دارای خط زیر هستند (_
) پسوند. این قرارداد نشان میدهد که این عملیات تانسور را در جای خود تغییر میدهد و دادههای آن را مستقیماً به جای ایجاد یک تانسور جدید تغییر میدهد.
Q3: آیا عملیات در محل می تواند بر نمودار محاسباتی مورد استفاده برای autograd تأثیر بگذارد؟
A3: بله. عملیات در محل میتواند مقادیری را که برای محاسبه گرادیانها در طول انتشار پسپخش لازم است، بازنویسی کند و منجر به خطا شود. ضروری است که از عملیات در محل با احتیاط استفاده کنید، به خصوص در مورد تانسورهایی که دارند requires_grad=True
.
Q4: PyTorch چگونه عملیات روی تانسورها را با انواع داده های مختلف مدیریت می کند؟
A4: PyTorch بر اساس سلسله مراتبی از انواع داده، ارسال خودکار نوع را انجام می دهد. اگر تانسورها انواع دادههای متفاوتی داشته باشند، PyTorch برای جلوگیری از از دست رفتن اطلاعات به نوع با دقت بالاتر ارسال میشود. با این حال، برای جلوگیری از رفتارهای غیرمنتظره، تمرین خوب این است که قبل از انجام عملیات از نوع داده تانسورها یکسان باشند.
Q5: اگر بخواهم تانسورهایی با اشکال ناسازگار اضافه کنم چه اتفاقی می افتد؟
A5: PyTorch یک را افزایش می دهد RuntimeError
نشان می دهد که اشکال برای پخش سازگار نیستند. برای حل این مشکل، مطمئن شوید که اشکال تانسور به قوانین پخش پایبند هستند یا به صورت دستی تانسورها را به اشکال سازگار تغییر شکل دهید.
💡 Deep Dive: درک مفاهیم گرادیان عملیات در محل
هنگام آموزش شبکه های عصبی، گرادیان ها برای به روز رسانی پارامترهای مدل ضروری هستند. عملیات در محل می تواند با محاسبات گرادیان تداخل داشته باشد، به خصوص اگر تانسورهایی را که بخشی از نمودار محاسباتی هستند تغییر دهند.
مثالی از تداخل گرادیان:
import torch
# Creating a tensor with requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)
# Performing an in-place operation
x.add_(1)
# Defining a simple operation
y = x * 2
# Computing gradients
y.sum().backward()
print("Gradients:", x.grad)
خروجی:
Gradients: tensor([2., 2.])
توضیح:
- افزودن در محل تغییر می کند
x
قبل ازy
محاسبه می شود. - PyTorch در این مورد ساده گرادیان ها را با موفقیت محاسبه می کند.
- با این حال، عملیات پیچیده تر یا توالی عملیات در محل می تواند نمودار محاسباتی را مختل کند و منجر به خطا شود.
سناریوی مشکل ساز:
import torch
# Creating tensors with requires_grad=True
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x * 2
# In-place operation that modifies x
x.add_(1)
# Attempting to compute gradients
try:
y.backward(torch.tensor([1.0, 1.0, 1.0]))
except RuntimeError as e:
print("Error:", e)
خروجی:
Error: one of the variables needed for gradient computation has been modified by an inplace operation
راه حل:
از انجام عملیات در محل روی تانسورهایی که بخشی از نمودار محاسباتی هستند خودداری کنید. در صورت لزوم، از عملیات خارج از محل استفاده کنید یا اطمینان حاصل کنید که تغییرات در محل در محاسبات گرادیان تداخلی ایجاد نمی کند.
🧩 امتیاز: تجسم عملیات تانسور
تجسم عملیات تانسور می تواند بینش بصری در مورد نحوه جریان داده ها از طریق محاسبات ارائه دهد.
استفاده از Matplotlib برای تجسم:
import torch
import matplotlib.pyplot as plt
# Creating tensors
x = torch.linspace(0, 10, steps=100)
y = torch.sin(x)
# Performing operations
y_squared = y.pow(2)
y_exp = y.exp()
# Plotting
plt.figure(figsize=(10, 6))
plt.plot(x.numpy(), y.numpy(), label='sin(x)')
plt.plot(x.numpy(), y_squared.numpy(), label='sin^2(x)')
plt.plot(x.numpy(), y_exp.numpy(), label='exp(sin(x))')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Tensor Operations Visualization')
plt.legend()
plt.grid(True)
plt.show()
نتیجه:
نموداری که موج سینوسی اصلی، مربع آن و نمایی موج سینوسی را نشان میدهد و نشان میدهد که چگونه عملیات تانسور دادهها را تبدیل میکند.
📌 سوالات متداول (FAQ) ادامه دارد
Q6: چگونه می توانم از تأثیر عملیات در محل بر نمودار محاسباتی من جلوگیری کنم؟
A6:
-
از انجام عملیات در محل روی تانسورها با
requires_grad=True
: هنگام کار با تانسورهایی که به گرادیان نیاز دارند، به عملیات خارج از محل خود پایبند باشید. -
کلون تانسورها قبل از عملیات در محل: اگر باید عملیات در محل انجام دهید، تانسور را برای ایجاد یک کپی جداگانه کلون کنید.
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True) x_clone = x.clone() x_clone.add_(1) # Safe in-place operation on the clone
-
به جای آن از عملیات غیر در محل استفاده کنید: برای حفظ یکپارچگی نمودار محاسباتی، عملیات در محل را با همتایان خارج از محل خود جایگزین کنید.
Q7: آیا می توانم عملیات روی تانسورهای انواع داده های مختلف انجام دهم؟
A7: بله، PyTorch به طور خودکار تانسورها را بر اساس یک سلسله مراتب از پیش تعریف شده به یک نوع داده معمولی میفرستد تا از از دست رفتن داده جلوگیری کند. با این حال، برای وضوح و جلوگیری از رفتارهای ناخواسته، توصیه میشود قبل از انجام عملیات از نوع داده تانسورها اطمینان حاصل کنید.
Q8: برخی از اشتباهات متداول که باید هنگام انجام عملیات تانسور اجتناب شود چیست؟
A8:
- اشکال تانسور نامتناسب: اطمینان حاصل کنید که تانسورها برای عملیات مورد نظر سازگار هستند، در صورت لزوم از پخش اهرمی استفاده کنید.
- استفاده نادرست از عملیات در محل: برای جلوگیری از خطاهای محاسباتی گرادیان، از تغییرات در محل روی تانسورها که بخشی از نمودار محاسباتی هستند، خودداری کنید.
- نادیده گرفتن سازگاری دستگاه: همیشه قبل از انجام عملیات، مطمئن شوید که تانسورها روی یک دستگاه (CPU/GPU) قرار دارند تا از خطاهای زمان اجرا جلوگیری کنید.
- نادیده گرفتن انواع داده ها: مراقب انواع داده های تانسور باشید تا از ریخته گری غیرمنتظره یا از دست دادن دقت در حین عملیات جلوگیری کنید.
🏁 افکار نهایی
امروز نقطه عطف مهمی در سفر PyTorch شما به عنوان استاد شما است عملیات تانسور– سنگ بنای همه محاسبات در یادگیری عمیق. با درک هر دو جنبه اساسی و پیشرفته دستکاری های تانسور، اکنون به خوبی برای انجام محاسبات پیچیده مورد نیاز برای ساخت و آموزش شبکه های عصبی مجهز شده اید.
به یاد داشته باشید، کلید تسلط در تمرین و کاوش مداوم نهفته است. خود را با تمرینهای متنوع به چالش بکشید، عملیاتهای مختلف را آزمایش کنید و همیشه سعی کنید «چرا» پشت هر محاسبات را درک کنید. همانطور که پیشرفت می کنید، این عملیات تانسور به ماهیت دوم تبدیل می شوند و به شما این امکان را می دهند که با اعتماد به نفس و کارایی به انجام وظایف پیچیده تر یادگیری عمیق بپردازید.
کنجکاو بمانید، به کدنویسی ادامه دهید و برای کاوش عمیق تر در دنیای شگفت انگیز آماده شوید Autograd و تمایز خودکار در روزهای آینده!