2014-11-20 12 views
7

मैं numpy सरणी के रूप में संग्रहीत लगभग पांच गीगाबाइट डेटा के साथ एक तंत्रिका नेटवर्क को प्रशिक्षण दे रहा हूं। डेटा को 100000 पंक्तियों के टुकड़ों में विभाजित किया गया है, और मैंने यादृच्छिक क्रम में सभी हिस्सों पर प्रशिक्षण के छह चक्र किए हैं। दुर्भाग्यवश, नेटवर्क खत्म हो गया है। मुझे लगता है कि अभी भी डेटा को अधिक बारीकी से फिट करने की क्षमता है; मेरा संदेह यह है कि प्रत्येक खंड के भीतर आंतरिक नियमितताएं एक-दूसरे से विरोधाभास शुरू कर रही हैं, और मुझे डेटा को और अधिक अच्छी तरह से घुमाने की जरूरत है ताकि यह विभिन्न संयोजनों पर प्रशिक्षित हो सके। मैं अधिक प्रशिक्षण डेटा प्राप्त करने की परेशानी पर जाने से पहले इसे आजमा देना चाहता हूं।समान डेटा के 5 गीगाबाइट्स को समान रूप से शफल करें

क्या किसी को भी numpy डेटा की 3.6 मिलियन (बहुत लंबी) पंक्तियों का नया क्रमपरिवर्तन उत्पन्न करने का एक अच्छा तरीका पता है? मैंने one of these तकनीकों का उपयोग करने के बारे में सोचा, लेकिन numpy.savetxt का उपयोग करके इन arrays को लिखने अविश्वसनीय रूप से बड़ी फ़ाइलें उत्पन्न करता है, और मैं यह नहीं बता सकता कि मानक npy फ़ाइल से अलग-अलग पंक्तियों को कैसे हल किया जाए, इस समस्या को हल करने में मदद करता है।

अभी, मेरे सबसे अच्छे विचार डेटा, जहां c एक हिस्सा choses और r कि हिस्सा से एक पंक्ति choses में बनती सूचकांक (c, r) का क्रमपरिवर्तन तैयार करना है। मैं प्रत्येक पंक्ति को एक नए प्रीलोकेटेड सरणी में स्टोर कर सकता हूं, और फिर इसे सहेज सकता हूं। लेकिन मुझे आश्चर्य है कि अगर मैं बहुत कम I/O-bound समाधान है। क्या आपके पास भाग के यादृच्छिक जोड़े को तब तक घुमाने के लिए कुछ सिद्धांतबद्ध तरीका है जब तक कि आप एक क्रमपरिवर्तन प्राप्त नहीं करते हैं जो प्रारंभिक क्रमपरिवर्तन से सांख्यिकीय रूप से स्वतंत्र है?

+0

क्या आप मछुआरों को पंक्तियों को जोड़ सकते हैं और फिर मछुआरे कॉलम को येट कर सकते हैं? चूंकि आप केवल व्यक्तिगत पंक्तियों/कोल्स को स्वैप कर रहे हैं, इसलिए इसे आपकी याददाश्त का दुरुपयोग नहीं करना चाहिए। यदि गति समस्या है तो आप इसे सी एक्सटेंशन के रूप में कर सकते हैं (आपको वास्तव में यादृच्छिक बनाने के लिए स्वैप का एक टन चाहिए)। –

+0

क्षमा करें, मैं स्पष्ट नहीं था - मुझे केवल पंक्तियों को कॉलम को घुमाने की आवश्यकता नहीं है। यह सिर्फ इतना है कि इसे सभी को स्मृति में लोड करने का कोई अच्छा तरीका नहीं है, न ही कुछ स्पष्ट डिस्क-आधारित विधियां व्यावहारिक हैं। – senderle

उत्तर

6

जिन चीजों में मैंने अभी तक कोशिश की है, उनमें से एक पीईटीबल्स समाधान वर्तमान में सबसे अच्छा है, इसके बाद एक समाधान के बाद numpy का उपयोग memmapped arrays के लिए करता है। हालांकि PyTables समाधान सरल नहीं है।यदि आप एक PyTables सरणी को सीधे अनुक्रमणित करने के लिए पूर्णांक की एक शफल सरणी का उपयोग करते हैं, तो यह बहुत धीमा है। निम्नलिखित दो-चरणीय प्रक्रिया बहुत तेज है:

  1. बूलियन इंडेक्स सरणी का उपयोग करके सरणी का एक यादृच्छिक सबसेट चुनें। यह एक chunkwise फैशन में किया जाना चाहिए। यदि आप सीधे इंडेक्स सरणी को PyTables सरणी में पास करते हैं, तो यह धीमा है।
    • Preallocate एक numpy सरणी और स्लाइस कि टुकड़ों में PyTables सरणी विभाजित की एक सूची बना।
    • प्रत्येक हिस्सा पूरी तरह स्मृति में पढ़ें, और फिर उस हिस्सा के लिए सही मूल्यों का चयन करने के सूचकांक सरणी की इसी हिस्सा का उपयोग करें।
    • चयनित मानों को प्रीलोकेटेड सरणी में संग्रहीत करें।
  2. फिर प्रीलोकेटेड सरणी को घुमाएं।

यह प्रक्रिया एक सामान्य शफल प्रक्रिया के रूप में यादृच्छिक रूप से क्रमपरिवर्तन उत्पन्न करती है। यदि यह स्पष्ट प्रतीत नहीं होता है, तो इस पर विचार करें: (n choose x) * x! = x! * n!/(x! * (n - x)!) = n!/(n - x)!। यह विधि प्रत्येक प्रशिक्षण चक्र के लिए एक शफल-ऑन-लोड करने के लिए पर्याप्त तेज़ है। यह डेटा को ~ 650 एम तक संपीड़ित करने में भी सक्षम है - लगभग 90% अपस्फीति।

मेरा वर्तमान कार्यान्वयन यहां है; इसे कॉर्पस में प्रत्येक प्रशिक्षण खंड के लिए एक बार कहा जाता है। (लौटे सरणियों कहीं shuffled हैं।)

def _h5_fast_bool_ix(self, h5_array, ix, read_chunksize=100000): 
    '''Iterate over an h5 array chunkwise to select a random subset 
    of the array. `h5_array` should be the array itself; `ix` should 
    be a boolean index array with as many values as `h5_array` has 
    rows; and you can optionally set the number of rows to read per 
    chunk with `read_chunksize` (default is 100000). For some reason 
    this is much faster than using `ix` to index the array directly.''' 

    n_chunks = h5_array.shape[0]/read_chunksize 
    slices = [slice(i * read_chunksize, (i + 1) * read_chunksize) 
       for i in range(n_chunks)] 

    a = numpy.empty((ix.sum(), h5_array.shape[1]), dtype=float) 
    a_start = 0 
    for sl in slices: 
     chunk = h5_array[sl][ix[sl]] 
     a_end = a_start + chunk.shape[0] 
     a[a_start:a_end] = chunk 
     a_start = a_end 

    return a 

यह मेरे लिए कुछ हद तक पागल है कि एक O (n^2) दृष्टिकोण (हर हिस्सा के लिए पूरे PyTables सरणी पर पुनरावृत्ति) एक हे की तुलना में तेजी इस मामले में है (एन) दृष्टिकोण (यादृच्छिक रूप से प्रत्येक पंक्ति को एक पास में चुनना)। लेकिन हे, यह काम करता है। थोड़ी अधिक संकेत के साथ, इसे मनमाने ढंग से गैर-यादृच्छिक क्रमपरिवर्तन लोड करने के लिए अनुकूलित किया जा सकता है, लेकिन इससे यहां की तुलना में अधिक जटिलता बढ़ जाती है।

mmap समाधान उन लोगों को जो किसी भी कारण से एक शुद्ध numpy समाधान की जरूरत के लिए यहाँ संदर्भ के लिए है। यह लगभग 25 मिनट में सभी डेटा को घुमाता है, जबकि उपर्युक्त समाधान उस समय आधा से भी कम समय में प्रबंधित करता है। यह रैखिक रूप से भी स्केल करना चाहिए, क्योंकि mmap (अपेक्षाकृत) कुशल यादृच्छिक पहुंच की अनुमति देता है।

import numpy 
import os 
import random 

X = [] 
Y = [] 

for filename in os.listdir('input'): 
    X.append(numpy.load(os.path.join('input', filename), mmap_mode='r')) 

for filename in os.listdir('output'): 
    Y.append(numpy.load(os.path.join('output', filename), mmap_mode='r')) 

indices = [(chunk, row) for chunk, rows in enumerate(X) 
         for row in range(rows.shape[0])] 
random.shuffle(indices) 

newchunks = 50 
newchunksize = len(indices)/newchunks 

for i in range(0, len(indices), newchunksize): 
    print i 
    rows = [X[chunk][row] for chunk, row in indices[i:i + newchunksize]] 
    numpy.save('X_shuffled_' + str(i), numpy.array(rows)) 
    rows = [Y[chunk][row] for chunk, row in indices[i:i + newchunksize]] 
    numpy.save('Y_shuffled_' + str(i), numpy.array(rows)) 
0

निम्नलिखित मानते हैं कि आपका डेटा पहले से ही किसी प्रकार के आसानी से पुनर्प्राप्त करने योग्य रिकॉर्ड में बांटा गया है। (मैं numpy डेटा के लिए एक मानक फ़ाइल स्वरूप हो, तो पता नहीं।)

  1. एक dict के रूप में डेटा के एक सूचकांक बनाएँ, n के माध्यम से एक अनूठा रिकॉर्ड आईडी (0 मानचित्रण - 1) फिर से डेटा खोजने के कुछ साधनों के लिए। उदाहरण के लिए, यदि यह सब एक बाइनरी फ़ाइल में है, तो आप फॉर्म (file_offset, record_length) के एक tuple स्टोर करेंगे। डेटा पर खुद को पकड़ने की जरूरत नहीं है।

  2. n तत्वों की एक सूची बनाएं, सूचकांक dict की कुंजियों युक्त (फिर से, 0 के माध्यम से n - 1)।

  3. रिकॉर्ड आईडी की सूची को घुमाएं। (यदि आवश्यक हो, तो अपना खुद का यादृच्छिक संख्या जनरेटर प्रदान करें।)

  4. शफल डेटा को रखने के लिए एक नई फ़ाइल (या जो भी) खोलें।

  5. शुरुआत से अंत तक सूची में से रिकॉर्ड आईडी पढ़ें। प्रत्येक रिकॉर्ड आईडी के लिए, इंडेक्स में उस रिकॉर्ड का स्थान देखें। उस स्थान पर डेटा पकड़ो और इसे आउटपुट फ़ाइल में संलग्न करें।

छद्म कोड:

# This assumes a binary file of unequal-length 
# records. It also assumes that the file won't 
# be changed while we're doing this. 

# Create index. 
index = {} 
rec_offset = 0 
for rec_id, record in original_data.iterate_records(): 
    # This bit depends greatly on how your data 
    # is stored... 
    rec_length = len(record) 
    index[rec_id] = (rec_offset, rec_length) 
    rec_offset += rec_length 

# Shuffle. 
num_records_indexed = rec_id + 1 # rec_id is still in scope. 
records_order = list(range(num_records_indexed)) 
records_order = random.shuffle(records_order, "<optional_RNG_here>") 

# Create new shuffled-data file. 
with open("output_file.bin", "wb") as output: 
    for rec_id in records_order: 
     rec_offset, rec_length = index[rec_id] 
     record = original_data.get_rec_at(rec_offset, rec_length) 
     output.write(record) 

अनुक्रमण, फेरबदल, और डी-अनुक्रमण सब ओ (n) हैं, इसलिए सबसे बुरी बात यह होना चाहिए मैं/हे: डाटा पढ़ने और फिर इसे कॉपी करना (एक दूसरा पठन, साथ ही एक लेखन)।

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