Không thể phân bổ mảng có hình dạng và kiểu dữ liệu


105

Tôi đang gặp phải sự cố phân bổ các mảng lớn trong numpy trên Ubuntu 18 trong khi không gặp phải vấn đề tương tự trên MacOS.

Tôi đang cố gắng cấp phát bộ nhớ cho một mảng numpy có hình dạng (156816, 36, 53806) với

np.zeros((156816, 36, 53806), dtype='uint8')

và trong khi tôi gặp lỗi trên Hệ điều hành 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

Tôi không nhận được nó trên 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)

Tôi đã đọc ở đâu đó rằng np.zeroskhông nên thực sự cấp phát toàn bộ bộ nhớ cần thiết cho mảng, mà chỉ cho các phần tử khác 0. Mặc dù máy Ubuntu có bộ nhớ 64gb, trong khi MacBook Pro của tôi chỉ có 16gb.

phiên bản:

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

Tái bút: cũng không thành công trên Google Colab


1
Có các quy trình khác đang chạy trong bộ nhớ không?
BlueRine S

nope, tôi đã cố gắng topfree -m, những lệnh mà xô đẩy 60GB của mem miễn phí và nhiều hơn nữa
Martin Brisiak

hmmm. kỳ dị. Điều đó sẽ không chiếm nhiều bộ nhớ. Nó đã chiếm bao nhiêu bộ nhớ trên Macos?
BlueRine S

1
Không có khả năng, nhưng bạn không tình cờ chạy trình thông dịch Python 32 bit trong Ubuntu phải không?
jdehesa

1
np.zeroskhông tạo sparsema trận. Có thể có sự chậm trễ trong việc điền vào các số không. Nhưng hãy xem stackoverflow.com/q/27464039
hpaulj

Câu trả lời:


108

Điều này có thể là do chế độ xử lý quá tải của hệ thống của bạn .

Ở chế độ mặc định 0,

Xử lý thừa số Heuristic. Không gian địa chỉ thừa rõ ràng bị từ chối. Được sử dụng cho một hệ thống điển hình. Nó đảm bảo phân bổ hoang dã nghiêm trọng không thành công trong khi cho phép gửi thừa để giảm sử dụng hoán đổi. root được phép cấp phát nhiều bộ nhớ hơn một chút trong chế độ này. Đây là mặc định.

Heuristic chính xác được sử dụng không được giải thích rõ ràng ở đây, nhưng điều này được thảo luận nhiều hơn trên Linux trên commit heuristictrên trang này .

Bạn có thể kiểm tra chế độ gửi quá mức hiện tại của mình bằng cách chạy

$ cat /proc/sys/vm/overcommit_memory
0

Trong trường hợp này, bạn đang phân bổ

>>> 156816 * 36 * 53806 / 1024.0**3
282.8939827680588

~ 282 GB và hạt nhân đang nói tốt rõ ràng là không có cách nào tôi có thể cam kết nhiều trang vật lý cho điều này và nó từ chối phân bổ.

Nếu (dưới dạng root) bạn chạy:

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

Điều này sẽ kích hoạt chế độ "luôn gửi quá mức" và bạn sẽ thấy rằng thực sự hệ thống sẽ cho phép bạn thực hiện phân bổ bất kể nó lớn đến mức nào (ít nhất là trong phạm vi bộ nhớ 64 bit).

Tôi đã tự mình thử nghiệm điều này trên máy có RAM 32 GB. Với chế độ overcommit, 0tôi cũng nhận được MemoryError, nhưng sau khi thay đổi nó trở lại 1nó hoạt động:

>>> import numpy as np
>>> a = np.zeros((156816, 36, 53806), dtype='uint8')
>>> a.nbytes
303755101056

Sau đó, bạn có thể tiếp tục và ghi vào bất kỳ vị trí nào trong mảng và hệ thống sẽ chỉ cấp phát các trang vật lý khi bạn ghi rõ ràng vào trang đó. Vì vậy, bạn có thể sử dụng nó, cẩn thận, cho các mảng thưa thớt.


2
Đây đặc biệt là một tính năng của hạt nhân Linux nên chắc chắn không có một tính năng tương đương trực tiếp nào trên MacOS, mặc dù có thể là một cái gì đó tương tự. Tôi không nghĩ rằng việc cài đặt kernel dễ dàng như trên máy Mac.
Iguananaut

1
@Iguananaut Ý nghĩa chính xác của cảnh báo "cẩn thận" là gì? I E. Trường hợp xấu nhất xảy ra sự cố với máy chủ Ubuntu 18 với GPU GTX 1080 là gì?
mLstudent33

1
@ mLstudent33 Đầu tiên, điều này không liên quan gì đến GPU của bạn, GPU có bộ nhớ riêng. Tất cả những gì tôi muốn nói là bạn vẫn có thể lấp đầy bộ nhớ của mình - mỗi khi bạn ghi vào một trang nào đó trong bộ nhớ trang đó (thường là 4k byte) phải được chuyển vào bộ nhớ vật lý. Vì vậy, trường hợp xấu nhất là bạn hết bộ nhớ.
Iguananaut

1
Thay đổi này có hiệu lực ngay lập tức hay chúng ta cần khởi động lại vỏ của chúng ta hoặc chính máy?
câm

2
Nó có hiệu lực ngay lập tức, nhưng nó sẽ không kéo dài sau khi khởi động lại mà không có các biện pháp bổ sung. Tìm kiếm các câu hỏi khác về cách tốt nhất để duy trì /proc/syscài đặt trên bản phân phối của bạn.
Iguananaut

45

Tôi đã gặp vấn đề tương tự trên Window's và tìm thấy giải pháp này. Vì vậy, nếu một người nào đó đi qua vấn đề này trong Windows giải pháp đối với tôi là để tăng pagefile kích thước, vì nó là một vấn đề Memory overcommitment cho tôi quá.

Windows 8

  1. Trên bàn phím Nhấn WindowsKey + X rồi nhấp vào Hệ thống trong menu bật lên
  2. Nhấn hoặc nhấp vào Cài đặt hệ thống nâng cao. Bạn có thể được yêu cầu nhập mật khẩu quản trị viên hoặc xác nhận lựa chọn của mình
  3. Trên tab Nâng cao, dưới Hiệu suất, chạm hoặc bấm Cài đặt.
  4. Chạm hoặc bấm vào tab Nâng cao, sau đó, trong Bộ nhớ ảo, hãy chạm hoặc bấm Thay đổi
  5. Bỏ chọn hộp kiểm Tự động quản lý kích thước tệp hoán trang cho tất cả các ổ đĩa.
  6. Trong Drive [Nhãn ổ đĩa], hãy nhấn hoặc nhấp vào ổ đĩa chứa tệp hoán trang bạn muốn thay đổi
  7. Chạm hoặc bấm Kích thước tùy chỉnh, nhập kích thước mới tính bằng megabyte vào hộp Kích thước ban đầu (MB) hoặc Kích thước tối đa (MB), chạm hoặc bấm Đặt, sau đó chạm hoặc bấm OK
  8. Khởi động lại hệ thống của bạn

Windows 10

  1. Nhấn phím Windows
  2. Loại Hệ thốngPropertiesAdvanced
  3. Nhấp vào Chạy với tư cách quản trị viên
  4. Nhấp vào Cài đặt
  5. Chọn tab Nâng cao
  6. Chọn Thay đổi ...
  7. Bỏ chọn Tự động quản lý kích thước tệp hoán trang cho tất cả các ổ đĩa
  8. Sau đó chọn Kích thước tùy chỉnh và điền kích thước phù hợp
  9. Nhấn Đặt rồi nhấn OK rồi thoát khỏi Hộp thoại Bộ nhớ Ảo, Tùy chọn Hiệu suất và Thuộc tính Hệ thống
  10. Khởi động lại hệ thống của bạn

Lưu ý: Tôi không có đủ bộ nhớ trên hệ thống cho ~ 282GB trong ví dụ này nhưng đối với trường hợp cụ thể của tôi, điều này đã hoạt động.

BIÊN TẬP

Từ đây, các đề xuất được đề xuất cho kích thước tệp trang:

Có một công thức để tính toán kích thước tệp trang chính xác. Kích thước ban đầu là 1,5 (1,5) x tổng bộ nhớ hệ thống. Kích thước tối đa là ba (3) x kích thước ban đầu. Vì vậy, giả sử bạn có 4 GB (1 GB = 1,024 MB x 4 = 4,096 MB) bộ nhớ. Kích thước ban đầu sẽ là 1,5 x 4,096 = 6,144 MB và kích thước tối đa sẽ là 3 x 6,144 = 18,432 MB.

Một số điều cần ghi nhớ từ đây :

Tuy nhiên, điều này không tính đến các yếu tố quan trọng khác và cài đặt hệ thống có thể là duy nhất cho máy tính của bạn. Một lần nữa, hãy để Windows chọn những gì để sử dụng thay vì dựa vào một số công thức tùy ý hoạt động trên một máy tính khác.

Cũng thế:

Tăng kích thước tệp trang có thể giúp ngăn chặn sự cố và sự cố trong Windows. Tuy nhiên, thời gian đọc / ghi ổ cứng chậm hơn nhiều so với thời gian nếu dữ liệu nằm trong bộ nhớ máy tính của bạn. Có một tệp trang lớn hơn sẽ làm tăng thêm công việc cho ổ cứng của bạn, khiến mọi thứ khác chạy chậm hơn. Kích thước tệp trang chỉ nên được tăng lên khi gặp lỗi hết bộ nhớ và chỉ là một cách khắc phục tạm thời. Một giải pháp tốt hơn là bổ sung thêm bộ nhớ cho máy tính.


Bạn có cài đặt kích thước tùy chỉnh nào (kích thước ban đầu + kích thước tối đa) ngay bây giờ? Không chắc phải phân bổ bao nhiêu cho bản thân
Azizbro

1
@Azizbro Bây giờ tôi đã quay lại mặc định nhưng chỉ điều chỉnh các giá trị cho đến khi lỗi hết bộ nhớ biến mất.
đệ quy cho đến

23

Tôi cũng gặp sự cố này trên Windows. Giải pháp cho tôi là chuyển từ phiên bản Python 32 bit sang 64 bit . Thật vậy, một phần mềm 32-bit, giống như một CPU 32-bit, có thể đáp ứng tối đa 4 GB RAM (2 ^ 32). Vì vậy, nếu bạn có nhiều hơn 4 GB RAM, phiên bản 32-bit không thể tận dụng lợi thế của nó.

Với phiên bản Python 64 bit (phiên bản có nhãn x86-64 trong trang tải xuống), sự cố đã biến mất.

Bạn có thể kiểm tra phiên bản mình có bằng cách nhập trình thông dịch. Tôi, với phiên bản 64 bit, hiện có : Python 3.7.5rc1 (tags/v3.7.5rc1:4082f600a5, Oct 1 2019, 20:28:14) [MSC v.1916 64 bit (AMD64)], trong đó [MSC v.1916 64 bit (AMD64)] có nghĩa là "Python 64 bit".

Lưu ý : tính đến thời điểm viết bài này (tháng 5 năm 2020), matplotlib không có sẵn trên python39, vì vậy tôi khuyên bạn nên cài đặt python37, 64 bit.

Nguồn:


cảm ơn bạn. Với phiên bản Python 64-bit ổn định cuối cùng (3.8.3), tôi cũng có thể cài đặt matplotlib.
Federico Tomasi

1
Làm cách nào để nhập thông dịch viên?
Shayan

Đã giải quyết vấn đề của tôi quá. Sử dụng Pycharm. Đã gỡ cài đặt phiên bản 32-bit, cài đặt lại phiên bản 64-bit, thay đổi trình thông dịch dự án thành python 64-bit mới.
Mục tiêu của Jason vào

3

Trong trường hợp của tôi, việc thêm một thuộc tính dtype đã thay đổi loại dtype của mảng thành một loại nhỏ hơn (từ float64 thành uint8), giảm kích thước mảng đủ để không ném MemoryError trong Windows (64 bit).

từ

mask = np.zeros(edges.shape)

đến

mask = np.zeros(edges.shape,dtype='uint8')


1

thay đổi kiểu dữ liệu sang kiểu khác sử dụng ít bộ nhớ hơn. Đối với tôi, tôi thay đổi kiểu dữ liệu thành numpy.uint8:

data['label'] = data['label'].astype(np.uint8)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.