El ahorro en hdf5 es muy lento (congelación de Python)

Estoy intentando guardar valores de cuello de botella en un archivo hdf5 recién creado. Los valores de cuello de botella vienen en lotes de forma (120,10,10, 2048) . Guardar un solo lote implica más de 16 conciertos y Python parece estar congelando en ese único lote. Según los hallazgos recientes (ver la actualización, parece que hdf5 es bueno, pero la parte de congelación parece ser una falla.

Solo bash guardar los primeros 2 lotes para fines de prueba y solo el conjunto de datos de entrenamiento (una vez más, esta es una prueba), pero ni siquiera puedo pasar el primer lote. Simplemente se detiene en el primer lote y no pasa a la siguiente iteración. Si bash comprobar el hdf5, el explorador se volverá lento y Python se congelará. Si trato de matar a Python (incluso sin verificar el archivo hdf5), Python no se cierra correctamente y obliga a reiniciar.

Aquí está el código y los datos relevantes:

Los puntos de datos totales son aproximadamente 90,000 ish, lanzados en lotes de 120.

 Bottleneck shape is (120,10,10,2048) 

Así que el primer lote que estoy tratando de guardar es (120,10,10,2048)

Aquí es cómo traté de guardar el conjunto de datos:

 with h5py.File(hdf5_path, mode='w') as hdf5: hdf5.create_dataset("train_bottle", train_shape, np.float32) hdf5.create_dataset("train_labels", (len(train.filenames), params['bottle_labels']),np.uint8) hdf5.create_dataset("validation_bottle", validation_shape, np.float32) hdf5.create_dataset("validation_labels", (len(valid.filenames),params['bottle_labels']),np.uint8) #this first part above works fine current_iteration = 0 print('created_datasets') for x, y in train: number_of_examples = len(train.filenames) # number of images prediction = model.predict(x) labels = y print(prediction.shape) # (120,10,10,2048) print(y.shape) # (120, 12) print('start',current_iteration*params['batch_size']) # 0 print('end',(current_iteration+1) * params['batch_size']) # 120 hdf5["train_bottle"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = prediction hdf5["train_labels"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = labels current_iteration += 1 print(current_iteration) if current_iteration == 3: break 

Esta es la salida de las declaraciones de impresión:

 (90827, 10, 10, 2048) # print(train_shape) (6831, 10, 10, 2048) # print(validation_shape) created_datasets (120, 10, 10, 2048) # print(prediction.shape) (120, 12) #label.shape start 0 #start of batch end 120 #end of batch # Just stalls here instead of printing `print(current_iteration)` 

Solo se detiene aquí por un tiempo (20 minutos o más), y el archivo hdf5 crece lentamente en tamaño (alrededor de 20 gigas ahora, antes de forzar la muerte). En realidad, ni siquiera puedo forzar la muerte con el administrador de tareas, tengo que reiniciar el sistema operativo para matar a Python en este caso.

Actualizar

Después de jugar un poco con mi código, parece que hay un error / comportamiento extraño.

La parte relevante está aquí:

  hdf5["train_bottle"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = prediction hdf5["train_labels"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = labels 

Si ejecuto cualquiera de estas líneas, mi script pasará por las iteraciones y se romperá automáticamente como se esperaba. Así que no hay congelación si corro o-o Sucede bastante rápido también, menos de un minuto.

Si ejecuto la primera línea ('train_bottle') , mi memoria está ocupando alrededor de 69-72 conciertos, incluso si son solo un par de lotes. Si bash más lotes, la memoria es la misma. Así que train_bottle decidió almacenamiento basado en los parámetros de tamaño que estoy asignando el conjunto de datos, y no en realidad cuando se llena. Entonces, a pesar de los 72 conciertos, se está ejecutando bastante rápido (un minuto).

Si ejecuto la segunda línea, train_labels , mi memoria ocupa unos pocos megabytes. No hay ningún problema con las iteraciones, y se ejecuta la instrucción break.

Sin embargo, ahora este es el problema: si bash ejecutar ambas líneas (lo que en mi caso es necesario, ya que necesito guardar tanto ‘train_bottle’ como ‘train_labels’), estoy experimentando un congelamiento en la primera iteración. No continúa a la segunda iteración, incluso después de 20 minutos. El archivo Hdf5 está creciendo lentamente, pero si bash acceder a él, el Explorador de Windows se vuelve lento y no puedo cerrar Python. Tengo que reiniciar el sistema operativo.

Así que no estoy seguro de cuál es el problema al intentar ejecutar ambas líneas, como si ejecutara la línea train_data hambrienta de memoria, si funciona perfectamente y termina en un minuto.

Escribir datos en HDF5

Si escribe en un conjunto de datos fragmentado sin especificar una forma de fragmento, h5py lo hará automáticamente por usted. Dado que h5py no puede saber cómo escribir o leer los datos del conjunto de datos, esto a menudo terminará en un mal rendimiento.

También usas el tamaño de caché predeterminado de 1 MB. Si solo escribe en una parte de un fragmento y el fragmento no cabe en el caché (que es muy probable que con un tamaño de caché de fragmento de 1MP), todo el fragmento se leerá en la memoria, se modificará y se volverá a escribir en el disco. Si eso sucede varias veces, verá un rendimiento que va mucho más allá de la velocidad de E / S secuencial de su HDD / SSD.

En el siguiente ejemplo, asumo que solo lee o escribe a lo largo de su primera dimensión. Si no, esto tiene que ser modificado a sus necesidades.

 import numpy as np import tables #register blosc import h5py as h5 import h5py_cache as h5c import time batch_size=120 train_shape=(90827, 10, 10, 2048) hdf5_path='Test.h5' # As we are writing whole chunks here this isn't realy needed, # if you forget to set a large enough chunk-cache-size when not writing or reading # whole chunks, the performance will be extremely bad. (chunks can only be read or written as a whole) f = h5c.File(hdf5_path, 'w',chunk_cache_mem_size=1024**2*200) #200 MB cache size dset_train_bottle = f.create_dataset("train_bottle", shape=train_shape,dtype=np.float32,chunks=(10, 10, 10, 2048),compression=32001,compression_opts=(0, 0, 0, 0, 9, 1, 1), shuffle=False) prediction=np.array(np.arange(120*10*10*2048),np.float32).reshape(120,10,10,2048) t1=time.time() #Testing with 2GB of data for i in range(20): #prediction=np.array(np.arange(120*10*10*2048),np.float32).reshape(120,10,10,2048) dset_train_bottle[i*batch_size:(i+1)*batch_size,:,:,:]=prediction f.close() print(time.time()-t1) print("MB/s: " + str(2000/(time.time()-t1))) 

Editar La creación de datos en el bucle tomó bastante tiempo, así que creo los datos antes de la medición del tiempo.

Esto debería proporcionar al menos 900 MB / s en grupo (CPU limitada). Con datos reales y menores relaciones de compresión, debería alcanzar fácilmente la velocidad de E / S secuencial de su disco duro.

Abrir un archivo HDF5 con la instrucción with también puede provocar un mal rendimiento si comete el error de llamar a este bloque varias veces. Esto cerraría y volvería a abrir el archivo, eliminando el caché de fragmentos.

Para determinar el tamaño correcto de trozo, también recomendaría: https://stackoverflow.com/a/48405220/4045774 https://stackoverflow.com/a/44961222/4045774

Si tiene suficiente memoria DDR y desea un rendimiento de carga y ahorro de datos extremadamente rápido, use np.load () & np.save () directamente. https://stackoverflow.com/a/49046312/2018567 np.load () & np.save () podría proporcionarle un rendimiento de carga y ahorro de datos más rápido, hasta ahora, no pude encontrar ninguna otra herramienta o marco que pudiera competir, incluso el rendimiento del HDF5 es solo 1/5 ~ 1/7.