Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .translate/state/jax_intro.md.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
source-sha: 11e7d823f7f355f5025d40cab40bf801b3262e56
synced-at: "2026-04-13"
source-sha: 450bafecd23db638602150b47f4272b98aad3146
synced-at: "2026-04-14"
model: claude-sonnet-4-6
mode: UPDATE
section-count: 7
Expand Down
4 changes: 2 additions & 2 deletions .translate/state/numpy_vs_numba_vs_jax.md.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
source-sha: 11e7d823f7f355f5025d40cab40bf801b3262e56
synced-at: "2026-04-13"
source-sha: 450bafecd23db638602150b47f4272b98aad3146
synced-at: "2026-04-14"
model: claude-sonnet-4-6
mode: UPDATE
section-count: 3
Expand Down
173 changes: 61 additions & 112 deletions lectures/jax_intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ translation:
Functional Programming::Examples: مثال‌ها
Functional Programming::Why Functional Programming?: چرا برنامه‌نویسی تابعی؟
Random numbers: اعداد تصادفی
Random numbers::Random number generation: تولید اعداد تصادفی
Random numbers::Why explicit random state?: چرا وضعیت تصادفی صریح؟
Random numbers::Why explicit random state?::NumPy's approach: رویکرد NumPy
Random numbers::Why explicit random state?::JAX's approach: رویکرد JAX
Random numbers::NumPy / MATLAB Approach: رویکرد NumPy / MATLAB
Random numbers::JAX: JAX
Random numbers::Benefits: مزایا
JIT Compilation: کامپایل JIT
JIT Compilation::With NumPy: با NumPy
JIT Compilation::With JAX: با JAX
Expand Down Expand Up @@ -416,15 +415,31 @@ JAX از سبک برنامه‌نویسی تابعی استفاده می‌کن

## اعداد تصادفی

اعداد تصادفی در JAX نسبت به آنچه در NumPy یا Matlab می‌یابید بسیار متفاوت هستند.
اعداد تصادفی در JAX نسبت به آنچه در NumPy یا MATLAB می‌یابید بسیار متفاوت هستند.

در ابتدا ممکن است نحو را نسبتاً مفصل بیابید.
### رویکرد NumPy / MATLAB

اما به زودی متوجه خواهید شد که نحو و معناشناسی برای حفظ سبک برنامه‌نویسی تابعی که به تازگی مورد بحث قرار دادیم، ضروری است.
در NumPy / MATLAB، تولید اعداد تصادفی با حفظ وضعیت سراسری پنهان کار می‌کند.

علاوه بر این، کنترل کامل وضعیت تصادفی برای برنامه‌نویسی موازی، مانند زمانی که می‌خواهیم آزمایش‌های مستقل را در چندین رشته اجرا کنیم، ضروری است.
```{code-cell} ipython3
np.random.seed(42)
print(np.random.randn(2))
```

هر بار که یک تابع تصادفی را فراخوانی می‌کنیم، وضعیت پنهان به‌روزرسانی می‌شود:

```{code-cell} ipython3
print(np.random.randn(2))
```

این تابع *خالص نیست* زیرا:

### تولید اعداد تصادفی
* غیرقطعی است: ورودی‌های یکسان، خروجی‌های متفاوت
* دارای عوارض جانبی است: وضعیت مولد اعداد تصادفی سراسری را تغییر می‌دهد

در موازی‌سازی خطرناک است --- باید با دقت کنترل کرد که در هر رشته چه اتفاقی می‌افتد!

### JAX

در JAX، وضعیت مولد اعداد تصادفی به صورت صریح کنترل می‌شود.

Expand Down Expand Up @@ -545,119 +560,48 @@ def gen_random_matrices(key, n=2, k=3):
key, subkey = jax.random.split(key)
A = jax.random.uniform(subkey, (n, n))
matrices.append(A)
print(A)
return matrices
```

```{code-cell} ipython3
seed = 42
key = jax.random.key(seed)
matrices = gen_random_matrices(key)
```

همچنین می‌توانیم هنگام تکرار در یک حلقه از `fold_in` استفاده کنیم:

```{code-cell} ipython3
def gen_random_matrices(key, n=2, k=3):
matrices = []
for i in range(k):
step_key = jax.random.fold_in(key, i)
A = jax.random.uniform(step_key, (n, n))
matrices.append(A)
print(A)
return matrices
```

```{code-cell} ipython3
key = jax.random.key(seed)
matrices = gen_random_matrices(key)
```

### چرا وضعیت تصادفی صریح؟

چرا JAX به این رویکرد نسبتاً مفصل برای تولید اعداد تصادفی نیاز دارد؟

یکی از دلایل حفظ توابع خالص است.

بیایید ببینیم که چگونه تولید اعداد تصادفی با توابع خالص با مقایسه NumPy و JAX مرتبط است.

#### رویکرد NumPy

در NumPy، تولید اعداد تصادفی با حفظ وضعیت سراسری پنهان کار می‌کند.

هر بار که یک تابع تصادفی را فراخوانی می‌کنیم، این وضعیت به‌روزرسانی می‌شود:

```{code-cell} ipython3
np.random.seed(42)
print(np.random.randn()) # Updates state of random number generator
print(np.random.randn()) # Updates state of random number generator
gen_random_matrices(key)
```

هر فراخوانی یک مقدار متفاوت را برمی‌گرداند، حتی اگر ما همان تابع را با همان ورودی‌ها (بدون آرگومان، در این مورد) فراخوانی می‌کنیم.
این تابع *خالص* است

این تابع *خالص نیست* زیرا:

* غیرقطعی است: ورودی‌های یکسان (در این مورد هیچ) خروجی‌های متفاوت می‌دهند
* دارای عوارض جانبی است: وضعیت مولد اعداد تصادفی سراسری را تغییر می‌دهد

#### رویکرد JAX

همانطور که در بالا دیدیم، JAX رویکرد متفاوتی اتخاذ می‌کند و تصادفی بودن را از طریق کلیدها صریح می‌کند.

برای مثال،

```{code-cell} ipython3
def random_sum_jax(key):
key1, key2 = jax.random.split(key)
x = jax.random.normal(key1)
y = jax.random.normal(key2)
return x + y
```

با همان کلید، همیشه نتیجه یکسانی دریافت می‌کنیم:

```{code-cell} ipython3
key = jax.random.key(42)
random_sum_jax(key)
```

```{code-cell} ipython3
random_sum_jax(key)
```

برای دریافت نمونه‌های جدید باید یک کلید جدید ارائه دهیم.

تابع `random_sum_jax` خالص است زیرا:

* قطعی است: کلید یکسان همیشه خروجی یکسان تولید می‌کند
* قطعی است: ورودی‌های یکسان، خروجی یکسان
* بدون عوارض جانبی: هیچ وضعیت پنهانی تغییر نمی‌کند

### مزایا

صریح بودن JAX مزایای قابل توجهی به همراه دارد:

* تکرارپذیری: با استفاده مجدد از کلیدها، تکرار نتایج آسان است
* موازی‌سازی: هر رشته می‌تواند کلید خاص خود را بدون تضاد داشته باشد
* اشکال‌زدایی: نبود وضعیت پنهان استدلال در مورد کد را آسان‌تر می‌کند
* موازی‌سازی: کنترل آنچه در رشته‌های جداگانه اتفاق می‌افتد
* اشکال‌زدایی: نبود وضعیت پنهان آزمایش کد را آسان‌تر می‌کند
* سازگاری با JIT: کامپایلر می‌تواند توابع خالص را به طور تهاجمی‌تری بهینه کند

نکته آخر در بخش بعدی گسترش داده می‌شود.

## کامپایل JIT

کامپایلر just-in-time (JIT) JAX اجرا را با تولید کد ماشین کارآمد که با هم اندازه وظیفه و هم سخت‌افزار متفاوت است، تسریع می‌کند.

ما قدرت کامپایلر JIT JAX را در ترکیب با سخت‌افزار موازی {ref}`در بالا <jax_speed>` مشاهده کردیم، هنگامی که `cos` را روی یک آرایه بزرگ اعمال کردیم.

بیایید همان کار را با یک تابع پیچیده‌تر امتحان کنیم:
در اینجا کامپایل JIT را برای توابع پیچیده‌تر بررسی می‌کنیم.

### با NumPy

ابتدا با NumPy امتحان خواهیم کرد، با استفاده از

```{code-cell}
def f(x):
y = np.cos(2 * x**2) + np.sqrt(np.abs(x)) + 2 * np.sin(x**4) - x**2
return y
```

### با NumPy

ابتدا با NumPy امتحان خواهیم کرد
بیایید با `x` بزرگ اجرا کنیم

```{code-cell}
n = 50_000_000
Expand All @@ -670,9 +614,17 @@ with qe.Timer():
y = f(x)
```

### با JAX
مدل اجرای **Eager**

* هر عملیات بلافاصله هنگامی که با آن مواجه می‌شود اجرا می‌شود و نتیجه آن را قبل از شروع عملیات بعدی مادی‌سازی می‌کند.

معایب

* موازی‌سازی حداقل
* ردپای حافظه سنگین --- آرایه‌های میانی زیادی تولید می‌کند
* خواندن/نوشتن حافظه زیاد

اکنون بیایید دوباره با JAX امتحان کنیم.
### با JAX

به عنوان اولین مرحله، `np` را در همه جا با `jnp` جایگزین می‌کنیم:

Expand Down Expand Up @@ -703,14 +655,15 @@ with qe.Timer():
jax.block_until_ready(y);
```

نتیجه مشابه مثال `cos` است --- JAX سریع‌تر است، به ویژه در
اجرای دوم پس از کامپایل JIT.
نتیجه مشابه مثال `cos` است --- JAX سریع‌تر است، به ویژه در اجرای دوم پس از کامپایل JIT.

علاوه بر این، با JAX، ترفند دیگری در آستین داریم --- می‌توانیم کل تابع را JIT-کامپایل کنیم، نه فقط عملیات‌های منفرد.
اما همچنان از اجرای eager استفاده می‌کنیم --- حافظه و خواندن/نوشتن زیاد.

### کامپایل کل تابع

کامپایلر just-in-time (JIT) JAX می‌تواند اجرا را در درون توابع با ادغام عملیات آرایه‌ای در یک هسته بهینه شده واحد تسریع کند.
خوشبختانه، با JAX، ترفند دیگری در آستین داریم --- می‌توانیم کل تابع را JIT-کامپایل کنیم، نه فقط عملیات‌های منفرد.

کامپایلر تمام عملیات آرایه‌ای را در یک هسته بهینه‌شده واحد ادغام می‌کند.

بیایید این را با تابع `f` امتحان کنیم:

Expand All @@ -734,9 +687,11 @@ with qe.Timer():
jax.block_until_ready(y);
```

زمان اجرا دوباره بهبود یافته است --- اکنون به این دلیل که تمام عملیات را ادغام کردیم و به کامپایلر اجازه دادیم به طور تهاجمی‌تری بهینه‌سازی کند.
زمان اجرا دوباره بهبود یافته است --- اکنون به این دلیل که تمام عملیات را ادغام کردیم.

برای مثال، کامپایلر می‌تواند چندین فراخوانی به شتاب‌دهنده سخت‌افزاری و ایجاد تعدادی آرایه میانی را حذف کند.
* بهینه‌سازی تهاجمی بر اساس کل دنباله محاسباتی
* حذف چندین فراخوانی به شتاب‌دهنده سخت‌افزاری
* عدم ایجاد آرایه‌های میانی

اتفاقاً، نحو رایج‌تر هنگام هدف قرار دادن یک تابع برای کامپایلر JIT این است

Expand All @@ -756,11 +711,9 @@ def f(x):

### کامپایل توابع غیرخالص

اکنون که دیدیم کامپایل JIT چقدر قدرتمند می‌تواند باشد، درک رابطه آن با توابع خالص مهم است.
در حالی که JAX معمولاً هنگام کامپایل توابع ناخالص خطا نمی‌دهد، اجرا غیرقابل پیش‌بینی می‌شود!

در حالی که JAX معمولاً هنگام کامپایل توابع ناخالص خطا نمی‌دهد، اجرا غیرقابل پیش‌بینی می‌شود.

در اینجا تصویری از این واقعیت با استفاده از متغیرهای سراسری آورده شده است:
در اینجا تصویری از این واقعیت آورده شده است:

```{code-cell} ipython3
a = 1 # global
Expand Down Expand Up @@ -840,17 +793,13 @@ for row in X:

با این حال، حلقه‌های Python کُند هستند و نمی‌توانند به‌طور کارآمد توسط JAX کامپایل یا موازی‌سازی شوند.

استفاده از `vmap` محاسبه را روی شتاب‌دهنده نگه می‌دارد و با سایر
تبدیل‌های JAX مانند `jit` و `grad` ترکیب می‌شود:
با استفاده از `vmap`، می‌توانیم از حلقه‌ها اجتناب کنیم و محاسبه را روی شتاب‌دهنده نگه داریم:

```{code-cell} ipython3
batch_mm_diff = jax.vmap(mm_diff)
batch_mm_diff(X)
batch_mm_diff = jax.vmap(mm_diff) # Create a new "vectorized" version
batch_mm_diff(X) # Apply to each row of X
Comment on lines +799 to +800
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

کامنت‌های اضافه‌شده در این بلوک کد (# Create a new "vectorized" version و # Apply to each row of X) انگلیسی هستند. برای نسخهٔ فارسی بهتر است این کامنت‌ها ترجمه شوند یا حذف شوند تا خوانایی یکدست بماند.

Suggested change
batch_mm_diff = jax.vmap(mm_diff) # Create a new "vectorized" version
batch_mm_diff(X) # Apply to each row of X
batch_mm_diff = jax.vmap(mm_diff) # ایجاد یک نسخهٔ «برداری‌شده» جدید
batch_mm_diff(X) # اعمال به هر سطرِ X

Copilot uses AI. Check for mistakes.
```

تابع `mm_diff` برای یک آرایه منفرد نوشته شده بود، و `vmap` به‌طور خودکار
آن را برای عمل سطربه‌سطر روی یک ماتریس ارتقا داد --- بدون حلقه، بدون تغییر شکل.

### ترکیب تبدیل‌ها

یکی از نقاط قوت JAX این است که تبدیل‌ها به‌طور طبیعی با هم ترکیب می‌شوند.
Expand Down
Loading
Loading