Computational graph
এই পাঠে যা শিখবেন
- Computational graph কী, কেন গুরুত্বপূর্ণ
- Dynamic vs static graph — দুই philosophy
- PyTorch-এ
.grad_fnদেখা - Graph visualization — torchviz দিয়ে
detach(),no_grad— graph নিয়ন্ত্রণ
১ · Computational graph কী
একটি computational graphComputational Graphএকটি Directed Acyclic Graph (DAG) যেখানে node = operation/variable, edge = data dependency। DL framework-এ autograd-এর basis। = একটি গণিত expression-এর graph representation। Node হলো operation বা variable, edge হলো data flow।
যেমন $f(x, y) = (x + y) \cdot x$ — এর graph:
- Leaf node: $x, y$ (input variables)।
- Add node: $u = x + y$।
- Mul node: $f = u \cdot x$।
- Edge: data flow direction।
১) Modularity: প্রতিটি op self-contained — local gradient জানে।
২) Automatic differentiation: graph traverse করেই backprop।
৩) Optimization: graph-এ pattern detect — fusion, pruning।
৪) Hardware mapping: graph distribute হয় GPU/TPU-তে।
২ · Forward — graph build
যখন আপনি একটি tensor expression লেখেন — PyTorch nodes তৈরি করে। প্রতিটি tensor-এর সাথে যুক্ত থাকে grad_fn — কোন operation এটি তৈরি করল।
import torch
x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)
u = x + y # AddBackward
f = u * x # MulBackward
print("f =", f.item())
print("f.grad_fn =", f.grad_fn)
print("u.grad_fn =", u.grad_fn)
print("x.grad_fn =", x.grad_fn) # None (leaf)
# Previous nodes দেখুন
print("\nf.grad_fn.next_functions:")
for fn, _ in f.grad_fn.next_functions:
print(" ", fn)
grad_fn থেকে আপনি পুরো graph backward-traverse করতে পারেন। PyTorch internal-এ ঠিক এটাই করে।
৩ · Backward — graph traverse
loss.backward() call-এ কী ঘটে?
- Topological sort: graph-এর nodes কোন order-এ visit করতে হবে — output থেকে input পর্যন্ত।
- Initialize: output node-এ $\frac{\partial L}{\partial L} = 1$।
- Visit each node: upstream gradient × local gradient → downstream-এ পাঠাও।
- Accumulate: একই leaf-এ একাধিক path থাকলে gradient যোগ করো।
- Store: leaf tensors-এর
.grad-এ result।
৪ · Dynamic vs Static graph
ML framework দু'রকম philosophy অনুসরণ করে:
Dynamic graph (PyTorch, JAX-এর এক mode):
- প্রতিটি forward pass-এ নতুন graph build।
- Python control flow (if/for/while) স্বাভাবিক ভাবে কাজ করে।
- Debug সহজ — print, breakpoint কাজ করে।
- Cost: প্রতিবার build overhead।
Static graph (TF 1.x, ONNX, TorchScript):
- Graph একবার define হয়, বহুবার run।
- Optimization possible — kernel fusion, dead code elimination।
- Production-friendly — serialize, deploy।
- Cost: control flow-এ awkward (placeholder, condition op)।
৫ · PyTorch — best of both
আধুনিক PyTorch (২.০+) torch.compile দিয়ে dynamic graph-কে JIT-compile করে — research-এ flexibility, production-এ speed।
import torch
import torch.nn as nn
# Normal model
model = nn.Sequential(
nn.Linear(10, 64),
nn.ReLU(),
nn.Linear(64, 1),
)
# JIT compile — graph optimization
fast_model = torch.compile(model)
x = torch.randn(32, 10)
y = fast_model(x) # প্রথম call-এ compile, পরে fast
print(y.shape)
৬ · Graph visualization — torchviz
Graph "দেখতে" — torchviz library:
# pip install torchviz
import torch
from torchviz import make_dot
x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)
z = x ** 2 + 2 * x * y + y ** 3
dot = make_dot(z, params={'x': x, 'y': y})
dot.render('graph', format='png') # graph.png save
# অথবা notebook-এ display
# dot
৭ · Detach ও no_grad — graph নিয়ন্ত্রণ
কখনো আমরা graph build চাই না (যেমন inference) বা graph থেকে subgraph "কাটতে" চাই (transfer learning)। দুটি tool:
import torch
x = torch.tensor(2.0, requires_grad=True)
# detach — graph থেকে বিচ্ছিন্ন copy
y = x.detach()
print(y.requires_grad) # False
# y-এর কোনো gradient flow হবে না
# no_grad context — graph build off
with torch.no_grad():
z = x ** 2 + 5
print(z.requires_grad) # False
# inference mode — আরও aggressive
with torch.inference_mode():
z = x ** 2 + 5
# version counting, autograd তৈরি বন্ধ — fastest
# eval mode — model-এর জন্য (Dropout/BN behavior)
# model.eval() ≠ no_grad — দু'টোই দরকার inference-এ
model.eval() + torch.no_grad() দু'টোই দরকার। প্রথমটি Dropout/BatchNorm-এর behavior switch, দ্বিতীয়টি graph build বন্ধ — memory ও speed দু'টোই improve।
৮ · Memory — graph-এর hidden cost
Backprop-এর জন্য সব intermediate activation graph-এ সংরক্ষিত থাকে। Deep network-এ memory $O(\text{depth})$।
- 50-layer network, batch 32: activations memory প্রায় 4× model-এর weight memory।
- Solution: gradient checkpointing — কিছু activation save, বাকি forward-এ recompute।
- Trade-off: 30% বেশি compute, 50%+ কম memory।
import torch
import torch.nn as nn
from torch.utils.checkpoint import checkpoint
class DeepBlock(nn.Module):
def __init__(self):
super().__init__()
self.layers = nn.Sequential(
*[nn.Linear(512, 512) for _ in range(20)]
)
def forward(self, x):
# সাধারণ forward
# return self.layers(x)
# checkpoint দিয়ে — memory save
return checkpoint(self.layers, x, use_reentrant=False)
model = DeepBlock()
x = torch.randn(64, 512, requires_grad=True)
y = model(x)
loss = y.sum()
loss.backward()
print("OK — checkpoint working")
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
TensorFlow ১.x static graph থেকে TF ২.x eager mode-এ গেল PyTorch-এর সাথে compete করতে। PyTorch আবার torch.compile দিয়ে static-এর benefit আনল। এই convergence কী বলে DL framework design-এ?
AI framework history-র সবচেয়ে fascinating arc। ২০১৫-২০২০ TF dominant ছিল production-এ, PyTorch research-এ। এখন PyTorch দু'টোতেই lead। কারণ design philosophy-র বিবর্তন।
Static graph (TF 1.x)-এর rationale:
- Compiler-style optimization — kernel fusion, constant folding।
- Distributed training — partition automatic।
- Cross-platform deployment — mobile, web।
- Production-grade serving (TF Serving)।
Static graph-এর pain:
- Define-then-run — debug nightmare।
- Control flow বিকৃত —
tf.cond,tf.while। - Variable scoping এক চ্যালেঞ্জ।
- Researcher-দের জন্য productivity killer।
Dynamic graph (PyTorch)-এর win:
- Pythonic — control flow স্বাভাবিক।
- Print, breakpoint কাজ করে।
- Quick prototyping।
- Research community দ্রুত adoption।
Dynamic-এর cost:
- Per-iteration build overhead।
- Optimization opportunity miss।
- Hardware-specific code generation কঠিন।
Convergence: best of both:
- TF 2.x eager mode default — PyTorch-এর experience।
tf.functiondecorator — selective static compilation।- PyTorch
torch.jit.script— early static option। torch.compile(২০২৩) — TorchInductor backend।- JAX — pure functional, jit-compilable।
Lesson: trace-then-compile:
- Eager execution → trace operations → compile graph → run optimized।
- Best abstraction — user pythonic, system optimized।
Why PyTorch won research:
- Cleaner API — fewer abstractions।
- NumPy-like — familiar।
- Hugging Face, FastAI — ecosystem।
- Meta-র aggressive open source push।
- Academic citation pattern — researcher A use → researcher B follow।
Why production catching up:
- TorchServe, TorchScript — deployment।
- ONNX export — cross-framework।
- Mobile (PyTorch Mobile) — edge।
torch.compile— production speed।
JAX-এর position:
- Functional pure — research-এ elegance।
- XLA compile — TPU-তে supreme।
- DeepMind, Google research preferred।
- Industry adoption সীমিত — learning curve।
Future trend:
- MLIR (Multi-Level IR) — universal compilation।
- Hardware-software co-design।
- OpenAI Triton — high-level kernel programming।
- Framework-agnostic models (HuggingFace adapters)।
মূল উপলব্ধি: "Static vs dynamic" false dichotomy। Modern framework — eager-by-default, compile-on-demand। Productivity ও performance দু'টোই pursue। Bangladesh-এ — PyTorch start, JAX explore, TF legacy deal — তিন framework ই জানা সমৃদ্ধ।
প্র ০২ Computational graph ML-এর বাইরে — physics simulation, finance, robotics-এ কেমন ব্যবহৃত? Differentiable programming কী ধরনের ক্ষেত্রে revolution আনছে?
Computational graph শুধু DL-এর tool না — যেকোনো differentiable computation-এর foundation। "Differentiable programming" এই broad framework।
Differentiable programming concept:
- প্রোগ্রামকে এমনভাবে লেখা যাতে input-এর সাপেক্ষে output-এর gradient compute সম্ভব।
- "Software 2.0" — Karpathy-এর term।
- Backprop = differentiable programming-এর special case।
Application: Physics simulation:
- Differentiable physics simulator (DiffTaichi, Brax)।
- Soft body, fluid, rigid body — সবই differentiable।
- Robot policy directly through simulation gradient learn।
- Material property infer — observed deformation থেকে।
Application: Finance:
- Option pricing — Black-Scholes graph differentiable।
- Greeks (sensitivity) — auto-compute।
- Portfolio optimization — gradient-based।
- Risk model calibration — backprop through Monte Carlo।
Application: Robotics:
- Differentiable kinematics — joint angle থেকে end-effector।
- Inverse kinematics — gradient descent।
- Policy learning — sim-to-real।
- Motion planning gradient-based।
Application: Computer graphics:
- Differentiable rendering — image থেকে 3D recover।
- NeRF (Neural Radiance Fields) — volumetric rendering।
- Material/lighting estimation।
- Inverse graphics — vision-এর dual।
Application: Probabilistic programming:
- Pyro, NumPyro — Bayesian model।
- Variational inference — gradient-based।
- Stan-এর modern alternative।
Application: Scientific computing:
- Climate model gradient-aware।
- Differential equation solver — neural ODE।
- Quantum circuit optimization।
- Drug discovery — molecular property gradient।
JAX-এর role:
- Pure functional — composable transformations।
jit,vmap,pmap,grad— primitive composability।- NumPy API — scientific community familiar।
- DeepMind AlphaFold internal — JAX।
Bangladesh research opportunity:
- Cyclone simulation differentiable — Bangladesh climate research।
- Agriculture yield prediction — physics + ML hybrid।
- River dynamics modeling।
- Garment supply chain optimization।
Limitations:
- সব function differentiable না (discrete, conditional)।
- Soft relaxation often required।
- Gumbel-softmax, straight-through estimator — tricks।
মূল উপলব্ধি: Computational graph just DL tool নয় — universal computational paradigm। Differentiable programming আগামী দশকে scientific computing transform করবে। Just learning ML থেকে এটি বহু broader।
প্র ০৩
retain_graph=True কেন কখনো কখনো লাগে? "Trying to backward through the graph a second time" error কেন আসে?
PyTorch-এর সবচেয়ে confusing error message-গুলোর একটি। বুঝতে — memory model-এ যেতে হবে।
Default behavior:
backward()-এর পর graph-এর intermediate buffer free হয়।- Memory save — common case (single backward per forward)।
- আবার
backward()call → buffer নেই → error।
The classic error:
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2
y.backward() # OK — x.grad = 4
y.backward() # RuntimeError: backward through graph second time
Solutions:
- Option 1: retain_graph=True
y.backward(retain_graph=True) y.backward() # works, x.grad = 8 (accumulated) - Option 2: Recompute
y = x ** 2 y.backward() y = x ** 2 # rebuild y.backward()
কখন দরকার:
- Multiple losses, shared graph:
অথবা better:shared = encoder(x) loss1 = head1(shared).mean() loss2 = head2(shared).mean() loss1.backward(retain_graph=True) loss2.backward()(loss1 + loss2).backward()। - GAN training:
Solution:# Discriminator update fake = G(z) d_loss = ... d_loss.backward() # Generator update — same fake! g_loss = ... g_loss.backward() # error if same graphfake.detach()in D-loss। - Higher-order gradients:
y.backward(create_graph=True) # auto-retain grad_x = x.grad grad2 = torch.autograd.grad(grad_x, x)[0] - Custom training loops: meta-learning, MAML।
Pitfall — memory leak:
retain_graph=Trueoveruse → graph accumulate, OOM।- Solution: explicit
del graph_tensorবা scope-এ end।
Better patterns:
- Combine losses:
(l1 + l2 + l3).backward()— single backward। - Use
autograd.gradinstead ofbackwardwhen partial gradient needed। detachaggressively — clear non-needed graph parts।
Debug strategy:
- Error হলে — কোন tensor বা loss double-backward হচ্ছে identify।
- Computation graph print:
print(loss.grad_fn)। - Hook দিয়ে gradient flow trace।
Performance impact:
retain_graph— buffer keep, memory cost।create_graph— backward graph build, even more memory।- Inference-এ
no_gradmandatory — no graph at all।
মূল উপলব্ধি: Default behavior memory-efficient। retain_graph escape hatch — sparingly use। Better — graph design rethink (single combined loss, detach proper)। GAN, meta-learning-এ unavoidable। Beginner-দের জন্য — error দেখলে graph restructure আগে চেষ্টা করুন।
প্র ০৪ আপনি একটি ৫০০-layer Transformer train করছেন। GPU memory অপ্রতুল। Gradient checkpointing কীভাবে save করে — trade-off কী?
Modern LLM training-এর backbone technique। GPT-3, LLaMA — সবই checkpoint-এ নির্ভরশীল।
Memory problem:
- Backprop-এর জন্য সব activation save।
- 50-layer Transformer, 2048 seq, 4096 hidden — ভয়ংকর memory।
- Activation memory প্রায় $O(\text{layers} \times \text{batch} \times \text{seq} \times \text{hidden})$।
Standard approach without checkpoint:
- Forward — সব layer activation save।
- Backward — saved activation read, gradient compute।
- Memory: O(L) activations।
Gradient checkpointing core idea:
- Forward — কিছু "checkpoint" save, বাকি discard।
- Backward — discarded part recompute (forward again from checkpoint)।
- Memory ↓, compute ↑।
Math: optimal checkpointing:
- Naive: every layer checkpoint → memory O(L), no save।
- Sqrt strategy: $\sqrt{L}$ checkpoints → memory $O(\sqrt{L})$, compute $1.5\times$।
- Chen et al. (২০১৬) — recursive scheme, memory $O(\log L)$।
PyTorch implementation:
from torch.utils.checkpoint import checkpoint
class Block(nn.Module):
def forward(self, x):
# heavy computation
...
# Without checkpoint
y = block(x)
# With checkpoint
y = checkpoint(block, x, use_reentrant=False)
# Forward — block-এর activation drop
# Backward — block recompute, then gradient
Sequential checkpointing:
from torch.utils.checkpoint import checkpoint_sequential
# Auto-divide layers into segments
y = checkpoint_sequential(model.layers, segments=4, input=x)
# 4 checkpoints — memory O(L/4), compute 1.25x
Trade-off quantification:
- 50-layer, sqrt strategy → memory ÷ 7, compute × 1.5।
- Practically — 30-50% memory save, 25-35% compute overhead।
- Larger batch possible → better GPU utilization compensates।
When to use:
- OOM error during training।
- Want larger batch।
- Want longer sequence।
- Want bigger model।
- Compute budget allows।
When NOT to use:
- Memory enough — pure waste।
- Compute-bound, latency-sensitive।
- Inference (no backward — no need)।
Combination with other techniques:
- Mixed precision (FP16/BF16): activation memory ÷ 2।
- ZeRO (DeepSpeed): optimizer state shard।
- Tensor parallelism: activation across GPUs।
- FlashAttention: attention memory linear in seq।
Modern LLM training stack:
- Activation checkpointing + ZeRO + FP16 + Tensor parallel।
- 13B model train possible on consumer multi-GPU।
- 70B+ → cluster needed।
Bangladesh perspective:
- Limited GPU (Colab, RTX 3090) → checkpointing critical।
- Bangla LLM fine-tune (LLaMA-2 7B) → ১২GB GPU + checkpoint workable।
- Research lab — multi-GPU + DeepSpeed।
Pitfalls:
- Random ops (dropout) — recompute different result! Use seeded RNG।
use_reentrant=Falserecommended (২.০+) — avoid hidden bugs।- Profile carefully — সব time-এ benefit guaranteed না।
মূল উপলব্ধি: Gradient checkpointing — memory ↔ compute trade। Modern LLM-এ "must"। Combination with FP16, distributed training বহু large model-কে accessible করেছে। Memory-constrained scenario-তে first reach for this tool।
অনুশীলন
-
Graph trace: $f = (x + y) \cdot (y + 2)$, $x = 1, y = 2$। PyTorch-এ
f.grad_fnও prev nodes কী হবে?f.grad_fn=MulBackward। Prev: দু'টিAddBackward— একটি $x+y$, একটি $y+2$।x = torch.tensor(1.0, requires_grad=True) y = torch.tensor(2.0, requires_grad=True) f = (x + y) * (y + 2) print(f.grad_fn) for fn, _ in f.grad_fn.next_functions: print(" ", fn) -
Multiple paths: $f = x^2 + 3x$। $\frac{df}{dx}$ — graph-এ $x$ দু'বার ব্যবহৃত। Manual ও autograd verify করুন।
$\frac{df}{dx} = 2x + 3$ — দু'টি path-এর সমষ্টি।
x = torch.tensor(2.0, requires_grad=True) f = x ** 2 + 3 * x f.backward() print(x.grad) # 2(2) + 3 = 7 -
no_grad ব্যবহার: একটি model-এর inference loop লিখুন যেখানে graph build হবে না।
model.eval() with torch.no_grad(): for x_batch in test_loader: y_pred = model(x_batch) # graph build না, memory save
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ১১ · SGD ও Mini-batch পরবর্তী পাঠ Gradient হাতে — এবার weight update।
- পাঠ ০৯ · Backpropagation আগের পাঠ Graph-এ chain rule প্রয়োগ।
- পাঠ ০৮ · PyTorch tensor এই পাঠের সাথে সম্পর্কিত Autograd-এর primitive।
- সব AI Courses দেখুন ABCL TECH Python, ML, DL, NLP, CV, GenAI, RL, MLOps — সব AI কোর্স একসাথে।