كيف يمكنني ملء مصفوفة ذات أبعاد n في HDF5 من مصدر أحادي الأبعاد؟

StackOverflow https://stackoverflow.com//questions/20007123

  •  20-12-2019
  •  | 
  •  

سؤال

لدي مصفوفة ذات أبعاد متعددة (x، y، القنوات، z، الخطوات الزمنية).ومع ذلك، يتم تخزين البيانات الأولية في صورة TIFF كمجموعة واحدة من (x، y، القنوات)، مع إطارات الخطوات الزمنية z *.

أخيرًا، تقوم الدالة Image.getdata() الخاصة بـ Pillow بإرجاع كائن يشبه المصفوفة أحادية الأبعاد والتي تحتاج إلى إعادة تشكيل.

ما هي أفضل طريقة لقراءة ذلك في HDF5 إذا كانت مجموعة البيانات كبيرة جدًا بحيث لا يمكن احتواؤها في الذاكرة؟هل من الممكن إعادة تشكيل المصفوفة بمجرد كتابتها في HDF5، أو كتابة بيانات أحادية الأبعاد بطريقة تملأ المصفوفة تلقائيًا (على سبيل المثال:يكتب مع x متفاوتًا الأسرع، y ثاني أسرع، وما إلى ذلك.) تحديث:شيء مثل numpy.ndarray.flat سيكون مثاليا.

إليك ما جربته حتى الآن (img هو PIL.Image، وdset عبارة عن مجموعة بيانات h5py):

1) قراءة الإطارات الفردية.هذه الطريقة بطيئة جدًا لأنها تستغرق حوالي 20 دقيقة لـ 300 ميجابايت في 1000 إطار.يتم قضاء معظم الوقت في dset[] = مكالمة.

for i in range(0, img_layers):
  img.seek(i)
  a = numpy.array(img.getdata(), dtype=dtype) # a.shape = (sx * sz * channels,)
  a.resize(sx, sy, channels)
  z = i % sz
  frame = i // sz
  dset[..., z, frame] = a

2) غير مكتمل: القراءة في أجزاء.يعد هذا أسرع بكثير (دقيقتان لنفس مجموعة البيانات)، ولكني أعمل فقط على صورة رباعية الأبعاد (sx، sy، القنوات، الخطوات الزمنية)، وأحتاج إلى بُعد إضافي لشرائح z:

chunk_bits = 256 * 1000**2 # 256MB
frame_bits = depth_bits[dtype] * sx * sy * channels
chunk_frames = chunk_bits // frame_bits
a = numpy.zeros((sx, sy, channels, chunk_frames), dtype=dtype)
for i in range(0, layers):
  img.seek(i)
  temp = numpy.array(img.getdata(), dtype=dtype)
  temp.resize(sx, sy, channels)
  a[..., i % chunk_frames] = temp
  if (i + 1) % chunk_frames == 0 or i == (layers - 1):
    chunk = i // chunk_frames
    dset[..., chunk * chunk_frames : i + 1] = a[..., : i % chunk_frames + 1
هل كانت مفيدة؟

المحلول

الخيار 1 كان الإجابة الصحيحة.ومع ذلك، هناك فرق كبير في تحديد البعد الذي يتغير بشكل أسرع:

~15 دقيقة:

for i in range(0, img_layers):
  img.seek(i)
  a = numpy.array(img.getdata(), dtype=dtype)
  a.resize(sx, sy, channels)
  z = i % sz
  frame = i // sz
  dset[..., z, frame] = a # Majority of time in this call

~3 دقائق:

for i in range(0, img_layers):
  img.seek(i)
  a = numpy.array(img.getdata(), dtype=dtype) # Majority of time in this call
  a.resize(sx, sy, channels)
  z = i % sz
  frame = i // sz
  dset[frame, z, ...] = a

لقراءة هذه البيانات بسرعة، يجب أن يكون الفهرس الأسرع تغيرًا هو الأخير، وليس الأول.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top