Triton 의 표현력은 살리되, PyTorch 의 텐서 의미를 그대로 안에 끌어들여 “한 줄 한 줄을 GPU 위 어디로 보낼지” 고민할 필요 없이 짠다는 시도. Jason Ansel · Oguz Ulgen · Will Feng 이 PyTorch Labs 안에서 만든 Helion 의 위치, lowering 파이프라인, 그리고 기존 Triton 코드와 어떻게 다른지를 — 자막 없이 — 외부 자료와 도메인 지식으로 재구성한 학습 노트.
2024–2025 사이 PyTorch 진영의 큰 흐름 하나는 — 커널 작성을 사용자에게서 컴파일러에게로 다시 끌어오는 방향이다. Helion 은 그 흐름의 가장 새로운 한 점. Triton 이 “파이썬으로 GPU 커널을 짜자” 였다면, Helion 은 “PyTorch 코드처럼 보이는 커널 DSL” 이 출발점이다.
강의는 PyTorch Labs 의 세 사람 — torch.compile / Inductor 의 핵심을 짠 Jason Ansel, Triton 통합을 끌고 온 Oguz Ulgen, 그리고 Will Feng — 이 함께 발표한 형태다. 자막이 실패해 화면에서 직접 코드를 본 디테일은 잡히지 않지만, 외부에 공개된 Helion 의 설계 문서와 PyTorch 컴파일러 진영의 일관된 이야기 흐름에서 다음 세 줄을 읽어낼 수 있다.
tl.load / tl.store / BLOCK_SIZE / mask 같은 GPU-네이티브 개념을 매번 손으로 다뤄야 한다.Helion 은 이 셋 사이의 빈 자리를 메우려 한다 — “직접 커널을 짜되, PyTorch 의 의미가 그대로 살아 있고, 결국에는 Triton 으로 lowering 되어 같은 백엔드 위에서 돈다”. 새 컴파일러를 처음부터 짜는 게 아니라, Triton 위에 얹는 더 친숙한 layer 라는 위치가 핵심이다.
이 노트는 자막이 실패한 상태에서 Helion 의 공식 repo / PyTorch 블로그 / Jason Ansel 의 컨퍼런스 발표(PyTorch Conference, GTC 2025 트랙)를 종합해 재구성했다. 강의 안에서만 등장한 구체적 벤치마크 수치, 데모의 정확한 시퀀스는 확인 필요 표시로 남겨둔다.
Triton 으로 커널을 한 100번 짠 사람이라면 같은 패턴이 반복된다는 걸 안다 — pid 계산, offsets 만들기, mask 처리, BLOCK_SIZE 상수 정의. 코드의 의미는 “이 텐서의 이 슬라이스를 그 텐서의 저 슬라이스에 더한다” 인데, 표현은 그것보다 한 층 아래에 머문다.
강의에서 Helion 팀이 정리한 Triton 의 친숙한 마찰점은 — 외부 발표 자료와 합쳐 보면 — 대략 다섯 갈래로 모인다.
@triton.autotune 데코레이터에 configs 를 매번 손으로 깐다.tl.load 의 mask 와 PyTorch 의 텐서 인덱싱은 서로 다른 추상.tl.where, tl.maximum, tl.exp 가 누적되면 “이 커널이 무엇을 하는 함수인지” 가 시야에서 빨리 사라진다.Helion 팀의 진단 — “이 다섯이 매번 등장한다는 건 DSL 한 단계 더 위 에서 자동화될 수 있는 표시” 라는 것. 그래서 Helion 은 Triton 의 lowering 백엔드를 그대로 두되, 사용자에게 보이는 표면을 PyTorch 텐서 의미로 가져온다.
Helion 은 Triton 을 대체하지 않는다. 커널 컴파일러로서의 Triton 은 그대로 산다. Helion 의 출력은 Triton 코드(또는 동등한 IR)이다. 이렇게 하면 Triton 의 빠른 진화(MLIR 백엔드, 새 PTX 생성) 를 Helion 도 그대로 받는다.
Helion 의 가장 큰 차별점은 “DSL 안의 변수가 PyTorch 텐서의 의미를 따른다” 는 것. 같은 사용자가 같은 인덱싱을 두 군데서 다르게 외울 필요가 없다는 게 핵심.
# row-wise softmax (대략)
@triton.jit
def softmax_kernel(x_ptr, y_ptr, n_cols,
stride_xm, stride_ym,
BLOCK: tl.constexpr):
pid = tl.program_id(0)
cols = tl.arange(0, BLOCK)
mask = cols < n_cols
x_row = x_ptr + pid * stride_xm
x = tl.load(x_row + cols, mask=mask,
other=-float("inf"))
x_max = tl.max(x, axis=0)
x = x - x_max
e = tl.exp(x)
z = tl.sum(e, axis=0)
y = e / z
y_row = y_ptr + pid * stride_ym
tl.store(y_row + cols, y, mask=mask)
# 강의 시연을 외부 자료로 재구성 — 확인 필요
@helion.kernel
def softmax(x: Tensor) -> Tensor:
# tile 단위 loop — 행 분할은 컴파일러에게 맡김
for tile_m in hl.tile(x.size(0)):
row = x[tile_m, :] # PyTorch slice
x_max = row.amax(dim=-1, keepdim=True)
e = (row - x_max).exp()
out = e / e.sum(dim=-1, keepdim=True)
y[tile_m, :] = out
return y
두 코드가 같은 일을 한다 — 그러나 표현이 “다른 언어” 다. Helion 의 코드 안에서 row.amax(dim=-1) 는 PyTorch 의 그것과 같은 의미다. tl.max 와 의미가 다른 별도의 함수가 아니다. 컴파일러가 알아서 tile 안에서의 reduction 으로 lowering 한다.
이 디자인이 사용자에게 주는 효과는 두 가지로 정리된다.
Helion 코드가 GPU 위에서 어떻게 도는지 한 번에 그려두는 게 빠르다. 자기 컴파일러를 다시 짜는 대신, 기존 인프라(Triton, Inductor, MLIR) 를 받아쓰는 형태가 일관된다.
이 그림에서 짚어야 하는 디자인 결정 세 가지.
TORCH_LOGS=output_code 의 사상과 같다.torch.compile 의 Inductor 도 Triton 을 출력한다. 차이는 — Inductor 는 fusion-driven 자동 컴파일러(주어진 graph 를 잘게 쪼개 fused Triton 커널을 만든다)고, Helion 은 사용자가 직접 짜는 DSL(어떤 알고리즘을 어떻게 tile 할지 사용자가 결정한다). 두 도구는 같은 lowering 인프라를 공유하지만 사용자에게 보이는 추상 레이어가 다르다.
강의의 마지막 데모로 등장했을 가능성이 가장 높은 예시 — FlashAttention-스타일 의 tiled softmax + masked attention. Triton 진영의 거의 모든 새 DSL 이 이걸 첫 데모로 쓰는 이유는 — 충분히 복잡해서 표현력의 차이가 드러난다.
@triton.jit
def attn_fwd(Q, K, V, O, M, ...,
BLOCK_M: tl.constexpr,
BLOCK_N: tl.constexpr):
pid_m = tl.program_id(0)
offs_m = pid_m*BLOCK_M + tl.arange(0, BLOCK_M)
offs_n = tl.arange(0, BLOCK_N)
q = tl.load(Q + offs_m[:,None]*sQm + ...,
mask=...)
m_i = tl.full([BLOCK_M], -float("inf"))
l_i = tl.zeros([BLOCK_M])
acc = tl.zeros([BLOCK_M, D])
for start_n in range(0, N, BLOCK_N):
k = tl.load(K + ..., mask=...)
v = tl.load(V + ..., mask=...)
s = tl.dot(q, tl.trans(k))
m_new = tl.maximum(m_i, tl.max(s, axis=1))
alpha = tl.exp(m_i - m_new)
p = tl.exp(s - m_new[:,None])
l_i = l_i*alpha + tl.sum(p, axis=1)
acc = acc*alpha[:,None] + tl.dot(p, v)
m_i = m_new
o = acc / l_i[:,None]
tl.store(O + ..., o, mask=...)
@helion.kernel
def attn_fwd(Q, K, V):
O = torch.empty_like(Q)
for tile_m in hl.tile(Q.size(0)):
q = Q[tile_m, :]
m_i = torch.full([q.size(0)], -inf)
l_i = torch.zeros_like(m_i)
acc = torch.zeros_like(q)
for tile_n in hl.tile(K.size(0)):
k = K[tile_n, :]
v = V[tile_n, :]
s = q @ k.transpose(-1, -2)
# online softmax — PyTorch op 그대로
m_new = torch.maximum(m_i, s.amax(-1))
alpha = (m_i - m_new).exp()
p = (s - m_new[..., None]).exp()
l_i = l_i*alpha + p.sum(-1)
acc = acc*alpha[..., None] + p @ v
m_i = m_new
O[tile_m, :] = acc / l_i[..., None]
return O
두 코드가 의도하는 알고리즘은 같다 — online softmax 로 score matrix 를 통째로 들지 않으면서 attention 을 계산. 차이는 코드의 밀도다. Helion 쪽에서 tl.load/tl.store/mask 의 boilerplate 가 사라진 자리에 알고리즘 자체가 더 잘 보인다.
Helion 이 FlashAttention 을 자동으로 만들어주는 것이 아니다. online softmax 라는 알고리즘 아이디어 자체는 사용자가 짜야 한다. Helion 이 자동화하는 건 “이 표현을 어떤 launch shape 으로 lowering 할지” 의 영역이다. 알고리즘 디자인과 launch 디자인의 분리 — 이게 Helion 이 PyTorch 사용자에게 주는 가장 큰 인지적 단순화.
Triton 의 @triton.autotune(configs=[...]) 를 한 번이라도 손으로 깔아본 사람은 안다 — configs 가 점점 길어지고, 새 모양이 등장할 때마다 다시 손을 봐야 한다. Helion 은 이 자리를 컴파일러 안으로 끌어들인다.
Helion 의 autotune 이 다루는 변수는 대략 다섯 갈래로 정리된다.
hl.tile 의 BLOCK 크기.실전 사용에서 Helion 의 autotune 이 의미를 갖는 자리는 shape 가 데이터에 따라 달라지는 워크로드다 — variable-length attention, KV cache 의 동적 크기, batch 별 다른 hidden_dim. Triton 의 정적 configs 에서 이런 워크로드가 가장 어렵게 다뤄지던 자리.
autotune 결과는 컴파일된 Triton 코드와 함께 cache 된다. 첫 호출에서만 search 가 돌고, 같은 (shape, dtype, hardware) 키에 대해서는 즉시 캐시된 변형이 쓰인다. ~/.cache/helion/ 같은 위치 — 확인 필요.
L001 의 의사결정 사다리(torch → Triton → CUDA) 에 한 칸이 추가된다 — torch → Helion → Triton → CUDA. 각 칸의 trigger 가 무엇인지 정리.
강의에서 팀이 명시적으로 강조한 입장 — “Helion 은 Triton 을 안 짜기 위해서가 아니라, Triton 을 더 잘 짤 수 있는 자리를 분명히 하기 위해서다”. 확인 필요 — 실제 발화는 자막이 없어 정확하지 않지만, 팀의 외부 발표에서 일관되게 등장하는 입장.
새 DSL 의 미래는 사용자 수가 결정한다. Helion 의 초기 채택 자리는 — 외부 자료에서 확인 가능한 한도 안에서 — 두 곳으로 모인다.
이 노트는 2025–2026 사이의 외부 자료를 기준으로 한다. Helion 이 정식 release 됐는지, 어디까지 PyTorch 본체에 머지됐는지는 시점에 민감 — 직접 github.com/pytorch-labs/helion 의 README 와 PyTorch 블로그 최신 글을 확인할 것.
실용적 관점 — 새 사용자가 Helion 을 처음 만질 때의 진입점은 같은 함수를 PyTorch eager / torch.compile / Helion 세 가지로 짜고 timing 비교다. 커널 작성 학습 곡선의 처음을 그래프 한 장으로 바로 잡을 수 있는 비교.
강의의 Q&A 에서 등장했을 법한 — 그리고 외부 자료에서 추정 가능한 — 향후 방향을 묶어둔다.
tl.load/tl.store boilerplate 사라짐.torch.compile ③ Helion 으로 짜고, 각 GPU 시간을 측정. torch.cuda.Event + warmup 5회 + sync 의 L001 패턴 그대로.HELION_LOGS 같은 환경변수 — 확인 필요.이 노트의 모든 코드 예시는 외부 자료와 도메인 지식 기반으로 개념적으로 재구성한 형태다. 정확한 API 이름(hl.tile, @helion.kernel) 은 repo 가 공개되면 바로 정정 필요. 강의에서 발표자가 라이브로 짠 코드와 차이가 있을 수 있다.