Altifigence Academy

18 / 24 · 개념

타일과 halo·부분합

Th=Tw=2,Tc=1,Tm=2,3×3 커널,stride 2,dilation 1입니다. int8 입력·가중치와 32비트 부분합·바이어스의 단일 버퍼 합계는 얼마인가요?

전체 텐서를 작은 묶음으로 나누기

타일링은 메모리 용량에 맞는 공간·입력 채널·출력 채널 묶음을 선택하는 방법입니다. 출력 타일의 높이 Th,너비 Tw,입력 채널 Tc,출력 채널 Tm을 정합니다. 출력 타일만큼의 입력이 필요한 것이 아니라 커널이 주변을 읽는 halo까지 필요합니다. stride S,dilation D,커널 R에 대해 입력 높이는 (Th−1)S+(R−1)D+1입니다. 너비에도 같은 식을 적용합니다. 패딩 경계의 일부는 실제 메모리 읽기 대신 0을 생성할 수 있습니다.

입력 채널을 여러 타일로 나누면 같은 출력 원소의 부분합을 계속 보존해야 합니다. 모든 입력 채널 묶음을 더하기 전에 출력으로 반올림하면 서로 다른 연산이 됩니다. 바이어스는 첫 입력 채널 타일에서 한 번 넣고 후속 타일에서는 기존 부분합을 이어 받습니다. 출력 채널 타일이 바뀌면 가중치와 바이어스도 그 채널에 맞춰 바뀝니다.

저장량 계산 예제

3×3,stride 1,dilation 1의 연산에 Th=Tw=2,Tc=2,Tm=2를 사용합니다. 입력 halo 영역은 4×4이므로 int8 입력은 2×4×4=32바이트입니다. 가중치는 2×2×3×3=36바이트입니다. 32비트 부분합 2×2×2개는 32바이트이고 32비트 바이어스 두 개는 8바이트입니다. 합계는 108바이트입니다. scale,주소,valid 비트와 기타 제어 저장은 여기서 제외했으므로 실제 설계 예산에는 별도 여유를 둬야 합니다.

입력·가중치에 각각 두 버퍼를 두어 로드와 연산을 겹치려면 2×(32+36)+32+8=176바이트입니다. 128바이트 예산에는 들어가지 않습니다. Tc를 1로 줄이면 입력 16,가중치 18바이트가 되고 이중 버퍼 합계는 2×34+32+8=108바이트입니다. 두 입력 채널 타일 동안 부분합을 유지하며 계산해야 합니다. 버퍼가 들어간다는 사실과 실제 겹침이 가능한지는 다음 단계의 전송 일정으로 따로 검증합니다.

타일 경계와 꼬리

stride를 2로 바꾸면 같은 2×2 출력 타일은 5×5 입력 범위를 필요로 합니다. dilation까지 바뀌면 범위가 또 달라집니다. 공간 타일 이웃이 halo 값을 공유하더라도 독립적으로 로드하면 중복 전송이 생깁니다. 전송량을 계산할 때 유일한 텐서 크기만 세는 최저 경계와 실제 타일 읽기 횟수를 구분해야 합니다.

전체 M=5를 Tm=2로 나누면 마지막 출력 채널 타일에는 하나만 유효합니다. 가중치와 출력 주소를 마스크로 막아 잘못된 두 번째 채널을 쓰지 않아야 합니다. 같은 검사를 Ho,Wo와 C의 마지막 타일에도 적용합니다. 전체 펼친 행렬 대신 필요한 타일을 생성하는 실제 구현의 한 예는 NVIDIA CUTLASS의 implicit GEMM 설명입니다. 이 실습은 그 CUDA 구현을 실행하는 것이 아니라 작은 타일의 저장량과 부분합을 직접 계산합니다.

직접 생각해 보기

Th=Tw=2,Tc=1,Tm=2,3×3 커널,stride 2,dilation 1입니다. int8 입력·가중치와 32비트 부분합·바이어스의 단일 버퍼 합계는 얼마인가요?

해설 보기

입력 범위는 5×5여서 25바이트입니다. 가중치 18,부분합 32,바이어스 8바이트를 더하면 83바이트입니다. 제어와 scale 저장은 별도입니다.

선택은 이 브라우저에만 적용됩니다. 언제든 푸터에서 변경할 수 있습니다.