Thursday, 1 October 2026

TensorFlow और PyTorch (भाग 2): basic डेटा स्ट्रक्चर — Tensors और कैलकुलस

नमस्कार मित्रों!

डीप लर्निंग श्रृंखला के पहले भाग में हमने TensorFlow और PyTorch के दार्शनिक और आर्किटेक्चरल अंतर को समझा। हमने देखा कि एक तरफ जहाँ TensorFlow एक सुगठित, Production-oriented फैक्ट्री की तरह काम करता है, वहीं PyTorch एक अत्यधिक लचीली और Research-friendly कार्यशाला की तरह कार्य करता है।

अब प्रश्न उठता है: न्यूरल नेटवर्क के भीतर डेटा वास्तव में किस रूप में प्रवाहित होता है, और मॉडल अपनी गलतियों को सुधारना कैसे सीखता है?

जब हम किसी Image, ध्वनि तरंग (Audio Waveform) या Text को न्यूरल नेटवर्क में इनपुट करते हैं, तो कंप्यूटर उसे सीधे नहीं समझता। कंप्यूटर के लिए हर इनपुट अनिवार्य रूप से संख्याओं का एक बहु-आयामी विन्यास होता है। गणित और कंप्यूटर विज्ञान की भाषा में इसे Tensor (टेंसर) कहते हैं।

आज AI Bodh पर हम तकनीकी गहराई के साथ समझेंगे:

  1. टेंसर का गणितीय और प्रोग्रामिंग स्वरूप क्या है?
  2. स्वचालित अवकलन (Automatic Differentiation) क्या है और न्यूरल नेटवर्क में इसकी क्या भूमिका है?
  3. PyTorch का Autograd और TensorFlow का GradientTape पर्दे के पीछे किस प्रकार काम करते हैं?

1. Tensor क्या है? गणितीय संरचना और विमाएँ (Dimensions)

सरल शब्दों में, टेंसर संख्याओं का एक ऐसा कंटेनर है जिसे किसी भी आयाम (N-Dimensions) में व्यवस्थित किया जा सकता है। यह सामान्य मैट्रिक्स का ही एक व्यापक रूप है:

टेंसर की विमाएँ और संरचना

Dimension (रैंक)

गणितीय नाम

व्यावहारिक उदाहरण

Rank-0

अदिश राशि (Scalar)

केवल एक संख्या (उदा. हानि/लॉस = 0.45)

Rank-1

सदिश (Vector)

1D क्रमबद्ध सूची (उदा. [10, 20, 30])

Rank-2

आव्यूह (Matrix)

2D टेबल: पंक्तियाँ और स्तंभ (Rows & Columns)

Rank-3

3D Tensor

एकल रंगीन छवि: [Height, Width, 3 (RGB)]

Rank-4

4D Tensor

छवियों का बैच: [Batch_Size, Height, Width, Channels]

मेमोरी और GPU संरेखण (Memory Layout & Accelerators)

साधारण Python सूची में मान बिखरे हुए पॉइंटर्स के रूप में संग्रहीत होते हैं, जो Parallel Computing के लिए अनुपयुक्त हैं।

इसके विपरीत, दोनों फ्रेमवर्क्स में टेंसर होमोजीनियस डेटा प्रकार (Homogeneous Data Types) के साथ मेमोरी में एक सतत खंड (Contiguous Memory Block) में संग्रहीत होते हैं। यही कारण है कि टेंसर ऑपरेशन्स को सीधे GPU (CUDA) और TPU जैसे विशेष हार्डवेयर पर भेजा जा सकता है।


2. कोड में टेंसर निर्माण और डिवाइस मैनेजमेंट

दोनों फ्रेमवर्क्स में सिंटैक्स NumPy के अत्यधिक निकट है, लेकिन इनमें हार्डवेयर त्वरण (Hardware Acceleration) की अंतर्निहित क्षमता होती है।


PyTorch: Explicit Device Handling

PyTorch डेवलपर को डिवाइस के आवंटन पर पूर्ण और स्पष्ट नियंत्रण देता है:

 

Python

import torch

 

# 1D Tensor का निर्माण

x = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32)

 

# डिवाइस का चयन और डेटा का स्थानांतरण

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

x = x.to(device)

 

print("PyTorch Tensor Device:", x.device)

TensorFlow: Implicit Device Placement

TensorFlow उपलब्ध होने पर स्वचालित रूप से GPU को प्राथमिकता देता है, यद्यपि संदर्भ प्रबंधक (Context Manager) द्वारा इसे स्पष्ट भी किया जा सकता है:

 

Python

import tensorflow as tf

 

# Tensor का निर्माण (अपरिवर्तनीय/Immutable मान)

x = tf.constant([1.0, 2.0, 3.0], dtype=tf.float32)

 

# डिवाइस की जानकारी देखना

print("TensorFlow Tensor Device:", x.device)

 

# आवश्यकता पड़ने पर स्पष्ट आवंटन

with tf.device('/CPU:0'):

    y = tf.constant([4.0, 5.0, 6.0])


3. स्वचालित अवकलन (Automatic Differentiation)

न्यूरल नेटवर्क अनिवार्य रूप से एक अनुकूलन समस्या (Optimization Problem) को हल करते हैं। वे अपने अनुमान और वास्तविक उत्तर के बीच की त्रुटि (Loss) को न्यूनतम करना चाहते हैं।

 

इसके लिए बैकप्रोपैगेशन (Backpropagation) एल्गोरिदम का उपयोग किया जाता है, जो कलन (Calculus) के चेन रूल (Chain Rule) पर आधारित है:

 $$\frac{\partial \text{Loss}}{\partial W} = \frac{\partial \text{Loss}}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial z} \cdot \frac{\partial z}{\partial W}$$

प्रत्येक पैरामीटर के सापेक्ष इस ढलान (Gradient) की गणना हाथ से करना असंभव है। यहीं पर फ्रेमवर्क्स का स्वचालित अवकलन इंजन कार्य करता है।

 

मान लीजिए हमारे पास एक साधारण द्विघात फलन है:

 $$y = x^2 + 3x$$

गणितीय रूप से, $x$ के सापेक्ष $y$ का अवकलज (Derivative):

 $$\frac{dy}{dx} = 2x + 3$$

यदि हम $x = 4.0$ का मूल्यांकन करें:

$$\left.\frac{dy}{dx}\right\vert{}_{x=4.0} = 2(4.0) + 3 = 11.0$$

आइए देखें कि दोनों फ्रेमवर्क्स इस गणना को प्रोग्रामेटिक रूप से कैसे क्रियान्वित करते हैं।


4. PyTorch Autograd: अंतर्निहित टेप और रिवर्स-मोड विभेदन

PyTorch में autograd इंजन कम्प्यूटेशनल ग्राफ को रन-टाइम पर गतिशील रूप से ट्रैक करता है। यदि किसी टेंसर के लिए requires_grad=True सेट किया गया है, तो उस पर होने वाले प्रत्येक ऑपरेशन का बैकवर्ड फंक्शन मेमोरी में एक निर्देशित चक्रीय ग्राफ (Directed Acyclic Graph - DAG) के रूप में जुड़ जाता है।


Python

import torch

 

# x को ट्रैक करने योग्य इनपुट के रूप में परिभाषित करना

x = torch.tensor(4.0, requires_grad=True)

 

# फॉरवर्ड समीकरण

y = x**2 + 3*x

 

# बैकवर्ड पास (रिवर्स-मोड ऑटोडिफ़)

y.backward()

 

# x के सापेक्ष ग्रेडिएंट प्राप्त करना

print("PyTorch Computed Gradient (dy/dx):", x.grad.item())

# आउटपुट: 11.0

  • विशेषता: y.backward(), execute होते ही कम्प्यूटेशनल ग्राफ मेमोरी से मुक्त (Freed) हो जाता है, जिससे मेमोरी का अत्यधिक कुशल प्रबंधन होता है।

5. TensorFlow GradientTape: स्पष्ट संदर्भ रिकॉर्डिंग

TensorFlow 2.x में ऑटोमैटिक डिफ़रेंशिएशन के लिए tf.GradientTape का उपयोग किया जाता है। जैसा कि नाम से स्पष्ट है, यह एक डिजिटल रिकॉर्डर की तरह काम करता है जो अपने संदर्भ (Context) के भीतर निष्पादित सभी फॉरवर्ड ऑपरेशन्स को रिकॉर्ड करता है और बाद में उल्टी दिशा में ग्रेडिएंट्स प्ले करता है।

Python

import tensorflow as tf

# x को एक परिवर्तनीय (Variable) के रूप में परिभाषित करना

x = tf.Variable(4.0)

 

# संदर्भ प्रबंधक के भीतर ऑपरेशन्स को रिकॉर्ड करना

with tf.GradientTape() as tape:

    y = x**2 + 3*x

 

# टेप से ग्रेडिएंट की गणना कराना

grad = tape.gradient(y, x)

print("TensorFlow Computed Gradient (dy/dx):", grad.numpy())

# आउटपुट: 11.0

  • विशेषता: डिफ़ॉल्ट रूप से, GradientTape का उपयोग केवल एक बार किया जा सकता है। यदि एक ही टेप से कई आउटपुट्स के लिए ग्रेडिएंट्स निकालने हों, तो persistent=True फ्लैग सेट करना पड़ता है।

 

6. Autograd बनाम GradientTape

तकनीकी पहलू

PyTorch (Autograd)

TensorFlow (GradientTape)

ग्राफ संरचना

इंप्लिसिट (टेंसर के निर्माण के साथ ही बैकवर्ड हुक्स सक्रिय हो जाते हैं)

एक्सप्लेसिट (केवल with tf.GradientTape() ब्लॉक के अंदर रिकॉर्डिंग)

वेरिएबल ट्रैकिंग

requires_grad=True वाले सभी फ्लोट टेंसर ट्रैक होते हैं

केवल tf.Variable स्वतः ट्रैक होते हैं; tf.constant के लिए tape.watch() आवश्यक

मेमोरी प्रबंधन

बैकवर्ड पास के बाद ग्राफ स्वतः डिलीट हो जाता है (जब तक retain_graph=True न हो)

ब्लॉक समाप्त होते ही टेप रिलीज़ हो जाती है (जब तक persistent=True न हो)

डिबगिंग सुविधा

सीधे सामान्य Python ब्रेकपॉइंट्स द्वारा मध्यवर्ती ग्रेडिएंट्स का निरीक्षण संभव

टेप के संदर्भ के बाहर ग्रेडिएंट्स की जाँच संभव, ग्राफ मोड में ट्रेसिंग आवश्यक

निष्कर्ष (Takeaway)

डीप लर्निंग के केंद्र में केवल दो चीजें हैं: डेटा को स्टोर करने के लिए Tensors और मॉडल को सुधारने के लिए Gradients।

जहाँ PyTorch का Autograd आपको एक सहज और स्वाभाविक प्रोग्रामिंग अनुभव देता है जिससे नए और गैर-पारंपरिक आर्किटेक्चर (जैसे डायनामिक रीइन्फोर्समेंट लर्निंग) आसानी से बनाए जा सकते हैं, वहीं TensorFlow का GradientTape आपको यह सूक्ष्म नियंत्रण देता है कि किन विशिष्ट गणनाओं पर नज़र रखनी है और किन्हें छोड़ना है।

श्रृंखला के भाग 3 में हम इन दोनों टूल्स का उपयोग करके अपना पहला न्यूरल नेटवर्क (Artificial Neural Network) बनाएंगे और देखेंगे कि Keras की सुव्यवस्थित लेयर्स और PyTorch के ऑब्जेक्ट-ओरिएंटेड nn.Module में कोड कैसे संरचित किया जाता है।

सीखते रहिए, कोड का अभ्यास करते रहिए और तकनीक के इस सफर में जुड़े रहिए!

–०–

– डॉ. चंद्रेश कुमार छतलानी

 

No comments:

Post a Comment