Найти - Пользователи
Полная версия: hdf5 и python
Начало » Python для экспертов » hdf5 и python
1 2
mrgloom
Вообщем нужно считывать(из любого места) и записывать в конец произвольные numpy array которые влезают в память, т.е. по сути на диске храниться большая матрица(десятки гигабайт) которую нельзя считать всю сразу по причине того, что в RAM она не влезет, а нам надо считать строки матрицы допустим с 10000 до 20000(которые в памяти могут поместиться).

hdf5 вроде как раз то что нужно? только я не смог найти внятного примера использования чтобы можно было дописывать в конец файла(не зная заранее размера, т.е. расширять матрицу).
mrgloom
опять же есть такой вариант как numpy.memmap, но получается, что размер файла на диске надо задавать заранее побольше(а это н есовсем правильно, т.к. надо хранить отдельную переменную сколько занято + память на диске выделяется подо всё заранее), т.к. добавления в конец там вроде как нету.

doza_and
mrgloom
я не смог найти внятного примера
dset = f.create_dataset("some_path_in_file", compression=arhopt, 
                shape=(l, N), maxshape=(None, N))
....
dset.resize((new_size, N))
т.е. можно по мере необходимости делать resize.

Возможные проблемы:
resize конечно лучше делать пореже, будет лучше если массивчик будет создаваться с запасом.
Для больших массивов бывает полезно использовать нетривиальных compression. В этом случае однозначно нужно кеширование данных в памяти перед записью.

р.s.
Если у вас просто большая матрица и вы не планируете использовать архивирование, то не нужен вам hdf5. Просто открываете обычный файл и пишете в него в двоичном виде np.array. Куски одинаковые, для извлечения рассчитываете позицию в файле, делаете seek и читаете данные. Будет и простое дописывание и быстрое извлечение.
mrgloom
тут написано

Datasets can be resized, up to a maximum value provided at creation time. You can specify this maximum size via the maxshape argument to create_dataset or require_dataset. Shape elements with the value None indicate unlimited dimensions.
так и не понятно, что конкретно происходит при ресайзе, т.е. какие накладные расходы, и почему бы не поставить unlimited dimensions сразу?

в идеале хотелось бы чтобы большая матрица хранилась на диске и к ней был “прозрачный” доступ как numpy.array, вроде как numpy.memmap как раз это и позволяет, т.е. возможно например посчитать среднее значение просто передав
np.mean(fp, axis=0)
, а не читая по кускам и не модифицирую функцию подсчёта или например sklearn тоже принимает numpy.memmap как данные на вход.

еще по поводу x32 и x64, для больших файлов обязательно должна быть система x64 (+ и сам питон)?
на х32 не получилось создать массив 1кк х 1к float32
fp = np.memmap('C:/data_1000000x1000', dtype='float32', mode='w+', shape=(1000000,1000))
т.е. понятно что мы имеем ограничение на адресное пространство, но мы же читаем не все сразу, а по идее имеем только ограничение на размер slice/view.
позволяет ли hdf5 работать с большими данными на x32?
про PyTables пишут (хотя это не тот объем)
PyTables program can deal with a table with around 30 columns and 1 million entries using as low as 13 MB of memory (on a 32-bit platform).
mrgloom
Опять же про перемножение больших матриц которые лежат на диске.
import numpy as np
import time
rows= 10000 # it can be large for example 1kk
cols= 1000
#create some data in memory
data = np.arange(rows*cols, dtype='float32') 
data.resize((rows,cols))
#create file on disk
fp0 = np.memmap('C:/data_0', dtype='float32', mode='w+', shape=(rows,cols))
fp1 = np.memmap('C:/data_1', dtype='float32', mode='w+', shape=(rows,cols))
fp0[:]=data[:]
fp1[:]=data[:]
#matrix transpose test
tr = np.memmap('C:/data_tr', dtype='float32', mode='w+', shape=(cols,rows))
tr= np.transpose(fp1)  #memory consumption?
print fp1.shape
print tr.shape
res = np.memmap('C:/data_res', dtype='float32', mode='w+', shape=(rows,rows))
t0 = time.time()
res[:]= np.dot(fp0,tr) #takes 342 seconds on my machine, if I multiplicate matrices in RAM it takes 345 seconds (I thinks it's a strange result)
print res.shape
print (time.time() - t0)

Как я понимаю память должна выделяться только при объявлении переменной data, а сколько её выделяется для работы с memmap непонятно.И еще при перемножении матриц через dot работает только одно ядро.


тут ещё всякие MKL и пр. описывается, но о размерах не говориться.
http://www.pytables.org/docs/LargeDataAnalysis.pdf


в R есть bigmemory
http://cran.r-project.org/web/packages/bigmemory/index.html
mrgloom
еще в тему
http://labrosa.ee.columbia.edu/millionsong/pages/fast-k-nn-using-hdf5

единственно непонятно за счёт чего это работает, за счёт того, что pytables предоставляет “прозрачный доступ” к numpy array или из-за того что scikits.ann умеет с большими файлами работать или у них просто всё в память и так влезает.
mrgloom
import numpy as np
import time
import tables
import cProfile
rows = 10000
cols = 1000
batches = 100
k= 10
#USING HDF5
vec= np.random.rand(1,cols)
data = np.random.rand(rows,cols)
fileName = 'C:\carray1.h5'
shape = (rows*batches, cols)  # predefined size
atom = tables.UInt8Atom()  #?
filters = tables.Filters(complevel=5, complib='zlib') #?
# h5f = tables.open_file(fileName, 'w')
# ca = h5f.create_carray(h5f.root, 'carray', atom, shape, filters=filters)
# for i in range(batches):
	# ca[i*rows:(i+1)*rows]= data[:]+i  # +i to modify data
# h5f.close()
def test_knn():
	h5f = tables.open_file(fileName)
	t0= time.time()
	d = np.empty((rows*batches,))
	for i in range(batches):
		d[i*rows:(i+1)*rows] = ((h5f.root.carray[i*rows:(i+1)*rows]-vec)**2).sum(axis=1)
	print (time.time()-t0)
	ndx = d.argsort()
	print ndx[:k]
	h5f.close()
cProfile.run('test_knn()')
Используя HDF5, для 1кк х 1к работает 31 сек, думаю возможно ускорение.
doza_and
mrgloom
думаю возможно ускорение.
А почему так думаете?
mrgloom
filters = tables.Filters(complevel=5, complib='zlib') #?
А почему так сделали? оказалось что вас ограничивает доступ к диску? Наверное надо попробовать хранить данные без сжатия, или сменить метод компрессии gzip один из самых медленных.

mrgloom
А почему так думаете?
Думаю, что саму норму можно быстрее считать, всякие питоновские трюки по производительности, например можно поробовать numexpr. Еще можно попробовать варьировать batch_size под кокретное железо, т.е. хорошо было бы если бы алгоритм был бы автонастраиваемым.

Может используя деревья быстрее(но там approximate nearest neighbor searches in high dimensional spaces, а не точный поиск)
Вообще тот же flann похоже имеет родную поддержку hdf5 и интерфейс pyflann.

Попробовал NearestNeighbors из sklearn.neighbors, работает медленней чем линейный поиск.
def test_tree_knn():
	h5f = tables.open_file(fileName)
        //так работать не будет
	# t0= time.time()
	# nbrs = NearestNeighbors(n_neighbors=k, algorithm='ball_tree').fit(h5f.root.carray)
	# distances, indices = nbrs.kneighbors(vec)
	# print (time.time()-t0)
		
        //надо еще distances, indices слеплять на каждой итерации
	t0= time.time()
	d = np.empty((rows*batches,))
	for i in range(batches):
		nbrs = NearestNeighbors(n_neighbors=k, algorithm='ball_tree').fit(h5f.root.carray[i*rows:(i+1)*rows])
		distances, indices = nbrs.kneighbors(vec)  # put in dict? 
		#d[i*rows:(i+1)*rows] = 
	print (time.time()-t0)
	#ndx = d.argsort()
	#print ndx[:k]
	h5f.close()

mrgloom
filters = tables.Filters(complevel=5, complib='zlib') #?

А почему так сделали? оказалось что вас ограничивает доступ к диску? Наверное надо попробовать хранить данные без сжатия, или сменить метод компрессии gzip один из самых медленных.
Я об этом не задумывался, надо попробовать.В презентации pytables пишут, что возможен вариант, что передать сжатое+разжать займет меньше времени, чем передать несжатое.
doza_and
mrgloom
В презентации pytables пишут
Попробовать вам проще простого
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB