2016-01-21 5 views
9

tf.cond के लिए (स्रोत कोड) दस्तावेज इस बात पर अस्पष्ट नहीं है कि भविष्यवाणी के मूल्यांकन के दौरान किए जाने वाले कार्यों का दुष्प्रभाव हो सकता है या नहीं। मैंने कुछ परीक्षण किए हैं लेकिन मुझे विवादित परिणाम मिल रहे हैं। उदाहरण के लिए नीचे दिया गया कोड काम नहीं करता है:दुष्प्रभावों के साथ टीएफ ओप का समर्थन कर सकते हैं?

import tensorflow as tf 
from tensorflow.python.ops import control_flow_ops 

pred = tf.placeholder(tf.bool, []) 
count = tf.Variable(0) 
adder = count.assign_add(1) 
subtractor = count.assign_sub(2) 

my_op = control_flow_ops.cond(pred, lambda: adder, lambda: subtractor) 

sess = tf.InteractiveSession() 
tf.initialize_all_variables().run() 

my_op.eval(feed_dict={pred: True}) 
count.eval() # returns -1 

my_op.eval(feed_dict={pred: False}) 
count.eval() # returns -2 

आईई। इससे कोई फर्क नहीं पड़ता कि भविष्यवाणी का मूल्यांकन किस मूल्य से होता है, दोनों कार्य चल रहे हैं, और इसलिए नेट परिणाम 1 का घटाव है। दूसरी तरफ, यह कोड स्निपेट काम करता है, जहां केवल अंतर यह है कि मैं ग्राफ में नए ऑप्स जोड़ता हूं हर बार my_op कहा जाता है:

pred = tf.placeholder(tf.bool, []) 
count = tf.Variable(0) 

my_op = control_flow_ops.cond(pred, lambda:count.assign_add(1), lambda:count.assign_sub(2)) 

sess = tf.InteractiveSession() 
tf.initialize_all_variables().run() 

my_op.eval(feed_dict={pred: False}) 
count.eval() # returns -2 

my_op.eval(feed_dict={pred: True}) 
count.eval() # returns -1 

सुनिश्चित नहीं हैं कि क्यों जबकि अन्य मामला नहीं करता है हर बार काम करता है नई ऑप्स बनाने, लेकिन मैं स्पष्ट रूप से नहीं बल्कि नहीं नोड्स जोड़ने होगी के रूप में ग्राफ अंत में बहुत बड़ा हो जाएगा।

उत्तर

10

आपका दूसरा संस्करण — जहां assign_add() और assign_sub() ऑप्स lambdas cond() — के लिए पारित अंदर पैदा कर रहे यह करने के लिए सही तरीका है। सौभाग्य से, दो lambdas में से प्रत्येक का मूल्यांकन केवल cond() पर कॉल के दौरान किया जाता है, इसलिए आपका ग्राफ बाध्य किए बिना नहीं बढ़ेगा।

  1. एक Switch नोड है, जो दो outputs का केवल एक ही करने के लिए अपने इनपुट अग्रेषित करता है, pred के मूल्य के आधार बनाएं:

    अनिवार्य रूप से क्या cond() करता है निम्नलिखित है। आइए आउटपुट pred_true और pred_false पर कॉल करें। (वे pred के रूप में एक ही मूल्य है, लेकिन यह महत्वहीन है, क्योंकि यह सीधे का मूल्यांकन कभी नहीं किया गया है।)

  2. subgraph if_true लैम्ब्डा, जहां नोड के सभी pred_true पर एक नियंत्रण में निर्भरता के लिए इसी बनाएँ।

  3. if_false लैम्ब्डा से संबंधित उपग्राफ बनाएं, जहां सभी नोड्स पर pred_false पर नियंत्रण निर्भरता है।

  4. दो लैम्ब्स से वापसी मानों की सूचियों को एक साथ ज़िप करें, और इनमें से प्रत्येक के लिए Merge नोड बनाएं। Merge नोड में दो इनपुट होते हैं, जिनमें से केवल एक ही उत्पादित होने की उम्मीद है, और इसे इसके आउटपुट में आगे बढ़ाया जाता है।

  5. Merge नोड्स के आउटपुट हैं जो टेंसर लौटें।

इसका मतलब है आप अपने दूसरे संस्करण चला सकते हैं, और कहा कि ग्राफ एक निश्चित आकार बना रहता है, आप कितने कदम चलाने की परवाह किए बिना ही संतोष।

कारण अपने पहले संस्करण से काम नहीं करता है कि, जब एक Tensor कब्जा कर लिया है (जैसे adder या अपने उदाहरण में subtractor), एक अतिरिक्त Switch नोड तर्क यह है कि टेन्सर का मूल्य केवल अग्रेषित किया जाता है लागू करने के लिए जोड़ा जाता है है वास्तव में निष्पादित शाखा में। यह एक आर्टिफैक्ट है कि कैसे टेंसरफ्लो फ़ीड निष्पादन डेटाफ्लो को नियंत्रित करता है और इसके निष्पादन मॉडल में नियंत्रण प्रवाह को जोड़ता है। नतीजा यह है कि कैप्चर किए गए टेंसर (इस मामले में assign_add और assign_sub के परिणाम) का हमेशा मूल्यांकन किया जाएगा, भले ही उनका उपयोग न किया जाए, और आप उनके दुष्प्रभाव देखेंगे। यह कुछ है जो हमें बेहतर दस्तावेज करने की आवश्यकता है, और as Michael says, हम भविष्य में इसे और अधिक उपयोग करने जा रहे हैं।

7

दूसरा मामला काम करता है क्योंकि आपने कंस के भीतर ओप जोड़ दिए हैं: इससे उन्हें सशर्त रूप से निष्पादित किया जाता है।

पहला मामला यह अनुरूप है कह रहे हैं:

adder = (count += 1) 
subtractor = (count -= 2) 
if (cond) { adder } else { subtractor } 

के बाद से योजक और subtractor सशर्त बाहर हैं, वे हमेशा क्रियान्वित कर रहे हैं।

दूसरे मामले अधिक

if (cond) { adder = (count += 1) } else { subtractor = (count -= 2) } 

कह इस मामले में करता है जो आप क्या उम्मीद की तरह है।

हमें एहसास है कि दुष्प्रभावों और (कुछ हद तक) आलसी मूल्यांकन के बीच बातचीत भ्रमित है, और हमारे पास चीजों को और समान बनाने के लिए एक मध्यम अवधि का लक्ष्य है। लेकिन अब समझने की महत्वपूर्ण बात यह है कि हम सच आलसी मूल्यांकन नहीं करते हैं: सशर्त किसी भी शाखा के भीतर उपयोग की जाने वाली सशर्त के बाहर परिभाषित हर मात्रा पर निर्भरता प्राप्त करता है।

संबंधित मुद्दे