TensorFlow 1.8 - A Tool Developer's Guide to TensorFlow Model Files

एक टूल डेवलपर की गाइड TensorFlow मॉडल फ़ाइलों के लिए




tensorflow

एक टूल डेवलपर की गाइड TensorFlow मॉडल फ़ाइलों के लिए

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

प्रोटोकॉल बफ़र्स

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

GraphDef

TensorFlow में अभिकलन की नींव Graph ऑब्जेक्ट है। यह नोड्स का एक नेटवर्क रखता है, प्रत्येक एक ऑपरेशन का प्रतिनिधित्व करता है, इनपुट और आउटपुट के रूप में एक दूसरे से जुड़ा हुआ है। एक Graph ऑब्जेक्ट बनाने के बाद, आप इसे as_graph_def() कहकर बचा सकते हैं, जो एक GraphDef ऑब्जेक्ट GraphDef है।

ग्राफडिफ क्लास प्रोनबॉफ लाइब्रेरी द्वारा tensorflow/core/framework/graph.proto में परिभाषा से बनाई गई एक वस्तु है। प्रोटोबॉफ़ उपकरण इस पाठ फ़ाइल को पार्स करते हैं, और ग्राफ़ परिभाषाओं को लोड, स्टोर और हेरफेर करने के लिए कोड उत्पन्न करते हैं। यदि आप एक स्टैंडअलोन TensorFlow फ़ाइल को एक मॉडल का प्रतिनिधित्व करते हुए देखते हैं, तो इसमें GraphDef कोड द्वारा सहेजे गए इन GraphDef ऑब्जेक्ट्स में से एक का क्रमबद्ध संस्करण शामिल होने की संभावना है।

इस जेनरेट किए गए कोड का उपयोग DiskDef फाइलों को डिस्क से बचाने और लोड करने के लिए किया जाता है। कोड जो वास्तव में मॉडल को लोड करता है वह इस तरह दिखता है:

graph_def = graph_pb2.GraphDef()

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

with open(FLAGS.graph, "rb") as f:

यहां हमें स्क्रिप्ट में पास किए गए पथ के लिए फ़ाइल हैंडल मिलता है

if FLAGS.input_binary:
  graph_def.ParseFromString(f.read())
else:
  text_format.Merge(f.read(), graph_def)

पाठ या बाइनरी?

वास्तव में दो अलग-अलग प्रारूप हैं जिन्हें प्रोटॉफ में बचाया जा सकता है। टेक्स्टफ़ॉर्मैट एक मानव-पठनीय रूप है, जो डिबगिंग और संपादन के लिए अच्छा है, लेकिन बड़े हो सकते हैं जब इसमें संख्यात्मक डेटा की तरह वजन होता है। आप graph_run_run2.pbtxt में graph_run_run2.pbtxt एक छोटा सा उदाहरण देख सकते हैं।

भले ही वे हमारे लिए पठनीय न हों, बाइनरी प्रारूप फाइलें उनके पाठ समकक्षों की तुलना में बहुत छोटी हैं। इस स्क्रिप्ट में, हम उपयोगकर्ता को एक झंडे की आपूर्ति करने के लिए कहते हैं जो यह दर्शाता है कि इनपुट फ़ाइल द्विआधारी या पाठ है, इसलिए हम कॉल करने के लिए सही फ़ंक्शन जानते हैं। आप inception_v3 संग्रह के अंदर एक बड़ी बाइनरी फ़ाइल का एक उदाहरण पा सकते हैं, जैसा कि inception_v3_2016_08_28_frozen.pb

API स्वयं थोड़ा भ्रमित हो सकता है - बाइनरी कॉल वास्तव में ParseFromString() , जबकि आप टेक्स्ट फ़ाइलों को लोड करने के लिए text_format मॉड्यूल से उपयोगिता फ़ंक्शन का उपयोग करते हैं।

नोड्स

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

for node in graph_def.node

प्रत्येक नोड एक NodeDef ऑब्जेक्ट है, जो tensorflow/core/framework/node_def.proto में परिभाषित किया गया है। ये TensorFlow रेखांकन के मूलभूत निर्माण खंड हैं, जिनमें से प्रत्येक एक इनपुट ऑपरेशन के साथ एकल ऑपरेशन को परिभाषित करता है। यहाँ एक NodeDef के सदस्य हैं, और उनका क्या अर्थ है।

name

प्रत्येक नोड में एक अद्वितीय पहचानकर्ता होना चाहिए जिसका उपयोग ग्राफ में किसी अन्य नोड द्वारा नहीं किया गया है। यदि आप एक को निर्दिष्ट नहीं करते हैं जैसा कि आप पायथन एपीआई का उपयोग करके एक ग्राफ का निर्माण कर रहे हैं, तो एक ऑपरेशन के नाम को दर्शाता है, जैसे कि "मैटमुल", जिसे मोनोटोनिक रूप से बढ़ती संख्या के साथ संक्षिप्त किया जाता है, जैसे "5", आपके लिए उठाया जाएगा। । नाम का उपयोग नोड्स के बीच कनेक्शन को परिभाषित करते समय किया जाता है, और जब यह चलता है तो पूरे ग्राफ के लिए इनपुट और आउटपुट सेट करते हैं।

op

यह परिभाषित करता है कि किस ऑपरेशन को चलाना है, उदाहरण के लिए "Add" , "MatMul" , या "Conv2D" । जब कोई ग्राफ़ चलाया जाता है, तो एक कार्यान्वयन को खोजने के लिए इस ऑप नाम को रजिस्ट्री में देखा जाता है। रजिस्ट्री को REGISTER_OP() मैक्रो, जैसे tensorflow/core/ops/nn_ops.cc कॉल द्वारा पॉपुलेट किया tensorflow/core/ops/nn_ops.cc

input

तार की एक सूची, जिनमें से प्रत्येक एक और नोड का नाम है, वैकल्पिक रूप से एक बृहदान्त्र और एक आउटपुट पोर्ट नंबर के बाद। उदाहरण के लिए, दो इनपुट वाले नोड में ["some_node_name", "another_node_name"] जैसी सूची हो सकती है, जो कि ["some_node_name:0", "another_node_name:0"] बराबर है, और नोड के पहले इनपुट को पहले के रूप में परिभाषित करता है। "some_node_name" नाम के साथ नोड से आउटपुट, और "some_node_name" के पहले आउटपुट से दूसरा इनपुट

device

ज्यादातर मामलों में आप इसे अनदेखा कर सकते हैं, क्योंकि यह परिभाषित करता है कि वितरित वातावरण में नोड को कहां चलाना है, या जब आप सीपीयू या जीपीयू पर ऑपरेशन को मजबूर करना चाहते हैं।

attr

यह नोड की सभी विशेषताओं को धारण करने वाला एक कुंजी / मूल्य संग्रह है। ये नोड्स के स्थायी गुण हैं, चीजें जो रनटाइम पर नहीं बदलती हैं जैसे कि दृढ़ संकल्प के लिए फिल्टर का आकार, या निरंतर डिस्क के मान। क्योंकि टेंसर वैल्यू के सरणियों के लिए स्ट्रिंग्स, टोट्स, से लेकर कई अलग-अलग प्रकार के विशेषता मान हो सकते हैं, डेटा tensorflow/core/framework/attr_value.proto को परिभाषित करने वाली एक अलग प्रोटोबॉफ़ फ़ाइल होती है, जो उन्हें tensorflow/core/framework/attr_value.proto

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

आप पायथन में node.name , node.op आदि कॉल करके इन सभी सदस्यों तक पहुंच सकते हैं। GraphDef में संग्रहीत नोड्स की सूची मॉडल आर्किटेक्चर की पूरी परिभाषा है।

जमना

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

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

भार स्वरूप

यदि आप TensorFlow मॉडल के साथ काम कर रहे हैं जो तंत्रिका नेटवर्क का प्रतिनिधित्व करते हैं, तो सबसे आम समस्याओं में से एक वजन मूल्यों को निकालने और व्याख्या करना है। उन्हें संग्रहीत करने का एक सामान्य तरीका, उदाहरण के लिए फ्रीज़_ग्राफ स्क्रिप्ट द्वारा बनाए गए ग्राफ़ में, कॉन्स ऑप्स के रूप में है जिसमें तने के रूप में वज़न होता है। ये tensorflow/core/framework/tensor.proto में परिभाषित किए गए हैं, और इसमें डेटा के आकार और प्रकार के साथ-साथ स्वयं मूल्यों के बारे में जानकारी शामिल है। पायथन में, आपको TensorProto से एक TensorProto ऑब्जेक्ट मिलता है जो Const ऑप का प्रतिनिधित्व करते हुए some_node_def.attr['value'].tensor जैसे कुछ कॉल करता है।

यह आपको वेट डेटा का प्रतिनिधित्व करने वाली एक वस्तु देगा। डेटा प्रत्यय _val वाली सूचियों में से एक में संग्रहीत किया जाएगा, जैसा कि ऑब्जेक्ट के प्रकार द्वारा इंगित किया गया है, उदाहरण के लिए 32-बिट फ्लोट डेटा प्रकारों के लिए float_val

विभिन्न फ्रेमवर्क के बीच में परिवर्तित होने पर निपटने के लिए दृढ़ संकल्प वजन मूल्यों का क्रम अक्सर मुश्किल होता है। TensorFlow में, Conv2D ऑपरेशन के लिए फ़िल्टर वेट को दूसरे इनपुट पर संग्रहीत किया जाता है, और क्रम में [filter_height, filter_width, input_depth, output_depth] होने की उम्मीद की जाती है, जहाँ मेमोरी में आसन्न मान में जाने से एक के बाद एक __count बढ़ जाता है।

उम्मीद है कि यह रंडाउन आपको एक बेहतर विचार देता है कि TensorFlow मॉडल फ़ाइलों के अंदर क्या चल रहा है, और यदि आपको कभी भी उन्हें हेरफेर करने की आवश्यकता होगी, तो आपकी मदद करेंगे।