No se puede asignar una matriz con forma y tipo de datos
Tengo un problema al asignar matrices enormes en numpy en Ubuntu 18, mientras que no tengo el mismo problema en MacOS.
Estoy intentando asignar memoria para una matriz numerosa con forma (156816, 36, 53806)
con
np.zeros((156816, 36, 53806), dtype='uint8')
y mientras recibo un error en el sistema operativo Ubuntu
>>> import numpy as np
>>> np.zeros((156816, 36, 53806), dtype='uint8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
numpy.core._exceptions.MemoryError: Unable to allocate array with shape (156816, 36, 53806) and data type uint8
No lo obtengo en MacOS:
>>> import numpy as np
>>> np.zeros((156816, 36, 53806), dtype='uint8')
array([[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],
[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],
[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],
...,
[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],
[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],
[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]]], dtype=uint8)
Leí en alguna parte que np.zeros
en realidad no debería asignarse toda la memoria necesaria para la matriz, sino solo para los elementos distintos de cero. Aunque la máquina Ubuntu tiene 64 GB de memoria, mientras que mi MacBook Pro solo tiene 16 GB.
versiones:
Ubuntu
os -> ubuntu mate 18
python -> 3.6.8
numpy -> 1.17.0
mac
os -> 10.14.6
python -> 3.6.4
numpy -> 1.17.0
PD: también falló en Google Colab
Es probable que esto se deba al modo de manejo de compromiso excesivo de su sistema .
En el modo predeterminado, 0
,
Manejo heurístico de sobrecompromiso. Se rechazan los compromisos excesivos obvios del espacio de direcciones. Utilizado para un sistema típico. Garantiza que una asignación grave falle y al mismo tiempo permite un compromiso excesivo para reducir el uso de swap. La raíz puede asignar un poco más de memoria en este modo. Este es el valor predeterminado.
La heurística exacta utilizada no se explica bien aquí, pero se analiza más en Linux sobre la heurística de confirmación y en esta página .
Puede verificar su modo de sobrecompromiso actual ejecutando
$ cat /proc/sys/vm/overcommit_memory
0
En este caso, estás asignando
>>> 156816 * 36 * 53806 / 1024.0**3
282.8939827680588
~ 282 GB y el kernel dice: bueno, obviamente no hay manera de que pueda asignar tantas páginas físicas a esto, y rechaza la asignación.
Si (como root) ejecutas:
$ echo 1 > /proc/sys/vm/overcommit_memory
Esto habilitará el modo "siempre sobrecompromiso" y descubrirá que, de hecho, el sistema le permitirá realizar la asignación sin importar cuán grande sea (al menos dentro del direccionamiento de memoria de 64 bits).
Lo probé yo mismo en una máquina con 32 GB de RAM. Con el modo de sobrecompromiso 0
también obtuve un MemoryError
, pero después de cambiarlo nuevamente 1
funciona:
>>> import numpy as np
>>> a = np.zeros((156816, 36, 53806), dtype='uint8')
>>> a.nbytes
303755101056
Luego puede continuar y escribir en cualquier ubicación dentro de la matriz, y el sistema solo asignará páginas físicas cuando escriba explícitamente en esa página. Entonces puedes usar esto, con cuidado, para arreglos dispersos.
Tuve el mismo problema en Windows y encontré esta solución. Entonces, si alguien se encuentra con este problema en Windows, la solución para mí fue aumentar el tamaño del archivo de paginación , ya que para mí también era un problema de compromiso excesivo de memoria.
ventana 8
- En el teclado Presione la tecla Windows + X y luego haga clic en Sistema en el menú emergente
- Toque o haga clic en Configuración avanzada del sistema. Es posible que se le solicite una contraseña de administrador o que confirme su elección.
- En la pestaña Avanzado, en Rendimiento, toque o haga clic en Configuración.
- Toque o haga clic en la pestaña Avanzado y luego, en Memoria virtual, toque o haga clic en Cambiar
- Desactive la casilla de verificación Administrar automáticamente el tamaño del archivo de paginación para todas las unidades.
- En Unidad [Etiqueta de volumen], toque o haga clic en la unidad que contiene el archivo de paginación que desea cambiar.
- Toque o haga clic en Tamaño personalizado, ingrese un nuevo tamaño en megabytes en el cuadro Tamaño inicial (MB) o Tamaño máximo (MB), toque o haga clic en Establecer y luego toque o haga clic en Aceptar.
- Reinicie su sistema
ventanas 10
- Presione la tecla de Windows
- Tipo Propiedades del sistema Avanzado
- Haga clic en Ejecutar como administrador
- En Rendimiento, haga clic en Configuración
- Seleccione la pestaña Avanzado
- Seleccione Cambiar...
- Desmarque Administrar automáticamente el tamaño del archivo de paginación para todas las unidades
- Luego seleccione Tamaño personalizado y complete el tamaño apropiado
- Presione Establecer, luego presione Aceptar y luego salga del cuadro de diálogo Memoria virtual, Opciones de rendimiento y Propiedades del sistema.
- Reinicie su sistema
Nota: No tenía suficiente memoria en mi sistema para los ~282 GB de este ejemplo, pero en mi caso particular funcionó.
EDITAR
Desde aquí las recomendaciones sugeridas para el tamaño del archivo de página:
Existe una fórmula para calcular el tamaño correcto del archivo de paginación. El tamaño inicial es uno y medio (1,5) x la cantidad de memoria total del sistema. El tamaño máximo es tres (3) x el tamaño inicial. Entonces digamos que tienes 4 GB (1 GB = 1024 MB x 4 = 4096 MB) de memoria. El tamaño inicial sería 1,5 x 4.096 = 6.144 MB y el tamaño máximo sería 3 x 6.144 = 18.432 MB.
Algunas cosas a tener en cuenta desde aquí :
Sin embargo, esto no tiene en cuenta otros factores importantes ni configuraciones del sistema que pueden ser exclusivos de su computadora. Nuevamente, deje que Windows elija qué usar en lugar de confiar en alguna fórmula arbitraria que funcionó en una computadora diferente.
También:
Aumentar el tamaño del archivo de página puede ayudar a prevenir inestabilidades y fallas en Windows. Sin embargo, los tiempos de lectura/escritura de un disco duro son mucho más lentos de lo que serían si los datos estuvieran en la memoria de su computadora. Tener un archivo de paginación más grande agregará trabajo adicional a su disco duro, lo que hará que todo lo demás funcione más lento. El tamaño del archivo de página sólo debe aumentarse cuando se produzcan errores de falta de memoria y sólo como solución temporal. Una mejor solución es agregar más memoria a la computadora.
También encontré este problema en Windows. La solución para mí fue cambiar de una versión de Python de 32 bits a una de 64 bits . De hecho, un software de 32 bits, como una CPU de 32 bits, puede gestionar un máximo de 4 GB de RAM (2^32). Por lo que si tienes más de 4 GB de RAM, una versión de 32 bits no podrá aprovecharla.
Con una versión de Python de 64 bits (la que está etiquetada como x86-64 en la página de descarga), el problema desaparece.
Puedes comprobar qué versión tienes ingresando al intérprete. Yo, con una versión de 64 bits, ahora tengo:
Python 3.7.5rc1 (tags/v3.7.5rc1:4082f600a5, Oct 1 2019, 20:28:14) [MSC v.1916 64 bit (AMD64)]
, donde [MSC v.1916 64 bit (AMD64)] significa "Python de 64 bits".
Fuentes:
Quora: error de memoria generado por una gran matriz numerosa
Stackoverflow: versión de Python de 32 o 64 bits
En mi caso, agregar un atributo dtype cambió el tipo d de la matriz a un tipo más pequeño (de float64 a uint8), disminuyendo el tamaño de la matriz lo suficiente como para no generar MemoryError en Windows (64 bits).
de
mask = np.zeros(edges.shape)
a
mask = np.zeros(edges.shape,dtype='uint8')