6.5. Hình dạng và stride¶
Dữ liệu bên trong một ndarray là một khối số đóng gói liên tục. Bộ mô tả phía trước khối đó quyết định cách đọc khối phẳng đó dưới dạng tensor.
6.5.1. Những gì bộ mô tả lưu trữ¶
Năm giá trị mô tả cách đọc khối dữ liệu dưới dạng tensor:
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint8)
a.ndim # 2 - number of dimensions
a.shape # (2, 3)- length along each dimension
a.itemsize # 1 - bytes per element (from dtype)
a.size # 6 - total number of elements
a.strides # (3, 1)- step pattern through the buffer
Hàm trợ giúp ndinfo() in tất cả chúng cùng với vị trí của bộ đệm nền trong một lần gọi. Hai mảng có cùng vị trí bộ đệm đang chia sẻ bộ nhớ:
np.ndinfo(a)
# class: ndarray
# shape: (2, 3)
# strides: (3, 1)
# itemsize: 1
# data pointer: 0x...
# type: uint8
6.5.2. Giải thích stride¶
Một stride là số byte cần bước trong khối dữ liệu để di chuyển một phần tử dọc theo một trục nhất định. Với mảng uint8 2x3 ở trên, các stride là (3, 1): di chuyển xuống một hàng nhảy 3 byte, di chuyển sang phải một cột nhảy 1 byte. Điều đó tương đương với việc các hàng được lưu trữ liên tiếp nhau, từ trái sang phải:
memory: [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ]
^ row 0 ^ row 1
<------- 3 bytes ---->
Để đọc a[i, j], numpy tính i * strides[0] + j * strides[1] từ đầu khối dữ liệu và đọc itemsize byte từ đó. Công thức tương tự mở rộng sang bất kỳ số chiều nào.
Bố cục này -- các hàng được lưu trữ liên tiếp, với trục cuối thay đổi nhanh nhất theo bộ nhớ -- được gọi là thứ tự row-major. Mọi mảng numpy cấp phát trên camera đều dùng bố cục này.
6.5.3. Row-major có những hệ quả¶
Hai điều xuất phát từ "các hàng được lưu trữ liên tiếp" quan trọng khi định hình bộ đệm trên camera.
Trục cuối là liên tục. Đi từ a[0, 0] đến a[0, 1] chạm vào byte tiếp theo. Đi từ a[0, 0] đến a[1, 0] nhảy qua cả một hàng.
Trục cuối là trục nhanh cho phép toán trên toàn mảng. numpy trên camera luôn duyệt trục cuối trong cùng, bất kể trục nào dài hơn. Thư viện numpy trên máy tính để bàn lặng lẽ sắp xếp lại vòng lặp để đặt trục dài nhất vào trong cùng; camera không làm vậy, vì vậy một lựa chọn bố cục mà numpy trên máy tính để bàn sẽ bỏ qua vẫn tốn thời gian ở đây. np.sum(m, axis=1) thu gọn trục cuối và chạy theo hướng liên tục; np.sum(m, axis=0) thì không. Khi ứng dụng có lựa chọn về cách bố trí bộ đệm, hãy đặt trục dài ở cuối để các thao tác dọc theo nó nằm trong vòng lặp trong.
Nếu bố cục ban đầu không đúng, transpose() (hoặc phím tắt .T) sẽ sửa mà không cần sao chép dữ liệu -- nó chỉ đổi chỗ các stride:
a = b.T # now iterates fast
Hiệu năng có thảo luận hiệu năng đầy đủ.
6.5.4. Reshape, transpose, slicing -- chỉnh sửa bộ mô tả¶
Mọi thao tác chỉ ghi lại bộ mô tả đều miễn phí. reshape hoán đổi shape và strides mới trên cùng một khối dữ liệu. transpose đảo ngược các stride. a[::2] nhân đôi một stride. Mỗi cái trả về một view của cùng bộ đệm nền.
Bất cứ điều gì phải duyệt dữ liệu và ghi một bộ đệm mới đều là bản sao. Quy tắc hiện tại là chỉnh sửa bộ mô tả miễn phí còn duyệt dữ liệu thì không.
6.5.5. Ghi chú về ndim¶
numpy trên camera được xây dựng với ndim được hỗ trợ tối đa là 4. Các thao tác tạo ra mảng bậc cao hơn sẽ phát sinh ValueError. Phần lớn công việc phía camera là 1-D hoặc 2-D, vì vậy giới hạn này hiếm khi là vấn đề.