6.5. 형태(shape)와 스트라이드(strides)¶
ndarray 내부의 데이터는 패킹된 하나의 숫자 블록입니다. 그 블록 앞의 디스크립터가 이 평탄한 블록을 어떻게 텐서로 읽어낼지 결정합니다.
6.5.1. 디스크립터가 기록하는 것¶
다섯 개의 값이 데이터 블록을 텐서로 읽는 방법을 기술합니다:
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
ndinfo() 헬퍼는 이 모두에 더해 기저 버퍼의 위치까지 한 번의 호출로 출력합니다. 버퍼 위치가 일치하는 두 배열은 메모리를 공유하고 있는 것입니다:
np.ndinfo(a)
# class: ndarray
# shape: (2, 3)
# strides: (3, 1)
# itemsize: 1
# data pointer: 0x...
# type: uint8
6.5.2. 스트라이드 설명¶
스트라이드는 주어진 축을 따라 한 요소 이동하기 위해 데이터 블록에서 몇 바이트를 건너뛸지를 나타냅니다. 위의 2x3 uint8 배열의 경우 스트라이드는 (3, 1)입니다: 한 행 아래로 이동하면 3바이트를 건너뛰고, 한 열 오른쪽으로 이동하면 1바이트를 건너뜁니다. 이는 행들이 왼쪽에서 오른쪽으로 연이어 저장되어 있다는 말과 같습니다:
memory: [ 1 ][ 2 ][ 3 ][ 4 ][ 5 ][ 6 ]
^ row 0 ^ row 1
<------- 3 bytes ---->
a[i, j]를 읽기 위해 numpy는 데이터 블록의 시작점으로부터 i * strides[0] + j * strides[1]을 계산하고 그곳에서 itemsize 바이트를 읽습니다. 같은 공식이 임의의 차원 수로 확장됩니다.
이 레이아웃 – 행들이 끝과 끝으로 이어 저장되며 마지막 축이 메모리를 따라 가장 빠르게 변하는 방식 – 을 행 우선(row-major) 순서라고 합니다. 카메라에서 numpy가 할당하는 모든 배열이 이 레이아웃을 사용합니다.
6.5.3. 행 우선에는 결과가 따릅니다¶
“행들이 연이어 저장됨”에서 두 가지가 도출되며, 이는 카메라에서 버퍼의 형태를 잡을 때 중요합니다.
마지막 축은 연속적입니다. a[0, 0]에서 a[0, 1]로 이동하면 바로 다음 바이트에 접근합니다. a[0, 0]에서 a[1, 0]으로 이동하면 행 전체를 건너뜁니다.
마지막 축은 전체 배열 연산에서 빠른 축입니다. 카메라의 numpy는 어느 축이 더 긴지에 관계없이 항상 마지막 축을 가장 안쪽에서 순회합니다. 데스크톱 numpy 라이브러리는 가장 긴 축을 가장 안쪽에 두도록 루프를 조용히 재정렬하지만, 카메라는 그렇지 않으므로 데스크톱 numpy라면 묻혀버렸을 레이아웃 선택이 여기서는 여전히 시간 비용이 듭니다. np.sum(m, axis=1)은 마지막 축을 축소하며 연속적인 방향으로 실행됩니다. np.sum(m, axis=0)은 그렇지 않습니다. 애플리케이션이 버퍼를 어떻게 배치할지 선택할 수 있을 때는, 긴 축을 따라가는 연산이 안쪽 루프에 머물도록 긴 축을 마지막에 두십시오.
레이아웃이 처음부터 잘못되어 있다면 transpose()(또는 .T 단축형)가 데이터를 복사하지 않고 이를 바로잡습니다 – 단지 스트라이드를 교환할 뿐입니다:
a = b.T # now iterates fast
성능에 전체 성능 논의가 있습니다.
6.5.4. Reshape, transpose, 슬라이싱 – 디스크립터 편집¶
디스크립터만 다시 쓰는 연산은 비용이 없습니다. reshape는 동일한 데이터 블록에 대해 새로운 shape과 strides를 교환합니다. transpose는 스트라이드를 뒤집습니다. a[::2]는 스트라이드를 두 배로 만듭니다. 각각은 동일한 기저 버퍼의 뷰를 반환합니다.
데이터를 순회하며 새 버퍼를 기록해야 하는 모든 것은 복사입니다. 지금의 규칙은 디스크립터 편집은 비용이 없고 데이터 순회는 그렇지 않다는 것입니다.
6.5.5. ndim에 관한 참고 사항¶
카메라의 numpy는 지원되는 최대 ndim이 4로 빌드되어 있습니다. 더 높은 차원의 배열을 생성하려는 연산은 ValueError를 발생시킵니다. 카메라 측 작업의 대다수는 1차원이나 2차원이므로 이 제한이 문제가 되는 경우는 드뭅니다.