बड़े सरणी भंडारण (फ्लैट बाइनरी फ़ाइलों के बजाय) के लिए एचडीएफ 5 का उपयोग करने के लिए एक विश्लेषण गति या मेमोरी उपयोग का लाभ है?


96

मैं बड़े 3 डी सरणियों को संसाधित कर रहा हूं, जिन्हें मुझे कई प्रकार के डेटा विश्लेषण करने के लिए अक्सर विभिन्न तरीकों से टुकड़ा करना पड़ता है। एक विशिष्ट "क्यूब" ~ 100GB हो सकता है (और भविष्य में संभवतः बड़ा हो जाएगा)

ऐसा लगता है कि अजगर में बड़े डेटासेट के लिए विशिष्ट अनुशंसित फ़ाइल प्रारूप एचडीएफ 5 (या तो एच 5 पी या पीएबी) का उपयोग करना है। मेरा प्रश्न है: क्या इन क्यूब्स को साधारण बाइनरी फाइलों में संग्रहीत करने के लिए इन क्यूब्स को स्टोर करने और उनका विश्लेषण करने के लिए कोई गति या मेमोरी उपयोग लाभ है? क्या सारणीबद्ध डेटा के लिए HDF5 अधिक उपयुक्त है, जैसे कि मैं जो काम कर रहा हूं, उसके लिए बड़े सरणियों के विपरीत? मैं देखता हूं कि एचडीएफ 5 अच्छा संपीड़न प्रदान कर सकता है, लेकिन मुझे गति को संसाधित करने और मेमोरी अतिप्रवाह से निपटने में अधिक रुचि है।

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

मैंने दोनों pytables और h5py का पता लगाया है, और अपने उद्देश्य के लिए अभी तक इसका लाभ नहीं देखा है।


1
HDF एक "chunked" फ़ाइल स्वरूप है। औसतन, यह आपको अपने डेटासेट के मनमाने ढंग से स्लाइस के लिए बहुत तेज़ी से पढ़ेगा। एक मेममैप में तेजी से सबसे अच्छा मामला होगा, लेकिन एक बहुत, बहुत धीमा सबसे खराब मामला। h5pyतुम्हारे जैसे डेटासेट के लिए बेहतर अनुकूल है pytables। साथ ही, इन-मेमोरी सुपीरियर एरे को वापस नहींh5py करता है । इसके बजाय यह कुछ ऐसा करता है जो एक जैसा व्यवहार करता है, लेकिन मेमोरी में लोड नहीं होता है ( सरणी के समान )। मैं एक और अधिक पूर्ण उत्तर लिख रहा हूं (इसे समाप्त नहीं कर सकता), लेकिन उम्मीद है कि यह टिप्पणी इस बीच थोड़ी मदद करती है। memmapped
जो किंग्सटन

धन्यवाद। मैं सहमत हूं कि h5py एक डेटासेट देता है जो एक मेममैप के समान है। लेकिन, यदि आप h5py डेटासेट का एक स्लाइस करते हैं, तो यह एक सुस्पष्ट सरणी देता है, जो मुझे विश्वास है (?) का अर्थ है कि डेटा को अनावश्यक रूप से मेमोरी में डाल दिया गया है। यदि संभव हो तो एक मेममैप मूल मेममैप पर एक दृश्य लौटाता है। दूसरे शब्दों में: type(cube)देता है h5py._hl.dataset.Dataset। जबकि type(cube[0:1,:,:])देता है numpy.ndarray
कालेब

हालांकि, औसत पढ़ने के समय के बारे में आपकी बात दिलचस्प है।
कालेब

4
यदि आपके पास I / O अड़चन है, तो कई मामलों में संपीड़न वास्तव में पढ़ने / लिखने के प्रदर्शन में सुधार कर सकता है (विशेष रूप से तेजी से संपीड़न पुस्तकालयों जैसे BLOSC और LZO का उपयोग करके), क्योंकि यह कुछ अतिरिक्त चक्रों की लागत पर आवश्यक I / O बैंडविड्थ को कम करता है । आप इस पृष्ठ को देखना चाहते हैं , जिसमें PyTables HDF5 फ़ाइलों का उपयोग करते हुए पठन-लेखन प्रदर्शन को अनुकूलित करने के बारे में बहुत सारी जानकारी है।
एलियाम

2
"अगर मैं एक फ्लैट बाइनरी फ़ाइल की एक numpy memmap स्लाइस, मैं एक दृश्य है, जो डिस्क पर डेटा रखता है प्राप्त कर सकते हैं" - यह सच हो सकता है लेकिन आप वास्तव में चाहते हैं, तो ऐसा अभी या बाद में तो है कि सरणी में मानों के साथ कुछ भी आपको उन्हें RAM में लोड करना होगा। एक मेमोरी-मैप की गई सरणी बस कुछ एनकैप्सुलेशन प्रदान करती है ताकि आपको डेटा के पढ़ने के बारे में ठीक से सोचना न पड़े या यह आपके सिस्टम की मेमोरी क्षमता से अधिक हो जाए। कुछ परिस्थितियों में याद किए गए सरणियों का मूल कैशिंग व्यवहार वास्तव में बहुत ही महत्वपूर्ण हो सकता है
एलिअम

जवाबों:


158

HDF5 लाभ: संगठन, लचीलापन, अंतर

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

HDF का एक और फायदा यह है कि डेटासेट निश्चित आकार या लचीले आकार के हो सकते हैं। इसलिए, पूरी नई प्रति बनाने के बिना बड़े डेटासेट में डेटा जोड़ना आसान है।

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

एक बड़े सरणी के लिए एचडीएफ लाभ: एक मनमाना टुकड़ा का तेज़ I / O

टीएल / डीआर के रूप में: ~ 8 जीबी 3 डी सरणी के लिए, किसी भी धुरी पर "पूर्ण" स्लाइस को पढ़ते हुए ~ 20 सेकंड के लिए एक घुटे हुए एचडीएफ 5 डेटासेट के साथ, और 0.3 सेकंड (सर्वश्रेष्ठ-केस) से तीन घंटे (सबसे खराब स्थिति) के लिए एक ही डेटा का एक याद किया सरणी।

ऊपर सूचीबद्ध चीज़ों से परे, "चंक्ड" * ऑन-डिस्क डेटा प्रारूप जैसे HDF5 का एक और बड़ा फायदा है: एक मनमाना टुकड़ा (मनमाना जोर देना) पढ़ना आमतौर पर बहुत तेज़ होगा, क्योंकि ऑन-डिस्क डेटा अधिक उपयोगी है औसत।

*(HDF5 को एक चैंकाने वाला डेटा फॉर्मेट होना जरूरी नहीं है। यह चैंकिंग का समर्थन करता है, लेकिन इसकी आवश्यकता नहीं है। वास्तव में, डेटासेट बनाने के लिए डिफ़ॉल्ट h5pyसही नहीं है, अगर मुझे सही तरीके से याद है।)

मूल रूप से, आपकी सबसे अच्छी स्थिति डिस्क-रीड स्पीड और आपके डेटासेट के दिए गए स्लाइस के लिए आपकी सबसे खराब स्थिति डिस्क रीड स्पीड एक chunked HDF डेटासेट के साथ काफी करीब होगी (यह मानते हुए कि आपने एक उचित चंक आकार चुना है या लाइब्रेरी को आपके लिए एक चुनने दें)। एक साधारण बाइनरी सरणी के साथ, सबसे अच्छा मामला तेज है, लेकिन सबसे खराब स्थिति बहुत खराब है।

एक चेतावनी, यदि आपके पास SSD है, तो आपको पढ़ने / लिखने की गति में बहुत बड़ा अंतर नजर नहीं आएगा। एक नियमित हार्ड ड्राइव के साथ, हालांकि, अनुक्रमिक रीड्स बहुत अधिक होते हैं, यादृच्छिक रीड की तुलना में बहुत तेज होते हैं। (यानी एक नियमित हार्ड ड्राइव में लंबा seekसमय होता है।) HDF का अभी भी SSD पर एक फायदा है, लेकिन यह इसकी अन्य विशेषताओं (जैसे मेटाडेटा, संगठन, आदि) के कारण कच्ची गति से अधिक है।


सबसे पहले, भ्रम को दूर करने के लिए, h5pyडेटासेट एक्सेस करने से एक ऑब्जेक्ट वापस आ जाता है जो काफी हद तक एक समान सरणी के साथ व्यवहार करता है, लेकिन डेटा को मेमोरी में लोड नहीं करता है जब तक कि यह कटा हुआ नहीं हो। (मेममैप के समान, लेकिन समान नहीं।) अधिक जानकारी के लिए h5pyपरिचय पर एक नज़र डालें ।

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

यदि आप आउट-ऑफ-कोर संगणना करना चाहते हैं, तो आप के साथ pandasया सारणीबद्ध डेटा के लिए काफी आसानी से कर सकते हैं pytables। यह h5py(बड़े एनडी सरणियों के लिए अच्छे) के साथ संभव है , लेकिन आपको एक स्पर्श निचले स्तर तक छोड़ने और अपने आप को पुनरावृत्ति को संभालने की आवश्यकता है।

हालांकि, भविष्य के प्रमुख-संगणना-योग्य संगणनाओं का भविष्य ब्लेज़ है। यदि आप वास्तव में उस मार्ग को लेना चाहते हैं तो इस पर एक नज़र डालें


"अनसंकटेड" मामला

सबसे पहले, डिस्क पर लिखे गए 3 डी सी-ऑर्डर किए गए सरणी पर विचार करें (मैं arr.ravel()परिणाम को कॉल करके और प्रिंट करके, चीजों को अधिक दृश्यमान बनाने के लिए अनुकरण करूंगा ):

In [1]: import numpy as np

In [2]: arr = np.arange(4*6*6).reshape(4,6,6)

In [3]: arr
Out[3]:
array([[[  0,   1,   2,   3,   4,   5],
        [  6,   7,   8,   9,  10,  11],
        [ 12,  13,  14,  15,  16,  17],
        [ 18,  19,  20,  21,  22,  23],
        [ 24,  25,  26,  27,  28,  29],
        [ 30,  31,  32,  33,  34,  35]],

       [[ 36,  37,  38,  39,  40,  41],
        [ 42,  43,  44,  45,  46,  47],
        [ 48,  49,  50,  51,  52,  53],
        [ 54,  55,  56,  57,  58,  59],
        [ 60,  61,  62,  63,  64,  65],
        [ 66,  67,  68,  69,  70,  71]],

       [[ 72,  73,  74,  75,  76,  77],
        [ 78,  79,  80,  81,  82,  83],
        [ 84,  85,  86,  87,  88,  89],
        [ 90,  91,  92,  93,  94,  95],
        [ 96,  97,  98,  99, 100, 101],
        [102, 103, 104, 105, 106, 107]],

       [[108, 109, 110, 111, 112, 113],
        [114, 115, 116, 117, 118, 119],
        [120, 121, 122, 123, 124, 125],
        [126, 127, 128, 129, 130, 131],
        [132, 133, 134, 135, 136, 137],
        [138, 139, 140, 141, 142, 143]]])

मानों को डिस्क पर क्रमिक रूप से संग्रहीत किया जाएगा जैसा कि नीचे पंक्ति 4 पर दिखाया गया है। (आइए फिलहाल फाइल सिस्टम विवरण और विखंडन की उपेक्षा करें।)

In [4]: arr.ravel(order='C')
Out[4]:
array([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,
        13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,
        26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
        39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,
        52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
        65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,
        78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
        91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103,
       104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
       117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
       130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143])

सबसे अच्छी स्थिति में, आइए पहले धुरी पर एक स्लाइस लें। ध्यान दें कि ये सरणी के पहले 36 मान हैं। यह बहुत तेजी से पढ़ा जाएगा! (एक तलाश, एक पढ़ा)

In [5]: arr[0,:,:]
Out[5]:
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35]])

इसी तरह, पहली धुरी के साथ अगला टुकड़ा सिर्फ अगले 36 मान होगा। इस अक्ष के साथ एक पूरा टुकड़ा पढ़ने के लिए, हमें केवल एक seekऑपरेशन की आवश्यकता है। यदि हम सभी पढ़ने जा रहे हैं तो इस अक्ष के साथ विभिन्न स्लाइस हैं, तो यह सही फ़ाइल संरचना है।

हालांकि, चलो सबसे खराब स्थिति पर विचार करते हैं: अंतिम अक्ष के साथ एक टुकड़ा।

In [6]: arr[:,:,0]
Out[6]:
array([[  0,   6,  12,  18,  24,  30],
       [ 36,  42,  48,  54,  60,  66],
       [ 72,  78,  84,  90,  96, 102],
       [108, 114, 120, 126, 132, 138]])

इस स्लाइस को पढ़ने के लिए, हमें 36 और 36 रीड की जरूरत है, क्योंकि सभी मान डिस्क पर अलग हो जाते हैं। उनमें से कोई भी आसन्न नहीं है!

यह बहुत मामूली लग सकता है, लेकिन जैसा कि हम बड़े और बड़े सरणियों में आते हैं, seekसंचालन की संख्या और आकार तेजी से बढ़ता है। इस तरह से संग्रहित एक बड़े-ईश (~ 10Gb) 3D सरणी memmapके लिए और "सबसे खराब" अक्ष के साथ एक पूर्ण स्लाइस को पढ़ते हुए, आधुनिक हार्डवेयर के साथ भी आसानी से दसियों मिनट ले सकते हैं। इसी समय, सबसे अच्छी धुरी के साथ एक टुकड़ा एक सेकंड से भी कम समय ले सकता है। सादगी के लिए, मैं केवल एक अक्ष के साथ "पूर्ण" स्लाइस दिखा रहा हूं, लेकिन सटीक वही होता है जो डेटा के किसी सबसेट के मनमाने स्लाइस के साथ होता है।

संयोग से कई फ़ाइल प्रारूप हैं जो इसका लाभ उठाते हैं और मूल रूप से डिस्क पर विशाल 3 डी सरणियों की तीन प्रतियां संग्रहीत करते हैं : सी-ऑर्डर में एक, एफ-ऑर्डर में एक और दोनों के बीच एक में। (इसका एक उदाहरण जियोप्राइव का डी 3 डी प्रारूप है, हालांकि मुझे यकीन नहीं है कि यह कहीं भी प्रलेखित नहीं है।) अगर अंतिम फ़ाइल का आकार 4TB है, तो भंडारण कौन सस्ता है! इसके बारे में पागल बात यह है कि क्योंकि मुख्य उपयोग का मामला प्रत्येक दिशा में एक एकल उप-स्लाइस निकाल रहा है, आप जो पढ़ना चाहते हैं वह बहुत तेज़ है। ये अच्छी तरह काम करता है!


सरल "chunked" मामला

मान लें कि हम डिस्क पर सन्निहित ब्लॉक के रूप में 3 डी सरणी के 2x2x2 "चंक्स" को संग्रहीत करते हैं। दूसरे शब्दों में, कुछ इस तरह:

nx, ny, nz = arr.shape
slices = []
for i in range(0, nx, 2):
    for j in range(0, ny, 2):
        for k in range(0, nz, 2):
            slices.append((slice(i, i+2), slice(j, j+2), slice(k, k+2)))

chunked = np.hstack([arr[chunk].ravel() for chunk in slices])

तो डिस्क पर डेटा की तरह दिखेगा chunked:

array([  0,   1,   6,   7,  36,  37,  42,  43,   2,   3,   8,   9,  38,
        39,  44,  45,   4,   5,  10,  11,  40,  41,  46,  47,  12,  13,
        18,  19,  48,  49,  54,  55,  14,  15,  20,  21,  50,  51,  56,
        57,  16,  17,  22,  23,  52,  53,  58,  59,  24,  25,  30,  31,
        60,  61,  66,  67,  26,  27,  32,  33,  62,  63,  68,  69,  28,
        29,  34,  35,  64,  65,  70,  71,  72,  73,  78,  79, 108, 109,
       114, 115,  74,  75,  80,  81, 110, 111, 116, 117,  76,  77,  82,
        83, 112, 113, 118, 119,  84,  85,  90,  91, 120, 121, 126, 127,
        86,  87,  92,  93, 122, 123, 128, 129,  88,  89,  94,  95, 124,
       125, 130, 131,  96,  97, 102, 103, 132, 133, 138, 139,  98,  99,
       104, 105, 134, 135, 140, 141, 100, 101, 106, 107, 136, 137, 142, 143])

और सिर्फ यह दिखाने के लिए कि वे 2x2x2 ब्लॉक हैं arr, ध्यान दें कि ये पहले 8 मान हैंchunked :

In [9]: arr[:2, :2, :2]
Out[9]:
array([[[ 0,  1],
        [ 6,  7]],

       [[36, 37],
        [42, 43]]])

एक धुरी के साथ किसी भी स्लाइस में पढ़ने के लिए, हम 6 या 9 सन्निकट विखंडू में पढ़ेंगे (जितना आवश्यक हो उतना ही दोगुना डेटा) और फिर केवल उस हिस्से को रखें जो हम चाहते थे। यह एक सबसे खराब स्थिति है, 9 गैर-chunked संस्करण के लिए अधिकतम 36 का प्रयास करता है। (लेकिन सबसे अच्छा मामला अभी भी याद किए गए एरे के लिए 6 बनाम 1 है।) क्योंकि अनुक्रमिक रीड्स, वॉच की तुलना में बहुत तेज हैं, यह स्मृति में एक मनमाना उपसमूह को पढ़ने में लगने वाले समय को काफी कम कर देता है। एक बार फिर, यह प्रभाव बड़े सरणियों के साथ बड़ा हो जाता है।

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


के साथ मंथन किया h5py

डिफ़ॉल्ट रूप से, h5pyडिस्क पर chunked HDF फ़ाइलें नहीं बनाई गई हैं (मुझे लगता pytablesहै कि , इसके विपरीत)। यदि आप chunks=Trueडाटासेट बनाते समय निर्दिष्ट करते हैं, हालांकि, आपको डिस्क पर एक chunked सरणी मिलेगी।

एक त्वरित, न्यूनतम उदाहरण के रूप में:

import numpy as np
import h5py

data = np.random.random((100, 100, 100))

with h5py.File('test.hdf', 'w') as outfile:
    dset = outfile.create_dataset('a_descriptive_name', data=data, chunks=True)
    dset.attrs['some key'] = 'Did you want some metadata?'

ध्यान दें कि स्वचालित रूप से हमारे लिए एक चंक आकार चुनने के लिए chunks=Trueकहता h5pyहै। यदि आप अपने सबसे सामान्य उपयोग-मामले के बारे में अधिक जानते हैं, तो आप आकार आकार (जैसे (2,2,2)ऊपर सरल उदाहरण में) निर्दिष्ट करके चंक आकार / आकार को अनुकूलित कर सकते हैं । यह आपको एक विशेष अक्ष के साथ रीड्स को अधिक कुशल बनाने या किसी निश्चित आकार के रीड / राइट के लिए अनुकूलन करने की अनुमति देता है।


I / O प्रदर्शन तुलना

बस इस बिंदु पर जोर देने के लिए, आइए एक कटा हुआ HDF5 डेटासेट और एक बड़े (~ 8 जीबी) स्लाइस में पढ़ने की तुलना करें, फोरट्रान-आदेशित 3 डी सरणी जिसमें एक ही सटीक डेटा है।

मैंने प्रत्येक रन के बीच सभी ओएस कैश को साफ कर दिया है , इसलिए हम "ठंडा" प्रदर्शन देख रहे हैं।

प्रत्येक फ़ाइल प्रकार के लिए, हम पहले अक्ष के साथ "पूर्ण" x- स्लाइस और अंतिम अक्ष के साथ "पूर्ण" z-slize में पढ़ने का परीक्षण करेंगे। फोरट्रान-द्वारा मेम किए गए सरणी के लिए, "x" स्लाइस सबसे खराब स्थिति है, और "z" स्लाइस सबसे अच्छा मामला है।

उपयोग किया गया कोड एक जिस्ट ( hdfफाइल बनाने सहित ) में है। मैं यहां उपयोग किए गए डेटा को आसानी से साझा नहीं कर सकता, लेकिन आप इसे उसी आकार ( 621, 4991, 2600)और प्रकार) के शून्य द्वारा अनुकरण कर सकते हैं np.uint8

इस chunked_hdf.pyतरह दिखता है:

import sys
import h5py

def main():
    data = read()

    if sys.argv[1] == 'x':
        x_slice(data)
    elif sys.argv[1] == 'z':
        z_slice(data)

def read():
    f = h5py.File('/tmp/test.hdf5', 'r')
    return f['seismic_volume']

def z_slice(data):
    return data[:,:,0]

def x_slice(data):
    return data[0,:,:]

main()

memmapped_array.pyसमान है, लेकिन यह सुनिश्चित करने के लिए एक स्पर्श अधिक जटिलता है कि स्लाइस वास्तव में मेमोरी में लोड किए गए हैं (डिफ़ॉल्ट रूप से, एक और memmappedसरणी वापस आ जाएगी, जो एक सेब से सेब की तुलना नहीं होगी)।

import numpy as np
import sys

def main():
    data = read()

    if sys.argv[1] == 'x':
        x_slice(data)
    elif sys.argv[1] == 'z':
        z_slice(data)

def read():
    big_binary_filename = '/data/nankai/data/Volumes/kumdep01_flipY.3dv.vol'
    shape = 621, 4991, 2600
    header_len = 3072

    data = np.memmap(filename=big_binary_filename, mode='r', offset=header_len,
                     order='F', shape=shape, dtype=np.uint8)
    return data

def z_slice(data):
    dat = np.empty(data.shape[:2], dtype=data.dtype)
    dat[:] = data[:,:,0]
    return dat

def x_slice(data):
    dat = np.empty(data.shape[1:], dtype=data.dtype)
    dat[:] = data[0,:,:]
    return dat

main()

पहले HDF प्रदर्शन पर एक नजर डालते हैं:

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python chunked_hdf.py z
python chunked_hdf.py z  0.64s user 0.28s system 3% cpu 23.800 total

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python chunked_hdf.py x
python chunked_hdf.py x  0.12s user 0.30s system 1% cpu 21.856 total

एक "पूर्ण" एक्स-स्लाइस और एक "पूर्ण" जेड-स्लाइस समय की एक ही राशि (~ 20 सेकंड) के बारे में लेते हैं। यह देखते हुए कि यह 8GB का सरणी है, यह बहुत बुरा नहीं है। सर्वाधिक समय

और अगर हम इसकी तुलना मेम्नेप्ड ऐरे बार से करते हैं (यह फोरट्रान-ऑर्डर किया गया है: "z-slice" सबसे अच्छा मामला है और "x-slice" सबसे खराब स्थिति है।):

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python memmapped_array.py z
python memmapped_array.py z  0.07s user 0.04s system 28% cpu 0.385 total

jofer at cornbread in ~ 
$ sudo ./clear_cache.sh

jofer at cornbread in ~ 
$ time python memmapped_array.py x
python memmapped_array.py x  2.46s user 37.24s system 0% cpu 3:35:26.85 total

हां, आपने उसे सही पढ़ा है। एक स्लाइस दिशा के लिए 0.3 सेकंड और दूसरे के लिए ~ 3.5 घंटे

"X" दिशा में टुकड़ा करने के लिए समय आ गया है अब तक अब समय की राशि यह स्मृति में पूरे 8GB सरणी लोड और टुकड़ा हम चाहते थे चयन करने के लिए ले जाएगा की तुलना में! (फिर से, यह एक फोरट्रान-ऑर्डर की गई सरणी है। विपरीत x / z टुकड़ा समय सी-ऑर्डर की गई सरणी के लिए मामला होगा।)

हालांकि, अगर हम हमेशा सर्वश्रेष्ठ-केस दिशा के साथ एक स्लाइस लेना चाहते हैं, तो डिस्क पर बड़ा बाइनरी सरणी बहुत अच्छा है। (~ 0.3 सेकंड!)

एक मेमरेप्ड सरणी के साथ, आप इस I / O विसंगति (या शायद aisotropy एक बेहतर शब्द है) के साथ फंस गए हैं। हालाँकि, एक chunked HDF डेटासेट के साथ, आप चुन सकते हैं जैसे कि एक्सेस समान है या किसी विशेष उपयोग-केस के लिए ऑप्टिमाइज़ किया गया है। यह आपको बहुत अधिक लचीलापन देता है।

संक्षेप में

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

कुल मिलाकर, इसे आज़माएँ और देखें कि क्या यह आपके उपयोग के मामले में अच्छा काम करता है। मुझे लगता है कि आप आश्चर्यचकित हो सकते हैं।


3
बहुत बढ़िया जवाब। मैं यह जोड़ना चाहूंगा कि आप अपने चुनिंदा लेआउट को अपने विशिष्ट डेटा एक्सेस पैटर्न में कस्टमाइज़ कर सकते हैं। यदि आप पैटर्न का उपयोग करने के लिए काफी पूर्वानुमानित स्टेंसिल आकार रखते हैं, तो आप आमतौर पर अपनी चुन चुन सकते हैं जैसे कि हर समय इष्टतम गति के पास प्राप्त करना।
इलको होगेंडोर्न

2
बहुत बढ़िया जवाब! एक चीज जो चैंकिंग के बारे में नहीं बताई गई है वह है चंक कैश का प्रभाव। प्रत्येक खुले डेटासेट का अपना चंक कैश होता है, जिसका डिफ़ॉल्ट आकार 1 MB होता है, जिसे C. में H5Pset_chunk_cache () का उपयोग करके समायोजित किया जा सकता है। आमतौर पर यह विचार करना उपयोगी होता है कि अपने एक्सेस पैटर्न के बारे में सोचते समय कितने चंक्स को मेमोरी में रखा जा सकता है। यदि आपका कैश होल्ड कर सकता है, कह सकता है, 8 चंक्स और आपके डेटासेट स्कैन की दिशा में 10 विखंडू हैं, तो आप बहुत जोर लगाएंगे और प्रदर्शन भयानक होगा।
डाना रॉबिन्सन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.