एक नियतात्मक मॉडल के रन के छोटे, अप्रत्याशित परिणाम


10

मेरे पास सी में लिखा गया एक बड़ा मॉडल (~ 5000 लाइनें) है। यह एक सीरियल प्रोग्राम है, जिसमें कोई रैंडम नंबर जेनरेशन नहीं है। यह FFTW लाइब्रेरी का उपयोग FFT के उपयोग से कार्यों के लिए करता है - मुझे FFTW कार्यान्वयन का विवरण नहीं पता है, लेकिन मुझे लगता है कि इसमें जो कार्य हैं वे निर्धारक भी हैं (मुझे सही करें तो मैं सही हूं)।

जिस समस्या को मैं नहीं समझ सकता, वह यह है कि मुझे एक ही मशीन (एक ही संकलक, एक ही पुस्तकालय) पर समान रनों के लिए परिणामों में छोटे अंतर मिल रहे हैं।

मैं दोहरे-सटीक चर का उपयोग करता हूं, और valueउदाहरण के लिए चर में परिणाम का उत्पादन करने के लिए, मैं जारी करता हूं: fprintf(outFID, "%.15e\n", value);या
fwrite(&value, 1, sizeof(double), outFID);

: और मैं लगातार इस तरह के रूप मतभेद मिलेगा
2.07843469652206 4 ई-16 बनाम 2.07843469652206 3 ई-16

मैंने यह जानने में बहुत समय बिताया है कि यह क्यों है। मैंने शुरू में सोचा था कि मेरी एक मेमोरी चिप खराब हो गई है, और मैंने कोई फायदा नहीं हुआ। मैंने बाद में एक सहयोगी की लिनक्स मशीन पर अपना कोड चलाने की कोशिश की, और मुझे उसी प्रकृति के अंतर मिलते हैं।

ऐसा किसके कारण हो सकता है? यह अब एक छोटा सा मुद्दा है, लेकिन मुझे आश्चर्य है कि यह "हिमशैल का टिप" (एक गंभीर समस्या का) है।

मुझे लगा कि मैं StackOverflow के बजाय यहाँ पोस्ट करूँगा अगर कोई संख्यात्मक मॉडल के साथ काम करता है तो इस मुद्दे पर आ सकता है। अगर कोई इस पर प्रकाश डाल सकता है, तो मैं बहुत मजबूर हो जाऊंगा।

फॉलोअप टू कमेंट्स:
क्रिश्चियन क्लैसन और विक्रम: सबसे पहले, मेरे सवाल पर ध्यान देने के लिए धन्यवाद। आपके द्वारा सुझाए गए लेख यह सुझाव देते हैं कि: 1. गोलाई त्रुटियां सटीकता को सीमित करती हैं, और 2. अलग-अलग कोड (जैसे कि प्रतीत होता है हानिरहित प्रिंट स्टेटमेंट) मशीन एप्सिलॉन तक के परिणामों को प्रभावित कर सकते हैं। मुझे स्पष्ट करना चाहिए कि मैं प्रभावों fwriteऔर fprintfकार्यों की तुलना नहीं कर रहा हूं । मैं एक या दूसरे का उपयोग कर रहा हूं। विशेष रूप से, दोनों रन के लिए एक ही निष्पादन योग्य का उपयोग किया जाता है। मैं बस इस मुद्दे को बताते हुए कह रहा हूं कि क्या मैं fprintfOR का उपयोग करता हूं fwrite

तो कोड पथ (और निष्पादन योग्य) समान है, और हार्डवेयर समान है। इन सभी बाहरी कारकों को स्थिर रखने के साथ, मौलिकता, यादृच्छिकता कहां से आती है? मुझे संदेह था कि गलती से मेमोरी सही तरीके से नहीं चल पाने के कारण बिट फ्लिप हो गया था, यही वजह है कि मैंने मेमोरी चिप्स को बदल दिया, लेकिन यह यहां मुद्दा नहीं लगता है, मैंने सत्यापित किया और आपने संकेत दिया। मेरा कार्यक्रम एक ही रन में हजारों इन हजारों सटीक संख्याओं को आउटपुट करता है, और हमेशा एक यादृच्छिक मुट्ठी भर होते हैं जिनमें यादृच्छिक बिट फ़्लिप होते हैं।

ईसाई Clason की पहली टिप्पणी करने के लिए अनुसरण करे: क्यों है मशीन परिशुद्धता के भीतर 0 के रूप में ही? एक डबल के लिए सबसे छोटी सकारात्मक संख्या 2.22e-308 है, इसलिए क्या यह 0 के बराबर नहीं होना चाहिए? मेरा कार्यक्रम 10 ^ -16 रेंज (1e-15 से 8e-17 तक) में हजारों मानों का आउटपुट देता है और हम अपने शोध प्रोजेक्ट में सार्थक बदलाव देख रहे हैं, इसलिए मुझे आशा है कि हम निरर्थक नहीं देख रहे हैं संख्या।210-16

फॉलोअप # 2 :
यह मॉडल द्वारा टाइम सीरीज़ आउटपुट का एक प्लॉट है, जो टिप्पणियों में ऑफशूट चर्चा में सहायता के लिए है। यहाँ छवि विवरण दर्ज करें


210-16

आप पूछ रहे हैं कि आपकी मशीन मशीन की सटीकता से अधिक सटीक क्यों नहीं है। en.wikipedia.org/wiki/Machine_epsilon
विक्रम

1
फ़्लोटिंग पॉइंट अंकगणित पर कोड पथ के सूक्ष्म प्रभाव के संबंधित उदाहरण के लिए inf.ethz.ch/personal/gander/Heisenberg/paper.html देखें । और, ज़ाहिर है, ece.uwaterloo.ca/~dwharder/NumericalAnalysis/02Numerics/Double/…
ईसाई

1
10-16

2
1

जवाबों:


9

आधुनिक कंप्यूटिंग प्रणालियों के ऐसे पहलू हैं जो स्वाभाविक रूप से गैर-नियतात्मक हैं जो इस प्रकार के मतभेदों का कारण बन सकते हैं। जब तक आपके समाधान की आवश्यक सटीकता की तुलना में अंतर बहुत छोटा है, तब तक शायद इस बारे में चिंता करने का कोई कारण नहीं है।

अपने स्वयं के अनुभव के आधार पर क्या गलत हो सकता है इसका एक उदाहरण। दो वैक्टर x और y के डॉट उत्पाद की गणना की समस्या पर विचार करें।

=Σमैं=1nएक्समैंyमैं

एक्समैंyमैं

उदाहरण के लिए, आप पहले दो वैक्टर के उत्पाद की गणना कर सकते हैं

=((एक्स1y1)+(एक्स2y2))+(एक्स3y3)

और फिर के रूप में

=(एक्स1y1)+((एक्स2y2)+(एक्स3y3))

यह कैसे हो सकता है? यहां दो संभावनाएं हैं।

  1. समानांतर कोर पर बहुपरत कम्प्यूटेशन। आधुनिक कंप्यूटरों में आम तौर पर 2, 4, 8 या इससे अधिक प्रोसेसर कोर होते हैं जो समानांतर में काम कर सकते हैं। यदि आपका कोड कई प्रोसेसर पर डॉट उत्पाद की गणना करने के लिए समानांतर थ्रेड का उपयोग कर रहा है, तो सिस्टम का कोई भी यादृच्छिक गड़बड़ी (उदाहरण के लिए उपयोगकर्ता अपने माउस को स्थानांतरित कर देता है और प्रोसेसर कोर में से एक को डॉट उत्पाद पर लौटने से पहले उस माउस को संसाधित करना पड़ता है) परिवर्धन के क्रम में परिवर्तन के परिणामस्वरूप।

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

आप अपने कोड को एक एकल धागे के रूप में चलाकर और सभी समानांतर प्रसंस्करण को अक्षम करके बिंदु 1 को संबोधित कर सकते हैं। आप स्मृति के ब्लॉक के संरेखित करने के लिए मेमोरी आवंटन की आवश्यकता से बिंदु 2 को संबोधित कर सकते हैं (टाइप करें कि आप कोड को स्विच जैसे कि -ign के साथ संकलित करके ऐसा करेंगे।) यदि आपका कोड अभी भी परिणाम दे रहा है जो भिन्न है तो देखने के लिए अन्य संभावनाएं हैं। पर।

इंटेल से यह प्रलेखन उन मुद्दों पर चर्चा करता है जो इंटेल मठ कर्नेल लाइब्रेरी के साथ परिणामों की गैर-प्रतिलिपि प्रस्तुत करने योग्यता को जन्म दे सकता है। इंटेल का एक अन्य दस्तावेज जो इंटेल के कंपाइलरों के साथ उपयोग करने के लिए कंपाइलर स्विच पर चर्चा करता है।


मैं देखता हूं कि आपको लगता है कि आपका कोड सिंगल थ्रेडेड चल रहा है। हालाँकि आप शायद अपने कोड को अच्छी तरह से जानते हैं, लेकिन अगर आप सबरूटीन्स (जैसे BLAS रूटीन) कह रहे हों तो आश्चर्यचकित रह जाएंगे। आपको यह देखने के लिए जांचना चाहिए कि आप किन पुस्तकालयों का उपयोग कर रहे हैं। आप अपने CPU उपयोग को देखने के लिए सिस्टम मॉनिटरिंग टूल का भी उपयोग कर सकते हैं।
ब्रायन बोरचर्स

1
या, जैसा कि कहा गया है, FFTW पुस्तकालय ...
ईसाई क्लैसन

@BrianBorchers, धन्यवाद। फ्लोटिंग पॉइंट जोड़ के गैर-सहयोगी प्रकृति से आने वाली यादृच्छिकता का उदाहरण ज्ञानवर्धक है। क्रिश्चियन क्लैसन ने एक माध्यमिक मुद्दा उठाया कि क्या मेरा मॉडल आउटपुट सार्थक है, संख्याओं का परिमाण देखते हुए - यह एक बड़ा मुद्दा हो सकता है अगर वह सही है (और मैं उसे सही ढंग से समझ रहा हूं), इसलिए मैं उस पर गौर कर रहा हूं।
Boxofchalk1

2

उल्लिखित FFTW पुस्तकालय गैर-नियतात्मक मोड में चल सकता है।

यदि आप FFTW_MEASURE या FFTW_PATIENT मोड का उपयोग कर रहे हैं, तो प्रोग्राम रनटाइम पर जांच करते हैं, कौन से पैरामीटर मान सबसे तेज काम करते हैं और फिर पूरे कार्यक्रम के दौरान उन मापदंडों का उपयोग करेंगे। क्योंकि रन टाइम स्पष्ट रूप से थोड़ा उतार-चढ़ाव होगा, पैरामीटर अलग-अलग होंगे और फूरियर ट्रांसफॉर्म का परिणाम गैर-निर्धारक होगा। यदि आप नियतात्मक FFTW चाहते हैं, तो FFTW_ESTIMATE मोड का उपयोग करें।


1

हालांकि यह सच है कि मल्टी-कोर / मल्टी-थ्रेड प्रोसेसिंग परिदृश्यों के कारण अभिव्यक्ति शब्द मूल्यांकन क्रम परिवर्तन बहुत अच्छी तरह से हो सकता है, यह मत भूलो कि काम पर हार्डवेयर डिजाइन दोष के कुछ प्रकार (भले ही यह एक लंबा शॉट है) हो सकता है। पेंटियम FDIV समस्या याद है? ( Https://en.wikipedia.org/wiki/Pentium_FDIV_bug देखें )। कुछ समय पहले, मैंने पीसी-आधारित एनालॉग सर्किट सिमुलेशन सोफ़वेयर पर काम किया। हमारी कार्यप्रणाली का एक हिस्सा रिग्रेशन-टेस्ट स्वीट्स विकसित करना है, जिसे हम सॉफ्टवेयर के नाइटली बिल्ड के खिलाफ चलाएंगे। हमारे द्वारा विकसित कई मॉडलों के साथ, पुनरावृत्त तरीके (जैसे न्यूटन-राफसन ( https://en.wikipedia.org/wiki/Newton%27s_method)) और रन-कुट्टा) का उपयोग सिमुलेशन एल्गोरिदम में बड़े पैमाने पर किया गया था। एनालॉग उपकरणों के साथ, यह अक्सर ऐसा होता है कि आंतरिक कलाकृतियों, जैसे कि वोल्टेज, धाराएं, आदि में बहुत छोटे संख्यात्मक मूल्य होते हैं। सिमुलेशन प्रक्रिया के हिस्से के रूप में ये मूल्य, समय के साथ (विविध) समय पर विविध रूप से भिन्न होते हैं। इन परिवर्तनों की भयावहता बहुत कम हो सकती है, और जो हम अक्सर देखते थे, वह यह था कि एफपीयू की सटीकता के "शोर" सीमा पर सीमावर्ती ऐसे डेल्टा मूल्यों पर बाद में FPU संचालन (64-बिट फ्लोटिंग में 53-बिट मंटिसा, IIRC) है। इस तथ्य के साथ युग्मित है कि हमें अक्सर डिबगिंग (आह, अच्छा राजभाषा दिवस!) की अनुमति देने के लिए "PrintF" लॉगिंग कोड को मॉडल में पेश करना पड़ता था, दैनिक आधार पर व्यावहारिक रूप से छिटपुट परिणामों की गारंटी! तो क्या' यह सब मतलब है? आपको ऐसी परिस्थितियों में अंतर देखने की उम्मीद करनी होगी, और सबसे अच्छी बात यह है कि उन्हें कैसे अनदेखा किया जाए / कैसे तय किया जाए (परिमाण, आवृत्ति, प्रवृत्ति आदि) को परिभाषित करने और लागू करने का एक तरीका।


शुक्रिया, अंतर्दृष्टि के लिए जिम। मौलिक घटनाएँ इस तरह की "आंतरिक कलाकृतियों" का क्या कारण है, इस पर कोई विचार? मैंने सोचा कि विद्युत चुम्बकीय हस्तक्षेप एक हो सकता है, लेकिन तब महत्वपूर्ण बिट्स भी प्रभावित होंगे, न?
Boxofchalk1

1

हालांकि Async ऑपरेशंस से फ्लोटिंग पॉइंट राउंडिंग मुद्दा हो सकता है, मुझे संदेह है कि यह कुछ और अधिक सामान्य है। असिंचित चर का उपयोग जो आपके अन्यथा नियतात्मक कोड में यादृच्छिकता जोड़ रहा है। यह एक सामान्य समस्या है जिसे अक्सर डेवलपर्स द्वारा अनदेखा किया जाता है क्योंकि जब आप डिबग मोड में चलते हैं तो सभी चर को घोषणा पर 0 से प्रारंभ किया जाता है। डिबग मोड में नहीं चलने पर, एक चर को सौंपी गई मेमोरी में असाइनमेंट से पहले मेमोरी का जो भी मूल्य होता है। अनुकूलन के रूप में मेमोरी को असाइनमेंट पर शून्य नहीं किया गया है। यदि यह आपके कोड में हो रहा है, तो इसे ठीक करना आसान होगा, लाइब्रेरी कोड में कम।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.