পাঠ ১২ · ২৫-এর মধ্যে · মডিউল ২

NumPy linalg — ম্যাট্রিক্স গণিত

NumPy linear algebra
৭ মিনিট পড়া মধ্যম · Intermediate NumPy কোডসহ

এই পাঠে যা শিখবেন

  • np.linalg কী এবং কেন এটা AI-র মেরুদণ্ড
  • Matrix multiplication — @, np.dot, np.matmul-এর পার্থক্য
  • Determinant, inverse, ও pseudo-inverse
  • solve() বনাম inv() — কোনটা কখন
  • Eigenvalue, eigenvector ও SVD
  • Norm — L1, L2, Frobenius

১ · np.linalg কী?

np.linalg — NumPy-র linear algebra subpackage। ভিতরে চলে দশকের পরিশ্রমে গড়া BLAS ও LAPACK — Fortran-এ লেখা, CPU-র cache & SIMD-এর জন্য hyper-optimized। PyTorch, TensorFlow, JAX — সবাই শেষমেশ এই দু'টি লাইব্রেরিকেই call করে।

AI-র সব heavy compute — neural network forward pass, gradient descent update, attention mechanism — এসবই matmul-এর সমষ্টি। তাই np.linalg ভাল করে জানা মানে — AI-র engine room চেনা।

Matmul shape rule

$A$-র shape $(m, k)$ এবং $B$-র shape $(k, n)$ হলে — $A B$-র shape $(m, n)$। ভেতরের মাত্রা দু'টি একই হতেই হবে; বাইরের দু'টি ফলাফলের shape। সংক্ষেপে: $(m, k) \cdot (k, n) \rightarrow (m, n)$।

২ · Matrix multiplication — @ , dot , matmul

Python ৩.৫+ থেকে @ operator এসেছে শুধু matrix multiplication-এর জন্য। তার আগে np.dot বা np.matmul ব্যবহার হতো।

গণিতে matmulMatrix Multiplicationদু'টি ম্যাট্রিক্সের গুণ — প্রথমটির row × দ্বিতীয়টির column-এর dot product। শুধু সংখ্যা গুণ নয় — geometric transformation-এর composition। Neural network-এর প্রতিটি layer একটি matmul + activation। ভেক্টর-ভেক্টর dot product-এর সাধারণীকরণ:

$$(A B)_{ij} = \sum_{k=1}^{K} A_{ik} \, B_{kj}$$

পার্থক্য:

  • A @ B — সবচেয়ে readable, Python ৩.৫+।
  • np.matmul(A, B) — @-র সমার্থক, broadcasting-aware (batch matmul-এ ভাল)।
  • np.dot(A, B) — পুরোনো API; ১-D ভেক্টরে inner product, ২-D-তে matmul, কিন্তু ৩-D+ এ অন্যরকম behavior — confusion-এর কারণ।
ম্যাট্রিক্সকে ভাবুন transformation হিসেবে — একটি ভেক্টরকে ঘোরায়, scale করে, project করে। দু'টি ম্যাট্রিক্স গুণ মানে — দু'টি transformation একে একে প্রয়োগ করা। যেমন আগে ৪৫° ঘোরালেন, তারপর দ্বিগুণ করলেন — ক্রম গুরুত্বপূর্ণ, তাই $A B \neq B A$।
Python · NumPy
import numpy as np

# A: shape (2, 3)  ·  B: shape (3, 2)  →  AB: shape (2, 2)
A = np.array([[1, 2, 3],
              [4, 5, 6]])
B = np.array([[ 7,  8],
              [ 9, 10],
              [11, 12]])

print("A @ B =\n", A @ B)
print("\nshape:", (A @ B).shape)        # (2, 2)
print("matmul same:", np.allclose(A @ B, np.matmul(A, B)))

# AB ≠ BA — order matters
BA = B @ A                                # (3, 3)
print("\nBA shape:", BA.shape)

    

৩ · Element-wise বনাম matmul

নবীনদের সবচেয়ে বড় confusion — A * B মানে matmul নয়, এটি element-wise (Hadamard) গুণ। দু'টির shape হুবহু একই হতে হবে (বা broadcastable)।

Python · NumPy
import numpy as np

A = np.array([[1, 2],
              [3, 4]])
B = np.array([[5, 6],
              [7, 8]])

print("A * B (element-wise):\n", A * B)   # [[ 5 12] [21 32]]
print("\nA @ B (matmul):\n", A @ B)        # [[19 22] [43 50]]

    
* = ভিতরের সংখ্যা একে একে গুণ। @ = পুরো row-column dot product। AI-র কোডে দু'টোই দরকার — কিন্তু কখন কোনটা সেটা সচেতনভাবে বুঝতে হবে।

৪ · Determinant — np.linalg.det

Determinant $\det(A)$ — একটি square matrix-এর "scaling factor"। Geometric অর্থে: $A$ যদি একটি unit square-কে রূপান্তর করে, তবে নতুন এলাকার পরিমাণ $|\det(A)|$।

$\det(A) = 0$ হলে — matrix singular, inverse নেই; transformation একটি dimension "ভেঙে দেয়"।

$$\det \begin{pmatrix} a & b \\ c & d \end{pmatrix} = ad - bc$$

৫ · Inverse — np.linalg.inv ও pinv

Inverse matrix $A^{-1}$ — যা দিয়ে গুণ করলে identity পাওয়া যায়: $A A^{-1} = I$। শুধু square ও non-singular matrix-এর inverse আছে।

বাস্তব AI-তে অনেক matrix singular বা ill-conditioned। তাই Moore-Penrose pseudo-inverse $A^+$ ব্যবহার হয় — np.linalg.pinv। এটি rectangular matrix-এও কাজ করে এবং SVD-র সাহায্যে স্থিরভাবে compute হয়।

Python · NumPy
import numpy as np

A = np.array([[4.0, 7.0],
              [2.0, 6.0]])

print("det(A) =", np.linalg.det(A))         # 10.0
A_inv = np.linalg.inv(A)
print("inv(A) =\n", A_inv)
print("A @ inv(A) =\n", A @ A_inv)           # ~ identity

# Pseudo-inverse — singular বা rectangular-এও কাজ করে
R = np.array([[1.0, 2.0, 3.0],
              [4.0, 5.0, 6.0]])              # 2×3 — square নয়
print("\npinv shape:", np.linalg.pinv(R).shape)   # (3, 2)

    

৬ · Linear system solve — Ax = b

বহু AI সমস্যা — least squares, ridge regression, Kalman filter — শেষে এসে দাঁড়ায় একটি linear system: $A \mathbf{x} = \mathbf{b}$ কে $\mathbf{x}$-র জন্য সমাধান।

সাধারণ ভুল: x = inv(A) @ b লেখা। এটি কাজ করে কিন্তু — (১) ধীর, (২) numerically unstable। বদলে np.linalg.solve(A, b) ব্যবহার করুন — এটি LU decomposition দিয়ে সমাধান করে, inverse compute না করেই।

$$A \mathbf{x} = \mathbf{b} \;\;\Longrightarrow\;\; \mathbf{x} = A^{-1} \mathbf{b}$$

Numerical stability সতর্কতা: inv() condition number বাড়িয়ে দেয় — ছোট floating-point error কয়েক হাজার গুণ বড় হতে পারে। solve() এই round-off propagation এড়ায়। Production AI কোডে নিয়ম: যেখানে x = inv(A) @ b দেখলে — solve(A, b)-তে বদলান।
Python · NumPy
import numpy as np

# 3x + 2y = 12
# 1x + 4y = 14
A = np.array([[3.0, 2.0],
              [1.0, 4.0]])
b = np.array([12.0, 14.0])

# ✅ ভাল উপায় — দ্রুত ও stable
x = np.linalg.solve(A, b)
print("x =", x)                   # [2. 3.]

# ❌ কখনো না — শুধু demo-র জন্য
x_bad = np.linalg.inv(A) @ b
print("x (inv) =", x_bad)         # গাণিতিকভাবে একই, কিন্তু কম stable

# যাচাই: A @ x == b ?
print("verify:", np.allclose(A @ x, b))

    

৭ · Eigenvalues ও eigenvectors

একটি square matrix $A$-র জন্য — যদি কোনো ভেক্টর $\mathbf{v}$ এমন থাকে যা $A$ দিয়ে গুণ হলে শুধু scale হয়, ঘোরে না — সেটি eigenvectorEigenvalue / Eigenvector"Eigen" জার্মান শব্দ — অর্থ "নিজস্ব"। যে ভেক্টরের দিক transformation-এ অপরিবর্তিত থাকে, শুধু দৈর্ঘ্য বদলায় — সেটি eigenvector; বদলের পরিমাণই eigenvalue। PCA-র গাণিতিক মূল।। সেই scaling factor — eigenvalue $\lambda$।

$$A \mathbf{v} = \lambda \mathbf{v}$$

AI-তে eigendecomposition-এর সবচেয়ে বিখ্যাত প্রয়োগ — PCA (Principal Component Analysis)। ডেটার covariance matrix-এর top-k eigenvectors-ই সেই directions যেদিকে variance সর্বোচ্চ — অর্থাৎ "তথ্য" সর্বাধিক।

Python · NumPy
import numpy as np

A = np.array([[4.0, -2.0],
              [1.0,  1.0]])

eigvals, eigvecs = np.linalg.eig(A)
print("eigenvalues  =", eigvals)         # [3. 2.]
print("eigenvectors =\n", eigvecs)        # column-wise

# যাচাই: A v == λ v
v0 = eigvecs[:, 0]
print("\nA @ v0  =", A @ v0)
print("λ0 * v0 =", eigvals[0] * v0)

    

৮ · SVD সংক্ষেপে — A = U Σ Vᵀ

SVDSingular Value Decompositionযেকোনো matrix-কে তিনটি ছোট matrix-এ ভাঙা: rotation, scaling, rotation। rectangular matrix-এও কাজ করে। PCA, recommender system (Netflix Prize), image compression, latent semantic analysis — সবার ভিত্তি। (Singular Value Decomposition) — eigendecomposition-এর সাধারণীকৃত রূপ। যেকোনো $m \times n$ matrix-কে তিনটি অংশে ভাঙা যায়:

$$A = U \Sigma V^{T}$$

যেখানে $U$ ও $V$ orthogonal, $\Sigma$ একটি diagonal matrix (singular values)। এই decomposition AI-এর সবচেয়ে শক্তিশালী tool-গুলোর একটি — recommender system (Netflix Prize-এর জয়ী), image compression, dimensionality reduction, latent semantic analysis — সবই SVD-র উপর গড়া।

Top-$k$ singular values রেখে বাকি ফেলে দিলে — পাওয়া যায় matrix-এর "best rank-$k$ approximation"। ১০০×১০০ ছবি (১০,০০০ values) মাত্র ২০-৩০ singular values দিয়ে চিনতে পারা যাবে — এটাই compression।
Python · NumPy
import numpy as np

A = np.array([[3.0, 1.0, 1.0],
              [-1.0, 3.0, 1.0]])

U, S, Vt = np.linalg.svd(A, full_matrices=False)
print("U shape:", U.shape)        # (2, 2)
print("S (singular values):", S)  # decreasing order
print("Vt shape:", Vt.shape)      # (2, 3)

# পুনঃনির্মাণ: A = U · diag(S) · Vt
A_recon = U @ np.diag(S) @ Vt
print("reconstructed correctly:", np.allclose(A, A_recon))

    

৯ · Norm — np.linalg.norm

NormNormভেক্টর/ম্যাট্রিক্সের "size" পরিমাপের গাণিতিক উপায়। L1 = |x| যোগ, L2 = পাইথাগোরাস, Frobenius = matrix-র সব entry-র L2। AI-তে loss function ও regularization-এ অপরিহার্য। = ভেক্টর/ম্যাট্রিক্সের "size" পরিমাপ। AI-তে loss function ও regularization-এ অপরিহার্য।

  • L1: $\|\mathbf{x}\|_1 = \sum_i |x_i|$ — Lasso regularization, sparsity inducing।
  • L2: $\|\mathbf{x}\|_2 = \sqrt{\sum_i x_i^2}$ — পাইথাগোরাস, default norm, Ridge regularization।
  • Frobenius: matrix-র সব entry-র L2 — $\|A\|_F = \sqrt{\sum_{ij} A_{ij}^2}$।
Python · NumPy
import numpy as np

v = np.array([3.0, -4.0, 0.0])
print("L1 norm:", np.linalg.norm(v, ord=1))    # 7.0
print("L2 norm:", np.linalg.norm(v, ord=2))    # 5.0
print("L∞ norm:", np.linalg.norm(v, ord=np.inf))  # 4.0

A = np.array([[1.0, 2.0],
              [3.0, 4.0]])
print("Frobenius:", np.linalg.norm(A, 'fro'))  # ~5.477

    
Matmul shape rule ও SVD decomposition (m,k) · (k,n) → (m,n) · A = U Σ Vᵀ শেপ-এর নিয়ম — ভেতরের মাত্রা একই A (m, k) m k × B (k, n) k n = A B (m, n) m n match ⚠ ভেতরের k একই (2,3) · (3,4) → (2,4) ✓ (2,3) · (4,3) → ❌ error বাইরের → result shape SVD: যেকোনো A কে তিনটি অংশে A (m, n) = U orthogonal · Σ diagonal · Vᵀ orthogonal 📦 ব্যবহার PCA · Recommender Image compression Dim reduction · LSA
ম্যাট্রিক্স গুণে ভেতরের মাত্রা মিলতে হবে — বাইরেরগুলো ফলাফলের shape। SVD যেকোনো matrix-কে rotation × scaling × rotation-এ ভেঙে দেয়।
মনে রাখুন: matmul commutative নয় — $A B \neq B A$। shape mismatch হলে NumPy ValueError: matmul: ... not aligned দেয়। ৯০% bug-এর কারণ shape ভুল — সবসময় .shape print করে দেখুন।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ AI-তে np.linalg.solve() কেন inv()-র চেয়ে বেশি ব্যবহার হয়? Numerical stability ও computational complexity দু'দিক থেকে ব্যাখ্যা করুন।

গাণিতিকভাবে $\mathbf{x} = A^{-1}\mathbf{b}$ এবং solve(A,b) একই উত্তর দেয়। কিন্তু কম্পিউটারে — যেখানে সংখ্যা finite precision-এ থাকে — এই দুই পদ্ধতি ভিন্নভাবে আচরণ করে। Production AI কোডে এই পার্থক্য কখনো কখনো model debugging-এর কয়েক ঘণ্টা বাঁচায়।

(১) Numerical stability:

  • inv(A) compute করতে — কম্পিউটার ভেতরে $A^{-1}$-র সব এন্ট্রি বের করে। যদি $A$ ill-conditioned হয় (condition number $\kappa(A)$ বড়) — ছোট floating-point round-off error inv(A)-তে গুণিতকভাবে বড় হয়ে যায়।
  • solve(A,b) ভেতরে LU decomposition করে এবং forward + back substitution চালায়। inverse কখনো explicitly compute করে না। তাই error propagation অনেক কম।
  • সাধারণ rule: solve-এর forward error প্রায় $\kappa(A) \cdot \epsilon_{machine}$, কিন্তু inv() @ b-র error প্রায় $\kappa(A)^2 \cdot \epsilon_{machine}$।

(২) Computational complexity:

  • inv(A) — Gauss-Jordan বা LU দিয়ে — খরচ $O(n^3)$।
  • তারপর inv(A) @ b — আরো $O(n^2)$।
  • solve(A, b) — LU decomposition $O(n^3)$ + substitution $O(n^2)$। কিন্তু LU আরো compact, fewer operations practically।
  • একাধিক $b$-র জন্য? তখন আরো ভাল: scipy.linalg.lu_factor() দিয়ে একবার factor করে — প্রতি নতুন $b$-র জন্য শুধু $O(n^2)$।

(৩) Memory:

  • inv(A) পুরো $n \times n$ matrix store করে। ১০,০০০×১০,০০০ matrix-এ ৮০০ MB!
  • solve()-এ শুধু LU factors থাকে — same size, কিন্তু sparse $A$-র জন্য sparse LU অনেক ছোট।

(৪) AI-তে কোথায় গুরুত্বপূর্ণ:

  • Linear/ridge regression: normal equation $(X^T X) \mathbf{w} = X^T \mathbf{y}$ — সবসময় solve।
  • Gaussian process: Kernel matrix-এর inverse লাগে predict-এ — practically Cholesky + solve।
  • Kalman filter: covariance update — solve।
  • Newton's method: Hessian inverse — Newton step solve(H, -g)।

মূল উপলব্ধি: "গণিতে যা সুন্দর — কম্পিউটারে তা সবসময় optimal নয়।" Linear algebra-র formula book এক জিনিস; numerical linear algebra আলাদা শাস্ত্র। ভাল AI engineer এই পার্থক্য জানে।

প্র ০২ Matrix multiplication-এর computational complexity $O(n^3)$ — Strassen algorithm, GPU parallelism, ও tensor core কীভাবে এটাকে accelerate করে? কেন AI hardware এত matmul-centric?

$n \times n$ দু'টি matrix-এর গুণে — naive পদ্ধতিতে $n^3$ গুণ ও $n^3 - n^2$ যোগ লাগে। GPT-৪-এর একটি forward pass-এ কোটি কোটি matmul — তাই এই খরচ AI-র মূল bottleneck।

(১) Algorithmic improvements:

  • Strassen (১৯৬৯): recursively ৭টি subproblem (নাইভে ৮)। Complexity $O(n^{2.807})$। Practical-এ small $n$-এ slower (constant বড়), তবে large $n$-এ helpful।
  • Coppersmith-Winograd ও variants: theoretical $O(n^{2.371})$ পর্যন্ত নামানো হয়েছে। কিন্তু constants এতই বড় যে practical না।
  • AlphaTensor (DeepMind, ২০২২): RL দিয়ে নতুন matmul algorithm আবিষ্কার — কিছু specific size-এ Strassen-কে হারায়।
  • বাস্তবে BLAS — naive $O(n^3)$-ই — কিন্তু hardware-aware optimization (cache blocking, SIMD) দিয়ে theoretical peak-এর ৯০%+ দেয়।

(২) GPU parallelism:

  • CPU — কয়েকটি (৮-৬৪) শক্তিশালী core, sequential workload-এ ভাল।
  • GPU — হাজার হাজার (RTX 4090-এ ১৬,৩৮৪) দুর্বল core, একই operation একসাথে অনেক data-এ চালায়। Matmul-এর প্রতিটি output cell স্বাধীনভাবে compute করা যায় — perfect parallelism।
  • Memory hierarchy: shared memory tile-এ matrix block লোড → on-chip compute → write back। Cache miss কমিয়ে throughput বহুগুণ।

(৩) Tensor core (NVIDIA, ২০১৭+):

  • একক clock cycle-এ ৪×৪ matmul — সম্পূর্ণ hardware-এ। Volta-এ FP16, Ampere-এ TF32, Hopper-এ FP8।
  • Throughput: H100-এ ~১,০০০ TFLOPS FP16 — CPU-র চেয়ে ১০,০০০× বেশি।
  • Mixed precision training — accuracy বজায় রেখে memory + speed।

(৪) TPU ও custom AI chip:

  • Google TPU — পুরোপুরি systolic array, matmul-only architecture। ১২৮×১২৮ multiply-accumulate প্রতি cycle।
  • Cerebras WSE-3 — পুরো wafer একটি chip — ৯০০,০০০ core।
  • Groq, Tenstorrent, Etched (Sohu) — সবাই matmul-prioritized design।

(৫) কেন AI hardware matmul-centric?

  • Neural network = stack of matmul + activation। Convolution-ও matmul-এ unfold হয় (im2col)।
  • Attention (Transformer) = $\text{softmax}(QK^T / \sqrt{d}) V$ — তিনটি matmul + একটি softmax।
  • Training = forward matmul + backward matmul (gradient)। সব AI compute matmul-dominated।

মূল উপলব্ধি: AI revolution মানে — আমরা এমন একটি problem-এ ঠেকেছি যা matmul-এ reduce হয়। Hardware industry সেই perspective-এ নতুন করে তৈরি হচ্ছে। CPU "general-purpose" থেকে GPU "matmul-purpose"-এ shift — last decade-এর সবচেয়ে বড় hardware transition।

প্র ০৩ Eigendecomposition ও SVD — দু'টি কীভাবে আলাদা? কোনটা কখন ব্যবহার করবেন? PCA, recommendation, ও image compression-এ কীভাবে কাজে আসে?

দু'টিই matrix-কে "ভাঙার" পদ্ধতি — কিন্তু capabilities ও use case ভিন্ন। AI-তে দু'টোর সঠিক প্রয়োগ জানা — applied linear algebra-র key skill।

(১) মূল পার্থক্য:

  • Eigendecomposition $A = Q \Lambda Q^{-1}$ — শুধু square matrix-এর জন্য, এবং সব square matrix-এ exist করে না (defective matrix-এ ভেঙে পড়ে)। Eigenvalue জটিল সংখ্যা হতে পারে।
  • SVD $A = U \Sigma V^T$ — যেকোনো $m \times n$ matrix-এ exist করে। Singular values সবসময় ≥০, real। Rectangular, singular, ill-conditioned — সবেতেই কাজ করে।

(২) সম্পর্ক:

  • $A^T A$-র eigenvalues = $A$-র singular values squared।
  • $A^T A$-র eigenvectors = $V$ (right singular vectors)।
  • $A A^T$-র eigenvectors = $U$ (left singular vectors)।
  • তাই symmetric positive-definite matrix-এ — eigendecomposition ও SVD প্রায় identical।

(৩) PCA — কোনটা?

  • Classical formulation: data $X$ (n × d) → covariance matrix $C = X^T X / n$ → eigendecomposition → top-k eigenvectors = principal components।
  • Modern, numerically better: data কে centered → SVD($X$) সরাসরি → $V$-র প্রথম k columns = principal components।
  • SVD ভাল কারণ — covariance matrix explicitly form করতে হয় না (memory + numerical stability)।

(৪) Recommendation system — Netflix Prize:

  • User-item rating matrix $R$ (millions × thousands) — sparse এবং rectangular।
  • SVD: $R \approx U_k \Sigma_k V_k^T$ — top-k singular values রেখে dimensionality reduction।
  • $U$-র প্রতিটি row = user-এর latent preference vector। $V$-র প্রতিটি row = item-এর latent feature vector।
  • Missing rating predict: $\hat{r}_{ui} = U_u \cdot V_i$।
  • Eigendecomposition এখানে কাজ করত না — matrix square নয়।

(৫) Image compression:

  • একটি grayscale image $A$ (h × w) — SVD করুন।
  • Top-k singular values + corresponding $U, V$ columns রাখুন। বাকি ফেলে দিন।
  • Reconstructed image visually almost identical, কিন্তু storage $k(h+w+1)$ — full $hw$-র ভগ্নাংশ।
  • JPEG নয় — কিন্তু concept-এ শুরু (JPEG ব্যবহার করে DCT, যা SVD-র special case)।

(৬) আরো প্রয়োগ:

  • LSA (Latent Semantic Analysis) — document-term matrix-এ SVD → topic discovery।
  • Pseudo-inverse — least squares solution SVD দিয়ে।
  • Total least squares regression — eigendecomposition-এর বদলে SVD।
  • PageRank — Google-এর original algorithm — link matrix-এর dominant eigenvector।

মূল কথা: "Square + diagonalizable হলে eigendecomposition; যেকোনো অবস্থায় SVD।" বাস্তবে modern AI কোডে SVD বেশি — কারণ ডেটা সাধারণত rectangular ও noisy। SVD-কে বলা হয় "linear algebra-র Swiss Army knife"।

প্র ০৪ Neural network-এর forward pass = একগুচ্ছ matmul + activation। GPU কেন এই pattern-এ এত efficient? Memory bandwidth, parallelism, ও Amdahl's law দিয়ে ব্যাখ্যা করুন।

একটি simple feed-forward neural network — input $\mathbf{x}$, layer-এ $\mathbf{h} = \sigma(W \mathbf{x} + \mathbf{b})$। প্রতিটি layer একটি matmul + bias addition + non-linear activation। কোটি কোটি parameter-এর model-এ এই pattern বার বার repeat — GPU-র জন্য আদর্শ workload।

(১) Embarrassingly parallel:

  • Matmul $C = A B$ — $C_{ij}$-র প্রতিটি cell স্বাধীনভাবে compute করা যায়। কোনো cell-এর জন্য অন্য কোনো cell-এর result-এর অপেক্ষা লাগে না।
  • GPU-র হাজার core একসাথে কাজ করে — প্রতিটি কয়েকটি output cell-এর দায়িত্ব নেয়।
  • Activation function (ReLU, sigmoid) — element-wise, পুরো parallel।

(২) Arithmetic intensity ও memory bandwidth:

  • Arithmetic intensity = (FLOPs) / (bytes loaded from memory)। উঁচু intensity = compute-bound (GPU-র powerhouse use)। নিচু intensity = memory-bound (slow)।
  • Matmul-এ intensity উঁচু — $n^3$ ops, $3n^2$ data load। যত বড় $n$, তত better ratio।
  • তাই batch size বাড়ালে GPU utilization বাড়ে — অনেক matmul একসাথে।
  • Element-wise ops (activation) memory-bound — GPU অলস বসে থাকে। সমাধান: kernel fusion (matmul + bias + activation একসাথে)।

(৩) Memory hierarchy ও tiling:

  • GPU-তে DRAM (HBM) — slow, কিন্তু capacity বড়। L2 cache → shared memory (per SM) → register — দ্রুত কিন্তু ছোট।
  • Matmul tile করা হয়: একবার ছোট block (যেমন ৬৪×৬৪) shared memory-তে লোড → বহু compute ওই block-এ → তারপর next block। DRAM trip কমে।
  • cuBLAS, cuDNN — হাত দিয়ে এই tile sizes optimized।

(৪) Specialized hardware — Tensor Core:

  • Volta (২০১৭) থেকে — dedicated matmul unit। ১ cycle-এ ৪×৪ FMA।
  • Mixed precision (FP16 multiply, FP32 accumulate) — accuracy বজায় রেখে ৮× speedup।
  • H100-এ FP8 support — large-scale training-এ আরো accelerate।

(৫) Amdahl's law-এর প্রভাব:

  • $\text{speedup} = 1 / ((1-p) + p/N)$, যেখানে $p$ parallelizable fraction।
  • Forward pass-এ ~৯৯% matmul (parallelizable)। বাকি ১% (control flow, host-device sync) sequential।
  • $p = 0.99$, $N = 10000$ → speedup ~৯৯×। সম্ভাব্য সর্বোচ্চ ১০০×।
  • তাই GPU-র সব core ব্যবহার করতে — sequential bottleneck (Python loop, CPU-GPU transfer) কমানো জরুরি।

(৬) Real-world implication:

  • Large batch + large hidden dim = GPU পুরো ব্যবহার। Small batch = তলানিতে utilization।
  • একটি LLM training run-এ batch size ১M+ token — GPU পরিপূর্ণ।
  • Inference-এ batch ছোট — তাই inference-specific hardware (Groq, Sambanova) আলাদা design।

(৭) ভবিষ্যৎ:

  • Sparse matmul (মাত্র non-zero entries) — pruned neural network-এ গুরুত্বপূর্ণ।
  • Mixture of Experts (MoE) — শুধু কিছু expert active per token, conditional matmul।
  • In-memory compute — analog matmul memristor-এ। Research stage।

মূল উপলব্ধি: Neural network পদার্থ-গণিতের সৌন্দর্য নয় — হাজারো matmul + activation। GPU exactly এই pattern-এর জন্য বানানো (NVIDIA initially graphics-এর জন্য, accidentally AI-এর জন্য perfect)। AI-হার্ডওয়্যার এই workload-কে কেন্দ্র করেই আগামীর directions ঠিক করছে।

অনুশীলন

  1. Matmul চর্চা: NumPy-তে $A = \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix}$ এবং $B = \begin{pmatrix} 5 & 6 \\ 7 & 8 \end{pmatrix}$ তৈরি করুন। $A B$ ও $B A$ compute করুন — কি একই উত্তর?
    import numpy as np
    A = np.array([[1, 2], [3, 4]])
    B = np.array([[5, 6], [7, 8]])
    print("A @ B =\n", A @ B)   # [[19 22] [43 50]]
    print("B @ A =\n", B @ A)   # [[23 34] [31 46]]

    না, $A B \neq B A$ — matmul commutative নয়। ক্রম গুরুত্বপূর্ণ।

  2. Linear system সমাধান: নিম্নলিখিত system-কে $A \mathbf{x} = \mathbf{b}$ আকারে লিখে np.linalg.solve দিয়ে $\mathbf{x}$ বের করুন:

    $$2x + y - z = 8, \quad -3x - y + 2z = -11, \quad -2x + y + 2z = -3$$

    import numpy as np
    A = np.array([[ 2,  1, -1],
                  [-3, -1,  2],
                  [-2,  1,  2]], dtype=float)
    b = np.array([8, -11, -3], dtype=float)
    
    x = np.linalg.solve(A, b)
    print("x =", x)                    # [ 2.  3. -1.]
    print("verify:", np.allclose(A @ x, b))

    উত্তর: $x = 2$, $y = 3$, $z = -1$।

  3. Eigenvalue হাতে ও NumPy-তে: $A = \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix}$-র eigenvalues হাতে বের করুন ($\det(A - \lambda I) = 0$ থেকে), তারপর NumPy দিয়ে যাচাই করুন।

    হাতে: $\det \begin{pmatrix} 2-\lambda & 1 \\ 1 & 2-\lambda \end{pmatrix} = (2-\lambda)^2 - 1 = 0$ ⇒ $\lambda^2 - 4\lambda + 3 = 0$ ⇒ $\lambda = 1, 3$।

    import numpy as np
    A = np.array([[2.0, 1.0],
                  [1.0, 2.0]])
    eigvals, eigvecs = np.linalg.eig(A)
    print("eigenvalues:", sorted(eigvals))      # [1. 3.]
    print("eigenvectors:\n", eigvecs)

    Eigenvectors: $\mathbf{v}_1 = (1, -1)/\sqrt{2}$ (λ=1), $\mathbf{v}_2 = (1, 1)/\sqrt{2}$ (λ=3)।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

কোড রানার কাজ না করলে? ব্রাউজারে কাজ না করলে Google Colab ব্যবহার করুন — Google-এর ফ্রি অনলাইন Python পরিবেশ, শুধু Gmail অ্যাকাউন্ট লাগে।
পূর্ববর্তী পাঠ
পাঠ ১১ · Broadcasting — অ্যারের জাদু