Memuat NumPy Array dari Disk: Perbandingan memmap () dan Zarr / HDF5

Jika array NumPy Anda terlalu besar untuk muat di RAM, Anda bisa mengolahnya dengan memecahnya menjadi fragmen . Anda dapat melakukan ini dalam mode transparan atau secara eksplisit dengan memuat fragmen-fragmen ini dari disk satu per satu. Dalam situasi ini, Anda dapat menggunakan dua kelas alat:





  • Metode NumPy memmap(), mekanisme transparan yang memungkinkan Anda melihat file yang terletak di disk seolah-olah semuanya ada di memori. 
  • Format penyimpanan data Zarr dan HDF5 yang mirip satu sama lain, yang memungkinkan, jika perlu, memuat dari disk dan menyimpan fragmen terkompresi dari array ke disk.

Masing-masing metode ini memiliki kekuatan dan kelemahannya sendiri. 

Bahan, terjemahan yang kami terbitkan hari ini, dikhususkan untuk analisis fitur-fitur metode bekerja dengan data ini, dan kisah di mana situasi mereka mungkin berguna. Secara khusus, perhatian khusus akan diberikan pada format data yang dioptimalkan untuk melakukan perhitungan dan tidak perlu dirancang untuk mentransfer data ini ke programmer lain.

Apa yang terjadi ketika membaca data dari disk atau menulis data ke disk?


Ketika file dibaca dari disk untuk pertama kalinya, sistem operasi tidak hanya menyalin data ke memori proses. Pertama, ia menyalin data ini ke dalam memorinya, menyimpan salinannya dalam apa yang disebut "buffer cache".

Apa gunanya di sini?

Faktanya adalah bahwa sistem operasi menyimpan data dalam cache jika Anda perlu membaca data yang sama dari file yang sama lagi.


Jika data dibaca lagi, maka ia memasukkan memori program bukan dari disk, tetapi dari RAM, yang merupakan urutan besarnya lebih cepat.


Jika memori ditempati oleh cache diperlukan untuk sesuatu yang lain, cache akan dihapus secara otomatis.

Ketika data ditulis ke disk, itu bergerak ke arah yang berlawanan. Awalnya hanya ditulis ke cache buffer. Ini berarti bahwa operasi penulisan biasanya sangat cepat, karena program tidak perlu fokus pada disk yang lambat. Dia, selama perekaman, hanya perlu bekerja dengan RAM.


Akibatnya, data memerah ke disk dari cache.


Bekerja dengan array menggunakan memmap ()


Dalam kasus kami, memmap()ini memungkinkan kami untuk melihat file pada disk seolah-olah itu adalah array yang disimpan dalam memori. Sistem operasi, transparan untuk program, melakukan operasi baca / tulis, mengakses cache buffer atau hard disk, tergantung pada apakah data yang diminta di-cache dalam memori atau tidak. Algoritma seperti ini dijalankan di sini:

  • Apakah data dalam cache? Jika begitu - hebat - Anda dapat menghubungi mereka secara langsung.
  • Apakah data pada disk? Akses ke mereka akan lebih lambat, tetapi Anda tidak perlu khawatir, mereka akan dimuat dalam mode transparan.

Sebagai tambahan tambahan, memmap()dapat dicatat bahwa dalam banyak kasus cache buffer untuk file akan dibangun ke dalam memori program. Ini berarti bahwa sistem tidak harus memelihara salinan tambahan dari data dalam memori program di luar buffer.


Metode memmap()ini dibangun ke dalam NumPy:

import numpy as np
array = np.memmap("mydata/myarray.arr", mode="r",
                  dtype=np.int16, shape=(1024, 1024))

Jalankan kode ini, dan Anda akan memiliki array yang Anda inginkan, pekerjaan yang akan sepenuhnya transparan untuk program - terlepas dari apakah pekerjaan dilakukan dengan cache buffer atau dengan hard disk.

Keterbatasan Memmap ()


Meskipun dalam situasi tertentu memmap()dapat menunjukkan dirinya dengan cukup baik, metode ini juga memiliki keterbatasan:

  • Data harus disimpan dalam sistem file. Data tidak dapat diunduh dari penyimpanan biner seperti AWS S3.
  • , . , . , , , .
  • N- , , , . .

Mari kita jelaskan poin terakhir. Bayangkan kita memiliki array dua dimensi yang berisi bilangan bulat 32-bit (4-byte). 4096 byte dibaca per disk. Jika Anda membaca data yang terletak di file secara berurutan dari disk (katakanlah, data tersebut berada di baris array), maka setelah setiap operasi baca kita akan memiliki 1024 integer. Tetapi jika Anda membaca data yang lokasinya di file tidak cocok dengan lokasinya di array (katakanlah, data terletak di kolom), maka setiap operasi membaca akan memungkinkan Anda untuk mendapatkan hanya 1 nomor yang diperlukan. Hasilnya, ternyata untuk mendapatkan jumlah data yang sama, Anda harus melakukan operasi baca ribuan kali lebih banyak.

Zarr dan HDF5


Untuk mengatasi keterbatasan di atas, Anda dapat menggunakan format penyimpanan data Zarr atau HDF5, yang sangat mirip:

  • Anda dapat bekerja dengan file HDF5 di Python menggunakan pytables atau h5py . Format ini lebih tua dari Zarr dan memiliki lebih banyak batasan, tetapi kelebihannya adalah ia dapat digunakan dalam program yang ditulis dalam berbagai bahasa.
  • Zarr adalah format yang diimplementasikan menggunakan paket Python dengan nama yang sama. Ini jauh lebih modern dan fleksibel daripada HDF5, tetapi Anda dapat menggunakannya (setidaknya untuk saat ini) hanya di lingkungan Python. Menurut perasaan saya, dalam kebanyakan situasi, jika tidak ada dukungan multibahasa untuk HDF5, ada baiknya memilih Zarr. Zarr, misalnya, memiliki dukungan multithreading yang lebih baik.

Lebih lanjut kami hanya akan membahas Zarr, tetapi jika Anda tertarik dengan format HDF5 dan perbandingannya yang lebih dalam dengan Zarr, Anda dapat menonton video ini .

Menggunakan Zarr


Zarr memungkinkan Anda untuk menyimpan potongan data dan memuatnya ke dalam memori dalam bentuk array, dan juga - menulis potongan data ini dalam bentuk array.

Berikut cara memuat array menggunakan Zarr:

>>> import zarr, numpy as np
>>> z = zarr.open('example.zarr', mode='a',
...               shape=(1024, 1024),
...               chunks=(512,512), dtype=np.int16)
>>> type(z)
<class 'zarr.core.Array'>
>>> type(z[100:200])
<class 'numpy.ndarray'>

Harap dicatat bahwa sampai sepotong objek diterima, kami tidak akan siap membantu kami numpy.ndarray. Entitas zarr.core.arrayhanyalah metadata. Hanya data yang termasuk dalam slice yang dimuat dari disk.

Mengapa saya memilih Zarr?


  • Zarr menghindari batasan yang memmap()dibahas di atas:
  • Fragmen data dapat disimpan pada disk, dalam penyimpanan AWS S3, atau dalam beberapa sistem penyimpanan yang menyediakan kemampuan untuk bekerja dengan catatan format kunci / nilai.
  • Ukuran dan struktur fragmen data ditentukan oleh programmer. Sebagai contoh, data dapat diatur sedemikian rupa agar dapat secara efisien membaca informasi yang terletak pada sumbu yang berbeda dari array multidimensi. Ini berlaku untuk HDF5.
  • Fragmen dapat dikompresi. Hal yang sama dapat dikatakan tentang HDF5.

Mari kita membahas dua poin terakhir lebih terinci.

Dimensi Fragmen


Misalkan kita sedang bekerja dengan array ukuran 30.000 x 3.000 elemen. Jika Anda perlu membaca array ini dan bergerak di sepanjang porosnya X, dan bergerak di sepanjang porosnya Y, Anda dapat menyimpan fragmen yang berisi data array ini, seperti yang ditunjukkan di bawah ini (dalam praktiknya, kemungkinan besar, Anda akan membutuhkan lebih dari 9 fragmen):


Sekarang, data yang terletak pada sumbu Xdan sumbu Ydapat dimuat secara efisien. Bergantung pada jenis data apa yang dibutuhkan dalam program, Anda dapat mengunduh, misalnya, fragmen (1, 0), (1, 1), (1, 2), atau fragmen (0, 1), (1, 1), (2, 1).

Kompresi data


Setiap fragmen dapat dikompresi. Ini berarti bahwa data dapat masuk ke program lebih cepat daripada disk memungkinkan Anda membaca informasi yang tidak terkompresi. Jika data dikompresi 3 kali, ini berarti dapat diunduh dari disk 3 kali lebih cepat dari data yang tidak terkompresi, dikurangi waktu yang dibutuhkan prosesor untuk membukanya.


Setelah fragmen diunduh, mereka dapat dihapus dari memori program.

Ringkasan: memmap () atau Zarr?


memmap()Mana yang lebih baik untuk digunakan - atau Zarr?

Memmap()Terlihat menarik dalam beberapa kasus:

  • Ada banyak proses yang membaca bagian dari file yang sama. Proses-proses ini, berkat aplikasi memmap(), akan dapat berbagi cache buffer yang sama. Ini berarti bahwa hanya satu salinan data yang perlu disimpan dalam memori, tidak peduli berapa banyak proses yang berjalan.
  • Pengembang tidak memiliki keinginan untuk mengelola memori secara manual. Dia berencana untuk hanya mengandalkan kemampuan sistem operasi, yang akan menyelesaikan semua masalah manajemen memori secara otomatis dan tidak terlihat oleh pengembang.

Zarr sangat berguna dalam situasi berikut (dalam beberapa dari mereka, seperti yang akan dicatat, format HDF5 juga berlaku):

  • Data diunduh dari sumber jarak jauh, bukan dari sistem file lokal.
  • Sangat mungkin bahwa kemacetan sistem akan membaca dari disk. Kompresi data akan memungkinkan penggunaan kemampuan perangkat keras yang lebih efisien. Ini juga berlaku untuk HDF5.
  • Jika Anda perlu mendapatkan irisan array multidimensi sepanjang sumbu yang berbeda, Zarr membantu mengoptimalkan operasi tersebut dengan memilih ukuran dan struktur fragmen yang sesuai. Ini berlaku untuk HDF5.

Saya akan memilih antara memmap()Zarr dan, pertama-tama, saya akan mencoba menggunakan Zarr - karena fleksibilitas yang diberikan paket ini dan format penyimpanan data yang diterapkannya.

Pembaca yang budiman! Bagaimana Anda memecahkan masalah bekerja dengan array NumPy besar?


All Articles