Guardar en hdf5 es muy lento(congelación de Python)
numpy keras (3)
Esta respuesta es más como un comentario sobre el argumento entre @ max9111 y @Clock ZHONG. Escribí esto para ayudar a otras personas a preguntarse cuál es más rápido HDF5 o np.save ().
Utilicé el código proporcionado por @ max9111 y lo modifiqué según lo sugerido por @Clock ZHONG. El cuaderno exacto de jupyter se puede encontrar en https://github.com/wornbb/save_speed_test .
En resumen, con mi especificación:
- SSD: Samsung 960 EVO
- CPU: i7-7700K
- RAM: 2133 MHz 16 GB
- OS: Gana 10
HDF5 alcanza 1339.5 MB / s mientras que np.save es solo 924.9 MB / s (sin compresión).
Además, como señaló @Clock ZHONG, tuvo un problema con lzf -Filter. Si también tiene este problema, el cuaderno jupyter publicado se puede ejecutar con distribución conda de python3 con paquetes instalados pip en win 10.
Estoy tratando de guardar los valores de cuello de botella en un archivo hdf5 recién creado.
Los valores del cuello de botella vienen en lotes de forma
(120,10,10, 2048)
.
Guardar un solo lote está ocupando más de 16 conciertos y Python parece congelarse en ese único lote.
Según los hallazgos recientes (ver actualización, parece que hdf5 ocupando una gran memoria está bien, pero la parte de congelación parece ser un problema técnico.
Solo estoy tratando de guardar los primeros 2 lotes para fines de prueba y solo el conjunto de datos de entrenamiento (una vez más, esta es una ejecución de 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 trato de verificar 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)
Entonces, el primer lote que estoy tratando de guardar es
(120,10,10,2048)
Así es como intenté 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
Este es el resultado 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)`
Simplemente se detiene aquí por un tiempo (20 minutos +), y el archivo hdf5 crece lentamente en tamaño (alrededor de 20 conciertos 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 realmente matar a Python en este caso.
Actualizar
Después de jugar un poco con mi código, parece haber 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. Por lo tanto, no hay congelación si ejecuto uno u otro. También ocurre bastante rápido, menos de un minuto.
Si ejecuto la primera línea
(''train_bottle'')
, mi memoria está ocupando entre 69 y 72 conciertos, incluso si solo son un par de lotes.
Si intento más lotes, la memoria es la misma.
Por lo tanto, supongo que
train_bottle
decidió el almacenamiento en función de los parámetros de tamaño que estoy asignando al conjunto de datos, y no realmente cuando se llena.
Entonces, a pesar de los 72 conciertos, está funcionando 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 aquí está el problema, si intento ejecutar ambas líneas (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, y no continúa a la segunda iteración, incluso después de 20 minutos. El archivo Hdf5 crece lentamente, pero si intento acceder a él, el Explorador de Windows se ralentiza y no puedo cerrar Python: tengo que reiniciar el sistema operativo.
Así que no estoy seguro de cuál es el problema cuando intento ejecutar ambas líneas, como si ejecuto la línea
train_data
hambrienta de memoria, si funciona perfectamente y termina en un minuto.
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://.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 con él, Incluso el rendimiento de HDF5 es solo 1/5 ~ 1/7 de la misma.
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 desea escribir o leer los datos del conjunto de datos, esto a menudo terminará en un mal desempeño.
También utiliza el tamaño de caché de fragmentos predeterminado de 1 MB. Si solo escribe en una parte de un fragmento y el fragmento no cabe en la memoria caché (lo cual es muy probable con un tamaño de caché de fragmento de 1 MP), 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, supongo que solo lee o escribe a lo largo de su primera dimensión. Si no, esto tiene que modificarse según 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, por lo que creo los datos antes de la medición del tiempo.
Esto debería dar al menos 900 MB / s throuput (CPU limitada). Con datos reales y relaciones de compresión más bajas, debe alcanzar fácilmente la velocidad de E / S secuencial de su disco duro.
Abrir un archivo HDF5 con la declaración with también puede conducir a 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 de fragmento correcto, también recomendaría: https://.com/a/48405220/4045774 https://.com/a/44961222/4045774