Эффективный доступ к атрибутам HDF5 с помощью h5py - PullRequest
0 голосов
/ 03 августа 2020

Я читаю данные атрибутов примерно для 10-15 групп в файле HDF5 с помощью h5py, а затем добавляю данные в словарь python для описания структуры файла, который я использую позже для анализа и доступа к остальной части наборы данных при необходимости. Большинство наборов атрибутов состоит из примерно 10 ключей, из которых меня обычно интересуют только 4-8 из.

struct = {}
temp = h5py.File(fname, 'r')
struct['a'] = dict(temp['Timestep']['0.1']['Groups']['1'].attrs.items())
struct['b'] = dict(temp['Timestep']['0.1']['Groups']['2'].attrs.items())
struct['c'] = dict(temp['Timestep']['0.1']['Groups']['3'].attrs.items())
...
...
tempt.close()

Я делаю это для каждого файла .h5, поскольку каждый файл представляет новый временной шаг данных моделирования. Поскольку каждая симуляция обычно состоит из нескольких тысяч временных шагов, я, кажется, трачу много времени на чтение всех необходимых метаданных, необходимых для последующего использования.

Я провел несколько простых проверок производительности, чтобы посмотреть, могу ли я что-нибудь сделать, чтобы ускорить работу, например, получить доступ только к нужным мне ключам или преобразовать их в списки вместо словарей, но ни один из них не работает значительно быстрее. данные (которые создают объект ItemsViewHDF5) относительно быстро составляют около 100 мкс, но преобразование их в словарь или список занимает намного больше времени - около 800 мкс. Чтение всего набора атрибутов происходит намного быстрее, чем просто чтение интересующих по отдельности.

Кто-нибудь знает, как получить данные атрибута в какую-то другую структуру данных, которая становится доступной после чтения файла h5 и закрыто? Я хотел бы иметь возможность сделать это ближе к 100 мкс, а не к отметке 1 мс!

Уточнение: Для ясности, данные атрибутов имеют смешанные типы. Например, var1 обычно представляет собой строку имени, назначенного пользователем, а затем var2 обычно будет целым числом, которое является размером (количеством строк в наборе данных). Другие переменные, как правило, представляют собой векторы (x, y, z), такие как скорость, которые хранятся в виде массивов, но иногда с плавающей точкой.

1 Ответ

0 голосов
/ 03 августа 2020

Создайте простой h5 с группой и добавьте к нему несколько attrs:

In [2]: f = h5py.File('testattr.h5','w')                                                             
In [3]: g = f.create_group('test')                                                                   
In [4]: g.attrs                                                                                      
Out[4]: <Attributes of HDF5 object at 139650561822480>
In [5]: g.attrs['var1'] = 'foobar'                                                                   
In [6]: g.attrs['var2'] = 23                                                                         
In [7]: g.attrs['var3'] = np.arange(24).reshape(2,3,4)                                               
In [8]: g.attrs['var4'] = np.pi                                                                      

Получите itemsview, а затем загрузите с помощью list (или dict):

In [9]: g.attrs.items()                                                                              
Out[9]: ItemsViewHDF5(<Attributes of HDF5 object at 139650561822480>)
In [10]: list(g.attrs.items())                                                                       
Out[10]: 
[('var1', 'foobar'),
 ('var2', 23),
 ('var3', 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]]])),
 ('var4', 3.141592653589793)]

Получение средства просмотра тривиально по времени :, но на самом деле загрузка данных в список или dict требует времени - фактический формат не имеет значения:

In [11]: timeit g.attrs.items()                                                                      
4.7 µs ± 177 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [13]: timeit list(g.attrs.items())                                                                
273 µs ± 2.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [15]: timeit dict(g.attrs.items())                                                                
272 µs ± 287 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Добавление другого атрибута (относительно большого), немного увеличивает время загрузки:

In [26]: g.attrs['var5'] = np.random.rand(1000)  
In [29]: timeit list(g.attrs.values())                                                               
337 µs ± 633 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Сравните это с использованием набора данных:

In [30]: g.create_dataset('oned', data=np.random.rand(1000))                                         
Out[30]: <HDF5 dataset "oned": shape (1000,), type "<f8">
In [31]: f.flush()                                                                                   
In [32]: g['oned']                                                                                   
Out[32]: <HDF5 dataset "oned": shape (1000,), type "<f8">
In [33]: g['oned'][:];                                                                               
In [34]: timeit g['oned']                                                                            
64.4 µs ± 143 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [35]: timeit g['oned'][:]                                                                         
239 µs ± 188 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [36]: ds = g['oned']                                                                              
In [37]: timeit ds[:]                                                                                
151 µs ± 2.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
...