๋จ์ผ ๋ธ๋ก์ ์ฌ์ฉํ ๊ธฐ๋ณธ ๋ฒ์
1D LayoutTensor a์ 1D LayoutTensor b์ 1D ํฉ์ฑ๊ณฑ์ ๊ณ์ฐํ์ฌ 1D LayoutTensor output์ ์ ์ฅํ๋ ์ปค๋์ ๊ตฌํํ์ธ์.
์ฐธ๊ณ : ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ์ค๋ ๋๋น ์ ์ญ ์ฝ๊ธฐ 2ํ, ์ ์ญ ์ฐ๊ธฐ 1ํ๋ง ํ์ํฉ๋๋ค.
ํต์ฌ ๊ฐ๋
์ด ํผ์ฆ์์ ๋ค๋ฃจ๋ ๋ด์ฉ:
- GPU์์ ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ์ฐ์ฐ ๊ตฌํํ๊ธฐ
- ์ค๋ ๋ ๊ฐ ๋ฐ์ดํฐ ์์กด์ฑ ๊ด๋ฆฌํ๊ธฐ
- ๊ฒน์น๋ ์์ญ์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ํ์ฉํ๊ธฐ
ํต์ฌ์ ๊ฒฝ๊ณ ์กฐ๊ฑด์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์งํ๋ฉด์๋ ๊ฒน์น๋ ์์์ ํจ์จ์ ์ผ๋ก ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ์ดํดํ๋ ๊ฒ์ ๋๋ค.
๊ตฌ์ฑ
- ์
๋ ฅ ๋ฐฐ์ด ํฌ๊ธฐ:
SIZE = 6 - ์ปค๋ ํฌ๊ธฐ:
CONV = 3 - ๋ธ๋ก๋น ์ค๋ ๋ ์:
TPB = 8 - ๋ธ๋ก ์: 1
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ:
SIZE์CONVํฌ๊ธฐ์ ๋ฐฐ์ด 2๊ฐ
์ฐธ๊ณ :
- ๋ฐ์ดํฐ ๋ก๋ฉ: ๊ฐ ์ค๋ ๋๊ฐ ์ ๋ ฅ ๋ฐฐ์ด๊ณผ ์ปค๋์์ ์์๋ฅผ ํ๋์ฉ ๋ก๋
- ๋ฉ๋ชจ๋ฆฌ ํจํด: ์ ๋ ฅ ๋ฐฐ์ด๊ณผ ํฉ์ฑ๊ณฑ ์ปค๋์ ์ ์ฅํ๋ ๊ณต์ ๋ฐฐ์ด
- ์ค๋ ๋ ๋๊ธฐํ: ์ฐ์ฐ ์์ ์ ์ค๋ ๋ ๊ฐ ์กฐ์จ
์์ฑํ ์ฝ๋
comptime TPB = 8
comptime SIZE = 6
comptime CONV = 3
comptime BLOCKS_PER_GRID = (1, 1)
comptime THREADS_PER_BLOCK = (TPB, 1)
comptime dtype = DType.float32
comptime in_layout = Layout.row_major(SIZE)
comptime out_layout = Layout.row_major(SIZE)
comptime conv_layout = Layout.row_major(CONV)
fn conv_1d_simple[
in_layout: Layout, out_layout: Layout, conv_layout: Layout
](
output: LayoutTensor[dtype, out_layout, MutAnyOrigin],
a: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
b: LayoutTensor[dtype, conv_layout, ImmutAnyOrigin],
):
global_i = block_dim.x * block_idx.x + thread_idx.x
local_i = Int(thread_idx.x)
# FILL ME IN (roughly 14 lines)
์ ์ฒด ํ์ผ ๋ณด๊ธฐ: problems/p13/p13.mojo
ํ
LayoutTensor[dtype, Layout.row_major(SIZE), MutAnyOrigin, address_space = AddressSpace.SHARED].stack_allocation()์ผ๋ก ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น- ์
๋ ฅ์
shared_a[local_i]์, ์ปค๋์shared_b[local_i]์ ๋ก๋ - ๋ฐ์ดํฐ ๋ก๋ ํ
barrier()ํธ์ถ - ๊ฒฝ๊ณ ์์์ ๊ณฑ์ ํฉ์ฐ:
if local_i + j < SIZE global_i < SIZE์ผ ๋๋ง ๊ฒฐ๊ณผ ๊ธฐ๋ก
์ฝ๋ ์คํ
์๋ฃจ์ ์ ํ ์คํธํ๋ ค๋ฉด ํฐ๋ฏธ๋์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ธ์:
pixi run p13 --simple
pixi run -e amd p13 --simple
pixi run -e apple p13 --simple
uv run poe p13 --simple
ํผ์ฆ์ ์์ง ํ์ง ์์๋ค๋ฉด ์ถ๋ ฅ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
out: HostBuffer([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
expected: HostBuffer([5.0, 8.0, 11.0, 14.0, 5.0, 0.0])
์๋ฃจ์
fn conv_1d_simple[
in_layout: Layout, out_layout: Layout, conv_layout: Layout
](
output: LayoutTensor[dtype, out_layout, MutAnyOrigin],
a: LayoutTensor[dtype, in_layout, ImmutAnyOrigin],
b: LayoutTensor[dtype, conv_layout, ImmutAnyOrigin],
):
global_i = block_dim.x * block_idx.x + thread_idx.x
local_i = Int(thread_idx.x)
shared_a = LayoutTensor[
dtype,
Layout.row_major(SIZE),
MutAnyOrigin,
address_space = AddressSpace.SHARED,
].stack_allocation()
shared_b = LayoutTensor[
dtype,
Layout.row_major(CONV),
MutAnyOrigin,
address_space = AddressSpace.SHARED,
].stack_allocation()
if global_i < SIZE:
shared_a[local_i] = a[global_i]
if global_i < CONV:
shared_b[local_i] = b[global_i]
barrier()
# Note: this is unsafe as it enforces no guard so could access `shared_a` beyond its bounds
# local_sum = Scalar[dtype](0)
# for j in range(CONV):
# if local_i + j < SIZE:
# local_sum += shared_a[local_i + j] * shared_b[j]
# if global_i < SIZE:
# out[global_i] = local_sum
# Safe and correct:
if global_i < SIZE:
# Note: using `var` allows us to include the type in the type inference
# `out.element_type` is available in LayoutTensor
var local_sum: output.element_type = 0
# Note: `@parameter` decorator unrolls the loop at compile time given `CONV` is a compile-time constant
# See: https://docs.modular.com/mojo/manual/decorators/parameter/#parametric-for-statement
@parameter
for j in range(CONV):
# Bonus: do we need this check for this specific example with fixed SIZE, CONV
if local_i + j < SIZE:
local_sum += shared_a[local_i + j] * shared_b[j]
output[global_i] = local_sum
๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์ฉํด ๊ฒน์น๋ ์์์ ํจ์จ์ ์ผ๋ก ์ ๊ทผํ๋ 1D ํฉ์ฑ๊ณฑ ๊ตฌํ์ ๋๋ค. ๋จ๊ณ๋ณ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค:
๋ฉ๋ชจ๋ฆฌ ๋ ์ด์์
์
๋ ฅ ๋ฐฐ์ด a: [0 1 2 3 4 5]
์ปค๋ b: [0 1 2]
์ฐ์ฐ ๊ณผ์
-
๋ฐ์ดํฐ ๋ก๋ฉ:
shared_a: [0 1 2 3 4 5] // ์ ๋ ฅ ๋ฐฐ์ด shared_b: [0 1 2] // ํฉ์ฑ๊ณฑ ์ปค๋ -
๊ฐ ์์น i์ ๋ํ ํฉ์ฑ๊ณฑ ์ฐ์ฐ:
output[0] = a[0]*b[0] + a[1]*b[1] + a[2]*b[2] = 0*0 + 1*1 + 2*2 = 5 output[1] = a[1]*b[0] + a[2]*b[1] + a[3]*b[2] = 1*0 + 2*1 + 3*2 = 8 output[2] = a[2]*b[0] + a[3]*b[1] + a[4]*b[2] = 2*0 + 3*1 + 4*2 = 11 output[3] = a[3]*b[0] + a[4]*b[1] + a[5]*b[2] = 3*0 + 4*1 + 5*2 = 14 output[4] = a[4]*b[0] + a[5]*b[1] + 0*b[2] = 4*0 + 5*1 + 0*2 = 5 output[5] = a[5]*b[0] + 0*b[1] + 0*b[2] = 5*0 + 0*1 + 0*2 = 0
๊ตฌํ ์์ธ
-
์ค๋ ๋ ์ฐธ์ฌ ๋ฒ์์ ํจ์จ์ฑ:
-
์ ์ ํ ์ค๋ ๋ ๊ฐ๋๊ฐ ์๋ ๋นํจ์จ์ ์ ๊ทผ:
# ๋นํจ์จ์ ๋ฒ์ - ๊ฒฐ๊ณผ๊ฐ ์ฌ์ฉ๋์ง ์์ ์ค๋ ๋๋ ๋ชจ๋ ์ฐ์ฐ ์ํ local_sum = Scalar[dtype](0) for j in range(CONV): if local_i + j < SIZE: local_sum += shared_a[local_i + j] * shared_b[j] # ๋ง์ง๋ง ์ฐ๊ธฐ๋ง ๊ฐ๋ if global_i < SIZE: output[global_i] = local_sum -
ํจ์จ์ ์ด๊ณ ์ฌ๋ฐ๋ฅธ ๊ตฌํ:
if global_i < SIZE: var local_sum: output.element_type = 0 # var๋ก ํ์ ์ถ๋ก ํ์ฉ @parameter # CONV๊ฐ ์์์ด๋ฏ๋ก ์ปดํ์ผ ํ์์ ๋ฃจํ ์ ๊ฐ for j in range(CONV): if local_i + j < SIZE: local_sum += shared_a[local_i + j] * shared_b[j] output[global_i] = local_sum
ํต์ฌ์ ์ธ ์ฐจ์ด๋ ๊ฐ๋์ ์์น์ ๋๋ค. ๋นํจ์จ์ ๋ฒ์ ์
global_i >= SIZE์ธ ์ค๋ ๋๋ฅผ ํฌํจํด ๋ชจ๋ ์ค๋ ๋๊ฐ ํฉ์ฑ๊ณฑ ์ฐ์ฐ์ ์ํํ ๋ค, ๋ง์ง๋ง ์ฐ๊ธฐ์์๋ง ๊ฐ๋๋ฅผ ์ ์ฉํฉ๋๋ค. ์ด๋ก ์ธํด:- ๋ถํ์ํ ์ฐ์ฐ: ์ ํจ ๋ฒ์ ๋ฐ์ ์ค๋ ๋๊ฐ ์ธ๋ชจ์๋ ์์ ์ ์ํ
- ํจ์จ ์ ํ: ์ฌ์ฉ๋์ง ์์ ์ฐ์ฐ์ ์์ ์๋น
- GPU ํ์ฉ๋ ์ ํ: ์๋ฏธ ์๋ ๊ณ์ฐ์ GPU ์ฝ์ด๋ฅผ ๋ญ๋น
ํจ์จ์ ๋ฒ์ ์ ์ ํจํ
global_i๊ฐ์ ๊ฐ์ง ์ค๋ ๋๋ง ์ฐ์ฐ์ ์ํํ๋ฏ๋ก GPU ์์์ ๋ ์ ํ์ฉํฉ๋๋ค. -
-
์ฃผ์ ๊ตฌํ ํน์ง:
var์output.element_type์ผ๋ก ์ ์ ํ ํ์ ์ถ๋ก@parameter๋ฐ์ฝ๋ ์ดํฐ๋ก ํฉ์ฑ๊ณฑ ๋ฃจํ๋ฅผ ์ปดํ์ผ ํ์์ ์ ๊ฐ- ์๊ฒฉํ ๊ฒฝ๊ณ ๊ฒ์ฌ๋ก ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ ํ๋ณด
- LayoutTensor์ ํ์ ์์คํ ์ผ๋ก ์ฝ๋ ์์ ์ฑ ํฅ์
-
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ:
- ์ ๋ ฅ ๋ฐฐ์ด๊ณผ ์ปค๋ ๋ชจ๋ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ
- ์ค๋ ๋๋น ์ ์ญ ๋ฉ๋ชจ๋ฆฌ์์ 1ํ ๋ก๋
- ๋ก๋ํ ๋ฐ์ดํฐ์ ํจ์จ์ ์ฌ์ฌ์ฉ
-
์ค๋ ๋ ์กฐ์จ:
barrier()๋ก ๋ชจ๋ ๋ฐ์ดํฐ ๋ก๋๊ฐ ๋๋ ํ ์ฐ์ฐ ์์์ ๋ณด์ฅ- ๊ฐ ์ค๋ ๋๊ฐ ์ถ๋ ฅ ์์ ํ๋๋ฅผ ๊ณ์ฐ
- ๋ณํฉ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ํจํด ์ ์ง
-
์ฑ๋ฅ ์ต์ ํ:
- ์ ์ญ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ์ต์ํ
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ก ๋น ๋ฅธ ๋ฐ์ดํฐ ์ ๊ทผ
- ๋ฉ์ธ ์ฐ์ฐ ๋ฃจํ์์ ์ค๋ ๋ ๋ถ๊ธฐ ํํผ
@parameter๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํตํ ๋ฃจํ ์ ๊ฐ