No se puede asignar una matriz con forma y tipo de datos

103

Estoy enfrentando un problema con la asignación de matrices enormes en numpy en Ubuntu 18 mientras no enfrento el mismo problema en MacOS.

Estoy tratando de asignar memoria para una matriz numpy 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 algún lugar que np.zerosno debería estar asignando 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

Martin Brisiak
fuente
1
¿Hay otros procesos ejecutándose en la memoria?
BlueRine S
no, lo intenté topy free -m, esos comandos donde empujar
60 gb
hmmm. extraño. Eso no debería tomar tanta memoria. ¿Cuánta memoria ocupaba en Macos?
BlueRine S
1
Es poco probable, pero no estás ejecutando un intérprete de Python de 32 bits en Ubuntu, ¿verdad?
jdehesa
1
np.zerosno crea una sparsematriz. Tal vez haya un retraso en completar los ceros. Pero vea stackoverflow.com/q/27464039
hpaulj

Respuestas:

106

Esto probablemente se deba al modo de manejo de sobreasignación de su sistema .

En el modo predeterminado 0,

Manejo heurístico de sobrecompromiso. Se rechazan los compromisos excesivos obvios de espacio de direcciones. Usado para un sistema típico. Asegura que una asignación gravemente salvaje falle al tiempo que permite un compromiso excesivo para reducir el uso de intercambio. root puede asignar un poco más de memoria en este modo. Este es el predeterminado.

La heurística exacta utilizada no se explica bien aquí, pero esto se discute más en Linux sobre la heurística de confirmación y en esta página .

Puede comprobar su modo de sobreasignación 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 que, obviamente, no hay forma de que pueda comprometer tantas páginas físicas en esto, y rechaza la asignación.

Si (como root) ejecuta:

$ echo 1 > /proc/sys/vm/overcommit_memory

Esto habilitará el modo "siempre sobreasignar" y encontrará 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 overcommit 0también obtuve un MemoryError, pero después de volver a cambiarlo 1funciona:

>>> 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. Por lo tanto, puede usar esto, con cuidado, para matrices dispersas.

Iguananaut
fuente
2
Esta es específicamente una característica del kernel de Linux, por lo que no necesariamente hay un equivalente directo en MacOS, aunque posiblemente algo similar. No creo que sea tan fácil en Mac manipular la configuración del kernel.
Iguananaut
1
@Iguananaut ¿cuál es el significado exacto de la advertencia "con cuidado"? es decir. ¿Cuál es el peor de los casos de que algo salga mal con esto en un servidor Ubuntu 18 con GPU GTX 1080?
mLstudent33
1
@ mLstudent33 Por un lado, esto no tiene nada que ver con su GPU, que tiene su propia memoria. Todo lo que quiero decir es que aún puede llenar su memoria: cada vez que escribe en alguna página en la memoria, esa página (generalmente 4k bytes) debe estar comprometida con la memoria física. Entonces, el peor de los casos es que te quedes sin memoria.
Iguananaut
1
¿Este cambio entra en vigor inmediatamente o necesitamos reiniciar nuestro shell o la propia máquina?
dumbledad
2
Tiene efecto inmediato, pero no persistirá más allá del reinicio sin medidas adicionales. Busque otras preguntas sobre la mejor manera de conservar la /proc/sysconfiguración en su distribución.
Iguananaut
44

Tuve este 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 también era un problema de sobreasignación de memoria para mí.

Windows 8

  1. En el teclado, presione la tecla de Windows + X y luego haga clic en Sistema en el menú emergente
  2. 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
  3. En la pestaña Avanzado, en Rendimiento, toque o haga clic en Configuración.
  4. Toque o haga clic en la pestaña Avanzado y luego, en Memoria virtual, toque o haga clic en Cambiar
  5. Desactive la casilla de verificación Administrar automáticamente el tamaño del archivo de paginación para todas las unidades.
  6. En Unidad [Etiqueta de volumen], toque o haga clic en la unidad que contiene el archivo de paginación que desea cambiar.
  7. Toque o haga clic en Tamaño personalizado, ingrese un nuevo tamaño en megabytes en el cuadro de tamaño inicial (MB) o Tamaño máximo (MB), toque o haga clic en Establecer, y luego toque o haga clic en Aceptar
  8. Reinicie su sistema

Windows 10

  1. Presione la tecla de Windows
  2. Tipo SystemPropertiesAdvanced
  3. Haga clic en Ejecutar como administrador
  4. Haga clic en Configuración
  5. Seleccione la pestaña Avanzado
  6. Seleccione Cambiar ...
  7. Desmarque Administrar automáticamente el tamaño del archivo de paginación para todas las unidades
  8. Luego seleccione Tamaño personalizado y complete el tamaño apropiado
  9. Presione Establecer, luego presione OK y luego salga del cuadro de diálogo Memoria virtual, Opciones de rendimiento y Propiedades del sistema
  10. Reinicie su sistema

Nota: No tenía suficiente memoria en mi sistema para los ~ 282GB en este ejemplo, pero para mi caso particular esto funcionó.

EDITAR

A partir de 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. Digamos que tiene 4 GB (1 GB = 1024 MB x 4 = 4096 MB) de memoria. El tamaño inicial sería 1,5 x 4096 = 6144 MB y el tamaño máximo sería 3 x 6144 = 18432 MB.

Algunas cosas a tener en cuenta a partir de aquí :

Sin embargo, esto no tiene en cuenta otros factores importantes y configuraciones del sistema que pueden ser exclusivas 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:

El aumento del 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 página más grande agregará trabajo adicional para su disco duro, haciendo que todo lo demás funcione más lento. El tamaño del archivo de página solo debe aumentarse cuando se encuentren errores de memoria insuficiente y solo como una solución temporal. Una mejor solución es agregar más memoria a la computadora.

recurrente hasta
fuente
¿Qué configuración de tamaño personalizado (tamaño inicial + tamaño máximo) tiene ahora? No estoy seguro de cuánto
asignarme
1
@Azizbro He vuelto al valor predeterminado ahora, pero solo ajusté los valores hasta que desapareció el error de memoria insuficiente.
recurrente hasta el
23

También encontré este problema en Windows. La solución para mí fue cambiar de una versión de 32 bits a una de 64 bits de Python . De hecho, un software de 32 bits, como una CPU de 32 bits, puede utilizar un máximo de 4 GB de RAM (2 ^ 32). Entonces, si tiene más de 4 GB de RAM, una versión de 32 bits no puede aprovecharlo.

Con una versión de Python de 64 bits (la etiquetada x86-64 en la página de descarga), el problema desapareció.

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 bits (AMD64)] significa "Python de 64 bits".

Nota : en el momento de escribir este artículo (mayo de 2020), matplotlib no está disponible en python39, por lo que recomiendo instalar python37, 64 bits.

Fuentes:

Kotchwane
fuente
gracias. Con la última versión estable de Python de 64 bits (3.8.3) también puedo instalar matplotlib.
Federico Tomasi
1
¿Cómo ingreso intérprete?
Shayan
También resolvió mi problema. Usando Pycharm. Versión de 32 bits desinstalada, reinstalada de 64 bits, intérprete de proyecto cambiado a la nueva Python de 64 bits.
Jason Goal
3

En mi caso, agregar un atributo dtype cambió dtype 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 lanzar MemoryError en Windows (64 bits).

desde

mask = np.zeros(edges.shape)

a

mask = np.zeros(edges.shape,dtype='uint8')
Pragya Agrawal
fuente
2

A veces, este error aparece porque el kernel ha alcanzado su límite. Intente reiniciar el kernel y vuelva a realizar los pasos necesarios.

Antonio Moreno Martín
fuente
4
Consulte: stackoverflow.com/help/how-to-answer Buen intento.
Kishan Mehta
1

cambiar el tipo de datos a otro que utilice menos memoria funciona. Para mí, cambio el tipo de datos a numpy.uint8:

data['label'] = data['label'].astype(np.uint8)
Mingming Qiu
fuente