Puzzle 11: ํ๋ง
๊ฐ์
1D TileTensor a์์ ๊ฐ ์์น์ ์ง์ 3๊ฐ ๊ฐ์ ํฉ์ ๊ณ์ฐํ์ฌ 1D TileTensor
output์ ์ ์ฅํ๋ ์ปค๋์ ๊ตฌํํ์ธ์.
ํ๋ง(pooling) ์ ์ผ์ ์์ญ์ ๊ฐ๋ค์ ํ๋์ ์์ฝ ๊ฐ(์: ํฉ, ์ต๋๊ฐ, ํ๊ท )์ผ๋ก ์์ถํ๋ ์ฐ์ฐ์ ๋๋ค. ์ฌ๋ผ์ด๋ฉ ์๋์ฐ(sliding window) ๋ ์ ๋ ฅ ์๋ก ๊ณ ์ ํฌ๊ธฐ์ ์๋์ฐ๋ฅผ ํ ์นธ์ฉ ์ฎ๊ฒจ ๊ฐ๋ฉฐ ์ด ์์ถ์ ๋ฐ๋ณต ์ ์ฉํด, ์๋์ฐ ์์น๋ง๋ค ์ถ๋ ฅ๊ฐ์ ํ๋์ฉ ๋ง๋ค์ด๋ ๋๋ค. ์ฌ๊ธฐ์๋ ์๋์ฐ ํญ์ด 3์ด๊ณ ์์ฝ ํจ์๊ฐ ํฉ์ด๋ฏ๋ก, ๊ฐ ์ถ๋ ฅ ์์๋ ํ์ฌ ์์์ ๊ทธ ์ ๋ ์์์ ํฉ์ด ๋ฉ๋๋ค(์ฌ์ฉ ๊ฐ๋ฅํ ์์๊ฐ 3๊ฐ๋ณด๋ค ์ ์ ๊ฒฝ๊ณ ์ง์ ์์๋ ํน์ ์ผ์ด์ค๋ก ์ฒ๋ฆฌ).
์ฐธ๊ณ : ๊ฐ ์์น๋ง๋ค ์ค๋ ๋ 1๊ฐ๊ฐ ์์ต๋๋ค. ์ค๋ ๋๋น ์ ์ญ ์ฝ๊ธฐ 1ํ, ์ ์ญ ์ฐ๊ธฐ 1ํ๋ง ํ์ํฉ๋๋ค.
ํต์ฌ ๊ฐ๋
์ด ํผ์ฆ์์ ๋ฐฐ์ธ ๋ด์ฉ:
- TileTensor๋ก ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฐ์ฐ ๊ตฌํํ๊ธฐ
- Puzzle 8์์ ๋ค๋ฃฌ TileTensor ์ฃผ์ ๊ณต๊ฐ(address_space)์ผ๋ก ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌํ๊ธฐ
- ํจ์จ์ ์ธ ์ด์ ์ ๊ทผ ํจํด
- ๊ฒฝ๊ณ ์กฐ๊ฑด ์ฒ๋ฆฌ
ํต์ฌ์ TileTensor๊ฐ ํจ์จ์ ์ธ ์๋์ฐ ๊ธฐ๋ฐ ์ฐ์ฐ์ ์ ์งํ๋ฉด์๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๋ฅผ ๊ฐ์ํํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
๊ตฌ์ฑ
- ๋ฐฐ์ด ํฌ๊ธฐ:
SIZE = 8 - ๋ธ๋ก๋น ์ค๋ ๋ ์:
TPB = 8 - ์๋์ฐ ํฌ๊ธฐ: 3
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ:
TPB๊ฐ
์ฐธ๊ณ :
- TileTensor ํ ๋น:
stack_allocation[dtype=dtype, address_space=AddressSpace.SHARED](row_major[TPB]())์ฌ์ฉ - ์๋์ฐ ์ ๊ทผ: 3๊ฐ์ง๋ฆฌ ์๋์ฐ์ ์์ฐ์ค๋ฌ์ด ์ธ๋ฑ์ฑ
- ๊ฒฝ๊ณ ์ฒ๋ฆฌ: ์ฒ์ ๋ ์์น๋ ํน์ ์ผ์ด์ค
- ๋ฉ๋ชจ๋ฆฌ ํจํด: ์ค๋ ๋๋น ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ก๋ 1ํ
์์ฑํ ์ฝ๋
comptime TPB = 8
comptime SIZE = 8
comptime BLOCKS_PER_GRID = (1, 1)
comptime THREADS_PER_BLOCK = (TPB, 1)
comptime dtype = DType.float32
comptime layout = row_major[SIZE]()
comptime LayoutType = type_of(layout)
def pooling(
output: TileTensor[mut=True, dtype, LayoutType, MutAnyOrigin],
a: TileTensor[mut=False, dtype, LayoutType, ImmutAnyOrigin],
size: Int,
):
# Allocate shared memory using stack_allocation
var shared = stack_allocation[
dtype=dtype, address_space=AddressSpace.SHARED
](row_major[TPB]())
var global_i = block_dim.x * block_idx.x + thread_idx.x
var local_i = thread_idx.x
# FILL ME IN (roughly 10 lines)
์ ์ฒด ํ์ผ ๋ณด๊ธฐ: problems/p11/p11.mojo
ํ
- TileTensor์ ์ฃผ์ ๊ณต๊ฐ(address_space)์ผ๋ก ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ฑ
- ์์ฐ์ค๋ฌ์ด ์ธ๋ฑ์ฑ์ผ๋ก ๋ฐ์ดํฐ ๋ก๋:
shared[local_i] = a[global_i] - ์ฒ์ ๋ ์์น๋ฅผ ํน์ ์ผ์ด์ค๋ก ์ฒ๋ฆฌ
- ์๋์ฐ ์ฐ์ฐ์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ํ์ฉ
- ๊ฒฝ๊ณ ์ด๊ณผ ์ ๊ทผ์ ๊ฐ๋ ์ถ๊ฐ
์ฝ๋ ์คํ
์๋ฃจ์ ์ ํ ์คํธํ๋ ค๋ฉด ํฐ๋ฏธ๋์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ธ์:
pixi run p11
pixi run -e amd p11
pixi run -e apple p11
uv run poe p11
ํผ์ฆ์ ์์ง ํ์ง ์์๋ค๋ฉด ์ถ๋ ฅ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
out: HostBuffer([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
expected: HostBuffer([0.0, 1.0, 3.0, 6.0, 9.0, 12.0, 15.0, 18.0])
์๋ฃจ์
def pooling(
output: TileTensor[mut=True, dtype, LayoutType, MutAnyOrigin],
a: TileTensor[mut=False, dtype, LayoutType, ImmutAnyOrigin],
size: Int,
):
# Allocate shared memory using stack_allocation
var shared = stack_allocation[
dtype=dtype, address_space=AddressSpace.SHARED
](row_major[TPB]())
var global_i = block_dim.x * block_idx.x + thread_idx.x
var local_i = thread_idx.x
# Load data into shared memory
if global_i < size:
shared[local_i] = a[global_i]
# Synchronize threads within block
barrier()
# Handle first two special cases
if global_i == 0:
output[0] = shared[0]
elif global_i == 1:
output[1] = shared[0] + shared[1]
# Handle general case
elif 1 < global_i < size:
output[global_i] = (
shared[local_i - 2] + shared[local_i - 1] + shared[local_i]
)
TileTensor๋ฅผ ํ์ฉํ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ํฉ๊ณ ๊ตฌํ์ ๋๋ค. ์ฃผ์ ๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
-
๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์ค์
-
TileTensor๊ฐ ์ฃผ์ ๊ณต๊ฐ(address_space)์ผ๋ก ๋ธ๋ก ๋ก์ปฌ ์ ์ฅ์๋ฅผ ์์ฑ:
shared = stack_allocation[dtype=dtype, address_space=AddressSpace.SHARED](row_major[TPB]()) -
๊ฐ ์ค๋ ๋๊ฐ ํ๋์ฉ ๋ก๋:
Input array: [0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0] Block shared: [0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0] -
barrier()๋ก ๋ชจ๋ ๋ฐ์ดํฐ ๋ก๋ ์๋ฃ๋ฅผ ๋ณด์ฅ
-
-
๊ฒฝ๊ณ ์ผ์ด์ค
-
์์น 0: ํ๋๋ง
output[0] = shared[0] = 0.0 -
์์น 1: ์ฒ์ ๋ ๊ฐ์ ํฉ
output[1] = shared[0] + shared[1] = 0.0 + 1.0 = 1.0
-
-
๋ฉ์ธ ์๋์ฐ ์ฐ์ฐ
-
์์น 2 ์ดํ:
Position 2: shared[0] + shared[1] + shared[2] = 0.0 + 1.0 + 2.0 = 3.0 Position 3: shared[1] + shared[2] + shared[3] = 1.0 + 2.0 + 3.0 = 6.0 Position 4: shared[2] + shared[3] + shared[4] = 2.0 + 3.0 + 4.0 = 9.0 ... -
TileTensor์ ์์ฐ์ค๋ฌ์ด ์ธ๋ฑ์ฑ:
# 3๊ฐ์ง๋ฆฌ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ window_sum = shared[i-2] + shared[i-1] + shared[i]
-
๋จ์ผ ๋ธ๋ก ์ ์ : ์ด ํผ์ฆ์ด
BLOCKS_PER_GRID = (1, 1)๊ณผSIZE == TPB = 8๋ก ๊ตฌ์ฑ๋์ด ์์ด์ ๋ชจ๋ ์ค๋ ๋๊ฐ ๊ฐ์ ๋ธ๋ก์ ์ํ๊ณglobal_i == local_i๊ฐ ๋ณด์ฅ๋๊ธฐ ๋๋ฌธ์ ์ด ์๋ฃจ์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํฉ๋๋ค. ์ด ์ ์ฝ์์๋global_i > 1์ผ ๋๋ง๋คlocal_i >= 2์ด๋ฏ๋กshared[local_i - 2]์shared[local_i - 1]์ด ์ธ์ ๋ ์ ํจํฉ๋๋ค.๋ค์ค ๋ธ๋ก ์ปค๋์์๋ 0๋ฒ ๋ธ๋ก ์ดํ์ ๊ฐ ๋ธ๋ก์์ ์ฒซ ๋ ์ค๋ ๋๊ฐ
global_i > 1์ธ๋ฐ๋local_i = 0๋๋local_i = 1์ด ๋์ด ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ฒ์ ์ด๊ณผ ์ฝ๊ธฐ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ค์ค ๋ธ๋ก ํ๋ง์์ ์์ ์ ์ผ๋ก ๋์ํ๋ ํจํด์local_i๋ก ๊ฐ๋๋ฅผ ๊ฑธ๊ณ , ํค์ผ๋ก(halo) ์์์ ๋ํด์๋ ์ ์ญ ์ฝ๊ธฐ๋ก ๋์ฒดํ๋ ๊ฒ์ ๋๋ค:if local_i >= 2: output[global_i] = shared[local_i-2] + shared[local_i-1] + shared[local_i] elif local_i == 1 and global_i >= 2: output[global_i] = a[global_i-2] + shared[0] + shared[1] elif local_i == 0 and global_i >= 2: output[global_i] = a[global_i-2] + a[global_i-1] + shared[0]
- ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ํจํด
- ์ค๋ ๋๋ง๋ค ๊ณต์ ํ ์๋ก ์ ์ญ ์ฝ๊ธฐ 1ํ
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํตํ ํจ์จ์ ์ธ ์ด์ ์ ๊ทผ
- TileTensor์ ์ฅ์ :
- ์๋ ๊ฒฝ๊ณ ๊ฒ์ฌ
- ์์ฐ์ค๋ฌ์ด ์๋์ฐ ์ธ๋ฑ์ฑ
- ๋ ์ด์์์ ์ธ์ํ๋ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ
- ์ ๊ณผ์ ์ ๊ฑธ์น ํ์ ์์ ์ฑ
๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ์ฑ๋ฅ๊ณผ TileTensor์ ์์ ์ฑ ๋ฐ ํธ์์ฑ์ ๊ฒฐํฉํ ๋ฐฉ์์ ๋๋ค:
- ์ ์ญ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ์ต์ํ
- ์๋์ฐ ์ฐ์ฐ ๊ฐ์ํ
- ๊น๋ํ ๊ฒฝ๊ณ ์ฒ๋ฆฌ
- ๋ณํฉ ์ ๊ทผ ํจํด ์ ์ง
์ต์ข ์ถ๋ ฅ์ ๋์ ์๋์ฐ ํฉ๊ณ์ ๋๋ค:
[0.0, 1.0, 3.0, 6.0, 9.0, 12.0, 15.0, 18.0]