실습 · 연습문제 2개
stride로 view와 contiguous 판정하기 strides-and-views
텐서는 1차원 메모리 위에 shape과 stride(각 축으로 한 칸 갈 때 건너뛰는 원소 수)를 얹은 것이다. transpose·permute는 메모리를 옮기지 않고 stride만 바꾼다. 세 함수를 완성한다. stride는 바이트가 아니라 원소 수 단위다.
row_major_strides(shape)— 새로 만든 행 우선(C 순서) 텐서의 stride. 마지막 축의 stride는 1이고, 앞 축의 stride는 뒤 축들의 길이를 곱한 값이다. 예:(2, 3, 4)→(12, 4, 1),()→().permute_strides(shape, strides, dims)—permute(dims)결과의(shape, strides). 축의 순서만 바꾼다. 예: shape(2, 3), strides(3, 1), dims(1, 0)→((3, 2), (1, 3)).is_contiguous(shape, strides)— 이 shape·stride가 행 우선으로 빈틈없이 놓인 배치와 같은지. 길이가 1인 축의 stride는 무시한다(그 축으로는 움직일 일이 없기 때문이다). PyTorch의is_contiguous(), NumPy의flags["C_CONTIGUOUS"]와 같은 판정이다.
각 함수는 tuple을 반환한다(is_contiguous는 bool). 테스트는 NumPy 배열의 실제 stride(arr.strides를 원소 크기로 나눈 값)와 비교한다. view는 contiguous가 아닌 텐서에서 실패할 수 있고, 그때 reshape는 복사를 한다는 본문의 내용을 이 판정으로 설명할 수 있다.
broadcasting의 gradient 되돌리기 unbroadcast-grad
y = x + b에서 b의 shape이 (1, 3)이고 x가 (4, 3)이면, b는 4개 행에 복제되어 더해진다. 같은 b가 여러 번 쓰였으므로 chain rule에 따라 각 사용처의 gradient를 더해야 한다(8.4장의 +=). autograd는 이 일을 자동으로 하지만, 직접 역전파를 쓰거나 custom 연산을 만들 때는 손으로 해야 한다.
함수 unbroadcast(grad, shape)를 완성한다.
grad: broadcast된 결과(출력) 쪽 gradient. shape은 출력의 shape이다.shape: 원래 입력의 shape(tuple).- 반환:
shape모양의 gradient. 출력에서 broadcast로 늘어난 축을 모두 합해 줄인다.
NumPy broadcasting 규칙(5.3장)을 떠올린다.
- 입력의 차원 수가 적으면 앞쪽에 길이 1인 축이 붙은 것으로 본다. 이렇게 앞에 붙은 축은 합한 뒤 없앤다.
- 입력에서 길이가 1이었던 축이 출력에서 늘어났다면, 그 축을 합하되 길이 1로 남긴다(
keepdims).
grad.shape |
shape |
반환 shape |
|---|---|---|
(4, 3) |
(1, 3) |
(1, 3) |
(4, 3) |
(3,) |
(3,) |
(2, 4, 3) |
(4, 1) |
(4, 1) |
(5,) |
() (스칼라) |
() |
테스트는 위 표의 경우들과 무작위 shape에서 수치미분과 비교한다.