मुख्य सामग्री पर जाएँ

शुरुआतीों के लिए TensorFlow ट्यूटोरियल

TensorFlow के साथ एक न्यूरल नेटवर्क बनाना और उसे ट्रेन, मूल्यांकन और अनुकूलित करना सीखें
· 15 मि॰ पढ़ें

AI के साथ खोजें

graphic

डीप लर्निंग, मशीन लर्निंग का एक उपक्षेत्र है जिसमें ऐसे एल्गोरिदम का समूह शामिल है जो मस्तिष्क की संरचना और कार्यप्रणाली से प्रेरित हैं।

TensorFlow Google द्वारा बनाया गया और उपयोग किया जाने वाला दूसरा मशीन लर्निंग फ्रेमवर्क है, जिसका उपयोग डीप लर्निंग मॉडल डिज़ाइन, निर्माण और ट्रेनिंग के लिए किया जाता है। आप TensorFlow लाइब्रेरी से संख्यात्मक गणनाएँ कर सकते हैं, जो अपने आप में बहुत खास नहीं लगतीं, पर ये गणनाएँ डेटा फ्लो ग्राफ़्स के साथ की जाती हैं। इन ग्राफ़्स में, नोड्स गणितीय ऑपरेशंस का प्रतिनिधित्व करते हैं, जबकि एजेस डेटा का प्रतिनिधित्व करते हैं, जो आमतौर पर बहु-आयामी डेटा एरेज़ या टेन्सर्स होते हैं, और जो इन एजेस के बीच संप्रेषित होते हैं।

देखा? “TensorFlow” नाम उन ऑपरेशंस से लिया गया है जो न्यूरल नेटवर्क बहु-आयामी डेटा एरेज़ या टेन्सर्स पर करते हैं! यह सचमुच टेन्सर्स का फ्लो है। फिलहाल, टेन्सर्स के बारे में आपको इतना ही जानना पर्याप्त है; आप अगले हिस्सों में इसे और गहराई से समझेंगे!

आज के शुरुआतीों के लिए TensorFlow ट्यूटोरियल में आप इंटरैक्टिव तरीके से डीप लर्निंग करना सीखेंगे:

इस ट्यूटोरियल की नोटबुक यहाँ से डाउनलोड करें।

आप Deep Learning in Python कोर्स, DataCamp का Keras ट्यूटोरियल या R के साथ keras ट्यूटोरियल में भी रुचि ले सकते हैं।

टेन्सर्स का परिचय

टेन्सर्स को अच्छी तरह समझने के लिए, रेखीय बीजगणित और वेक्टर कैलकुलस का थोड़ा कार्यसिद्ध ज्ञान होना अच्छा है। आपने प्रस्तावना में पढ़ा कि TensorFlow में टेन्सर्स बहु-आयामी डेटा एरेज़ के रूप में लागू होते हैं, पर टेन्सर्स और उनके मशीन लर्निंग में उपयोग को पूरी तरह समझने के लिए थोड़ी और भूमिका ज़रूरी हो सकती है।

समतलीय वेक्टर

समतलीय वेक्टरों में जाने से पहले, “वेक्टर” की अवधारणा को संक्षेप में दोहराना अच्छा होगा; वेक्टर मैट्रिसेज़ (जो संख्याओं की आयताकार सरणियाँ होती हैं) के विशेष प्रकार हैं। क्योंकि वेक्टर संख्याओं के क्रमबद्ध संग्रह होते हैं, उन्हें अक्सर कॉलम मैट्रिक्स के रूप में देखा जाता है: इनमें केवल एक कॉलम और कुछ पंक्तियाँ होती हैं। अन्य शब्दों में, आप वेक्टरों को ऐसे स्केलर परिमाण मान सकते हैं जिन्हें दिशा दी गई है।

ध्यान रखें: स्केलर का एक उदाहरण “5 मीटर” या “60 m/sec” है, जबकि वेक्टर, उदाहरण के लिए, “5 मीटर उत्तर” या “60 m/sec पूर्व” है। इन दोनों में अंतर स्पष्ट रूप से यह है कि वेक्टर में दिशा होती है। फिर भी, अब तक दिखे उदाहरण उन वेक्टरों से दूर लग सकते हैं जो आपको मशीन लर्निंग समस्याओं में मिलते हैं। यह स्वाभाविक है; गणितीय वेक्टर की लंबाई एक शुद्ध संख्या है: यह निरपेक्ष है। दूसरी ओर, दिशा सापेक्ष है: इसे किसी संदर्भ दिशा के सापेक्ष मापा जाता है और इसके इकाई रैडियन या डिग्री होते हैं। आप आम तौर पर मानते हैं कि दिशा संदर्भ दिशा से वामावर्त घुमाव में सकारात्मक है।

vector

दृश्य रूप में, आप वेक्टरों को तीरों के रूप में दर्शाते हैं, जैसा कि ऊपर की तस्वीर में है। इसका मतलब है कि आप वेक्टरों को दिशा और लंबाई वाले तीरों के रूप में भी मान सकते हैं। दिशा तीर के सिर से इंगित होती है, जबकि लंबाई तीर की लंबाई से।

तो फिर समतलीय वेक्टर क्या हैं?

समतलीय वेक्टर टेन्सर्स की सबसे सीधी स्थापना हैं। वे ऊपर दिखे सामान्य वेक्टरों जैसे ही हैं, सिवाय इसके कि वे एक वेक्टर स्पेस में होते हैं। इसे बेहतर समझने के लिए, एक उदाहरण से शुरू करें: आपके पास एक 2 X 1 वेक्टर है। इसका अर्थ है कि वेक्टर वास्तविक संख्याओं के उस समुच्चय से संबंधित है जो एक समय में दो-दो के जोड़े में आते हैं। या, दूसरे शब्दों में, वे टू-स्पेस का हिस्सा हैं। ऐसे मामलों में, आप वेक्टरों को निर्देशांक (x,y) तल पर तीरों या किरणों से दर्शा सकते हैं।

मानक स्थिति में इस निर्देशांक तल से काम करते हुए, जहाँ वेक्टरों का अंतिम बिंदु मूलबिंदु (0,0) पर होता है, आप वेक्टर की पहली पंक्ति देखकर x निर्देशांक निकाल सकते हैं, जबकि y निर्देशांक दूसरी पंक्ति में मिलेगा। बेशक, यह मानक स्थिति हमेशा बनाए रखना आवश्यक नहीं है: वेक्टर तल में अपने आप के समानांतर चलते हुए बदलते नहीं हैं।

ध्यान दें कि इसी तरह, 3 X 1 आकार के वेक्टरों के लिए, आप थ्री-स्पेस की बात करते हैं। आप वेक्टर को त्रि-आयामी आकृति के रूप में दर्शा सकते हैं जिसमें तीर वेक्टर स्पेस में स्थितियों की ओर संकेत करते हैं: उन्हें मानक x, y और z अक्षों पर खींचा जाता है।

इन वेक्टरों का होना और उन्हें निर्देशांक तल पर दर्शाना अच्छा है, पर मूलतः, आपके पास ये वेक्टर इसलिए हैं कि आप उन पर ऑपरेशन कर सकें, और इसमें मदद के लिए आप अपने वेक्टरों को बेसिस या यूनिट वेक्टरों के रूप में व्यक्त कर सकते हैं।

यूनिट वेक्टर वेक्टर होते हैं जिनका परिमाण एक होता है। आप अक्सर यूनिट वेक्टर को छोटे अक्षर पर सर्कमफ्लेक्स या “हैट” से पहचानेंगे। यदि आप किसी 2-डी या 3-डी वेक्टर को दो या तीन आर्थोगोनल अवयवों, जैसे x− और y−अक्ष, या z−अक्ष के योग के रूप में व्यक्त करना चाहते हैं, तो यूनिट वेक्टर सुविधाजनक रहते हैं।

और जब आप किसी एक वेक्टर को, उदाहरण के लिए, अवयवों के योग के रूप में व्यक्त करने की बात करते हैं, तो आप कॉम्पोनेंट वेक्टरों की बात कर रहे होते हैं, जो दो या अधिक वेक्टर होते हैं जिनका योग वही दिया गया वेक्टर होता है।

टिप: यह वीडियो देखें, जो साधारण घरेलू वस्तुओं की मदद से टेन्सर्स समझाता है!

टेन्सर्स

समतलीय वेक्टरों के अलावा, कोवेक्टर और रैखिक ऑपरेटर दो अन्य मामले हैं जो तीनों में एक समान बात रखते हैं: ये टेन्सर्स के विशिष्ट मामले हैं। आप अभी भी याद रखते हैं कि पिछले खंड में वेक्टर को दिशा दिए गए स्केलर परिमाणों के रूप में परिभाषित किया गया था। तब टेन्सर किसी भौतिक इकाई का गणितीय प्रतिनिधित्व है जिसे परिमाण और एकाधिक दिशाओं से व्यक्त किया जा सकता है।

और, जैसे आप स्केलर को एक एकल संख्या से और, उदाहरण के लिए, 3-आयामी स्पेस में वेक्टर को तीन संख्याओं के अनुक्रम से व्यक्त करते हैं, वैसे ही 3-आयामी स्पेस में किसी टेन्सर को 3R संख्याओं की सरणी से व्यक्त किया जा सकता है।

इस संकेतन में “R” टेन्सर की रैंक का प्रतिनिधित्व करता है: इसका अर्थ है कि 3-आयामी स्पेस में, द्वितीय-रैंक टेन्सर को 3 की घात 2 यानी 9 संख्याओं से व्यक्त किया जा सकता है। N-आयामी स्पेस में, स्केलर को अभी भी केवल एक संख्या चाहिए होगी, वेक्टर को N संख्याएँ चाहिए होंगी, और टेन्सर को N^R संख्याएँ चाहिए होंगी। यही कारण है कि आप अक्सर सुनते हैं कि स्केलर रैंक 0 के टेन्सर होते हैं: क्योंकि उनकी कोई दिशा नहीं होती, आप उन्हें एक संख्या से व्यक्त कर सकते हैं।

इसे ध्यान में रखते हुए, स्केलर, वेक्टर और टेन्सर को पहचानना और अलग करना अपेक्षाकृत आसान है: स्केलर एक संख्या से, वेक्टर क्रमबद्ध संख्याओं के सेट से, और टेन्सर संख्याओं की सरणी से व्यक्त होते हैं।

टेन्सर्स को विशिष्ट बनाता है अवयवों और बेसिस वेक्टरों का संयोजन: बेसिस वेक्टर संदर्भ फ़्रेमों के बीच एक तरीके से ट्रांसफ़ॉर्म होते हैं और अवयव ऐसे तरीके से ट्रांसफ़ॉर्म होते हैं कि अवयवों और बेसिस वेक्टरों के बीच का संयोजन समान बना रहे।

TensorFlow इंस्टॉल करना

अब जब आप TensorFlow के बारे में अधिक जानते हैं, तो शुरुआत करने और लाइब्रेरी इंस्टॉल करने का समय है। यहाँ यह जानना अच्छा है कि TensorFlow Python, C++, Haskell, Java, Go, Rust के लिए API प्रदान करता है, और R के लिए tensorflow नामक एक थर्ड-पार्टी पैकेज भी है।

टिप: यदि आप R में डीप लर्निंग पैकेजों के बारे में अधिक जानना चाहते हैं, तो DataCamp का keras: Deep Learning in R ट्यूटोरियल देखें।

इस ट्यूटोरियल में, आप TensorFlow का ऐसा संस्करण डाउनलोड करेंगे जो आपको अपने डीप लर्निंग प्रोजेक्ट का कोड Python में लिखने देगा। TensorFlow इंस्टॉल पेज पर, आप virtualenv, pip, Docker का उपयोग करके TensorFlow इंस्टॉल करने के सामान्य तरीके और नवीनतम निर्देश देखेंगे, और अंत में, अपने पर्सनल कंप्यूटर पर TensorFlow इंस्टॉल करने के अन्य तरीकों के बारे में भी जानकारी होगी।

ध्यान दें आप Windows पर काम कर रहे हों तो Conda से भी TensorFlow इंस्टॉल कर सकते हैं। हालाँकि, क्योंकि TensorFlow की यह इंस्टॉलेशन कम्युनिटी-सपोर्टेड है, आधिकारिक इंस्टॉलेशन निर्देश देखना बेहतर है।

अब जब आप इंस्टॉलेशन प्रक्रिया से गुजर चुके हैं, तो यह सुनिश्चित करने का समय है कि आपने TensorFlow सही तरीके से इंस्टॉल किया है, इसे अपने वर्कस्पेस में tf उपनाम के साथ इम्पोर्ट करके:

import tensorflow as tf

ध्यान दें कि ऊपर की कोड लाइन में इस्तेमाल किया गया उपनाम एक तरह का मानक है - इसका उपयोग इस बात को सुनिश्चित करने के लिए किया जाता है कि आप एक तरफ डेटा साइंस प्रोजेक्ट्स में TensorFlow का उपयोग करने वाले अन्य डेवलपर्स के साथ और दूसरी तरफ ओपन-सोर्स TensorFlow प्रोजेक्ट्स के साथ सुसंगत बने रहें।

TensorFlow के साथ शुरुआत: बुनियादी बातें

आप आमतौर पर TensorFlow प्रोग्राम लिखते हैं, जिन्हें आप एक खंड के रूप में चलाते हैं; यह पहली नज़र में Python के साथ काम करते समय थोड़ा विरोधाभासी लगता है। हालाँकि, यदि आप चाहें, तो आप TensorFlow का Interactive Session भी इस्तेमाल कर सकते हैं, जिससे आप लाइब्रेरी के साथ अधिक इंटरैक्टिव तरीके से काम कर सकते हैं। यदि आप IPython के साथ काम करने के आदी हैं, तो यह खास तौर पर उपयोगी है।

इस ट्यूटोरियल में, आप दूसरे विकल्प पर ध्यान देंगे: यह आपको TensorFlow में डीप लर्निंग शुरू करने में मदद करेगा। पर इससे आगे बढ़ने से पहले, भारी काम से पहले कुछ छोटी चीज़ें आज़मा लें।

सबसे पहले, पिछले खंड में दिखाए अनुसार tensorflow लाइब्रेरी को tf उपनाम के साथ इम्पोर्ट करें। फिर दो वेरिएबल्स इनिशियलाइज़ करें जो वास्तव में कॉन्स्टैंट्स हैं। constant() फ़ंक्शन को चार संख्याओं की एक एरे पास करें।

ध्यान दें कि आप चाहें तो एक integer भी पास कर सकते हैं, पर अधिकांश समय आप एरेज़ के साथ काम करेंगे। प्रस्तावना में आपने देखा, टेन्सर्स का सार ही एरेज़ हैं! इसलिए सुनिश्चित करें कि आप एरे पास करें :) अब, आप multiply() का उपयोग करके अपने दोनों वेरिएबल्स को गुणा कर सकते हैं। परिणाम को result वेरिएबल में स्टोर करें। अंत में, print() फ़ंक्शन की मदद से result को प्रिंट करें।

# Import `tensorflow`
import tensorflow as tf

# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])

# Multiply
result = tf.multiply(x1, x2)

# Print the result
print(result)

ध्यान दें कि आपने ऊपर DataCamp Light कोड खंड में कॉन्स्टैंट्स परिभाषित किए हैं। हालाँकि, आप संभावित रूप से दो अन्य प्रकार के मानों का भी उपयोग कर सकते हैं, यानी placeholders, जो असाइन नहीं होते और सेशन चलने पर इनिशियलाइज़ होंगे। जैसा कि नाम से स्पष्ट है, यह एक टेन्सर के लिए प्लेसहोल्डर है, जिसे सेशन चलाने पर हमेशा फ़ीड किया जाएगा; वहीं Variables भी हैं, जो बदल सकते हैं। कॉन्स्टैंट्स, जैसा कि आप समझ चुके होंगे, वे मान हैं जो नहीं बदलते।

इन कोड लाइनों का परिणाम कंप्यूटेशन ग्राफ में एक अमूर्त टेन्सर है। पर, आपकी अपेक्षा के विपरीत, result वास्तव में कैलकुलेट नहीं होता। इसने केवल मॉडल परिभाषित किया है, पर कोई प्रक्रिया परिणाम की गणना के लिए नहीं चली। आप इसे प्रिंट-आउट में देख सकते हैं: वास्तव में वह परिणाम (यानी, 30) नहीं दिखता जो आप देखना चाहते हैं। इसका मतलब है कि TensorFlow में lazy evaluation होती है!

हालाँकि, यदि आप परिणाम देखना चाहते हैं, तो आपको यह कोड एक इंटरैक्टिव सेशन में चलाना होगा। आप इसे कई तरीकों से कर सकते हैं, जैसा कि नीचे दिए DataCamp Light कोड खंडों में दिखाया गया है:

# Import `tensorflow` 
import tensorflow as tf

# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])

# Multiply
result = tf.multiply(x1, x2)

# Intialize the Session
sess = tf.Session()

# Print the result
print(sess.run(result))

# Close the session
sess.close()

ध्यान दें कि आप निम्नलिखित कोड लाइनों का उपयोग करके एक इंटरैक्टिव सेशन शुरू कर सकते हैं, result चला सकते हैं और output प्रिंट करने के बाद सेशन अपने आप बंद हो जाएगा:

# Import `tensorflow`
import tensorflow as tf

# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])

# Multiply
result = tf.multiply(x1, x2)

# Initialize Session and run `result`
with tf.Session() as sess:
  output = sess.run(result)
  print(output)

ऊपर के कोड खंडों में आपने एक डिफ़ॉल्ट सेशन परिभाषित किया है, पर यह जानना भी अच्छा है कि आप विकल्प पास कर सकते हैं। उदाहरण के लिए, आप config आर्गुमेंट निर्दिष्ट कर सकते हैं और फिर ConfigProto प्रोटोकॉल बफर का उपयोग करके अपने सेशन के लिए कॉन्फ़िगरेशन विकल्प जोड़ सकते हैं।

उदाहरण के लिए, यदि आप

config=tf.ConfigProto(log_device_placement=True)

अपनी सेशन में जोड़ते हैं, तो आप उस GPU या CPU डिवाइस को लॉग करेंगे जिसे किसी ऑपरेशन को असाइन किया गया है। उसके बाद आपको प्रत्येक ऑपरेशन के लिए सेशन में उपयोग किए गए डिवाइसेज़ की जानकारी मिलेगी। आप निम्नलिखित कॉन्फ़िगरेशन सेशन का उपयोग तब भी कर सकते हैं, उदाहरण के लिए, जब आप डिवाइस प्लेसमेंट के लिए सॉफ्ट constraints का उपयोग करते हैं:

config=tf.ConfigProto(allow_soft_placement=True)

अब जब आपने TensorFlow इंस्टॉल कर लिया है और उसे अपने वर्कस्पेस में इम्पोर्ट कर लिया है और इस पैकेज के साथ काम करने की बुनियादी बातें देख ली हैं, तो इसे कुछ देर के लिए एक तरफ रखकर अपने डेटा पर ध्यान देना समय है। हमेशा की तरह, आप न्यूरल नेटवर्क का मॉडलिंग शुरू करने से पहले अपने डेटा को समझने और खोजने के लिए समय निकालेंगे।

बेल्जियम के ट्रैफिक साइन: पृष्ठभूमि

भले ही ट्रैफिक एक ऐसा विषय है जिससे आप सभी सामान्यतः परिचित हैं, पर यह बुरा नहीं कि इस डेटासेट में शामिल प्रेक्षणों पर संक्षेप में नजर डाली जाए ताकि आप शुरू करने से पहले सब कुछ समझते हों। मूल रूप से, इस खंड में, आप इस ट्यूटोरियल को आगे बढ़ाने के लिए आवश्यक डोमेन ज्ञान से अवगत हो जाएंगे।

बेशक, क्योंकि मैं बेल्जियन हूँ, मैं सुनिश्चित करूँगा कि आपको कुछ किस्से भी मिलें :)

  • बेल्जियन ट्रैफिक साइन आम तौर पर डच और फ्रेंच में होते हैं। यह जानना अच्छा है, पर जिस डेटासेट पर आप काम करेंगे, उसके लिए यह बहुत महत्वपूर्ण नहीं है!
  • बेल्जियम में ट्रैफिक साइन की छह श्रेणियाँ हैं: चेतावनी संकेत, प्राथमिकता संकेत, निषेधात्मक संकेत, अनिवार्य संकेत, सड़क पर पार्किंग और खड़े रहने से संबंधित संकेत और, अंत में, सूचक संकेत।
  • 1 जनवरी, 2017 को, बेल्जियम की सड़कों से 30,000 से अधिक ट्रैफिक साइन हटा दिए गए। ये सभी गति से संबंधित निषेधात्मक संकेत थे।
  • हटाए जाने की बात करें, तो ट्रैफिक साइन की भारी उपस्थिति बेल्जियम (और विस्तार से, पूरे यूरोपीय संघ) में लगातार चर्चा का विषय रही है।

डेटा लोड करना और खोज करना

अब जब आपने कुछ और पृष्ठभूमि जानकारी एकत्र कर ली है, तो यहाँ से डेटासेट डाउनलोड करने का समय है। आपको "BelgiumTS for Classification (cropped images)" के पास सूचीबद्ध दो ज़िप फाइलें मिलनी चाहिए, जिनके नाम "BelgiumTSC_Training" और "BelgiumTSC_Testing" हैं।

टिप: यदि आपने फाइलें डाउनलोड कर ली हैं या इस ट्यूटोरियल को पूरा करने के बाद करेंगे, तो डाउनलोड किए गए डेटा के फ़ोल्डर स्ट्रक्चर पर नज़र डालें! आप देखेंगे कि टेस्टिंग और ट्रेनिंग डेटा फ़ोल्डर्स में 61 सबफ़ोल्डर्स हैं, जो 62 प्रकार के ट्रैफिक साइन हैं जिन्हें आप इस ट्यूटोरियल में वर्गीकरण के लिए उपयोग करेंगे। साथ ही, आप पाएँगे कि फाइलों का एक्सटेंशन .ppm या Portable Pixmap Format है। आपने ट्रैफिक साइन की छवियाँ डाउनलोड की हैं!

आइए डेटा को अपने वर्कस्पेस में इम्पोर्ट करने से शुरू करें। यूज़र-डिफाइंड फ़ंक्शन (UDF) load_data() के नीचे दिखाई देने वाली कोड लाइनों से शुरू करें:

  • सबसे पहले, अपना ROOT_PATH सेट करें। यह वह पथ है जहाँ आपने अपने ट्रेनिंग और टेस्ट डेटा के साथ डायरेक्टरी बनाई है।
  • इसके बाद, आप join() फ़ंक्शन की मदद से अपने ROOT_PATH में विशिष्ट पथ जोड़ सकते हैं। आप इन दो विशिष्ट पथों को train_data_directory और test_data_directory में स्टोर करते हैं।
  • आप देखते हैं कि इसके बाद, आप load_data() फ़ंक्शन को कॉल कर सकते हैं और इसमें train_data_directory पास कर सकते हैं।
  • अब, load_data() फ़ंक्शन स्वयं train_data_directory में मौजूद सभी सबडायरेक्टरीज़ एकत्र करके शुरू होता है; यह लिस्ट कम्प्रीहेंशन की मदद से ऐसा करता है, जो सूचियाँ बनाने का एक स्वाभाविक तरीका है - यह मूल रूप से कहता है कि, यदि आपको train_data_directory में कुछ मिलता है, तो आप डबल-चेक करेंगे कि यह एक डायरेक्टरी है या नहीं, और यदि है, तो आप इसे अपनी सूची में जोड़ देंगे। याद रखें कि प्रत्येक सबडायरेक्टरी एक लेबल का प्रतिनिधित्व करती है।
  • इसके बाद, आपको सबडायरेक्टरीज़ के माध्यम से लूप करना होगा। आप पहले दो सूचियाँ इनिशियलाइज़ करते हैं, labels और images। फिर, आप सबडायरेक्टरीज़ के पथ और उन सबडायरेक्टरीज़ में संग्रहीत छवियों के फाइल नाम एकत्र करते हैं। इसके बाद, आप append() फ़ंक्शन की मदद से इन दो सूचियों में डेटा इकट्ठा कर सकते हैं।
def load_data(data_directory):
    directories = [d for d in os.listdir(data_directory) 
                   if os.path.isdir(os.path.join(data_directory, d))]
    labels = []
    images = []
    for d in directories:
        label_directory = os.path.join(data_directory, d)
        file_names = [os.path.join(label_directory, f) 
                      for f in os.listdir(label_directory) 
                      if f.endswith(".ppm")]
        for f in file_names:
            images.append(skimage.data.imread(f))
            labels.append(int(d))
    return images, labels

ROOT_PATH = "/your/root/path"
train_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Training")
test_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Testing")

images, labels = load_data(train_data_directory)

ध्यान दें कि ऊपर दिए कोड खंड में, ट्रेनिंग और टेस्ट डेटा "Training" और "Testing" नामक फ़ोल्डर्स में हैं, जो दोनों "TrafficSigns" नामक दूसरी डायरेक्टरी की सबडायरेक्टरीज़ हैं। लोकल मशीन पर, यह कुछ इस तरह दिख सकता है "/Users/Name/Downloads/TrafficSigns", जिनमें "Training" और "Testing" नामक दो सबफ़ोल्डर हों।

टिप: DataCamp के Python Functions ट्यूटोरियल से Python में फ़ंक्शन्स लिखना दोहराएँ।

ट्रैफिक साइन सांख्यिकी

डेटा लोड हो जाने के बाद, कुछ डेटा निरीक्षण का समय है! आप images एरे के ndim और size एट्रीब्यूट्स की मदद से एक सरल विश्लेषण से शुरू कर सकते हैं:

ध्यान दें कि images और labels वेरिएबल सूचियाँ हैं, इसलिए आपको अपने वर्कस्पेस में उन्हें एरे में बदलने के लिए np.array() का उपयोग करने की आवश्यकता हो सकती है। यहाँ आपके लिए यह कर दिया गया है!

# Print the `images` dimensions
print(images.ndim)

# Print the number of `images`'s elements
print(images.size)

# Print the first instance of `images`
images[0]

ध्यान दें कि आपने जो images[0] प्रिंट किया है, वह वास्तव में एरेज़ के भीतर एरेज़ से दर्शाई गई एक एकल छवि है! यह शुरू में सहज नहीं लगेगा, पर जैसे-जैसे आप मशीन लर्निंग या डीप लर्निंग अनुप्रयोगों में छवियों के साथ काम करेंगे, इसकी आदत हो जाएगी।

अब, आप labels पर भी एक छोटी नज़र डाल सकते हैं, पर इस बिंदु पर कोई बड़ी हैरानी नहीं होनी चाहिए:

# Print the `labels` dimensions
print(labels.ndim)

# Print the number of `labels`'s elements
print(labels.size)

# Count the number of labels
print(len(set(labels)))

ये संख्याएँ पहले से ही आपको इस बारे में कुछ जानकारी देती हैं कि आपका इम्पोर्ट कितना सफल रहा और आपके डेटा का सटीक आकार क्या है। पहली नज़र में, सब कुछ वैसा ही निष्पादित हुआ जैसा आपने अपेक्षा की थी, और आप देखते हैं कि एरे का आकार काफ़ी बड़ा है यदि आप ध्यान दें कि आप एरेज़ के भीतर एरेज़ से निपट रहे हैं।

टिप अपनी एरेज़ में निम्न एट्रीब्यूट जोड़कर आज़माएँ: flags, itemsize, और nbytes, ताकि आप मेमोरी लेआउट, किसी एक एरे एलिमेंट की लंबाई (बाइट्स में) और एरे के सभी एलिमेंट्स द्वारा उपभोगित कुल बाइट्स के बारे में अधिक जानकारी प्राप्त कर सकें। आप इसे ऊपर के DataCamp Light खंड में IPython कंसोल में आज़मा सकते हैं!

अब, आप ट्रैफिक साइन के वितरण पर भी नज़र डाल सकते हैं:

# Import the `pyplot` module
import matplotlib.pyplot as plt 

# Make a histogram with 62 bins of the `labels` data
plt.hist(labels, 62)

# Show the plot
plt.show()

शानदार काम! अब आपके द्वारा बनाए गए हिस्टोग्राम पर नज़दीकी नज़र डालते हैं!

distribution of traffic sign labels

आप स्पष्ट रूप से देखते हैं कि सभी प्रकार के ट्रैफिक साइन डेटासेट में समान रूप से प्रतिनिधित्व नहीं करते। यह वह बात है जिससे आप बाद में निपटेंगे जब आप न्यूरल नेटवर्क का मॉडलिंग शुरू करने से पहले डेटा का संसाधन करेंगे।

पहली नज़र में, आप देखते हैं कि कुछ लेबल डेटासेट में दूसरों की तुलना में अधिक मौजूद हैं: लेबल 22, 32, 38 और 61 निश्चित रूप से अलग दिखाई देते हैं। इस बिंदु पर, इसे ध्यान में रखना अच्छा है, पर आप अगले खंड में निश्चित रूप से इसे और आगे बढ़ाएंगे!

ट्रैफिक साइन का दृश्यांकन

पिछले छोटे विश्लेषणों या जाँचों ने आपको आपके डेटा के बारे में कुछ अंदाज़ा दे दिया है, पर जब आपका डेटा मुख्यतः छवियों से बना हो, तो आपको उसे खोजने के लिए जो कदम उठाना चाहिए, वह है उनका दृश्यांकन।

कुछ यादृच्छिक ट्रैफिक साइन देखें:

  • सबसे पहले, matplotlib पैकेज के pyplot मॉड्यूल को सामान्य उपनाम plt के साथ इम्पोर्ट करें।
  • फिर, आप 4 यादृच्छिक संख्याओं की एक सूची बनाएँगे। इनका उपयोग images एरे से ट्रैफिक साइन चुनने के लिए किया जाएगा, जिसे आपने पिछले खंड में जाँचा था। इस मामले में, आप 300, 2250, 3650 और 4000 चुनते हैं।
  • इसके बाद, आप कहेंगे कि उस सूची की लंबाई के प्रत्येक तत्व के लिए, यानी 0 से 4 तक, आप बिना एक्सिस वाले सबप्लॉट बनाएँगे (ताकि उनका ध्यान न भटके और आपका फोकस केवल छवियों पर रहे!)। इन सबप्लॉट्स में, आप images एरे से एक विशिष्ट छवि दिखाएँगे जो इंडेक्स i पर मौजूद संख्या के अनुरूप है। पहले लूप में, आप 300 images[] को देंगे, दूसरे राउंड में 2250, वगैरह। आखिर में, आप सबप्लॉट्स को समायोजित करेंगे ताकि उनके बीच पर्याप्त चौड़ाई हो।
  • आखिरी काम है show() फ़ंक्शन की मदद से अपना प्लॉट दिखाना!

लीजिए:

# Import the `pyplot` module of `matplotlib`
import matplotlib.pyplot as plt

# Determine the (random) indexes of the images that you want to see 
traffic_signs = [300, 2250, 3650, 4000]

# Fill out the subplots with the random images that you defined 
for i in range(len(traffic_signs)):
    plt.subplot(1, 4, i+1)
    plt.axis('off')
    plt.imshow(images[traffic_signs[i]])
    plt.subplots_adjust(wspace=0.5)

plt.show()

जैसा कि आपने इस डेटासेट में शामिल 62 लेबल्स से अंदाज़ा लगाया था, संकेत आपस में अलग हैं।

पर और क्या ध्यान देते हैं? नीचे दी गई छवियों पर फिर से नज़दीकी नज़र डालें:

traffic signs

ये चारों छवियाँ एक ही आकार की नहीं हैं!

आप traffic_signs सूची में निहित संख्याओं के साथ खेल सकते हैं और इस अवलोकन का और विस्तार से अनुसरण कर सकते हैं, पर जैसा भी हो, यह एक महत्वपूर्ण अवलोकन है जिसे आपको अपने डेटा में अधिक हेरफेर करने और उसे न्यूरल नेटवर्क को फ़ीड करने की दिशा में काम शुरू करते समय ध्यान में रखना होगा।

आइए अलग-अलग आकारों की परिकल्पना की पुष्टि उन विशिष्ट छवियों के आकार, न्यूनतम और अधिकतम मान प्रिंट करके करें जिन्हें आपने सबप्लॉट्स में शामिल किया है।

नीचे का कोड ऊपर बनाए गए प्लॉट जैसा ही है, पर अंतर यह है कि यहाँ आप एक-दूसरे के बगल में केवल छवियों को प्लॉट करने के बजाय आकार और छवियों को बारी-बारी से दिखाएँगे:

# Import `matplotlib`
import matplotlib.pyplot as plt

# Determine the (random) indexes of the images
traffic_signs = [300, 2250, 3650, 4000]

# Fill out the subplots with the random images and add shape, min and max values
for i in range(len(traffic_signs)):
    plt.subplot(1, 4, i+1)
    plt.axis('off')
    plt.imshow(images[traffic_signs[i]])
    plt.subplots_adjust(wspace=0.5)
    plt.show()
    print("shape: {0}, min: {1}, max: {2}".format(images[traffic_signs[i]].shape, 
                                                  images[traffic_signs[i]].min(), 
                                                  images[traffic_signs[i]].max()))

ध्यान दें कि आप स्ट्रिंग "shape: {0}, min: {1}, max: {2}" पर format() मेथड का उपयोग करते हैं ताकि आपने जो आर्गुमेंट {0}, {1}, और {2} परिभाषित किए हैं, वे भर सकें।

traffic signs 2

अब जब आपने अलग-अलग छवियाँ देख ली हैं, तो आप अपने डेटा एक्सप्लोरेशन के पहले चरणों में प्रिंट किए गए हिस्टोग्राम पर भी फिर से जाना चाहेंगे; आप 62 सभी क्लासेस और प्रत्येक क्लास से संबंधित एक छवि का अवलोकन प्लॉट करके इसे आसानी से कर सकते हैं:

# Import the `pyplot` module as `plt`
import matplotlib.pyplot as plt 

# Get the unique labels 
unique_labels = set(labels)

# Initialize the figure
plt.figure(figsize=(15, 15))

# Set a counter
i = 1

# For each unique label,
for label in unique_labels:
    # You pick the first image for each label
    image = images[labels.index(label)]
    # Define 64 subplots 
    plt.subplot(8, 8, i)
    # Don't include axes
    plt.axis('off')
    # Add a title to each subplot 
    plt.title("Label {0} ({1})".format(label, labels.count(label)))
    # Add 1 to the counter
    i += 1
    # And you plot this first image 
    plt.imshow(image)
    
# Show the plot
plt.show()

ध्यान दें कि भले ही आप 64 सबप्लॉट परिभाषित करते हैं, सभी में छवियाँ नहीं दिखेंगी (क्योंकि केवल 62 लेबल हैं!)। यह भी ध्यान दें कि फिर से, आप कोई एक्सिस शामिल नहीं करते ताकि पाठकों का ध्यान मुख्य विषय से न भटके: ट्रैफिक साइन!

traffic signs 3

जैसा कि आपने ऊपर के हिस्टोग्राम में अनुमान लगाया था, लेबल 22, 32, 38 और 61 वाले ट्रैफिक साइन काफ़ी अधिक हैं। यह परिकल्पना अब इस प्लॉट में पुष्टि होती है: आप देखते हैं कि लेबल 22 के 375 उदाहरण, लेबल 32 के 316 उदाहरण, लेबल 38 के 285 उदाहरण और अंत में, लेबल 61 के 282 उदाहरण हैं।

अब आप अपने आप से पूछ सकते हैं कि क्या इन सभी उदाहरणों के बीच कोई संबंध है - शायद ये सभी सूचक संकेत हैं?

गहराई से देखें: आप देखते हैं कि लेबल 22 और 32 निषेधात्मक संकेत हैं, पर लेबल 38 और 61 क्रमशः सूचक और प्राथमिकता संकेत हैं। इसका मतलब है कि इन चारों के बीच कोई तात्कालिक संबंध नहीं है, सिवाय इसके कि डेटासेट में पर्याप्त उपस्थिति वाले संकेतों में से आधे निषेधात्मक प्रकार के हैं।

DataCamp की Python कोर्स लाइब्रेरी बैनर का अन्वेषण करें

फ़ीचर निष्कर्षण

अब जब आपने अपने डेटा का अच्छी तरह से अन्वेषण कर लिया है, तो अब काम शुरू करने का समय है! यह सुनिश्चित करने के लिए कि आप मैनिपुलेशन में कोई कदम न भूलें, संक्षेप में देखें कि आपने क्या खोजा:

  • छवियों का आकार असमान था;
  • 62 लेबल या टार्गेट वैल्यू हैं (क्योंकि आपके लेबल 0 से शुरू होते हैं और 61 पर समाप्त होते हैं);
  • ट्रैफिक साइन वैल्यू का वितरण काफ़ी असमान है; डेटासेट में अधिक मौजूद संकेतों के बीच कोई वास्तविक संबंध नहीं था।

अब जब आपको स्पष्ट पता है कि क्या सुधार करना है, तो आप अपने डेटा में इस तरह से हेरफेर करना शुरू कर सकते हैं कि वह न्यूरल नेटवर्क या किसी भी मॉडल को फ़ीड किए जाने के लिए तैयार हो। पहले कुछ फ़ीचर्स निकालने से शुरू करें - आप छवियों को रिस्केल करेंगे, और images एरे में रखी छवियों को ग्रेस्केल में बदलेंगे। आप यह रंग परिवर्तन मुख्य रूप से इसलिए करेंगे क्योंकि ऐसी वर्गीकरण समस्याओं में रंग कम मायने रखता है जैसी कि आप अभी सुलझा रहे हैं। पर डिटेक्शन के लिए, रंग का बड़ा महत्व होता है! इसलिए उन मामलों में, यह रूपांतरण ज़रूरी नहीं है!

छवियों का रिस्केलिंग

अलग-अलग छवि आकारों से निपटने के लिए, आप छवियों को रिस्केल करने जा रहे हैं; आप इसे skimage या Scikit-Image लाइब्रेरी की मदद से आसानी से कर सकते हैं, जो इमेज प्रोसेसिंग के लिए एल्गोरिदम का संग्रह है।

इस मामले में, transform मॉड्यूल काम आएगा, क्योंकि यह आपको resize() फ़ंक्शन देता है; आप देखेंगे कि आप (फिर से!) लिस्ट कम्प्रीहेंशन का उपयोग करके प्रत्येक छवि को 28 बाय 28 पिक्सल में रिसाइज़ करते हैं। एक बार फिर, आप देखते हैं कि आप सूची वास्तव में कैसे बनाते हैं: images एरे में मिलने वाली प्रत्येक छवि के लिए, आप skimage लाइब्रेरी से लिया गया ट्रांसफॉर्मेशन ऑपरेशन करते हैं। अंततः, आप परिणाम को images28 वेरिएबल में स्टोर करते हैं:

# Import the `transform` module from `skimage`
from skimage import transform 

# Rescale the images in the `images` array
images28 = [transform.resize(image, (28, 28)) for image in images]

यह काफ़ी आसान था, है न?

ध्यान दें कि अब छवियाँ चार-आयामी हैं: यदि आप images28 को एरे में बदलते हैं और उसमें shape एट्रीब्यूट जोड़ते हैं, तो प्रिंटआउट बताएगा कि images28 के आयाम (4575, 28, 28, 3) हैं। छवियाँ 784-आयामी हैं (क्योंकि आपकी छवियाँ 28 बाय 28 पिक्सल हैं)।

आप रिस्केलिंग ऑपरेशन के परिणाम की जाँच traffic_signs वेरिएबल की मदद से 4 यादृच्छिक छवियाँ प्लॉट करने के लिए ऊपर उपयोग किए गए कोड को फिर से उपयोग करके कर सकते हैं। बस images के सभी संदर्भों को images28 में बदलना न भूलें।

परिणाम यहाँ देखें:

4 random images

ध्यान दें कि रिस्केल करने के कारण आपके min और max मान भी बदल गए हैं; वे अब सभी समान रेंज में प्रतीत होते हैं, जो बहुत अच्छा है क्योंकि तब आपको आवश्यक रूप से अपने डेटा को normalize करने की ज़रूरत नहीं है!

छवियों को ग्रेस्केल में बदलना

जैसा कि इस खंड की प्रस्तावना में कहा गया, तस्वीरों में रंग वर्गीकरण प्रश्न का उत्तर देते समय कम मायने रखता है। इसलिए आप छवियों को ग्रेस्केल में बदलने का कष्ट भी उठाएँगे।

ध्यान दें, हालाँकि, कि आप यह भी खुद टेस्ट कर सकते हैं कि यदि आप इस विशेष चरण का पालन नहीं करते तो आपके मॉडल के अंतिम परिणामों पर क्या असर पड़ता।

रिस्केलिंग की तरह ही, आप फिर से Scikit-Image लाइब्रेरी पर भरोसा कर सकते हैं; इस मामले में, color मॉड्यूल का rgb2gray() फ़ंक्शन आपको वहाँ पहुँचने में मदद करेगा जहाँ आपको होना है।

यह बढ़िया और आसान रहेगा!

हालाँकि, images28 वेरिएबल को वापस एरे में बदलना न भूलें, क्योंकि rgb2gray() फ़ंक्शन एक आर्गुमेंट के रूप में एरे की अपेक्षा करता है।

# Import `rgb2gray` from `skimage.color`
from skimage.color import rgb2gray

# Convert `images28` to an array
images28 = np.array(images28)

# Convert `images28` to grayscale
images28 = rgb2gray(images28)

कुछ छवियाँ प्लॉट करके अपने ग्रेस्केल रूपांतरण के परिणाम की दोबारा जाँच करें; यहाँ भी, आप समायोजित छवियों को दिखाने के लिए थोड़ा अनुकूलित कोड फिर से उपयोग कर सकते हैं:

import matplotlib.pyplot as plt

traffic_signs = [300, 2250, 3650, 4000]

for i in range(len(traffic_signs)):
    plt.subplot(1, 4, i+1)
    plt.axis('off')
    plt.imshow(images28[traffic_signs[i]], cmap="gray")
    plt.subplots_adjust(wspace=0.5)
    
# Show the plot
plt.show()

ध्यान दें कि आपको वास्तव में कलर मैप या cmap निर्दिष्ट करना होगा और उसे "gray" पर सेट करना होगा ताकि छवियाँ ग्रेस्केल में प्लॉट हों। ऐसा इसलिए है क्योंकि imshow() डिफ़ॉल्ट रूप से, एक हीटमैप-जैसा कलर मैप उपयोग करता है। और पढ़ें यहाँ।

traffic signs 4

टिप: चूँकि आपने इस फ़ंक्शन का इस ट्यूटोरियल में काफी उपयोग किया है, आप देख सकते हैं कि इसे एक फ़ंक्शन में कैसे बदला जाए :)

ये दोनों कदम बहुत बुनियादी हैं; अन्य ऑपरेशंस जो आप अपने डेटा पर आज़मा सकते थे उनमें डेटा ऑग्मेंटेशन (रोटेट करना, ब्लर करना, शिफ्ट करना, ब्राइटनेस बदलना, …) शामिल हैं। यदि आप चाहें, तो आप डेटा मैनिपुलेशन ऑपरेशंस की पूरी पाइपलाइन भी सेटअप कर सकते हैं, जिनसे होकर आप अपनी छवियाँ भेजें।

TensorFlow के साथ डीप लर्निंग

अब जब आपने अपने डेटा का अन्वेषण और मैनिपुलेशन कर लिया है, तो TensorFlow पैकेज की मदद से अपना न्यूरल नेटवर्क आर्किटेक्चर बनाने का समय है!

न्यूरल नेटवर्क का मॉडलिंग

जैसा कि आपने Keras के साथ किया होगा, अब समय है कि आप अपने न्यूरल नेटवर्क को लेयर दर लेयर बनाएं।

यदि आपने अब तक नहीं किया है, तो tensorflow को अपने वर्कस्पेस में सामान्य उपनाम tf के साथ इम्पोर्ट करें। फिर, आप Graph() की मदद से ग्राफ इनिशियलाइज़ कर सकते हैं। आप इस फ़ंक्शन का उपयोग कंप्यूटेशन को परिभाषित करने के लिए करते हैं। ध्यान दें कि ग्राफ से आप कुछ कंप्यूट नहीं करते, क्योंकि यह कोई मान नहीं रखता। यह केवल उन ऑपरेशंस को परिभाषित करता है जिन्हें आप बाद में चलाना चाहते हैं।

इस मामले में, आप as_default() की मदद से एक डिफ़ॉल्ट संदर्भ सेट करते हैं, जो एक कॉन्टेक्स्ट मैनेजर लौटाता है जो इस विशिष्ट ग्राफ को डिफ़ॉल्ट ग्राफ बनाता है। यदि आप उसी प्रक्रिया में कई ग्राफ बनाना चाहते हैं, तो आप इस मेथड का उपयोग करते हैं: इस फ़ंक्शन से, आपके पास एक ग्लोबल डिफ़ॉल्ट ग्राफ होता है जिसमें सभी ऑपरेशंस जोड़ दिए जाएँगे यदि आप स्पष्ट रूप से नया ग्राफ नहीं बनाते।

इसके बाद, आप अपने ग्राफ में ऑपरेशंस जोड़ने के लिए तैयार हैं। जैसा कि आपको Keras के साथ काम करने से याद होगा, आप अपना मॉडल बनाते हैं, और फिर उसे कंपाइल करते समय, आप एक लॉस फ़ंक्शन, एक ऑप्टिमाइज़र, और एक मेट्रिक परिभाषित करते हैं। अब जब आप TensorFlow के साथ काम करते हैं तो यह सब एक ही चरण में होता है:

    • सबसे पहले, आप इनपुट्स और लेबल्स के लिए प्लेसहोल्डर्स परिभाषित करते हैं क्योंकि आप अभी “वास्तविक” डेटा नहीं डालेंगे। याद रखें कि प्लेसहोल्डर्स वे मान होते हैं जो असाइन नहीं होते और सेशन चलने पर इनिशियलाइज़ होते हैं। तो जब आप अंततः सेशन चलाते हैं, तो ये प्लेसहोल्डर्स आपके डेटासेट के उन मानों को लेंगे जिन्हें आप run() फ़ंक्शन में पास करते हैं!
    • फिर, आप नेटवर्क बनाते हैं। आप पहले flatten() फ़ंक्शन की मदद से इनपुट को flatten करते हैं, जो आपको [None, 28, 28] के बजाय [None, 784] आकार की एरे देगा, जो आपकी ग्रेस्केल छवियों का आकार है।
    • इनपुट को flatten करने के बाद, आप एक fully connected लेयर बनाते हैं जो [None, 62] आकार के logits उत्पन्न करती है। Logits वह फ़ंक्शन है जो पिछले लेयरों के unscaled आउटपुट पर काम करता है और units के linear होने को सापेक्ष स्केल से समझता है।
    • मल्टी-लेयर परसेप्ट्रॉन बनाने के बाद, आप लॉस फ़ंक्शन परिभाषित कर सकते हैं। लॉस फ़ंक्शन का चुनाव आपके कार्य पर निर्भर करता है: इस मामले में, आप उपयोग करते हैं
sparse_softmax_cross_entropy_with_logits()
  • यह logits और लेबल्स के बीच sparse softmax cross entropy की गणना करता है। दूसरे शब्दों में, यह डिस्क्रीट क्लासिफिकेशन टास्क में संभावना त्रुटि को मापता है जिसमें क्लासेस परस्पर अनन्य होती हैं। इसका अर्थ है कि प्रत्येक प्रविष्टि ठीक एक क्लास में है। यहाँ, किसी ट्रैफिक साइन का केवल एक ही लेबल हो सकता है। याद रखें कि जहाँ regression का उपयोग सतत मानों की भविष्यवाणी के लिए होता है, वहीं classification का उपयोग डिस्क्रीट मानों या डेटा बिंदुओं की क्लासेज़ की भविष्यवाणी के लिए होता है। आप इस फ़ंक्शन को reduce_mean() से wrap करते हैं, जो किसी टेन्सर के आयामों में एलिमेंट्स का mean निकालता है।
  • आप एक training optimizer भी परिभाषित करना चाहते हैं; सबसे लोकप्रिय optimization एल्गोरिद्म में Stochastic Gradient Descent (SGD), ADAM और RMSprop शामिल हैं। आप जो भी एल्गोरिद्म चुनें, आपको learning rate या momentum जैसे कुछ पैरामीटर्स ट्यून करने होंगे। इस मामले में, आप ADAM ऑप्टिमाइज़र चुनते हैं, जिसके लिए आप learning rate 0.001 परिभाषित करते हैं।
  • अंत में, ट्रेनिंग पर जाने से पहले आप ऑपरेशंस को इनिशियलाइज़ करते हैं।
# Import `tensorflow` 
import tensorflow as tf 

# Initialize placeholders 
x = tf.placeholder(dtype = tf.float32, shape = [None, 28, 28])
y = tf.placeholder(dtype = tf.int32, shape = [None])

# Flatten the input data
images_flat = tf.contrib.layers.flatten(x)

# Fully connected layer 
logits = tf.contrib.layers.fully_connected(images_flat, 62, tf.nn.relu)

# Define a loss function
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels = y, 
                                                                    logits = logits))
# Define an optimizer 
train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)

# Convert logits to label indexes
correct_pred = tf.argmax(logits, 1)

# Define an accuracy metric
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

आपने अब TensorFlow के साथ अपना पहला न्यूरल नेटवर्क सफलतापूर्वक बना लिया है!

यदि आप चाहें, तो आप (अधिकांश) वेरिएबल्स के मान प्रिंट करके अभी जो कोड लिखा है उसका एक त्वरित पुनरावलोकन या जाँच भी कर सकते हैं:

print("images_flat: ", images_flat)
print("logits: ", logits)
print("loss: ", loss)
print("predicted_labels: ", correct_pred)

टिप: यदि आपको “module 'pandas' has no attribute 'computation'” जैसी त्रुटि दिखती है, तो कमांड लाइन में pip install --upgrade dask चलाकर dask पैकेज अपग्रेड करने पर विचार करें। अधिक जानकारी के लिए यह StackOverflow पोस्ट देखें।

न्यूरल नेटवर्क चलाना

अब जब आपने अपने मॉडल को लेयर दर लेयर बना लिया है, तो अब इसे वास्तव में चलाने का समय है! ऐसा करने के लिए, पहले आपको Session() की मदद से एक सेशन इनिशियलाइज़ करना होगा, जिसमें आप पिछले खंड में परिभाषित अपना graph पास कर सकते हैं। फिर, आप run() से सेशन चला सकते हैं, जिसमें आप पिछले खंड में ही परिभाषित init वेरिएबल के रूप में इनिशियलाइज़ ऑपरेशंस पास करते हैं।

इसके बाद, आप इस इनिशियलाइज़ सेशन का उपयोग epochs या ट्रेनिंग लूप शुरू करने के लिए कर सकते हैं। इस मामले में, आप 201 चुनते हैं क्योंकि आप आखिरी loss_value को दर्ज करने में सक्षम होना चाहते हैं; लूप में, आप पिछले खंड में परिभाषित training optimizer और loss (या accuracy) metric के साथ सेशन चलाते हैं। आप एक feed_dict आर्गुमेंट भी पास करते हैं, जिससे आप मॉडल को डेटा फ़ीड करते हैं। हर 10 epochs के बाद, आपको लॉग मिलेगा जो मॉडल के loss या cost के बारे में अधिक जानकारी देता है।

जैसा कि आपने TensorFlow की बुनियादी बातों वाले खंड में देखा, सेशन को मैन्युअली बंद करने की ज़रूरत नहीं है; यह आपके लिए कर दिया जाता है। हालाँकि, यदि आप कोई अन्य सेटअप आज़माना चाहते हैं, तो आपको शायद sess.close() से ऐसा करना होगा यदि आपने अपना सेशन sess के रूप में परिभाषित किया है, जैसा कि नीचे के कोड खंड में है:

tf.set_random_seed(1234)
sess = tf.Session()

sess.run(tf.global_variables_initializer())

for i in range(201):
        print('EPOCH', i)
        _, accuracy_val = sess.run([train_op, accuracy], feed_dict={x: images28, y: labels})
        if i % 10 == 0:
            print("Loss: ", loss)
        print('DONE WITH EPOCH')

याद रखें कि आप निम्न कोड भी चला सकते हैं, पर वह सेशन को तुरंत बाद में बंद कर देगा, जैसा कि आपने इस ट्यूटोरियल की शुरुआत में देखा था:

tf.set_random_seed(1234)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(201):
        _, loss_value = sess.run([train_op, loss], feed_dict={x: images28, y: labels})
        if i % 10 == 0:
            print("Loss: ", loss)

ध्यान दें कि आप global_variables_initializer() का उपयोग करते हैं क्योंकि initialize_all_variables() फ़ंक्शन अप्रचलित (deprecated) है।

आपने अब अपने मॉडल को सफलतापूर्वक ट्रेन कर लिया है! यह बहुत कठिन नहीं था, है न?

अपने न्यूरल नेटवर्क का मूल्यांकन

आप अभी पूरी तरह से समाप्त नहीं हुए हैं; आपको अपने न्यूरल नेटवर्क का मूल्यांकन अभी भी करना है। इस मामले में, आप 10 यादृच्छिक छवियाँ चुनकर और भविष्यवाणी किए गए लेबल्स की वास्तविक लेबल्स से तुलना करके अपने मॉडल के प्रदर्शन की एक झलक पाने की कोशिश कर सकते हैं।

आप उन्हें पहले प्रिंट कर सकते हैं, पर क्यों न matplotlib का उपयोग करके ट्रैफिक साइन को स्वयं प्लॉट किया जाए और एक दृश्य तुलना की जाए?

 # Import `matplotlib`
import matplotlib.pyplot as plt
import random

# Pick 10 random images
sample_indexes = random.sample(range(len(images28)), 10)
sample_images = [images28[i] for i in sample_indexes]
sample_labels = [labels[i] for i in sample_indexes]

# Run the "correct_pred" operation
predicted = sess.run([correct_pred], feed_dict={x: sample_images})[0]
                        
# Print the real and predicted labels
print(sample_labels)
print(predicted)

# Display the predictions and the ground truth visually.
fig = plt.figure(figsize=(10, 10))
for i in range(len(sample_images)):
    truth = sample_labels[i]
    prediction = predicted[i]
    plt.subplot(5, 2,1+i)
    plt.axis('off')
    color='green' if truth == prediction else 'red'
    plt.text(40, 10, "Truth:        {0}\nPrediction: {1}".format(truth, prediction), 
             fontsize=12, color=color)
    plt.imshow(sample_images[i],  cmap="gray")

plt.show()

traffic signs 6

हालाँकि, केवल यादृच्छिक छवियों को देखना आपको यह नहीं बताता कि आपका मॉडल वास्तव में कितना अच्छा प्रदर्शन करता है। इसलिए आप टेस्ट डेटा लोड करेंगे।

ध्यान दें कि आप load_data() फ़ंक्शन का उपयोग करते हैं, जिसे आपने ट्यूटोरियल की शुरुआत में परिभाषित किया था।

# Import `skimage`
from skimage import transform

# Load the test data
test_images, test_labels = load_data(test_data_directory)

# Transform the images to 28 by 28 pixels
test_images28 = [transform.resize(image, (28, 28)) for image in test_images]

# Convert to grayscale
from skimage.color import rgb2gray
test_images28 = rgb2gray(np.array(test_images28))

# Run predictions against the full test set.
predicted = sess.run([correct_pred], feed_dict={x: test_images28})[0]

# Calculate correct matches 
match_count = sum([int(y == y_) for y, y_ in zip(test_labels, predicted)])

# Calculate the accuracy
accuracy = match_count / len(test_labels)

# Print the accuracy
print("Accuracy: {:.3f}".format(accuracy))

याद रखें कि यदि आपने with tf.Session() as sess: से अपना TensorFlow सेशन शुरू नहीं किया था, तो sess.close() से सेशन बंद करना न भूलें।

अब आगे क्या?

यदि आप इस डेटासेट और इस ट्यूटोरियल में बनाए गए मॉडल के साथ काम जारी रखना चाहते हैं, तो निम्न चीज़ें आज़माएँ:

  • मॉडल को फ़ीड करने से पहले डेटा पर regularized LDA लागू करें। यह सुझाव मूल शोध पत्रों में से एक से आता है, जिसे इस डेटासेट को एकत्रित और विश्लेषित करने वाले शोधकर्ताओं ने लिखा है।
  • जैसा कि ट्यूटोरियल में भी कहा गया, आप ट्रैफिक साइन छवियों पर किए जा सकने वाले अन्य डेटा ऑग्मेंटेशन ऑपरेशंस देख सकते हैं। इसके अलावा, आप इस नेटवर्क को और भी ट्यून करने की कोशिश कर सकते हैं; जो आपने अभी बनाया, वह काफ़ी सरल था।
  • अर्ली स्टॉपिंग: न्यूरल नेटवर्क को ट्रेन करते समय ट्रेनिंग और टेस्टिंग त्रुटि पर नज़र रखें। जब दोनों त्रुटियाँ नीचे जाएँ और फिर अचानक ऊपर जाने लगें - यह संकेत है कि न्यूरल नेटवर्क ने ट्रेनिंग डेटा पर overfit करना शुरू कर दिया है - तब ट्रेनिंग रोक दें।
  • ऑप्टिमाइज़र्स के साथ प्रयोग करें।

Nishant Shukla द्वारा लिखी गई पुस्तक Machine Learning With TensorFlow ज़रूर देखें।

टिप TensorFlow Playground और TensorBoard भी देखें।

यदि आप छवियों के साथ काम जारी रखना चाहते हैं, तो DataCamp का scikit-learn ट्यूटोरियल अवश्य देखें, जो PCA, K-Means और Support Vector Machines (SVMs) की मदद से MNIST डेटासेट पर काम करता है। या यह ट्यूटोरियल देखें जो बेल्जियन ट्रैफिक साइन डेटासेट का उपयोग करता है।

विषय